/Users/lyon/j4p/src/classUtils/pack/util/EnvironmentVariables.java
|
1 package classUtils.pack.util;
2
3 import java.io.BufferedReader;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.io.StringReader;
7 import java.io.StringWriter;
8 import java.text.CharacterIterator;
9 import java.text.StringCharacterIterator;
10 import java.util.ArrayList;
11 import java.util.HashMap;
12 import java.util.HashSet;
13 import java.util.Iterator;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Properties;
17 import java.util.Set;
18
19 /**
20 * An helper class to handle environment variables when they're present on
21 * the underlying operating system.
22 * So far, the only supported operating system is Windows 2000 - but the
23 * underlying mechanism (based on running a 'set' command on the system
24 * shell) is easly usable for different o/s.
25 * <p>
26 * In order to add support for one OS, add the identification string and
27 * the associated shell command in the private <b>getGenerator()</b> method,
28 * and check that the parsing code in setBasedGenerator.getEnvironment() is
29 * correct for parsing the result.
30 * <p>
31 * A typical usage consists in just invoking
32 * <pre>
33 * EnvironmentVariables.getInstance().{@link #toSystemProperties() toSystemProperties()};
34 * </pre>
35 * <p>
36 * and then browse the system properties for <tt>env.</tt> entries.
37 *
38 * @author cris
39 */
40 public class EnvironmentVariables {
41
42 /**
43 * A class implementing this interface is able to retrieve environment
44 * information in some way.
45 *
46 * @author cris
47 */
48 public static interface Generator {
49
50 /**
51 * Return an array of a 2-columns array of Strings containing variable
52 * names and values
53 * @return String
54 */
55 public String[][] getEnvironment();
56
57 }
58
59 /**
60 * Classes implementing this interface can transform environment
61 * names in a "canonical" form
62 *
63 * @author cris
64 */
65 public static interface NameTransformer {
66
67 public String transform(String name);
68 }
69
70
71 /**
72 * A {@link Generator Generator} based on running 'set' and parsing the
73 * result
74 *
75 * @author cris
76 */
77 private class SetBasedGenerator implements Generator {
78
79 private String cmd;
80
81 public SetBasedGenerator(String cmd) {
82 this.cmd=cmd;
83 }
84
85 /**
86 * @see classUtils.pack.util.EnvironmentVariables.Generator#getEnvironment()
87 */
88 public String[][] getEnvironment() {
89 try {
90 Process p = Runtime.getRuntime().exec(cmd);
91 try {
92 InputStream is = p.getInputStream();
93 StringWriter sw = new StringWriter();
94 int c;
95 while ((c=is.read())!=-1) sw.write(c);
96 is.close();
97
98 BufferedReader br = new BufferedReader(new StringReader(sw.toString()));
99 String line;
100 List l = new ArrayList();
101 while((line=br.readLine())!=null) {
102 int i=line.indexOf("=");
103 if (i==-1) continue;
104 String [] envEntry = new String[2];
105 envEntry[0]=line.substring(0, i);
106 if (line.length()==i+1) continue;
107 envEntry[1]=line.substring(i+1);
108 l.add(envEntry);
109 }
110 String[][] result=new String[l.size()][2];
111 l.toArray(result);
112 return result;
113
114 } catch (IOException e) {
115 e.printStackTrace();
116 throw new RuntimeException("Problem obtaining the result of the 'set' command");
117 }
118 } catch (IOException e) {
119 e.printStackTrace();
120 throw new RuntimeException("Impossible to run the 'set' command");
121 }
122 }
123 }
124
125 /**
126 * A {@link EnvironmentVariables.NameTransformer NameTransformer} which doesn't make any trasformation
127 *
128 * @author cris
129 */
130 private static class IdenticalNameTransformer implements NameTransformer {
131
132 private static IdenticalNameTransformer instance = new IdenticalNameTransformer();
133
134 private IdenticalNameTransformer() { }
135
136 public static IdenticalNameTransformer getInstance() { return instance; }
137
138 /**
139 * @see classUtils.pack.util.EnvironmentVariables.NameTransformer#transform(java.lang.String)
140 */
141 public String transform(String name) {
142 return name;
143 }
144 }
145
146 /**
147 * A {@link EnvironmentVariables.NameTransformer NameTransformer} which produces names in the style
148 * of typical java property names. In detail:
149 * <ul>
150 * <li>Each property is prefixed with a given prefix (default <tt>env.</tt>)
151 * <li>Character case is lowered
152 * <li>Underscores are substituted with dots
153 * <li>If the original variable name contains both lowercase and uppercase letters,
154 * every nonconsecutive uppercase letter is considered the start of a word,
155 * and words are divided by dots.
156 * </ul>
157 * <p>
158 * For example, <tt>JAVA_HOME</tt> will become <tt>env.java.home</tt>,
159 * <tt>CommSpec</tt> will become <tt>comm.spec</tt> and
160 * <tt>My_StrangeVariableName</tt> will become my.strange.variable.name
161 *
162 * @version 1.1
163 * @author cris
164 */
165 public class SimpleNameTransformer implements NameTransformer {
166
167 private Map cachedNames = new HashMap();
168 private String prefix;
169
170 public SimpleNameTransformer(String prefix) {
171 this.prefix=prefix;
172 }
173
174 public SimpleNameTransformer() {
175 this("env");
176 }
177
178 public String transform(String name) {
179 if (name.toUpperCase().equals(name)) {
180 return transformAllUpperCase(name);
181 } else {
182 // Preprocess the name
183 CharacterIterator iter = new StringCharacterIterator(name);
184 StringBuffer sb = new StringBuffer(prefix);
185 boolean lastWasUpperCase=false;
186 for(char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) {
187 if (Character.isUpperCase(c)) {
188 if (! lastWasUpperCase) {
189 sb.append("_");
190 lastWasUpperCase=true;
191 } else {
192 lastWasUpperCase=false;
193 }
194 sb.append(c);
195 }
196 }
197 return transformAllUpperCase(sb.toString());
198 }
199 }
200
201 /**
202 * @see classUtils.pack.util.EnvironmentVariables.NameTransformer#transform(java.lang.String)
203 */
204 public String transformAllUpperCase(String name) {
205 String result;
206
207 if ((result=(String)cachedNames.get(name)) != null)
208 return result;
209
210 CharacterIterator iter = new StringCharacterIterator(name);
211 StringBuffer sb = new StringBuffer(prefix);
212 if (prefix.length()>0) sb.append(".");
213 for(char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) {
214 if (c=='_') {
215 if (sb.length()>0) sb.append(".");
216 } else sb.append(Character.toLowerCase(c));
217 }
218
219 result=sb.toString();
220 cachedNames.put(name, result);
221
222 return result;
223 }
224 }
225
226 private static EnvironmentVariables instance;
227 private Map env = new HashMap();
228 private SimpleNameTransformer simpleNameTransformer;
229
230
231 /**
232 * Constructor for EnvironmentVariables.
233 */
234 public EnvironmentVariables() {
235 String [][] env=getGenerator().getEnvironment();
236 for(int i=0;i<env.length;i++) {
237 this.env.put(env[i][0], env[i][1]);
238 }
239 this.simpleNameTransformer=new SimpleNameTransformer();
240 }
241
242 /**
243 * Return the name of the given variable, after applying the
244 * given {@link NameTransformer name transformation}
245 *
246 * @param name the name of the required environment entry
247 * @param t the transformation to apply
248 * @return the value of the variable with the transformed name,
249 * or <b>null</b> if such a name is undefined
250 */
251 protected String getEnv(String name, NameTransformer t) {
252 return (String)env.get(t.transform(name));
253 }
254
255 /**
256 * Return the value of the environemnt variable of the given
257 * name
258 * @param name the environemnt variable name
259 * @return the environemnt variable value
260 */
261 public String getEnv(String name) {
262 return getEnv(name, IdenticalNameTransformer.getInstance());
263 }
264
265 /**
266 * Return the value of a property whose name is a transformation
267 * of an environment variable name according to a {@link SimpleNameTransformer
268 * SimpleNameTransformer}
269 * @param name
270 * @return String
271 */
272 public String getEnvProperty(String name) {
273 return getEnv(name, simpleNameTransformer);
274 }
275
276 /**
277 * Return the set of environment variables names
278 * @return the set of environment variables names
279 */
280 public Set envNames() { return new HashSet(env.keySet()); }
281
282 /**
283 * Return the set of property names derived by the environment variables,
284 * as obtained by {@link #getEnvProperty(java.lang.String) getEnvProperty()}
285 *
286 * @return the set of property names derived by the environment variables
287 */
288 public Set envPropertyNames() {
289 Set s = new HashSet();
290 for(Iterator i=env.keySet().iterator();i.hasNext();) {
291 s.add(simpleNameTransformer.transform((String)i.next()));
292 }
293 return s;
294 }
295
296 /**
297 * Return a Properties object with the environment properties, whose
298 * names are names derived by the environment variables,
299 * as obtained by {@link #getEnvProperty(java.lang.String) getEnvProperty()}
300 *
301 * @return Properties
302 */
303 public Properties getAsProperties() {
304 return getAsProperties(new Properties());
305 }
306
307 private Properties getAsProperties(Properties p) {
308
309 for(Iterator i=env.keySet().iterator();i.hasNext();) {
310 String name=(String)i.next();
311 p.put(simpleNameTransformer.transform(name), env.get(name));
312 }
313 return p;
314 }
315
316 /**
317 * Add properties obtained by {@link #getEnvProperty(java.lang.String)
318 * getEnvProperty()} to the system properties.
319 */
320 public void toSystemProperties() {
321 getAsProperties(System.getProperties());
322 }
323
324 /**
325 * Return the single instance of this class
326 * @return EnvironmentVariables
327 */
328 public static EnvironmentVariables getInstance() {
329 if (instance==null) instance=new EnvironmentVariables();
330 return instance;
331 }
332
333 /**
334 * This method checks the operating system name to know
335 * and produces a suitable EnvironmentListGenerator for the
336 * platform, or throws an UnsupportedOperationException
337 *
338 * @throws UnsupportedOperationException
339 */
340 private Generator getGenerator() throws UnsupportedOperationException {
341 String osName = System.getProperties().getProperty("os.name");
342
343 if (osName.startsWith("Windows"))
344 return new SetBasedGenerator("cmd /c set");
345 // Else, we can't
346 throw new UnsupportedOperationException("");
347 }
348
349 }
350