View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  package org.waarp.common.utility;
21  
22  import org.waarp.common.exception.InvalidArgumentException;
23  import org.waarp.common.logging.SysErrLogger;
24  
25  import java.io.PrintStream;
26  import java.lang.reflect.Field;
27  import java.nio.charset.Charset;
28  import java.util.Properties;
29  
30  import static org.waarp.common.digest.WaarpBC.*;
31  
32  /**
33   * A collection of utility methods to retrieve and parse the values of the Java
34   * system properties.
35   */
36  public final class SystemPropertyUtil {
37    // Since logger could be not available yet, one must not declare there a Logger
38  
39    private static final String USING_THE_DEFAULT_VALUE2 =
40        "using the default value: ";
41    private static final String FIND_0_9 = "-?[0-9]+";
42    private static final String USING_THE_DEFAULT_VALUE =
43        USING_THE_DEFAULT_VALUE2;
44    public static final String FILE_ENCODING = "file.encoding";
45    /**
46     * Maximum Connections to the Database. Waarp will manage by default up
47     * to 10 connections, except if this is set. The minimum value is 2.
48     */
49    public static final String WAARP_DATABASE_CONNECTION_MAX =
50        "waarp.database.connection.max";
51    private static final String IO_NETTY_ALLOCATOR_TYPE =
52        "io.netty.allocator.type";
53    private static final String IO_POOLED = "pooled";
54    private static final String IO_NETTY_NOPREFERDIRECT =
55        "io.netty.noPreferDirect";
56    /**
57     * Recommended value is 0. Giving too small valud (>0) coud cause issues.
58     * Value of -1 is default behavior of Netty.
59     * Value of 0 allows Netty to allocate more memory but still
60     * stable.
61     * If <0, means Netty use twice Direct memory from JDK and don't use cleaner.
62     * If 0, means Netty use the max JDK Direct ram and use Cleaner (recommended).
63     * If >0, means Netty use this max Direct, not related to max of JDK, and
64     * don't use cleaner.
65     */
66    private static final String IO_NETTY_MAXDIRECTMEMORY =
67        "io.netty.maxDirectMemory";
68  
69    private static final Properties PROPS = new Properties();
70    private static final String INVALID_PROPERTY = "Invalid property ";
71    public static final String JAVAX_XML_TRANSFORM_TRANSFORMER_FACTORY =
72        "javax.xml.transform.TransformerFactory";
73    public static final String NET_SF_SAXON_TRANSFORMER_FACTORY_IMPL =
74        "net.sf.saxon.TransformerFactoryImpl";
75    private static Platform mOs;
76  
77    // Retrieve all system properties at once so that there's no need to deal with
78    // security exceptions from next time. Otherwise, we might end up with logging every
79    // security exceptions on every system property access or introducing more complexity
80    // just because of less verbose logging.
81    static {
82      refresh();
83      initializedTlsContext();
84    }
85  
86    /**
87     * Re-retrieves all system properties so that any post-launch properties
88     * updates are retrieved.
89     */
90    public static void refresh() {
91      Properties newProps;
92      try {
93        newProps = System.getProperties();
94      } catch (final SecurityException e) {
95        SysErrLogger.FAKE_LOGGER.ignoreLog(e);
96        SysErrLogger.FAKE_LOGGER.syserr(
97            "Unable to retrieve the system properties; default values will be used: " +
98            e.getMessage());
99        newProps = new Properties();
100     }
101 
102     synchronized (PROPS) {
103       PROPS.clear();
104       PROPS.putAll(newProps);
105     }
106     // Ensure Pooled allocator except if something different set
107     if (!contains(IO_NETTY_ALLOCATOR_TYPE) ||
108         ParametersChecker.isEmpty(get(IO_NETTY_ALLOCATOR_TYPE))) {
109       try {
110         System.setProperty(IO_NETTY_ALLOCATOR_TYPE, IO_POOLED);
111         synchronized (PROPS) {
112           PROPS.clear();
113           PROPS.putAll(newProps);
114         }
115         SysErrLogger.FAKE_LOGGER.sysout(IO_NETTY_ALLOCATOR_TYPE + ":" +
116                                         io.netty.util.internal.SystemPropertyUtil.get(
117                                             IO_NETTY_ALLOCATOR_TYPE));
118       } catch (final Throwable ignored) {//NOSONAR
119         SysErrLogger.FAKE_LOGGER.ignoreLog(ignored);
120       }
121     }
122     // Ensure minimize DIRECT except if something different set
123     if (!contains(IO_NETTY_NOPREFERDIRECT) ||
124         ParametersChecker.isEmpty(get(IO_NETTY_NOPREFERDIRECT))) {
125       try {
126         System.setProperty(IO_NETTY_NOPREFERDIRECT, "true");
127         synchronized (PROPS) {
128           PROPS.clear();
129           PROPS.putAll(newProps);
130         }
131         SysErrLogger.FAKE_LOGGER.sysout(IO_NETTY_NOPREFERDIRECT + ":" +
132                                         io.netty.util.internal.SystemPropertyUtil.get(
133                                             IO_NETTY_NOPREFERDIRECT));
134       } catch (final Throwable ignored) {//NOSONAR
135         SysErrLogger.FAKE_LOGGER.ignoreLog(ignored);
136       }
137     }
138     // Ensure minimize Direct except if something different set
139     if (!contains(IO_NETTY_MAXDIRECTMEMORY) ||
140         ParametersChecker.isEmpty(get(IO_NETTY_MAXDIRECTMEMORY))) {
141       try {
142         System.setProperty(IO_NETTY_MAXDIRECTMEMORY, "0");
143         synchronized (PROPS) {
144           PROPS.clear();
145           PROPS.putAll(newProps);
146         }
147         SysErrLogger.FAKE_LOGGER.sysout(IO_NETTY_MAXDIRECTMEMORY + ":" +
148                                         io.netty.util.internal.SystemPropertyUtil.get(
149                                             IO_NETTY_MAXDIRECTMEMORY));
150       } catch (final Throwable ignored) {//NOSONAR
151         SysErrLogger.FAKE_LOGGER.ignoreLog(ignored);
152       }
153     }
154     if (!contains(JAVAX_XML_TRANSFORM_TRANSFORMER_FACTORY) ||
155         ParametersChecker.isEmpty(
156             get(JAVAX_XML_TRANSFORM_TRANSFORMER_FACTORY))) {
157       try {
158         System.setProperty(JAVAX_XML_TRANSFORM_TRANSFORMER_FACTORY,
159                            NET_SF_SAXON_TRANSFORMER_FACTORY_IMPL);
160         synchronized (PROPS) {
161           PROPS.clear();
162           PROPS.putAll(newProps);
163         }
164       } catch (final Throwable ignored) {//NOSONAR
165         SysErrLogger.FAKE_LOGGER.ignoreLog(ignored);
166       }
167     }
168     if (!contains(FILE_ENCODING) ||
169         !WaarpStringUtils.UTF_8.equalsIgnoreCase(get(FILE_ENCODING))) {
170       try {
171         System.setProperty(FILE_ENCODING, WaarpStringUtils.UTF_8);
172         try {
173           final Field charset =
174               Charset.class.getDeclaredField("defaultCharset");
175           charset.setAccessible(true); //NOSONAR
176           charset.set(null, null); //NOSONAR
177         } catch (final Throwable e) {//NOSONAR
178           SysErrLogger.FAKE_LOGGER.ignoreLog(e);
179         }
180         synchronized (PROPS) {
181           PROPS.clear();
182           PROPS.putAll(newProps);
183         }
184       } catch (final Throwable e1) {//NOSONAR
185         // ignore since it is a security issue and -Dfile.encoding=UTF-8 should be used
186         SysErrLogger.FAKE_LOGGER.ignoreLog(e1);
187         SysErrLogger.FAKE_LOGGER.syserr(
188             "Issue while trying to set UTF-8 as default file encoding: use -Dfile.encoding=UTF-8 as java command argument: " +
189             e1.getMessage());
190         SysErrLogger.FAKE_LOGGER.syserr(
191             "Currently file.encoding is: " + get(FILE_ENCODING));
192       }
193     }
194   }
195 
196   /**
197    * @return True if Encoding is Correct
198    */
199   public static boolean isFileEncodingCorrect() {
200     return contains(FILE_ENCODING) &&
201            WaarpStringUtils.UTF_8.equalsIgnoreCase(get(FILE_ENCODING));
202   }
203 
204   /**
205    * Returns {@code true} if and only if the system property with the
206    * specified
207    * {@code key} exists.
208    */
209   public static boolean contains(final String key) {
210     ParametersChecker.checkParameter("Key", key);
211     return PROPS.containsKey(key);
212   }
213 
214   /**
215    * Returns the value of the Java system property with the specified {@code
216    * key}, while falling back to
217    * {@code null} if the property access fails.
218    *
219    * @return the property value or {@code null}
220    */
221   public static String get(final String key) {
222     return get(key, null);
223   }
224 
225   /**
226    * Returns the value of the Java system property with the specified {@code
227    * key}, while falling back to the specified
228    * default value if the property access fails.
229    *
230    * @param key of system property
231    * @param def the default value
232    *
233    * @return the property value. {@code def} if there's no such property or if
234    *     an access to the specified property is
235    *     not allowed.
236    *
237    * @throws IllegalArgumentException key null
238    */
239   public static String get(final String key, final String def) {
240     ParametersChecker.checkParameter("Key", key);
241     String value = PROPS.getProperty(key);
242     if (value == null) {
243       return def;
244     }
245 
246     try {
247       value = ParametersChecker.checkSanityString(value);
248     } catch (final InvalidArgumentException e) {
249       SysErrLogger.FAKE_LOGGER.syserr(INVALID_PROPERTY + key, e);
250       return def;
251     }
252 
253     return value;
254   }
255 
256   /**
257    * Returns the value of the Java system property with the specified {@code
258    * key}, while falling back to the specified
259    * default value if the property access fails.
260    *
261    * @param key of system property
262    * @param def the default value
263    *
264    * @return the property value. {@code def} if there's no such property or if
265    *     an access to the specified property is
266    *     not allowed.
267    *
268    * @throws IllegalArgumentException key null
269    */
270   public static boolean get(final String key, final boolean def) {
271     ParametersChecker.checkParameter("Key", key);
272     String value = PROPS.getProperty(key);
273     if (value == null) {
274       return def;
275     }
276 
277     value = value.trim().toLowerCase();
278     if (value.isEmpty()) {
279       return true;
280     }
281 
282     if ("true".equals(value) || "yes".equals(value) || "1".equals(value)) {
283       return true;
284     }
285 
286     if ("false".equals(value) || "no".equals(value) || "0".equals(value)) {
287       return false;
288     }
289     try {
290       ParametersChecker.checkSanityString(value);
291     } catch (final InvalidArgumentException e) {
292       SysErrLogger.FAKE_LOGGER.syserr(INVALID_PROPERTY + key, e);
293       return def;
294     }
295     SysErrLogger.FAKE_LOGGER.syserr(
296         "Unable to parse the boolean system property '" + key + "':" + value +
297         " - " + USING_THE_DEFAULT_VALUE + def);
298 
299     return def;
300   }
301 
302   /**
303    * Returns the value of the Java system property with the specified {@code
304    * key}, while falling back to the specified
305    * default value if the property access fails.
306    *
307    * @param key the system property
308    * @param def the default value
309    *
310    * @return the property value. {@code def} if there's no such property or if
311    *     an access to the specified property is
312    *     not allowed.
313    *
314    * @throws IllegalArgumentException key null
315    */
316   public static int get(final String key, final int def) {
317     ParametersChecker.checkParameter("Key", key);
318     String value = PROPS.getProperty(key);
319     if (value == null) {
320       return def;
321     }
322 
323     value = value.trim().toLowerCase();
324     if (value.matches(FIND_0_9)) {
325       try {
326         return Integer.parseInt(value);
327       } catch (final Exception ignored) {
328         // Since logger could be not available yet
329         // Ignore
330         SysErrLogger.FAKE_LOGGER.ignoreLog(ignored);
331       }
332     }
333     try {
334       ParametersChecker.checkSanityString(value);
335     } catch (final InvalidArgumentException e) {
336       SysErrLogger.FAKE_LOGGER.syserr(INVALID_PROPERTY + key, e);
337       return def;
338     }
339     SysErrLogger.FAKE_LOGGER.syserr(
340         "Unable to parse the integer system property '" + key + "':" + value +
341         " - " + USING_THE_DEFAULT_VALUE + def);
342 
343     return def;
344   }
345 
346   /**
347    * Returns the value of the Java system property with the specified {@code
348    * key}, while falling back to the specified
349    * default value if the property access fails.
350    *
351    * @param key of system property
352    * @param def the default value
353    *
354    * @return the property value. {@code def} if there's no such property or if
355    *     an access to the specified property is
356    *     not allowed.
357    *
358    * @throws IllegalArgumentException key null
359    */
360   public static long get(final String key, final long def) {
361     ParametersChecker.checkParameter("Key", key);
362     String value = PROPS.getProperty(key);
363     if (value == null) {
364       return def;
365     }
366 
367     value = value.trim().toLowerCase();
368     if (value.matches(FIND_0_9)) {
369       try {
370         return Long.parseLong(value);
371       } catch (final Exception ignored) {
372         // Since logger could be not available yet
373         // Ignore
374         SysErrLogger.FAKE_LOGGER.ignoreLog(ignored);
375       }
376     }
377     try {
378       ParametersChecker.checkSanityString(value);
379     } catch (final InvalidArgumentException e) {
380       SysErrLogger.FAKE_LOGGER.syserr(INVALID_PROPERTY + key, e);
381       return def;
382     }
383 
384     SysErrLogger.FAKE_LOGGER.syserr(
385         "Unable to parse the long integer system property '" + key + "':" +
386         value + " - " + USING_THE_DEFAULT_VALUE + def);
387 
388     return def;
389   }
390 
391   /**
392    * Returns the value of the Java system property with the specified {@code
393    * key}, while falling back to the
394    * specified default value if the property access fails.
395    *
396    * @return the property value. {@code def} if there's no such property or if
397    *     an access to the specified
398    *     property is not allowed.
399    */
400   public static boolean getBoolean(final String key, final boolean def) {
401     ParametersChecker.checkParameter("Key", key);
402 
403     String value = PROPS.getProperty(key);
404     if (value == null) {
405       return def;
406     }
407 
408     value = value.trim().toLowerCase();
409     if (value.isEmpty()) {
410       return true;
411     }
412 
413     if ("true".equals(value) || "yes".equals(value) || "1".equals(value)) {
414       return true;
415     }
416 
417     if ("false".equals(value) || "no".equals(value) || "0".equals(value)) {
418       return false;
419     }
420 
421     SysErrLogger.FAKE_LOGGER.syserr(
422         "Unable to parse the boolean system property '" + key + "':" + value +
423         " - " + USING_THE_DEFAULT_VALUE2 + def);
424 
425     return def;
426   }
427 
428   /**
429    * Returns the value of the Java system property with the specified {@code
430    * key}, while falling back to the
431    * specified default value if the property access fails.
432    *
433    * @return the property value. {@code def} if there's no such property or if
434    *     an access to the specified
435    *     property is not allowed.
436    */
437   public static int getInt(final String key, final int def) {
438     ParametersChecker.checkParameter("Key", key);
439 
440     String value = PROPS.getProperty(key);
441     if (value == null) {
442       return def;
443     }
444 
445     value = value.trim().toLowerCase();
446     if (value.matches(FIND_0_9)) {
447       try {
448         return Integer.parseInt(value);
449       } catch (final Exception e) {
450         // Ignore
451       }
452     }
453 
454     SysErrLogger.FAKE_LOGGER.syserr(
455         "Unable to parse the integer system property '" + key + "':" + value +
456         " - " + USING_THE_DEFAULT_VALUE2 + def);
457 
458     return def;
459   }
460 
461   /**
462    * Returns the value of the Java system property with the specified {@code
463    * key}, while falling back to the
464    * specified default value if the property access fails.
465    *
466    * @return the property value. {@code def} if there's no such property or if
467    *     an access to the specified
468    *     property is not allowed.
469    */
470   public static long getLong(final String key, final long def) {
471     ParametersChecker.checkParameter("Key", key);
472 
473     String value = PROPS.getProperty(key);
474     if (value == null) {
475       return def;
476     }
477 
478     value = value.trim().toLowerCase();
479     if (value.matches(FIND_0_9)) {
480       try {
481         return Long.parseLong(value);
482       } catch (final Exception e) {
483         // Ignore
484       }
485     }
486 
487     SysErrLogger.FAKE_LOGGER.syserr(
488         "Unable to parse the long integer system property '" + key + "':" +
489         value + " - " + USING_THE_DEFAULT_VALUE2 + def);
490 
491     return def;
492   }
493 
494   /**
495    * Returns the value of the Java system property with the specified {@code
496    * key}, while falling back to the specified
497    * default value if the property access fails.
498    *
499    * @param key of system property
500    * @param def the default value
501    *
502    * @return the property value. {@code def} if there's no such property or if
503    *     an access to the specified property is
504    *     not allowed.
505    *
506    * @throws IllegalArgumentException key or def null
507    */
508   public static String getAndSet(final String key, final String def) {
509     ParametersChecker.checkParameter("Key", key);
510     if (def == null) {
511       throw new IllegalArgumentException("Def cannot be null");
512     }
513     if (!PROPS.containsKey(key)) {
514       System.setProperty(key, def);
515       refresh();
516       return def;
517     }
518     return PROPS.getProperty(key);
519   }
520 
521   /**
522    * Returns the value of the Java system property with the specified {@code
523    * key}, while falling back to the specified
524    * default value if the property access fails.
525    *
526    * @param key of system property
527    * @param def the default value
528    *
529    * @return the property value. {@code def} if there's no such property or if
530    *     an access to the specified property is
531    *     not allowed.
532    *
533    * @throws IllegalArgumentException key null
534    */
535   public static boolean getAndSet(final String key, final boolean def) {
536     ParametersChecker.checkParameter("Key", key);
537     if (!PROPS.containsKey(key)) {
538       System.setProperty(key, Boolean.toString(def));
539       refresh();
540       return def;
541     }
542     return get(key, def);
543   }
544 
545   /**
546    * Returns the value of the Java system property with the specified {@code
547    * key}, while falling back to the specified
548    * default value if the property access fails.
549    *
550    * @param key of system property
551    * @param def the default value
552    *
553    * @return the property value. {@code def} if there's no such property or if
554    *     an access to the specified property is
555    *     not allowed.
556    *
557    * @throws IllegalArgumentException key null
558    */
559   public static int getAndSet(final String key, final int def) {
560     ParametersChecker.checkParameter("Key", key);
561     if (!PROPS.containsKey(key)) {
562       System.setProperty(key, Integer.toString(def));
563       refresh();
564       return def;
565     }
566     return get(key, def);
567   }
568 
569   /**
570    * Returns the value of the Java system property with the specified {@code
571    * key}, while falling back to the specified
572    * default value if the property access fails.
573    *
574    * @param key of system property
575    * @param def the default value
576    *
577    * @return the property value. {@code def} if there's no such property or if
578    *     an access to the specified property is
579    *     not allowed.
580    *
581    * @throws IllegalArgumentException key null
582    */
583   public static long getAndSet(final String key, final long def) {
584     ParametersChecker.checkParameter("Key", key);
585     if (!PROPS.containsKey(key)) {
586       System.setProperty(key, Long.toString(def));
587       refresh();
588       return def;
589     }
590     return get(key, def);
591   }
592 
593   /**
594    * Set the value of the Java system property with the specified {@code key}
595    * to the specified default value.
596    *
597    * @param key of system property
598    * @param def the default value
599    *
600    * @return the ancient value.
601    *
602    * @throws IllegalArgumentException key or def null
603    */
604   public static String set(final String key, final String def) {
605     ParametersChecker.checkParameter("Key", key);
606     if (def == null) {
607       throw new IllegalArgumentException("Def cannot be null");
608     }
609     String old = null;
610     if (PROPS.containsKey(key)) {
611       old = PROPS.getProperty(key);
612     }
613     System.setProperty(key, def);
614     refresh();
615     return old;
616   }
617 
618   /**
619    * Set the value of the Java system property with the specified {@code key}
620    * to the specified default value.
621    *
622    * @param key of system property
623    * @param def the default value
624    *
625    * @return the ancient value.
626    *
627    * @throws IllegalArgumentException key null
628    */
629   public static boolean set(final String key, final boolean def) {
630     ParametersChecker.checkParameter("Key", key);
631     boolean old = false;
632     if (PROPS.containsKey(key)) {
633       old = get(key, def);
634     }
635     System.setProperty(key, Boolean.toString(def));
636     refresh();
637     return old;
638   }
639 
640   /**
641    * Set the value of the Java system property with the specified {@code key}
642    * to the specified default value.
643    *
644    * @param key of system property
645    * @param def the default value
646    *
647    * @return the ancient value.
648    *
649    * @throws IllegalArgumentException key null
650    */
651   public static int set(final String key, final int def) {
652     ParametersChecker.checkParameter("Key", key);
653     int old = 0;
654     if (PROPS.containsKey(key)) {
655       old = get(key, def);
656     }
657     System.setProperty(key, Integer.toString(def));
658     refresh();
659     return old;
660   }
661 
662   /**
663    * Set the value of the Java system property with the specified {@code key}
664    * to the specified default value.
665    *
666    * @param key of system property
667    * @param def the default value
668    *
669    * @return the ancient value.
670    *
671    * @throws IllegalArgumentException key null
672    */
673   public static long set(final String key, final long def) {
674     ParametersChecker.checkParameter("Key", key);
675     long old = 0;
676     if (PROPS.containsKey(key)) {
677       old = get(key, def);
678     }
679     System.setProperty(key, Long.toString(def));
680     refresh();
681     return old;
682   }
683 
684   /**
685    * Remove the key of the Java system property with the specified {@code
686    * key}.
687    *
688    * @param key of system property
689    *
690    * @throws IllegalArgumentException key null
691    */
692   public static void clear(final String key) {
693     ParametersChecker.checkParameter("Key", key);
694     PROPS.remove(key);
695     System.clearProperty(key);
696     refresh();
697   }
698 
699   /**
700    * Print to System.out the content of the properties
701    *
702    * @param out the output stream to be used
703    *
704    * @throws IllegalArgumentException out null
705    */
706   public static void debug(final PrintStream out) {
707     ParametersChecker.checkParameter("Out", out);
708     PROPS.list(out);
709   }
710 
711   /**
712    * Inspired from http://commons.apache.org/lang/api-2.4/org/apache/commons/lang/
713    * SystemUtils.html
714    */
715   public enum Platform {
716     /**
717      * Windows
718      */
719     WINDOWS,
720     /**
721      * Mac
722      */
723     MAC,
724     /**
725      * Unix
726      */
727     UNIX,
728     /**
729      * Solaris
730      */
731     SOLARIS,
732     /**
733      * Unsupported
734      */
735     UNSUPPORTED
736   }
737 
738   /**
739    * @return the Platform
740    */
741   public static Platform getOS() {
742     if (mOs == null) {
743       mOs = Platform.UNSUPPORTED;
744       String os = "";
745       try {
746         os = System.getProperty("os.name").toLowerCase();
747       } catch (final Exception ignored) {
748         // ignore
749         SysErrLogger.FAKE_LOGGER.ignoreLog(ignored);
750       }
751       if (os.contains("win")) {
752         mOs = Platform.WINDOWS;
753         // Windows
754       }
755       if (os.contains("mac")) {
756         mOs = Platform.MAC;
757         // Mac
758       }
759       if (os.contains("nux")) {
760         mOs = Platform.UNIX;
761         // Linux
762       }
763       if (os.contains("nix")) {
764         mOs = Platform.UNIX;
765         // Unix
766       }
767       if (os.contains("sunos")) {
768         mOs = Platform.SOLARIS;
769         // Solaris
770       }
771     }
772     return mOs;
773   }
774 
775   /**
776    * @return True if Windows
777    */
778   public static boolean isWindows() {
779     return getOS() == Platform.WINDOWS;
780   }
781 
782   /**
783    * @return True if Mac
784    */
785   public static boolean isMac() {
786     return getOS() == Platform.MAC;
787   }
788 
789   /**
790    * @return True if Unix
791    */
792   public static boolean isUnix() {
793     return getOS() == Platform.UNIX;
794   }
795 
796   /**
797    * @return True if Solaris
798    */
799   public static boolean isSolaris() {
800     return getOS() == Platform.SOLARIS;
801   }
802 
803   public static void debug() {
804     PROPS.list(System.out);//NOSONAR
805   }
806 
807   private SystemPropertyUtil() {
808     // Unused
809   }
810 }