Source code: org/edelbyte/util/UnixCfgParser.java
1 /* ######################################################################### */
2 /* ## ## */
3 /* ## U T I L / U N I X C F G P A R S E R . J A V A ## */
4 /* ## ## */
5 /* ## ------------------------------------------------------------------- ## */
6 /* ## ## */
7 /* ## Job .......: Parse a Unix Configuration file from an instance ## */
8 /* ## of java.io.BufferedReader (or its subclasses) ## */
9 /* ## ## */
10 /* ## ------------------------------------------------------------------- ## */
11 /* ## ## */
12 /* ## Copyright (C) 2002 Daniel Scheibli ## */
13 /* ## ## */
14 /* ## This library is free software; you can redistribute it and/or ## */
15 /* ## modify it under the terms of the GNU Lesser General Public ## */
16 /* ## License as published by the Free Software Foundation; either ## */
17 /* ## version 2.1 of the License, or (at your option) any later version. ## */
18 /* ## ## */
19 /* ## This library is distributed in the hope that it will be useful, ## */
20 /* ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## */
21 /* ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## */
22 /* ## Lesser General Public License for more details. ## */
23 /* ## ## */
24 /* ## You should have received a copy of the GNU Lesser General Public ## */
25 /* ## License along with this library; if not, write to the Free ## */
26 /* ## Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, ## */
27 /* ## MA 02111-1307 USA ## */
28 /* ## ## */
29 /* ## ------------------------------------------------------------------- ## */
30 /* ## ## */
31 /* ## Remark ....: <none> ## */
32 /* ## ## */
33 /* ## ------------------------------------------------------------------- ## */
34 /* ## ## */
35 /* ## Author ....: Daniel Scheibli <daniel.scheibli@edelbyte.org> ## */
36 /* ## Date ......: 2002-11-10 ## */
37 /* ## Changes ...: ----- UnixCfgParser.java V00.99/R020 ---------------- ## */
38 /* ## <none> ## */
39 /* ## ----- UnixCfgParser.java V00.99/R011 ---------------- ## */
40 /* ## <none> ## */
41 /* ## ## */
42 /* ######################################################################### */
43
44
45
46 /* ##### Presettings */
47 /* ------------------------------------------------------------------------- */
48 package org.edelbyte.util;
49 /* ------------------------------------------------------------------------- */
50
51
52
53
54
55 /* ##### Class definition */
56 /** ************************************************************************
57 * A basic Unix configuration file parser. The parser reads from
58 * a <code>java.io.BufferedReader</code> (or one of its subclasses)
59 * and returns a <code>java.util.Properties</code> object with
60 * the found key and value pairs. It is an alternative to the
61 * <code>java.lang.Properties.load()</code> method (which
62 * has some strange behavior).<br />
63 * <br />
64 * More information can be found in the detailed description
65 * of the {@link #parse} method.
66 *
67 * @author Daniel Scheibli <daniel.scheibli at edelbyte.org>
68 * ************************************************************************* */
69 public class UnixCfgParser
70 {
71 /* ##### Presettings (class fields) */
72 /* ------------------------------------------------------------------------ */
73 /** ***********************************************************************
74 * Constant holding the token used for the comment detection
75 * within the stream.
76 * ************************************************************************ */
77 protected static final java.lang.String COMMENT_TOKEN = "#";
78 /** ***********************************************************************
79 * Constant holding the token used for the key and value pair
80 * separation within the stream.
81 * ************************************************************************ */
82 protected static final java.lang.String EQUALS_TOKEN = "=";
83 /** ***********************************************************************
84 * Constant holding the token used for the line continuation detection
85 * within the stream.
86 * ************************************************************************ */
87 protected static final java.lang.String CONTINUATION_TOKEN = " \\";
88 /* ------------------------------------------------------------------------ */
89
90
91
92
93
94 /* ##### Presettings (instance fields) */
95 /* ------------------------------------------------------------------------ */
96 /** ***********************************************************************
97 * Field holding the token, which indicates the beginning of the
98 * key and value pairs part of the stream. It is used for the
99 * Between Check mechanism.
100 * ************************************************************************ */
101 protected java.lang.String oBetweenBeginToken = "#BEGIN";
102 /** ***********************************************************************
103 * Field holding the token, which indicates the end of the
104 * key and value pairs part of the stream. It is used for the
105 * Between Check mechanism.
106 * ************************************************************************ */
107 protected java.lang.String oBetweenEndToken = "#END";
108 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- */
109 /** ***********************************************************************
110 * Field holding the activation status of the Between Check
111 * mechanism (default is <code>false</code>).
112 * ************************************************************************ */
113 protected boolean bBetweenCheckEnabled = false;
114 /* ------------------------------------------------------------------------ */
115
116
117
118
119
120 /* ######################################################################## */
121 /* ## ## */
122 /* ## U N I X C F G P A R S E R () ## */
123 /* ## ## */
124 /* ######################################################################## */
125 /** ***********************************************************************
126 * Creates a new instance of this class.
127 * ************************************************************************ */
128 public UnixCfgParser( )
129 { }
130
131
132
133
134
135 /* ######################################################################## */
136 /* ## ## */
137 /* ## G E T B E T W E E N B E G I N T O K E N () ## */
138 /* ## ## */
139 /* ######################################################################## */
140 /** ***********************************************************************
141 * Returns the token, which indicates the beginning of the
142 * key and value pairs part
143 * (from the {@link #oBetweenBeginToken} field).
144 *
145 * @return A new String, containing the indicator token
146 * ************************************************************************ */
147 public java.lang.String getBetweenBeginToken( )
148 { return( this.oBetweenBeginToken ); }
149
150
151
152
153
154 /* ######################################################################## */
155 /* ## ## */
156 /* ## G E T B E T W E E N E N D T O K E N () ## */
157 /* ## ## */
158 /* ######################################################################## */
159 /** ***********************************************************************
160 * Returns the token, which indicates the end of the
161 * key and value pairs part
162 * (from the {@link #oBetweenEndToken} field).
163 *
164 * @return A new String, containing the indicator token
165 * ************************************************************************ */
166 public java.lang.String getBetweenEndToken( )
167 { return( this.oBetweenEndToken ); }
168
169
170
171
172
173 /* ######################################################################## */
174 /* ## ## */
175 /* ## I S B E T W E E N C H E C K E N A B L E D () ## */
176 /* ## ## */
177 /* ######################################################################## */
178 /** ***********************************************************************
179 * Returns <code>true</code> for the case, that the Between Check
180 * mechanism is active.<br />
181 * <br />
182 * The Between Check mechanism ensures, that there are key and value
183 * pairs between the so called BetweenBegin and BetweenEnd tokens
184 * (see {@link #getBetweenBeginToken} and {@link #getBetweenEndToken})
185 * only.
186 *
187 * @return <code>true</code> if the Between Check mechanism
188 * is active.
189 * ************************************************************************ */
190 public boolean isBetweenCheckEnabled( )
191 { return( this.bBetweenCheckEnabled ); }
192
193
194
195
196
197 /* ######################################################################## */
198 /* ## ## */
199 /* ## P A R S E () ## */
200 /* ## ## */
201 /* ######################################################################## */
202 /** ***********************************************************************
203 * Reads key and value pairs from a <code>java.io.BufferedReader</code>
204 * (or one of its subclasses).<br />
205 * <br />
206 * The parser reads the stream line wise using the <code>readLine()</code>
207 * method of the object given by the <code>oReader</code> parameter.
208 * A line can hold up to one key and value pair. Everything after the
209 * first occurrence of "<code>#</code>" is interpreted as
210 * comment and therefore skipped. Lines containing tabs and blanks only
211 * are skipped as well. The first occurrence of "<code>=</code>"
212 * is interpreted as a delimiter separating key and value. After the
213 * separation of key and value, the key is converted to upper case.
214 * Lines ending with "<code> \</code>" (please notice the
215 * blank leading the backslash!) indicates a line continuation.<br />
216 * <br />
217 * An sample configuration file is listed below:<br />
218 * <br />
219 * <tt>##### Database configuration file for SAMPLE database<br />
220 * <br />
221 * #BEGIN<br />
222 * Backup.Enabled = YES             ##### Backup allowed [YES|NO]<br />
223 * Backup.Rule.1  = (A > B) &&  \   ##### Backup rule number one<br />
224 *                  (C != D)<br />
225 * #END<br /></tt>
226 * <br />
227 * For the given example, the returning <code>java.util.Properties</code>
228 * object contains the following key and value pairs:<br />
229 * <ul>
230 * <li>The key is "<code>BACKUP.ENABLED</code>" and the associated
231 * value is "<code>YES</code>".</li>
232 * <li>The key is "<code>BACKUP.RULE.1</code>" and the associated
233 * value is "<code>(A > B) && (C != D)</code>".</li>
234 * </ul>
235 *
236 * @param oReader
237 * The name of the DB2 Instance to be addressed.
238 * @return The <code>java.util.Properties</code> object containing
239 * the key and value pairs found while parsing.
240 * @exception java.io.IOException
241 * For the case, that there was an error while reading
242 * the stream.
243 * @exception java.text.ParseException
244 * For the case, that there was an error while parsing
245 * the stream.
246 * ************************************************************************ */
247 public java.util.Properties parse( java.io.BufferedReader oReader ) throws java.io.IOException,
248 java.text.ParseException
249 {
250 /* ##### Presettings */
251 /* ----------------------------------------------------------------------- */
252 java.util.Properties oPairTable = new java.util.Properties();
253 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
254 boolean bIsBetweenFlag;
255 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
256 java.lang.String oCurrentRow;
257 java.lang.String oCurrentRowKey = null;
258 java.lang.String oCurrentRowValue;
259 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
260 int iRowNumber = -1;
261 int iRowNumberValueNext = -1;
262 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
263 int iDummy;
264 /* ----------------------------------------------------------------------- */
265
266
267
268 /* ##### Initialize the Between Check related stuff */
269 /* ----------------------------------------------------------------------- */
270 if( bBetweenCheckEnabled == true )
271 { bIsBetweenFlag = false; }
272 else
273 { bIsBetweenFlag = true; }
274 /* ----------------------------------------------------------------------- */
275
276
277
278 /* ##### Loop over the stream */
279 /* ----------------------------------------------------------------------- */
280 while( (oCurrentRow = oReader.readLine()) != null )
281 {
282 /* ##### Presettings */
283 iRowNumber++;
284
285 /* ##### BetweenCheck: Detect the indicators */
286 /* ##### (given the fact, that the check is enabled) */
287 if( bBetweenCheckEnabled == true )
288 {
289 if( oCurrentRow.trim().equals( oBetweenBeginToken ) == true )
290 { bIsBetweenFlag = true; continue; }
291 if( oCurrentRow.trim().equals( oBetweenEndToken ) == true )
292 { bIsBetweenFlag = false; continue; }
293 }
294
295 /* ##### Remove the comment part from the current row */
296 iDummy = oCurrentRow.indexOf( COMMENT_TOKEN );
297 if( iDummy > -1 )
298 { oCurrentRow = oCurrentRow.substring( 0, iDummy ); }
299
300 /* ##### Skip empty rows */
301 if( oCurrentRow.trim().length() == 0 )
302 { continue; }
303
304 /* ##### BetweenCheck: If there is content,... */
305 /* ##### (given the fact, that the check is enabled) */
306 if( (bBetweenCheckEnabled == true) && (bIsBetweenFlag == false) )
307 { throw new java.text.ParseException( "The Between Check feature found content outside the allowed boundaries (RowNo = " + iRowNumber + ").", iRowNumber ); }
308
309 /* ##### Check integrity (based on line continuation only) */
310 if( (iRowNumberValueNext >= 0) && (iRowNumberValueNext != iRowNumber) )
311 { throw new java.text.ParseException( "A line continuation was indicated, but seems to be interrupted (RowNo = " + iRowNumber + ").", iRowNumber ); }
312
313 /* ##### Seperate the current row into (Key and) Value part */
314 if( iRowNumberValueNext < 0 )
315 {
316 /* ##### Detect the first equals character (our delimiter) */
317 iDummy = oCurrentRow.indexOf( EQUALS_TOKEN );
318 if( iDummy > -1 )
319 {
320 oCurrentRowValue = ("A" + oCurrentRow.substring( iDummy + 1 )).trim();
321 oCurrentRowKey = oCurrentRow.substring( 0, iDummy ).trim().toUpperCase();
322 /* ##### On error,... */
323 if( oCurrentRowKey.length() == 0 )
324 { throw new java.text.ParseException( "Invalid Key part within the current Key/Value pair found (RowNo = " + iRowNumber + ").", iRowNumber ); }
325 }
326 /* ##### On error,... */
327 else
328 { throw new java.text.ParseException( "A Key/Value pair was expected, but there was no equals/delimiter found (RowNo = " + iRowNumber + ").", iRowNumber ); }
329 }
330 else
331 { oCurrentRowValue = ("A" + oCurrentRow).trim(); }
332
333 /* ##### Process tailing Continuation Token (indicates line continuation) */
334 if( oCurrentRowValue.endsWith( CONTINUATION_TOKEN ) == true )
335 {
336 oCurrentRowValue = oCurrentRowValue.substring( 0, oCurrentRowValue.length() - CONTINUATION_TOKEN.length() );
337 iRowNumberValueNext = iRowNumber + 1;
338 }
339 else
340 { iRowNumberValueNext = -1; }
341
342 /* ##### Remove the magic "A" and temporary append the magic "Z" */
343 /* ##### to remove the leading [tabs|blanks] */
344 oCurrentRowValue = (oCurrentRowValue.substring( 1 ) + "Z").trim();
345 oCurrentRowValue = oCurrentRowValue.substring( 0, oCurrentRowValue.length() - 1 );
346
347 /* ##### Add the Key/Value pairs to the Hashtable */
348 if( oPairTable.get( oCurrentRowKey ) != null )
349 { oPairTable.put( oCurrentRowKey, oPairTable.get(oCurrentRowKey).toString() + oCurrentRowValue ); }
350 else
351 { oPairTable.put( oCurrentRowKey, oCurrentRowValue ); }
352 }
353 /* ----------------------------------------------------------------------- */
354
355
356
357 /* ##### Check integrity (based on "open" line continuation) */
358 /* ----------------------------------------------------------------------- */
359 if( iRowNumberValueNext >= 0 )
360 { throw new java.text.ParseException( "A line continuation was indicated, but there was no line continuation found (RowNo = " + iRowNumber + ").", iRowNumber ); }
361 /* ----------------------------------------------------------------------- */
362
363
364
365 /* ##### Return the Key/Value pairs */
366 /* ----------------------------------------------------------------------- */
367 return( oPairTable );
368 /* ----------------------------------------------------------------------- */
369 }
370
371
372
373
374
375 /* ######################################################################## */
376 /* ## ## */
377 /* ## S E T B E T W E E N B E G I N T O K E N () ## */
378 /* ## ## */
379 /* ######################################################################## */
380 /** ***********************************************************************
381 * Set a alternative value for the BetweenBegin token, which is
382 * used by the Between Check mechanism.
383 *
384 * @param oBetweeenBeginToken
385 * The String containing the new value
386 * (for the {@link #oBetweenBeginToken} field).
387 * ************************************************************************ */
388 public void setBetweenBeginToken( java.lang.String oBetweenBeginToken )
389 { this.oBetweenBeginToken = oBetweenBeginToken; }
390
391
392
393
394
395 /* ######################################################################## */
396 /* ## ## */
397 /* ## S E T B E T W E E N C H E C K E N A B L E D () ## */
398 /* ## ## */
399 /* ######################################################################## */
400 /** ***********************************************************************
401 * Enables or disables the Between Check mechanism while parsing the
402 * stream.<br />
403 * <br />
404 * The Between Check mechanism ensures, that there are key and value
405 * pairs between the so called BetweenBegin and BetweenEnd tokens
406 * (see {@link #getBetweenBeginToken} and {@link #getBetweenEndToken})
407 * only.
408 *
409 * @param bStatus
410 * The status for the Between Check mechanism to be set.
411 * ************************************************************************ */
412 public void setBetweenCheckEnabled( boolean bStatus )
413 { this.bBetweenCheckEnabled = bStatus; }
414
415
416
417
418
419 /* ######################################################################## */
420 /* ## ## */
421 /* ## S E T B E T W E E N E N D T O K E N () ## */
422 /* ## ## */
423 /* ######################################################################## */
424 /** ***********************************************************************
425 * Set a alternative value for the BetweenEnd token, which is
426 * used by the Between Check mechanism.
427 *
428 * @param oBetweeenEndToken
429 * The String containing the new value
430 * (for the {@link #oBetweenEndToken} field).
431 * ************************************************************************ */
432 public void setBetweenEndToken( java.lang.String oBetweenEndToken )
433 { this.oBetweenEndToken = oBetweenEndToken; }
434 }
435 /* ------------------------------------------------------------------------- */
436
437
438
439