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