View Javadoc

1   /*
2    * Copyright (c) 2002-2012, the original author or authors.
3    *
4    * This software is distributable under the BSD license. See the terms of the
5    * BSD license in the documentation provided with this software.
6    *
7    * http://www.opensource.org/licenses/bsd-license.php
8    */
9   package jline.internal;
10  
11  import java.io.BufferedInputStream;
12  import java.io.File;
13  import java.io.IOException;
14  import java.io.InputStream;
15  import java.net.URL;
16  import java.nio.charset.Charset;
17  import java.util.Map;
18  import java.util.Properties;
19  
20  import static jline.internal.Preconditions.checkNotNull;
21  
22  /**
23   * Provides access to configuration values.
24   *
25   * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
26   * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
27   * @since 2.4
28   */
29  public class Configuration
30  {
31      /**
32       * System property which can point to a file or URL containing configuration properties to load.
33       *
34       * @since 2.7
35       */
36      public static final String JLINE_CONFIGURATION = "jline.configuration";
37  
38      /**
39       * Default configuration file name loaded from user's home directory.
40       */
41      public static final String JLINE_RC = ".jline.rc";
42  
43      private static volatile Properties properties;
44  
45      private static Properties initProperties() {
46          URL url = determineUrl();
47          Properties props = new Properties();
48          try {
49              loadProperties(url, props);
50          }
51          catch (IOException e) {
52              // debug here instead of warn, as this can happen normally if default jline.rc file is missing
53              Log.debug("Unable to read configuration from: ", url, e);
54          }
55          return props;
56      }
57  
58      private static void loadProperties(final URL url, final Properties props) throws IOException {
59          Log.debug("Loading properties from: ", url);
60          InputStream input = url.openStream();
61          try {
62              props.load(new BufferedInputStream(input));
63          }
64          finally {
65              try {
66                  input.close();
67              }
68              catch (IOException e) {
69                  // ignore
70              }
71          }
72  
73          if (Log.DEBUG) {
74              Log.debug("Loaded properties:");
75              for (Map.Entry<Object,Object> entry : props.entrySet()) {
76                  Log.debug("  ", entry.getKey(), "=", entry.getValue());
77              }
78          }
79      }
80  
81      private static URL determineUrl() {
82          // See if user has customized the configuration location via sysprop
83          String tmp = System.getProperty(JLINE_CONFIGURATION);
84          if (tmp != null) {
85              return Urls.create(tmp);
86          }
87          else {
88              // Otherwise try the default
89              File file = new File(getUserHome(), JLINE_RC);
90              return Urls.create(file);
91          }
92      }
93  
94      /**
95       * @since 2.7
96       */
97      public static void reset() {
98          Log.debug("Resetting");
99          properties = null;
100 
101         // force new properties to load
102         getProperties();
103     }
104 
105     /**
106      * @since 2.7
107      */
108     public static Properties getProperties() {
109         // Not sure its worth to guard this with any synchronization, volatile field probably sufficient
110         if (properties == null) {
111             properties = initProperties();
112         }
113         return properties;
114     }
115 
116     public static String getString(final String name, final String defaultValue) {
117         checkNotNull(name);
118 
119         String value;
120 
121         // Check sysprops first, it always wins
122         value = System.getProperty(name);
123 
124         if (value == null) {
125             // Next try userprops
126             value = getProperties().getProperty(name);
127 
128             if (value == null) {
129                 // else use the default
130                 value = defaultValue;
131             }
132         }
133 
134         return value;
135     }
136 
137     public static String getString(final String name) {
138         return getString(name, null);
139     }
140 
141     public static boolean getBoolean(final String name, final boolean defaultValue) {
142         String value = getString(name);
143         if (value == null) {
144             return defaultValue;
145         }
146         return value.length() == 0
147             || value.equalsIgnoreCase("1")
148             || value.equalsIgnoreCase("on")
149             || value.equalsIgnoreCase("true");
150     }
151 
152     /**
153      * @since 2.6
154      */
155     public static int getInteger(final String name, final int defaultValue) {
156         String str = getString(name);
157         if (str == null) {
158             return defaultValue;
159         }
160         return Integer.parseInt(str);
161     }
162 
163     /**
164      * @since 2.6
165      */
166     public static long getLong(final String name, final long defaultValue) {
167         String str = getString(name);
168         if (str == null) {
169             return defaultValue;
170         }
171         return Long.parseLong(str);
172     }
173 
174     //
175     // System property helpers
176     //
177 
178     /**
179      * @since 2.7
180      */
181     public static String getLineSeparator() {
182         return System.getProperty("line.separator");
183     }
184 
185     public static File getUserHome() {
186         return new File(System.getProperty("user.home"));
187     }
188 
189     public static String getOsName() {
190         return System.getProperty("os.name").toLowerCase();
191     }
192 
193     /**
194      * @since 2.7
195      */
196     public static boolean isWindows() {
197         return getOsName().startsWith("windows");
198     }
199 
200     // FIXME: Sort out use of property access of file.encoding in InputStreamReader, consolidate should configuration access here
201 
202     public static String getFileEncoding() {
203         return System.getProperty("file.encoding");
204     }
205 
206     /**
207      * Get the default encoding.  Will first look at the LC_CTYPE environment variable, then the input.encoding
208      * system property, then the default charset according to the JVM.
209      *
210      * @return The default encoding to use when none is specified.
211      */
212     public static String getEncoding() {
213         // LC_CTYPE is usually in the form en_US.UTF-8
214         String envEncoding = extractEncodingFromCtype(System.getenv("LC_CTYPE"));
215         if (envEncoding != null) {
216             return envEncoding;
217         }
218         return System.getProperty("input.encoding", Charset.defaultCharset().name());
219     }
220 
221     /**
222      * Parses the LC_CTYPE value to extract the encoding according to the POSIX standard, which says that the LC_CTYPE
223      * environment variable may be of the format <code>[language[_territory][.codeset][@modifier]]</code>
224      *
225      * @param ctype The ctype to parse, may be null
226      * @return The encoding, if one was present, otherwise null
227      */
228     static String extractEncodingFromCtype(String ctype) {
229         if (ctype != null && ctype.indexOf('.') > 0) {
230             String encodingAndModifier = ctype.substring(ctype.indexOf('.') + 1);
231             if (encodingAndModifier.indexOf('@') > 0) {
232                 return encodingAndModifier.substring(0, encodingAndModifier.indexOf('@'));
233             } else {
234                 return encodingAndModifier;
235             }
236         }
237         return null;
238     }
239 }