root / import / ext3D / trunk / install-extension3d / IzPack / src / lib / com / izforge / izpack / installer / VariableSubstitutor.java @ 15280
History | View | Annotate | Download (13 KB)
1 |
/*
|
---|---|
2 |
* $Id: VariableSubstitutor.java,v 1.1 2006/06/14 07:29:07 cesar Exp $
|
3 |
* IzPack
|
4 |
* Copyright (C) 2001 Johannes Lehtinen
|
5 |
*
|
6 |
* File : VariableSubstitutor.java
|
7 |
* Description : Variable substitutor backend.
|
8 |
* Author's email : johannes.lehtinen@iki.fi
|
9 |
* Author's Website : http://www.iki.fi/jle/
|
10 |
*
|
11 |
* This program is free software; you can redistribute it and/or
|
12 |
* modify it under the terms of the GNU General Public License
|
13 |
* as published by the Free Software Foundation; either version 2
|
14 |
* of the License, or any later version.
|
15 |
*
|
16 |
* This program is distributed in the hope that it will be useful,
|
17 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
18 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
19 |
* GNU General Public License for more details.
|
20 |
*
|
21 |
* You should have received a copy of the GNU General Public License
|
22 |
* along with this program; if not, write to the Free Software
|
23 |
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
24 |
*/
|
25 |
package com.izforge.izpack.installer; |
26 |
|
27 |
import java.io.IOException; |
28 |
import java.io.InputStream; |
29 |
import java.io.InputStreamReader; |
30 |
import java.io.OutputStream; |
31 |
import java.io.OutputStreamWriter; |
32 |
import java.io.Reader; |
33 |
import java.io.Serializable; |
34 |
import java.io.StringReader; |
35 |
import java.io.StringWriter; |
36 |
import java.io.UnsupportedEncodingException; |
37 |
import java.io.Writer; |
38 |
import java.util.HashMap; |
39 |
import java.util.Map; |
40 |
|
41 |
import com.izforge.izpack.util.IoHelper; |
42 |
|
43 |
/**
|
44 |
* Substitutes variables occurring in an input stream or a string. This
|
45 |
* implementation supports a generic variable value mapping and escapes the
|
46 |
* possible special characters occurring in the substituted values. The file
|
47 |
* types specifically supported are plain text files (no escaping), Java
|
48 |
* properties files, and XML files. A valid variable name matches the regular
|
49 |
* expression [a-zA-Z][a-zA-Z0-9_]* and names are case sensitive. Variables are
|
50 |
* referenced either by $NAME or ${NAME} (the latter syntax being useful in
|
51 |
* situations like ${NAME}NOTPARTOFNAME). If a referenced variable is undefined
|
52 |
* then it is not substituted but the corresponding part of the stream is
|
53 |
* copied as is.
|
54 |
*
|
55 |
* @author Johannes Lehtinen <johannes.lehtinen@iki.fi>
|
56 |
*/
|
57 |
public class VariableSubstitutor implements Serializable |
58 |
{ |
59 |
|
60 |
/** The variable value mappings */
|
61 |
protected transient Map variables; |
62 |
|
63 |
/** Whether braces are required for substitution. */
|
64 |
protected boolean bracesRequired = false; |
65 |
|
66 |
/** A constant for file type. Plain file. */
|
67 |
protected final static int TYPE_PLAIN = 0; |
68 |
|
69 |
/** A constant for file type. Java properties file. */
|
70 |
protected final static int TYPE_JAVA_PROPERTIES = 1; |
71 |
|
72 |
/** A constant for file type. XML file. */
|
73 |
protected final static int TYPE_XML = 2; |
74 |
|
75 |
/** A constant for file type. Shell file. */
|
76 |
protected final static int TYPE_SHELL = 3; |
77 |
|
78 |
/** A constant for file type. Plain file with '@' start char. */
|
79 |
protected final static int TYPE_AT = 4; |
80 |
|
81 |
/** A mapping of file type names to corresponding integer constants. */
|
82 |
protected final static Map typeNameToConstantMap; |
83 |
|
84 |
// Initialize the file type map
|
85 |
static
|
86 |
{ |
87 |
typeNameToConstantMap = new HashMap(); |
88 |
typeNameToConstantMap.put("plain", new Integer(TYPE_PLAIN)); |
89 |
typeNameToConstantMap.put("javaprop",
|
90 |
new Integer(TYPE_JAVA_PROPERTIES)); |
91 |
typeNameToConstantMap.put("xml", new Integer(TYPE_XML)); |
92 |
typeNameToConstantMap.put("shell", new Integer(TYPE_SHELL)); |
93 |
typeNameToConstantMap.put("at", new Integer(TYPE_AT)); |
94 |
} |
95 |
|
96 |
|
97 |
/**
|
98 |
* Constructs a new substitutor using the specified variable value mappings.
|
99 |
* The environment hashtable is copied by reference. Braces are not required
|
100 |
* by default
|
101 |
*
|
102 |
* @param variables the map with variable value mappings
|
103 |
*/
|
104 |
public VariableSubstitutor(Map variables) |
105 |
{ |
106 |
this.variables = variables;
|
107 |
} |
108 |
|
109 |
/**
|
110 |
* Get whether this substitutor requires braces.
|
111 |
*/
|
112 |
public boolean areBracesRequired() { |
113 |
return bracesRequired;
|
114 |
} |
115 |
|
116 |
/**
|
117 |
* Specify whether this substitutor requires braces.
|
118 |
*/
|
119 |
public void setBracesRequired(boolean braces) { |
120 |
bracesRequired = braces; |
121 |
} |
122 |
|
123 |
|
124 |
/**
|
125 |
* Substitutes the variables found in the specified string. Escapes special
|
126 |
* characters using file type specific escaping if necessary.
|
127 |
*
|
128 |
* @param str the string to check for variables
|
129 |
* @param type the escaping type or null for plain
|
130 |
* @return the string with substituted variables
|
131 |
* @exception IllegalArgumentException if unknown escaping type specified
|
132 |
*/
|
133 |
public String substitute(String str, String type) |
134 |
throws IllegalArgumentException |
135 |
{ |
136 |
if (str == null) return null; |
137 |
|
138 |
// Create reader and writer for the strings
|
139 |
StringReader reader = new StringReader(str); |
140 |
StringWriter writer = new StringWriter(); |
141 |
|
142 |
// Substitute any variables
|
143 |
try
|
144 |
{ |
145 |
substitute(reader, writer, type); |
146 |
} |
147 |
catch (IOException e) |
148 |
{ |
149 |
throw new Error |
150 |
("Unexpected I/O exception when reading/writing memory "
|
151 |
+ "buffer; nested exception is: " + e);
|
152 |
} |
153 |
|
154 |
// Return the resulting string
|
155 |
return writer.getBuffer().toString();
|
156 |
} |
157 |
|
158 |
|
159 |
/**
|
160 |
* Substitutes the variables found in the specified input stream. Escapes
|
161 |
* special characters using file type specific escaping if necessary.
|
162 |
*
|
163 |
* @param in the input stream to read
|
164 |
* @param out the output stream to write
|
165 |
* @param type the file type or null for plain
|
166 |
* @param encoding the character encoding or null
|
167 |
* for default
|
168 |
* @exception IllegalArgumentException if unknown file type specified
|
169 |
* @exception UnsupportedEncodingException if encoding not supported
|
170 |
* @exception IOException if an I/O error occurs
|
171 |
*/
|
172 |
public void substitute(InputStream in, OutputStream out, |
173 |
String type, String encoding) |
174 |
throws IllegalArgumentException, UnsupportedEncodingException, |
175 |
IOException
|
176 |
{ |
177 |
// Check if file type specific default encoding known
|
178 |
if (encoding == null) |
179 |
{ |
180 |
int t = getTypeConstant(type);
|
181 |
switch (t)
|
182 |
{ |
183 |
case TYPE_JAVA_PROPERTIES:
|
184 |
encoding = "ISO-8859-1";
|
185 |
break;
|
186 |
case TYPE_XML:
|
187 |
encoding = "UTF-8";
|
188 |
break;
|
189 |
} |
190 |
} |
191 |
|
192 |
// Create the reader and writer
|
193 |
InputStreamReader reader =
|
194 |
(encoding != null ?
|
195 |
new InputStreamReader(in, encoding) : new InputStreamReader(in)); |
196 |
OutputStreamWriter writer =
|
197 |
(encoding != null ?
|
198 |
new OutputStreamWriter(out, encoding) : |
199 |
new OutputStreamWriter(out)); |
200 |
|
201 |
// Copy the data and substitute variables
|
202 |
substitute(reader, writer, type); |
203 |
|
204 |
// Flush the writer so that everything gets written out
|
205 |
writer.flush(); |
206 |
} |
207 |
|
208 |
|
209 |
/**
|
210 |
* Substitutes the variables found in the data read from the specified
|
211 |
* reader. Escapes special characters using file type specific escaping if
|
212 |
* necessary.
|
213 |
*
|
214 |
* @param reader the reader to read
|
215 |
* @param writer the writer used to write data out
|
216 |
* @param type the file type or null for plain
|
217 |
* @exception IllegalArgumentException if unknown file type specified
|
218 |
* @exception IOException if an I/O error occurs
|
219 |
*/
|
220 |
public void substitute(Reader reader, Writer writer, String type) |
221 |
throws IllegalArgumentException, IOException |
222 |
{ |
223 |
// Check the file type
|
224 |
int t = getTypeConstant(type);
|
225 |
|
226 |
// determine character which starts a variable
|
227 |
char variable_start = '$'; |
228 |
if (t == TYPE_SHELL)
|
229 |
variable_start = '%';
|
230 |
else if (t == TYPE_AT) |
231 |
variable_start = '@';
|
232 |
|
233 |
// Copy data and substitute variables
|
234 |
int c = reader.read();
|
235 |
while (true) |
236 |
{ |
237 |
// Find the next potential variable reference or EOF
|
238 |
while (c != -1 && c != variable_start) |
239 |
{ |
240 |
writer.write(c); |
241 |
c = reader.read(); |
242 |
} |
243 |
if (c == -1) |
244 |
return;
|
245 |
|
246 |
// Check if braces used or start char escaped
|
247 |
boolean braces = false; |
248 |
c = reader.read(); |
249 |
if (c == '{') |
250 |
{ |
251 |
braces = true;
|
252 |
c = reader.read(); |
253 |
} |
254 |
else if (bracesRequired) |
255 |
{ |
256 |
writer.write(variable_start); |
257 |
continue;
|
258 |
} |
259 |
else if (c == -1) |
260 |
{ |
261 |
writer.write(variable_start); |
262 |
return;
|
263 |
} |
264 |
|
265 |
// Read the variable name
|
266 |
StringBuffer nameBuffer = new StringBuffer(); |
267 |
while (c != -1 && |
268 |
(braces && c != '}') ||
|
269 |
(c >= 'a' && c <= 'z') || |
270 |
(c >= 'A' && c <= 'Z') || |
271 |
(braces && (c == '[') || (c == ']')) || |
272 |
(((c >= '0' && c <= '9') || c == '_') && nameBuffer.length() > 0)) |
273 |
{ |
274 |
nameBuffer.append((char) c);
|
275 |
c = reader.read(); |
276 |
} |
277 |
String name = nameBuffer.toString();
|
278 |
|
279 |
// Check if a legal and defined variable found
|
280 |
String varvalue = null; |
281 |
|
282 |
if ((!braces || c == '}') && name.length() > 0) |
283 |
{ |
284 |
// check for environment variables
|
285 |
if (braces && name.startsWith("ENV[") && (name.lastIndexOf(']') == name.length()-1)) |
286 |
{ |
287 |
varvalue = IoHelper.getenv(name.substring(4, name.length()-1)); |
288 |
} |
289 |
else
|
290 |
varvalue = (String)variables.get(name);
|
291 |
} |
292 |
|
293 |
// Substitute the variable...
|
294 |
if (varvalue != null) |
295 |
{ |
296 |
writer.write |
297 |
(escapeSpecialChars(varvalue, t)); |
298 |
if (braces)
|
299 |
c = reader.read(); |
300 |
} |
301 |
// ...or ignore it
|
302 |
else
|
303 |
{ |
304 |
writer.write(variable_start); |
305 |
if (braces)
|
306 |
writer.write('{');
|
307 |
writer.write(name); |
308 |
} |
309 |
} |
310 |
} |
311 |
|
312 |
|
313 |
/**
|
314 |
* Returns the internal constant for the specified file type.
|
315 |
*
|
316 |
* @param type the type name or null for plain
|
317 |
* @return the file type constant
|
318 |
*/
|
319 |
protected int getTypeConstant(String type) |
320 |
{ |
321 |
if (type == null) |
322 |
return TYPE_PLAIN;
|
323 |
Integer integer = (Integer) typeNameToConstantMap.get(type); |
324 |
if (integer == null) |
325 |
throw new IllegalArgumentException |
326 |
("Unknown file type " + type);
|
327 |
else
|
328 |
return integer.intValue();
|
329 |
} |
330 |
|
331 |
|
332 |
/**
|
333 |
* Escapes the special characters in the specified string using file type
|
334 |
* specific rules.
|
335 |
*
|
336 |
* @param str the string to check for special characters
|
337 |
* @param type the target file type (one of TYPE_xxx)
|
338 |
* @return the string with the special characters properly escaped
|
339 |
*/
|
340 |
protected String escapeSpecialChars(String str, int type) |
341 |
{ |
342 |
StringBuffer buffer;
|
343 |
int len;
|
344 |
int i;
|
345 |
switch (type)
|
346 |
{ |
347 |
case TYPE_PLAIN:
|
348 |
case TYPE_SHELL:
|
349 |
case TYPE_AT:
|
350 |
return str;
|
351 |
case TYPE_JAVA_PROPERTIES:
|
352 |
buffer = new StringBuffer(str); |
353 |
len = str.length(); |
354 |
for (i = 0; i < len; i++) |
355 |
{ |
356 |
// Check for control characters
|
357 |
char c = buffer.charAt(i);
|
358 |
if (c == '\t' || c == '\n' || c == '\r') |
359 |
{ |
360 |
char tag;
|
361 |
if (c == '\t') |
362 |
tag = 't';
|
363 |
else if (c == '\n') |
364 |
tag = 'n';
|
365 |
else
|
366 |
tag = 'r';
|
367 |
buffer.replace(i, i + 1, "\\" + tag); |
368 |
len++; |
369 |
i++; |
370 |
} |
371 |
|
372 |
// Check for special characters
|
373 |
if (c == '\\' || c == '"' || c == '\'' || c == ' ') |
374 |
{ |
375 |
buffer.insert(i, '\\');
|
376 |
len++; |
377 |
i++; |
378 |
} |
379 |
} |
380 |
return buffer.toString();
|
381 |
case TYPE_XML:
|
382 |
buffer = new StringBuffer(str); |
383 |
len = str.length(); |
384 |
for (i = 0; i < len; i++) |
385 |
{ |
386 |
String r = null; |
387 |
char c = buffer.charAt(i);
|
388 |
switch (c)
|
389 |
{ |
390 |
case '<': |
391 |
r = "<";
|
392 |
break;
|
393 |
case '>': |
394 |
r = ">";
|
395 |
break;
|
396 |
case '&': |
397 |
r = "&";
|
398 |
break;
|
399 |
case '\'': |
400 |
r = "'";
|
401 |
break;
|
402 |
case '"': |
403 |
r = """;
|
404 |
break;
|
405 |
} |
406 |
if (r != null) |
407 |
{ |
408 |
buffer.replace(i, i + 1, r);
|
409 |
len = buffer.length(); |
410 |
i += r.length() - 1;
|
411 |
} |
412 |
} |
413 |
return buffer.toString();
|
414 |
default:
|
415 |
throw new Error |
416 |
("Unknown file type constant " + type);
|
417 |
} |
418 |
} |
419 |
} |
420 |
|