KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > de > susebox > jtopas > AbstractTokenizerProperties


1 /*
2  * AbstractTokenizerProperties.java: Core implementation of TokenizerProperties
3  *
4  * Copyright (C) 2003 Heiko Blau
5  *
6  * This file belongs to the JTopas Library.
7  * JTopas is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as published by the
9  * Free Software Foundation; either version 2.1 of the License, or (at your
10  * option) any later version.
11  *
12  * This software is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.
15  * See the GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License along
18  * with JTopas. If not, write to the
19  *
20  * Free Software Foundation, Inc.
21  * 59 Temple Place, Suite 330,
22  * Boston, MA 02111-1307
23  * USA
24  *
25  * or check the Internet: http://www.fsf.org
26  *
27  * Contact:
28  * email: heiko@susebox.de
29  */

30
31 package de.susebox.jtopas;
32
33 //-----------------------------------------------------------------------------
34
// Imports
35
//
36
import java.lang.ref.WeakReference JavaDoc;
37 import java.util.Iterator JavaDoc;
38 import java.util.LinkedList JavaDoc;
39 import java.util.Map JavaDoc;
40 import java.util.TreeMap JavaDoc;
41
42 import de.susebox.java.lang.ExtIllegalArgumentException;
43
44
45 //-----------------------------------------------------------------------------
46
// Class AbstractTokenizerProperties
47
//
48

49 /**<p>
50  * The class <code>AbstractTokenizerProperties</code> provides the skeleton for
51  * implementations of the {@link TokenizerProperties} interface. It leaves only
52  * the more general methods to these implementations. For instance, the simple
53  * method {@link #addKeyword(String)} can and should call the more complex
54  * method {@link #addKeyword(String, String)} with the second parameter
55  * <code>null</code>. That method in turn should call
56  * {@link #addKeyword(String, String, int)} etc.
57  *</p>
58  *
59  * @see TokenizerProperties
60  * @see Tokenizer
61  * @author Heiko Blau
62  */

63 public abstract class AbstractTokenizerProperties implements TokenizerProperties
64 {
65   
66   //---------------------------------------------------------------------------
67
// Abstract methods
68
//
69

70   /**
71    * This method must be implemented by derived classes to register a
72    * {@link TokenizerProperty}. When called, the given <code>property</code>
73    * has already been checked for not being <code>null</code> or incomplete
74    * (no leading image).
75    *<br>
76    * If the property to register is already known, perhaps with a different
77    * type, different flags or a different companion, it is replaced and returned.
78    *<br>
79    * The notification of the registered {@link TokenizerPropertyListener} is
80    * done by this abstract class, the implementations must not do it themselves.
81    *<br>
82    * The method is called in a thread-safe way. That means only one thread can
83    * enter the method at a given time.
84    *
85    * @param property a non-null, complete token description
86    * @return the old, replaced property or <code>null</code>
87    */

88   protected abstract TokenizerProperty doAddProperty(TokenizerProperty property);
89   
90   /**
91    * This method must be implemented by derived classes to deregister a
92    * {@link TokenizerProperty}. When called, the given <code>property</code>
93    * has already been checked for not being <code>null</code> or incomplete
94    * (no leading image).
95    *<br>
96    * According to the {@link TokenizerProperties} interface specification of the
97    * {@link TokenizerProperties#removeProperty} method, this method does nothing
98    * if the given property is unknown. In this case <code>null</code> is returned.
99    *<br>
100    * Otherwise the removed property is returned.
101    *<br>
102    * The notification of the registered {@link TokenizerPropertyListener} is
103    * done by this abstract class, the implementations must not do it themselves.
104    *<br>
105    * The method is called in a thread-safe way. That means only one thread can
106    * enter the method at a given time.
107    *
108    * @param property a non-null, complete token description
109    * @return the removed property or <code>null</code>
110    */

111   protected abstract TokenizerProperty doRemoveProperty(TokenizerProperty property);
112   
113   /**
114    * This method must be implemented by derived classes to retrieve the
115    * {@link TokenizerProperty} for the given image. When called, the given
116    * <code>image</code> has already been checked for not being <code>null</code>.
117    *<br>
118    * According to the {@link TokenizerProperties} interface specification of the
119    * various get methods, this method must return <code>null</code> if there is
120    * no property that matches the given image.
121    *<br>
122    * The method is called in a thread-safe way. That means only one thread can
123    * enter the method at a given time.
124    *
125    * @param type the type the returned property should have
126    * @param startImage the (starting) image
127    * @return the token description for the image or <code>null</code>
128    */

129   protected abstract TokenizerProperty doGetProperty(int type, String JavaDoc startImage);
130   
131   /**
132    * This method must be implemented by derived classes to register the given
133    * simple whitespaces. When called, the calling method has already ensured that
134    * the parameter is not <code>null</code> (but could be empty) and uppercase
135    * if the {@link Flags#F_NO_CASE} flag is set.
136    *<br>
137    * The method should return the old whitespace set. When first called, this
138    * is the default whitespace set. It is ok to return <code>null</code> if the
139    * old set is empty.
140    *<br>
141    * The notification of the registered {@link TokenizerPropertyListener} is
142    * done by this abstract class, the implementations must not do it themselves.
143    *<br>
144    * The method is called in a thread-safe way. That means only one thread can
145    * enter the method at a given time.
146    *
147    * @param whitespaces the new whitespace set
148    * @return the old whitespace set
149    */

150   protected abstract String JavaDoc doSetWhitespaces(String JavaDoc whitespaces);
151   
152   /**
153    * This method must be implemented by derived classes to set the given
154    * simple separators. When called, the calling method
155    * {@link #setSeparators} has already ensured that the parameter is not
156    * <code>null</code> (but empty) and uppercase if the {@link Flags#F_NO_CASE}
157    * flag is set.
158    *<br>
159    * The method should return the old separator set. When first called, this
160    * is the default separator set. It is ok to return <code>null</code> if the
161    * old set is empty.
162    *<br>
163    * The notification of the registered {@link TokenizerPropertyListener} is
164    * done by this abstract class, the implementations must not do it themselves.
165    *<br>
166    * The method is called in a thread-safe way. That means only one thread can
167    * enter the method at a given time.
168    *
169    * @param separators the new separator set
170    * @return the old separator set
171    */

172   protected abstract String JavaDoc doSetSeparators(String JavaDoc separators);
173   
174
175   //---------------------------------------------------------------------------
176
// Methods of the TokenizerProperties interface
177
//
178

179   /**
180    * See the method description in {@link TokenizerProperties}.
181    *
182    * @param flags the parser control flags
183    * @see #getParseFlags
184    */

185   public void setParseFlags(int flags) {
186     // normalize flags
187
flags = normalizeFlags(flags, flags);
188     
189     // set flags
190
synchronized(this) {
191       int oldFlags = _flags;
192       
193       _flags = flags;
194       if (oldFlags != _flags) {
195         notifyListeners(new TokenizerPropertyEvent(
196                               TokenizerPropertyEvent.PROPERTY_MODIFIED,
197                               new TokenizerProperty(TokenizerProperty.PARSE_FLAG_MASK,
198                                                     new String JavaDoc[] { Integer.toBinaryString(_flags) } ),
199                               new TokenizerProperty(TokenizerProperty.PARSE_FLAG_MASK,
200                                                     new String JavaDoc[] { Integer.toBinaryString(oldFlags) } )));
201       }
202     }
203   }
204
205   /**
206    * See the method description in {@link TokenizerProperties}.
207    *
208    * @return the current parser control flags
209    * @see #setParseFlags
210    */

211   public int getParseFlags() {
212     return _flags;
213   }
214   
215   /**
216    * Returns <code>true</code> if a given flag is set in the current parse flags.
217    * If the parameter contains more than one bit the method returns only
218    * <code>true</code> if all bits are set.
219    *
220    * @param flag the flag to test
221    * @return <code>true</code> if all bits in flag are set.
222    * @see #setParseFlags
223    */

224   public boolean isFlagSet(int flag) {
225     return (_flags & flag) == flag;
226   }
227     
228   /**
229    * Checks if a given flag (see the constants in {@link Flags}) is set for the
230    * given {@link TokenizerProperty} in the context of this <code>TokenizerProperties</code>
231    * instance.
232    *
233    * @param prop the {@link TokenizerProperty} concerned
234    * @param flag the flag to check (may contain more than one bit)
235    * @return <code>true</code> if the flag is set either explicit in the property
236    * or globally for this <code>TokenizerProperties</code> object,
237    * <code>false</code> otherwise
238    * @throws NullPointerException if no property is given
239    */

240   public boolean isFlagSet(TokenizerProperty prop, int flag) throws NullPointerException JavaDoc {
241     return prop.isFlagSet(flag, isFlagSet(flag));
242   }
243   
244   
245   //---------------------------------------------------------------------------
246
// simple whitespaces and separators
247
//
248

249   /**
250    * Setting the whitespace character set of the tokenizer.
251    * See the method description in {@link TokenizerProperties}.
252    *<br>
253    * This method calls the abstract method {@link #doSetWhitespaces}. It guaranties
254    * that the parameter passed to <code>doSetWhitespaces</code> is not null
255    * (instead empty) and uppercase if the Flag {@link Flags#F_NO_CASE}
256    * is set.
257    *
258    * @param whitespaces the whitespace set
259    */

260   public void setWhitespaces(String JavaDoc whitespaces) {
261     // normalize whitespaces
262
String JavaDoc newValue = (whitespaces != null) ? whitespaces : "";
263     String JavaDoc oldValue;
264       
265     if ((_flags & Flags.F_NO_CASE) != 0) {
266       newValue = newValue.toUpperCase();
267     }
268
269     // set new whitespaces
270
synchronized(this) {
271       oldValue = doSetWhitespaces(newValue);
272
273       // notify listeners
274
handleEvent(Token.WHITESPACE, newValue, oldValue);
275     }
276   }
277
278   /**
279    * Adding new whitespaces to the existing set.
280    *
281    * @param additional whitespaces for the whitespace set
282    * @throws IllegalArgumentException when <code>null</code> is passed or incomplete
283    * ranges are specified (e.g. <code>"a-"</code>)
284    */

285   public void addWhitespaces(String JavaDoc whitespaces) throws IllegalArgumentException JavaDoc {
286     try {
287       if (whitespaces.length() > 0) {
288         setWhitespaces(mergeSet(getWhitespaces(), whitespaces, false));
289       }
290     } catch (NullPointerException JavaDoc ex) {
291       throw new IllegalArgumentException JavaDoc();
292     }
293   }
294   
295   /**
296    * Removing whitespaces from the existing set.
297    *
298    * @param whitespaces whitespaces to remove from the whitespace set
299    * @throws IllegalArgumentException when <code>null</code> is passed or incomplete
300    * ranges are specified (e.g. <code>"a-"</code>)
301    */

302   public void removeWhitespaces(String JavaDoc whitespaces) throws IllegalArgumentException JavaDoc {
303     try {
304       if (whitespaces.length() > 0) {
305         setWhitespaces(mergeSet(getWhitespaces(), whitespaces, true));
306       }
307     } catch (NullPointerException JavaDoc ex) {
308       throw new IllegalArgumentException JavaDoc();
309     }
310   }
311   
312   /**
313    * Setting the separator character set of the tokenizer.
314    * See the method description in {@link TokenizerProperties}.
315    *<br>
316    * This method calls the abstract method {@link #doSetSeparators}. It guaranties
317    * that the parameter passed to <code>doSetSeparators</code> is not null
318    * (instead empty) and uppercase if the Flag {@link Flags#F_NO_CASE}
319    * is set.
320    *
321    * @param separators the separator set
322    */

323   public void setSeparators(String JavaDoc separators) {
324     // normalize separators
325
String JavaDoc newValue = (separators != null) ? separators : "";
326     String JavaDoc oldValue;
327       
328     if ((_flags & Flags.F_NO_CASE) != 0) {
329       newValue = newValue.toUpperCase();
330     }
331     
332     // set new separator set
333
synchronized(this) {
334       oldValue = doSetSeparators(newValue);
335
336       // notify listeners
337
handleEvent(Token.SEPARATOR, newValue, oldValue);
338     }
339   }
340
341   /**
342    * Adding new separators to the existing set.
343    *
344    * @param separators additional separators for the separator set
345    * @throws IllegalArgumentException when <code>null</code> is passed or incomplete
346    * ranges are specified (e.g. <code>"a-"</code>)
347    */

348   public void addSeparators(String JavaDoc separators) throws IllegalArgumentException JavaDoc {
349     try {
350       if (separators.length() > 0) {
351         setSeparators(mergeSet(getSeparators(), separators, false));
352       }
353     } catch (NullPointerException JavaDoc ex) {
354       throw new IllegalArgumentException JavaDoc();
355     }
356   }
357   
358   /**
359    * Removing separators from the existing set.
360    *
361    * @param separators separating characters to remove from the separator set
362    * @throws IllegalArgumentException when <code>null</code> is passed or incomplete
363    * ranges are specified (e.g. <code>"a-"</code>)
364    */

365   public void removeSeparators(String JavaDoc separators) throws IllegalArgumentException JavaDoc {
366     try {
367       if (separators.length() > 0) {
368         setSeparators(mergeSet(getSeparators(), separators, true));
369       }
370     } catch (NullPointerException JavaDoc ex) {
371       throw new IllegalArgumentException JavaDoc();
372     }
373   }
374   
375   
376   //---------------------------------------------------------------------------
377
// string properties
378
//
379

380   /**
381    * Registering a string description. See the method description in the interface
382    * {@link TokenizerProperties}.
383    *
384    * @param start the starting sequence of a string
385    * @param end the finishing sequence of a string
386    * @param escape the escape sequence inside the string
387    * @throws IllegalArgumentException when <code>null</code> or an empty string
388    * is passed for start or end
389    * @see #removeString
390    * @see #addString(String, String, String, Object)
391    */

392   public void addString(String JavaDoc start, String JavaDoc end, String JavaDoc escape)
393     throws IllegalArgumentException JavaDoc
394   {
395     addString(start, end, escape, null);
396   }
397
398   /**
399    * Registering a the sequences that are used for string-like text parts.
400    * See the method description in {@link TokenizerProperties}.
401    *
402    * @param start the starting sequence of a string
403    * @param end the finishing sequence of a string
404    * @param escape the escape sequence inside the string
405    * @param companion the associated information
406    * @throws IllegalArgumentException when <code>null</code> or an empty string is passed for start or end
407    *
408    */

409   public void addString(String JavaDoc start, String JavaDoc end, String JavaDoc escape, Object JavaDoc companion)
410     throws IllegalArgumentException JavaDoc
411   {
412     addString(start, end, escape, companion, getParseFlags());
413   }
414   
415   /**
416    * Registering a the sequences that are used for string-like text parts.
417    * See the method description in {@link TokenizerProperties}.
418    *
419    * @param start the starting sequence of a string
420    * @param end the finishing sequence of a string
421    * @param escape the escape sequence inside the string
422    * @param companion the associated information
423    * @param flags modification flags
424    * @throws IllegalArgumentException when <code>null</code> or an empty string is passed for start or end
425    */

426   public void addString(String JavaDoc start, String JavaDoc end, String JavaDoc escape, Object JavaDoc companion, int flags)
427     throws IllegalArgumentException JavaDoc
428   {
429     addString(start, end, escape, companion, flags, flags);
430   }
431   
432   /**
433    * Registering a string with a set of flags and an associated flag mask.
434    *
435    * @param start the starting sequence of a string
436    * @param end the finishing sequence of a string
437    * @param escape the escape sequence inside the string
438    * @param companion the associated information
439    * @param flags modification flags
440    * @param flagMask flags that have valid values in the parameter <code>flags</code>
441    * @throws IllegalArgumentException when <code>null</code> or an empty string
442    * is passed for keyword
443    */

444   public void addString(String JavaDoc start, String JavaDoc end, String JavaDoc escape, Object JavaDoc companion, int flags, int flagMask)
445     throws IllegalArgumentException JavaDoc
446   {
447     addProperty(
448       new TokenizerProperty(Token.STRING, new String JavaDoc[] { start, end, escape },
449                             companion, flags, flagMask)
450     );
451   }
452   
453   /**
454    * Removing a string description.
455    * See the method description in {@link TokenizerProperties}.
456    *
457    * @param start the starting sequence of a string
458    * @throws IllegalArgumentException when <code>null</code> or an empty string is passed for start
459    */

460   public void removeString(String JavaDoc start) throws IllegalArgumentException JavaDoc {
461     TokenizerProperty prop = getString(start);
462     
463     if (prop != null) {
464       removeProperty(prop);
465     }
466   }
467   
468     
469   /**
470    * Retrieving the information associated with a certain string. See the method
471    * description in {@link TokenizerProperties}.
472    *
473    * @param start the starting sequence of a string
474    * @return the associated information or <code>null</code>
475    * @throws IllegalArgumentException when <code>null</code> or an empty string is passed for start
476    */

477   public Object JavaDoc getStringCompanion(String JavaDoc start) throws IllegalArgumentException JavaDoc {
478     TokenizerProperty prop = getString(start);
479     
480     if (prop != null) {
481       return prop.getCompanion();
482     } else {
483       return null;
484     }
485   }
486   
487
488   /**
489    * Checks if the given starting sequence of the string is known to the parser.
490    * See the method description in {@link TokenizerProperties}.
491    *
492    * @param start the starting sequence of a string
493    * @return <code>true</code> if the string is registered,
494    * <code>false</code> otherwise
495    */

496   public boolean stringExists(String JavaDoc start) {
497     try {
498       return getString(start) != null;
499     } catch (IllegalArgumentException JavaDoc ex) {
500       return false;
501     }
502   }
503
504   /**
505    * Get the full description of a string property.
506    * See the method description in {@link TokenizerProperties}.
507    *
508    * @param start the starting sequence of a string
509    * @return the full string description or <code>null</code>
510    * @throws IllegalArgumentException if the given keyword is empty or null
511    */

512   public TokenizerProperty getString(String JavaDoc start) throws IllegalArgumentException JavaDoc {
513     // check parameter
514
checkArgument(start, "String");
515     
516     // get the real thing
517
synchronized(this) {
518       return doGetProperty(Token.STRING, start);
519     }
520   }
521
522   
523   //---------------------------------------------------------------------------
524
// line comment properties
525
//
526

527   /**
528    * Registering a the starting sequence of a line comment.
529    * See the method description in {@link TokenizerProperties}.
530    *
531    * @param lineComment the starting sequence of the line comment
532    * @throws IllegalArgumentException when <code>null</code> or an empty string is passed for start sequence of the line comment
533    */

534   public void addLineComment(String JavaDoc lineComment) throws IllegalArgumentException JavaDoc {
535     addLineComment(lineComment, null);
536   }
537
538   /**
539    * Registering a the starting sequence of a line comment.
540    *
541    * See the method description in {@link TokenizerProperties}.
542    * @param lineComment the starting sequence of a line comment
543    * @param companion the associated information
544    * @throws IllegalArgumentException when <code>null</code> or an empty string is passed for start sequence of the line comment
545    */

546   public void addLineComment(String JavaDoc lineComment, Object JavaDoc companion) throws IllegalArgumentException JavaDoc {
547     addLineComment(lineComment, companion, getParseFlags());
548   }
549
550   
551   /**
552    * Registering a the starting sequence of a line comment.
553    * See the method description in {@link TokenizerProperties}.
554    *
555    * @param lineComment the starting sequence of a line comment
556    * @param companion the associated information
557    * @param flags modification flags
558    * @throws IllegalArgumentException when <code>null</code> or an empty string
559    * is passed for start sequence of the line comment
560    */

561   public void addLineComment(String JavaDoc lineComment, Object JavaDoc companion, int flags) throws IllegalArgumentException JavaDoc {
562     addLineComment(lineComment, companion, flags, flags);
563   }
564
565   /**
566    * Registering a line comment with a set of flags and an associated flag mask.
567    *
568    * @param lineComment the starting sequence of a line comment
569    * @param companion the associated information
570    * @param flags modification flags
571    * @param flagMask flags that have valid values in the parameter <code>flags</code>
572    * @throws IllegalArgumentException when <code>null</code> or an empty string
573    * is passed for keyword
574    */

575   public void addLineComment(String JavaDoc lineComment, Object JavaDoc companion, int flags, int flagMask)
576     throws IllegalArgumentException JavaDoc
577   {
578     addProperty(
579       new TokenizerProperty(Token.LINE_COMMENT, new String JavaDoc[] { lineComment },
580                             companion, flags, flagMask)
581     );
582   }
583
584   /**
585    * Removing a certain line comment.
586    * See the method description in {@link TokenizerProperties}.
587    *
588    * @param lineComment the starting sequence of the line comment
589    * @throws IllegalArgumentException when <code>null</code> or an empty string is passed for start sequence of the line comment
590    */

591   public void removeLineComment(String JavaDoc lineComment) throws IllegalArgumentException JavaDoc {
592     TokenizerProperty prop = getLineComment(lineComment);
593     
594     if (prop != null) {
595       removeProperty(prop);
596     }
597   }
598   
599   
600   /**
601    * Retrieving the associated object of a certain line comment.
602    * See the method description in {@link TokenizerProperties}.
603    *
604    * @param lineComment the starting sequence of the line comment
605    * @return the object associated with the line comment
606    * @throws IllegalArgumentException when <code>null</code> or an empty string is passed for start sequence of the line comment
607    */

608   public Object JavaDoc getLineCommentCompanion(String JavaDoc lineComment) throws IllegalArgumentException JavaDoc {
609     TokenizerProperty prop = getLineComment(lineComment);
610     
611     if (prop != null) {
612       return prop.getCompanion();
613     } else {
614       return null;
615     }
616   }
617
618   /**
619    * Checks if the give line comment is known.
620    * See the method description in {@link TokenizerProperties}.
621    *
622    * @param lineComment the starting sequence of the line comment
623    * @return <code>true</code> if the line comment is known,
624    * <code>false</code> otherwise
625    */

626   public boolean lineCommentExists(String JavaDoc lineComment) {
627     try {
628       return getLineComment(lineComment) != null;
629     } catch (IllegalArgumentException JavaDoc ex) {
630       return false;
631     }
632   }
633
634   /**
635    * Get the full description of a line comment property.
636    * See the method description in {@link TokenizerProperties}.
637    *
638    * @param lineComment the starting sequence of the line comment
639    * @return the full line comment description or <code>null</code>
640    * @throws IllegalArgumentException if the given image is empty or null
641    */

642   public TokenizerProperty getLineComment(String JavaDoc lineComment) throws IllegalArgumentException JavaDoc {
643     // check parameter
644
checkArgument(lineComment, "Line comment");
645     
646     // get the real thing
647
synchronized(this) {
648       return doGetProperty(Token.LINE_COMMENT, lineComment);
649     }
650   }
651   
652
653   //---------------------------------------------------------------------------
654
// block comment properties
655
//
656

657   /**
658    * Registering a block comment. See the method description in
659    * {@link TokenizerProperties}.
660    *
661    * @param start the starting sequence of the block comment
662    * @param end the finishing sequence of the block comment
663    * @throws IllegalArgumentException when <code>null</code> or an empty string
664    * is passed for start / end sequence of the block comment
665    */

666   public void addBlockComment(String JavaDoc start, String JavaDoc end) throws IllegalArgumentException JavaDoc {
667     addBlockComment(start, end, null);
668   }
669   
670   /**
671    * Registering a block comment.
672    * See the method description in {@link TokenizerProperties}.
673    *
674    * @param start the starting sequence of the block comment
675    * @param end the finishing sequence of the block comment
676    * @param companion information object associated with this block comment
677    * @throws IllegalArgumentException when <code>null</code> or an empty string
678    * is passed for start / end sequence of the block comment
679    */

680   public void addBlockComment(String JavaDoc start, String JavaDoc end, Object JavaDoc companion) throws IllegalArgumentException JavaDoc {
681     addBlockComment(start, end, companion, getParseFlags());
682   }
683   
684   /**
685    * Registering a block comment.
686    * See the method description in {@link TokenizerProperties}.
687    *
688    * @param start the starting sequence of the block comment
689    * @param end the finishing sequence of the block comment
690    * @param companion information object associated with this block comment
691    * @param flags modification flags
692    * @throws IllegalArgumentException when <code>null</code> or an empty string
693    * is passed for start / end sequence of the block comment
694    */

695   public void addBlockComment(String JavaDoc start, String JavaDoc end, Object JavaDoc companion, int flags) throws IllegalArgumentException JavaDoc {
696     addBlockComment(start, end, companion, flags, flags);
697   }
698   
699   /**
700    * Registering a block comment with a set of flags and an associated flag mask.
701    *
702    * @param start the starting sequence of the block comment
703    * @param end the finishing sequence of the block comment
704    * @param companion information object associated with this block comment
705    * @param flags modification flags
706    * @param flagMask flags that have valid values in the parameter <code>flags</code>
707    * @throws IllegalArgumentException when <code>null</code> or an empty string
708    * is passed for keyword
709    */

710   public void addBlockComment(String JavaDoc start, String JavaDoc end, Object JavaDoc companion, int flags, int flagMask)
711     throws IllegalArgumentException JavaDoc
712   {
713     addProperty(
714       new TokenizerProperty(Token.BLOCK_COMMENT, new String JavaDoc[] { start, end },
715                             companion, flags, flagMask)
716     );
717   }
718
719   /**
720    * Removing a certain block comment.
721    * See the method description in {@link TokenizerProperties}.
722    *
723    * @param start the starting sequence of the block comment
724    * @throws IllegalArgumentException when <code>null</code> or an empty string
725    * is passed for start sequence of the block comment
726    */

727   public void removeBlockComment(String JavaDoc start) throws IllegalArgumentException JavaDoc {
728     TokenizerProperty prop = getBlockComment(start);
729     
730     if (prop != null) {
731       removeProperty(prop);
732     }
733   }
734   
735   /**
736    * Retrieving a certain block comment.
737    * See the method description in {@link TokenizerProperties}.
738    *
739    * @param start the starting sequence of the block comment
740    * @return the associated object of the block comment
741    * @throws IllegalArgumentException when <code>null</code> or an empty string
742    * is passed for start sequence of the block comment
743    */

744   public Object JavaDoc getBlockCommentCompanion(String JavaDoc start) throws IllegalArgumentException JavaDoc {
745     TokenizerProperty prop = getBlockComment(start);
746     
747     if (prop != null) {
748       return prop.getCompanion();
749     } else {
750       return null;
751     }
752   }
753   
754   /**
755    * Checks if the given block comment is known.
756    * See the method description in {@link TokenizerProperties}.
757    *
758    * @param start the starting sequence of the block comment
759    * @return <code>true</code> if the block comment is known,
760    * <code>false</code> otherwise
761    */

762   public boolean blockCommentExists(String JavaDoc start) {
763     try {
764       return getBlockComment(start) != null;
765     } catch (IllegalArgumentException JavaDoc ex) {
766       return false;
767     }
768   }
769
770   /**
771    * Get the full description of a block comment property.
772    * See the method description in {@link TokenizerProperties}.
773    *
774    * @param start the starting sequence of the block comment
775    * @return the full block comment description or <code>null</code>
776    * @throws IllegalArgumentException if the given image is empty or null
777    */

778   public TokenizerProperty getBlockComment(String JavaDoc start) throws IllegalArgumentException JavaDoc {
779     // check parameter
780
checkArgument(start, "Block comment");
781     
782     // get the real thing
783
synchronized(this) {
784       return doGetProperty(Token.BLOCK_COMMENT, start);
785     }
786   }
787   
788   
789   //---------------------------------------------------------------------------
790
// special sequence properties
791
//
792

793   /**
794    * Registering a special sequence of characters.
795    * See the method description in {@link TokenizerProperties}.
796    *
797    * @param specSeq special sequence to register
798    * @throws IllegalArgumentException if the given sequence is empty or null
799    * @see #addKeyword
800    * @see #setSeparators
801    */

802   public void addSpecialSequence(String JavaDoc specSeq) throws IllegalArgumentException JavaDoc {
803     addSpecialSequence(specSeq, null);
804   }
805   
806   
807   /**
808    * Registering a special sequence of characters.
809    * See the method description in {@link TokenizerProperties}.
810    *
811    * @param specSeq special sequence to register
812    * @param companion information object associated with this special sequence
813    * @throws IllegalArgumentException if the given sequence is empty or null
814    * @see #addKeyword
815    * @see #setSeparators
816    */

817   public void addSpecialSequence(String JavaDoc specSeq, Object JavaDoc companion) throws IllegalArgumentException JavaDoc {
818     addSpecialSequence(specSeq, companion, getParseFlags());
819   }
820
821   
822   /**
823    * Registering a special sequence of characters.
824    * See the method description in {@link TokenizerProperties}.
825    *
826    * @param specSeq special sequence to register
827    * @param companion information object associated with this special sequence
828    * @param flags modification flags
829    * @throws IllegalArgumentException if the given sequence is empty or null
830    * @see #addKeyword
831    * @see #setSeparators
832    */

833   public void addSpecialSequence(String JavaDoc specSeq, Object JavaDoc companion, int flags) throws IllegalArgumentException JavaDoc {
834     addSpecialSequence(specSeq, companion, flags, flags);
835   }
836     
837   /**
838    * Registering a special sequence with a set of flags and an associated flag mask.
839    *
840    * @param specSeq special sequence to register
841    * @param companion information object associated with this special sequence
842    * @param flags modification flags
843    * @param flagMask flags that have valid values in the parameter <code>flags</code>
844    * @throws IllegalArgumentException when <code>null</code> or an empty string
845    * is passed for keyword
846    */

847   public void addSpecialSequence(String JavaDoc specSeq, Object JavaDoc companion, int flags, int flagMask)
848     throws IllegalArgumentException JavaDoc
849   {
850     addProperty(
851       new TokenizerProperty(Token.SPECIAL_SEQUENCE, new String JavaDoc[] { specSeq },
852                             companion, flags, flagMask)
853     );
854   }
855
856   /**
857    * Deregistering a special sequence from the parser.
858    * See the method description in {@link TokenizerProperties}.
859    *
860    * @param specSeq sequence to remove
861    * @throws IllegalArgumentException if the given sequence is empty or null
862    */

863   public void removeSpecialSequence(String JavaDoc specSeq) throws IllegalArgumentException JavaDoc {
864     TokenizerProperty prop = getSpecialSequence(specSeq);
865     
866     if (prop != null) {
867       removeProperty(prop);
868     }
869   }
870   
871   
872   /**
873    * Retrieving the companion of the given special sequence.
874    * See the method description in {@link TokenizerProperties}.
875    *
876    * @param specSeq sequence to remove
877    * @return the object associated with the special sequence
878    * @throws IllegalArgumentException if the given sequence is empty or null
879    */

880   public Object JavaDoc getSpecialSequenceCompanion(String JavaDoc specSeq) throws IllegalArgumentException JavaDoc {
881     TokenizerProperty prop = getSpecialSequence(specSeq);
882     
883     if (prop != null) {
884       return prop.getCompanion();
885     } else {
886       return null;
887     }
888   }
889   
890
891   /**
892    * Checks if the given special sequence is known to the <code>Tokenizer</code>.
893    * See the method description in {@link TokenizerProperties}.
894    *
895    * @param specSeq sequence to check
896    * @return <code>true</code> if the block comment is known,
897    * <code>false</code> otherwise
898    */

899   public boolean specialSequenceExists(String JavaDoc specSeq) {
900     try {
901       return getSpecialSequence(specSeq) != null;
902     } catch (IllegalArgumentException JavaDoc ex) {
903       return false;
904     }
905   }
906   
907   /**
908    * Get the full description of a special sequence property.
909    * See the method description in {@link TokenizerProperties}.
910    *
911    * @param specSeq sequence to search
912    * @return the full sequence description or <code>null</code>
913    * @throws IllegalArgumentException if the given keyword is empty or null
914    */

915   public TokenizerProperty getSpecialSequence(String JavaDoc specSeq) throws IllegalArgumentException JavaDoc {
916     // check parameter
917
checkArgument(specSeq, "Special sequence");
918     
919     // get the keyword
920
synchronized(this) {
921       return doGetProperty(Token.SPECIAL_SEQUENCE, specSeq);
922     }
923   }
924
925   
926   //---------------------------------------------------------------------------
927
// keyword properties
928
//
929

930   /**
931    * Registering a keyword.
932    * See the method description in {@link TokenizerProperties}.
933    *
934    * @param keyword keyword to register
935    * @throws IllegalArgumentException if the given keyword is empty or null
936    */

937   public void addKeyword(String JavaDoc keyword) throws IllegalArgumentException JavaDoc {
938     addKeyword(keyword, null);
939   }
940   
941   
942   /**
943    * Registering a keyword.
944    * See the method description in {@link TokenizerProperties}.
945    *
946    * @param keyword keyword to register
947    * @param companion information object associated with this keyword
948    * @throws IllegalArgumentException if the given keyword is empty or null
949    */

950   public void addKeyword(String JavaDoc keyword, Object JavaDoc companion) throws IllegalArgumentException JavaDoc {
951     addKeyword(keyword, companion, getParseFlags());
952   }
953   
954   
955   /**
956    * Registering a keyword.
957    * See the method description in {@link TokenizerProperties}.
958    *
959    * @param keyword keyword to register
960    * @param companion information object associated with this keyword
961    * @throws IllegalArgumentException if the given keyword is empty or null
962    */

963   public void addKeyword(String JavaDoc keyword, Object JavaDoc companion, int flags) throws IllegalArgumentException JavaDoc {
964     addKeyword(keyword, companion, flags, flags);
965   }
966   
967   /**
968    * Registering a keyword with a set of flags and an associated flag mask..
969    *
970    * @param keyword keyword to register
971    * @param companion information object associated with this keyword
972    * @param flags modification flags
973    * @param flagMask flags that have valid values in the parameter <code>flags</code>
974    * @throws IllegalArgumentException when <code>null</code> or an empty string
975    * is passed for keyword
976    */

977   public void addKeyword(String JavaDoc keyword, Object JavaDoc companion, int flags, int flagMask)
978     throws IllegalArgumentException JavaDoc
979   {
980     addProperty(
981       new TokenizerProperty(Token.KEYWORD, new String JavaDoc[] { keyword }, companion, flags, flagMask)
982     );
983   }
984   
985   /**
986    * Deregistering a keyword.
987    * See the method description in {@link TokenizerProperties}.
988    *
989    * @param keyword keyword to remove
990    * @throws IllegalArgumentException if the given keyword is empty or null
991    */

992   public void removeKeyword(String JavaDoc keyword) throws IllegalArgumentException JavaDoc {
993     TokenizerProperty prop = getKeyword(keyword);
994     
995     if (prop != null) {
996       removeProperty(prop);
997     }
998   }
999   
1000  
1001  /**
1002   * Retrieving the companion of the given keyword.
1003   * See the method description in {@link TokenizerProperties}.
1004   *
1005   * @param keyword keyword thats companion is sought
1006   * @return the object associated with the keyword
1007   * @throws IllegalArgumentException if the given keyword is empty or null
1008   */

1009  public Object JavaDoc getKeywordCompanion(String JavaDoc keyword) throws IllegalArgumentException JavaDoc {
1010    TokenizerProperty prop = getKeyword(keyword);
1011    
1012    if (prop != null) {
1013      return prop.getCompanion();
1014    } else {
1015      return null;
1016    }
1017  }
1018
1019  /**
1020   * Checks if the given keyword is known to the <code>Tokenizer</code>.
1021   * See the method description in {@link TokenizerProperties}.
1022   *
1023   * @param keyword keyword to search
1024   * @return <code>true</code> if the keyword is known,
1025   * <code>false</code> otherwise
1026   */

1027  public boolean keywordExists(String JavaDoc keyword) {
1028    try {
1029      return getKeyword(keyword) != null;
1030    } catch (IllegalArgumentException JavaDoc ex) {
1031      return false;
1032    }
1033  }
1034
1035  /**
1036   * Get the full description of a keyword property.
1037   * See the method description in {@link TokenizerProperties}.
1038   *
1039   * @param keyword keyword to search
1040   * @return the full keyword description or <code>null</code>
1041   * @throws IllegalArgumentException if the given keyword is empty or null
1042   */

1043  public TokenizerProperty getKeyword(String JavaDoc keyword) throws IllegalArgumentException JavaDoc {
1044    // check parameter
1045
checkArgument(keyword, "Keyword");
1046    
1047    // get the keyword
1048
synchronized(this) {
1049      return doGetProperty(Token.KEYWORD, keyword);
1050    }
1051  }
1052
1053
1054  //---------------------------------------------------------------------------
1055
// pattern properties
1056
//
1057

1058  /**
1059   * Registering a pattern. See the method description in {@link TokenizerProperties}.
1060   *
1061   * @param pattern the regular expression to be added
1062   * @throws IllegalArgumentException when <code>null</code> or an empty pattern
1063   * is passed
1064   * @see #removePattern
1065   * @see #addPattern(String, Object)
1066   * @see #addPattern(String, Object, int)
1067   */

1068  public void addPattern(String JavaDoc pattern) throws IllegalArgumentException JavaDoc {
1069    addPattern(pattern, null);
1070  }
1071
1072  /**
1073   * Registering a pattern with an associated object. See the method description
1074   * in {@link TokenizerProperties}.
1075   *
1076   * @param pattern the regular expression to be added
1077   * @param companion information object associated with this pattern
1078   * @throws IllegalArgumentException when <code>null</code> or an empty pattern
1079   * is passed
1080   * @see #removePattern
1081   * @see #addPattern(String)
1082   * @see #addPattern(String, Object, int)
1083   */

1084  public void addPattern(String JavaDoc pattern, Object JavaDoc companion) throws IllegalArgumentException JavaDoc {
1085    addPattern(pattern, companion, getParseFlags());
1086  }
1087
1088  /**
1089   * Registering a pattern with an associated object. See the method description
1090   * in {@link TokenizerProperties}.
1091   *
1092   * @param pattern the regular expression to be added
1093   * @param companion information object associated with this keyword
1094   * @param flags modification flags
1095   * @throws IllegalArgumentException when <code>null</code> or an empty pattern
1096   * is passed
1097   * @see #removePattern
1098   * @see #addPattern(String)
1099   * @see #addPattern(String, Object)
1100   */

1101  public void addPattern(String JavaDoc pattern, Object JavaDoc companion, int flags) throws IllegalArgumentException JavaDoc {
1102    addPattern(pattern, companion, flags, flags);
1103  }
1104  
1105  /**
1106   * Registering a pattern with an associated object and explicitely given flags.
1107   * See the description of the {@link #addPattern(String)} for details on pattern.
1108   *
1109   * @param pattern the regular expression to be added
1110   * @param companion information object associated with this keyword
1111   * @param flags values for modification flags
1112   * @param flagMask flags that have valid values in the parameter <code>flags</code>
1113   * @throws IllegalArgumentException when <code>null</code> or an empty pattern
1114   * is passed
1115   */

1116  public void addPattern(String JavaDoc pattern, Object JavaDoc companion, int flags, int flagMask)
1117    throws IllegalArgumentException JavaDoc
1118  {
1119    addProperty(
1120      new TokenizerProperty(Token.PATTERN, new String JavaDoc[] { pattern }, companion, flags, flagMask)
1121    );
1122  }
1123  
1124  /**
1125   * Removing a pattern. See the method description in {@link TokenizerProperties}.
1126   *
1127   * @param pattern the regular expression to be removed
1128   * @throws IllegalArgumentException when <code>null</code> or an empty string
1129   * is passed
1130   */

1131  public void removePattern(String JavaDoc pattern) throws IllegalArgumentException JavaDoc {
1132    TokenizerProperty prop = getPattern(pattern);
1133    
1134    if (prop != null) {
1135      removeProperty(prop);
1136    }
1137  }
1138  
1139  /**
1140   * Retrieving the information associated with a given pattern. See the method
1141   * description in {@link TokenizerProperties}.
1142   *
1143   * @param pattern the regular expression to be removed
1144   * @return the associated information or <code>null</code>
1145   * @throws IllegalArgumentException when <code>null</code> or an emtpy pattern
1146   * is passed
1147   */

1148  public Object JavaDoc getPatternCompanion(String JavaDoc pattern) throws IllegalArgumentException JavaDoc {
1149    TokenizerProperty prop = getPattern(pattern);
1150    
1151    if (prop != null) {
1152      return prop.getCompanion();
1153    } else {
1154      return null;
1155    }
1156  }
1157  
1158  /**
1159   * Checks if the given pattern is known to the parser.
1160   * See the method description in {@link TokenizerProperties}.
1161   *
1162   * @param pattern the regular expression to be looked for
1163   * @return <code>true</code> if the pattern is registered,
1164   * <code>false</code> otherwise
1165   */

1166  public boolean patternExists(String JavaDoc pattern) {
1167    try {
1168      return getPattern(pattern) != null;
1169    } catch (IllegalArgumentException JavaDoc ex) {
1170      return false;
1171    }
1172  }
1173  
1174
1175  /**
1176   * Get the full description of a string property starting with the given
1177   * prefix. The method returns <code>null</code> if the passed <code>start</code>
1178   * parameter cannot be mapped to a known string description ({@link #stringExists}
1179   * would return <code>false</code>).
1180   *
1181   * @param pattern the regular expression to be looked for
1182   * @return the full pattern description or <code>null</code>
1183   * @throws IllegalArgumentException when <code>null</code> or an emtpy pattern
1184   * is passed
1185   */

1186  public TokenizerProperty getPattern(String JavaDoc pattern) throws IllegalArgumentException JavaDoc {
1187    // check parameter
1188
checkArgument(pattern, "Pattern");
1189    
1190    // get the pattern
1191
synchronized(this) {
1192      return doGetProperty(Token.PATTERN, pattern);
1193    }
1194  }
1195
1196  
1197  //---------------------------------------------------------------------------
1198
// Common properties
1199
//
1200

1201  /**
1202   * Registering a {@link TokenizerProperty}.
1203   * See the method description in {@link TokenizerProperties}.
1204   *
1205   * @param property property to register
1206   * @throws IllegalArgumentException when <code>null</code>, an incomplete or
1207   * otherwise unusable property is passed
1208   */

1209  public void addProperty(TokenizerProperty property) throws IllegalArgumentException JavaDoc {
1210    // check the parameter
1211
checkPropertyArgument(property);
1212    
1213    // check special cases
1214
String JavaDoc[] images = property.getImages();
1215    
1216    switch (property.getType()) {
1217    case Token.STRING:
1218    case Token.BLOCK_COMMENT:
1219      checkArgument((images.length < 2) ? null : images[1], "End sequence");
1220      break;
1221    }
1222
1223    // add property according to type
1224
synchronized(this) {
1225      TokenizerProperty oldProp = doAddProperty(property);
1226
1227      if (oldProp == null) {
1228        notifyListeners(new TokenizerPropertyEvent(TokenizerPropertyEvent.PROPERTY_ADDED, property));
1229      } else if ( ! oldProp.equals(property)) {
1230        notifyListeners(new TokenizerPropertyEvent(TokenizerPropertyEvent.PROPERTY_MODIFIED, property, oldProp));
1231      }
1232    }
1233  }
1234  
1235  /**
1236   * Deregistering a {@link TokenizerProperty} from the store.
1237   * See the method description in {@link TokenizerProperties}.
1238   *
1239   * @param property property to register
1240   * @throws IllegalArgumentException when <code>null</code>, an incomplete or
1241   * otherwise unusable property is passed
1242   */

1243  public void removeProperty(TokenizerProperty property) throws IllegalArgumentException JavaDoc {
1244    // check the parameter
1245
checkPropertyArgument(property);
1246    
1247    // removing property according to type
1248
synchronized(this) {
1249      TokenizerProperty removed = doRemoveProperty(property);
1250    
1251      if (removed != null) {
1252        notifyListeners(new TokenizerPropertyEvent(TokenizerPropertyEvent.PROPERTY_REMOVED, removed));
1253      }
1254    }
1255  }
1256  
1257
1258  /**
1259   * Checks if the given {@link TokenizerProperty} is known.
1260   * See the method description in {@link TokenizerProperties}.
1261   *
1262   * @param property the property to search
1263   * @return <code>true</code> if the property is known,
1264   * <code>false</code> otherwise
1265   */

1266  public boolean propertyExists(TokenizerProperty property) {
1267    try {
1268      checkPropertyArgument(property);
1269      synchronized(this) {
1270        return doGetProperty(property.getType(), property.getImages()[0]) != null;
1271      }
1272    } catch (IllegalArgumentException JavaDoc ex) {
1273      return false;
1274    }
1275  }
1276
1277
1278  //---------------------------------------------------------------------------
1279
// Methods of the DataMapper interface
1280
//
1281

1282  /**
1283   * Registering a new {@link TokenizerPropertyListener}.
1284   * See the method description in {@link TokenizerProperties}.
1285   *
1286   * @param listener the new {@link TokenizerPropertyListener}
1287   * @see #removeTokenizerPropertyListener
1288   */

1289  public void addTokenizerPropertyListener(TokenizerPropertyListener listener) {
1290    if (listener != null) {
1291      synchronized(_listeners) {
1292        WeakReference JavaDoc ref = new WeakReference JavaDoc(listener);
1293        _listeners.add(ref);
1294      }
1295    }
1296  }
1297  
1298  
1299  /**
1300   * Removing a listener from the list of registered {@link TokenizerPropertyListener}
1301   * instances.
1302   * See the method description in {@link TokenizerProperties}.
1303   *
1304   * @param listener the {@link TokenizerPropertyListener} to deregister
1305   * @see #addTokenizerPropertyListener
1306   */

1307  public void removeTokenizerPropertyListener(TokenizerPropertyListener listener) {
1308    if (listener != null) {
1309      synchronized(_listeners) {
1310        Iterator JavaDoc iter = _listeners.iterator();
1311
1312        while (iter.hasNext()) {
1313          WeakReference JavaDoc ref = (WeakReference JavaDoc)iter.next();
1314          Object JavaDoc elem = ref.get();
1315          
1316          if (elem == null) {
1317            // implicit cleanup
1318
iter.remove();
1319          } else if (listener.equals(elem)) {
1320            // found the real one
1321
iter.remove();
1322            break;
1323          }
1324        }
1325      }
1326    }
1327  }
1328 
1329  
1330  //---------------------------------------------------------------------------
1331
// Implementation
1332
//
1333

1334  /**
1335   * Puts or removes all characters in the given set into or from a given
1336   * {@link java.util.Map}.
1337   *
1338   * @param map put the characters of the set into this map
1339   * @param set the character set to map
1340   * @param removeIt if <code>true</code> remove the characters of the set, otherwise add them
1341   * @throws IllegalArgumentException if the set contains incomplete ranges
1342   */

1343  private void mapCharacterSet(Map JavaDoc map, String JavaDoc set, boolean removeIt) throws IllegalArgumentException JavaDoc {
1344    for (int index = 0; index < set.length(); ++index) {
1345      char cc = set.charAt(index);
1346      
1347      switch (cc) {
1348      case '-':
1349        try {
1350          char start = set.charAt(index - 1);
1351          char end = set.charAt(index + 1);
1352          if (end == '\\') {
1353            end = set.charAt(index + 2);
1354            index += 2;
1355          } else {
1356            index++;
1357          }
1358          for (char rangeCC = start; rangeCC <= end; ++rangeCC) {
1359            if (removeIt) {
1360              map.remove(new Character JavaDoc(rangeCC));
1361            } else {
1362              map.put(new Character JavaDoc(rangeCC), null);
1363            }
1364          }
1365        } catch (Exception JavaDoc ex) {
1366          throw new IllegalArgumentException JavaDoc(set);
1367        }
1368        break;
1369        
1370      case '\\':
1371        index++;
1372        cc = set.charAt(index);
1373        /* no break; */
1374      default:
1375        if (index + 1 >= set.length() || set.charAt(index + 1) != '-') {
1376          if (removeIt) {
1377            map.remove(new Character JavaDoc(cc));
1378          } else {
1379            map.put(new Character JavaDoc(cc), null);
1380          }
1381        }
1382      }
1383    }
1384  }
1385  
1386  /**
1387   * Build the escape sequence for a character in a set if nessecary.
1388   *
1389   * @param cc the character to test
1390   * @return <code>true</code> if the given character must be escaped,
1391   * <code>false</code> otherwise
1392   */

1393  private boolean escapeChar(char cc) {
1394    switch (cc) {
1395    case '\\':
1396    case '-':
1397      return true;
1398    default:
1399      return false;
1400    }
1401  }
1402
1403  /**
1404   * Add a character range to a string. The method checks if the given start
1405   * and end characters actually form a range.
1406   *
1407   * @param buffer add range to this buffer
1408   * @param rangeStart first character in range
1409   * @param rangeEnd last character in range
1410   */

1411  private void addRange(StringBuffer JavaDoc buffer, char rangeStart, char rangeEnd) {
1412    if (escapeChar(rangeStart)) {
1413      buffer.append('\\');
1414    }
1415    buffer.append((char)rangeStart);
1416    if (rangeStart < rangeEnd - 1) {
1417      buffer.append('-');
1418    }
1419    if (rangeStart != rangeEnd) {
1420      if (escapeChar(rangeEnd)) {
1421        buffer.append('\\');
1422      }
1423      buffer.append((char)rangeEnd);
1424    }
1425  }
1426
1427  
1428  /**
1429   * Merges tho character set strings that may contain characters ranges like
1430   * "a-z". The result is united character set of both parameters.
1431   *
1432   * @param set1 first character set
1433   * @param set2 second character set
1434   * @param removeSet2 should the second set ber removed rather than added?
1435   * @return the characters of the first set + the characters of the second set
1436   * if not already present in the first set.
1437   * @throws IllegalArgumentException if the set contains incomplete ranges
1438   */

1439  private String JavaDoc mergeSet(String JavaDoc set1, String JavaDoc set2, boolean removeSet2) throws IllegalArgumentException JavaDoc {
1440    // merge the sets into a map
1441
TreeMap JavaDoc map = new TreeMap JavaDoc();
1442    
1443    mapCharacterSet(map, set1, false);
1444    mapCharacterSet(map, set2, removeSet2);
1445    
1446    // iterate through the map in a predefined order
1447
StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(set1.length() + set2.length());
1448    
1449    if (map.size() > 0) {
1450      Iterator JavaDoc iter = map.keySet().iterator();
1451      char rangeStart = ((Character JavaDoc)map.firstKey()).charValue();
1452      char rangeEnd = rangeStart;
1453
1454      while (iter.hasNext()) {
1455        char cc = ((Character JavaDoc)iter.next()).charValue();
1456
1457        if (cc > rangeEnd + 1) {
1458          addRange(buffer, rangeStart, rangeEnd);
1459          rangeStart = rangeEnd = cc;
1460        } else {
1461          rangeEnd = cc;
1462        }
1463      }
1464      addRange(buffer, rangeStart, rangeEnd);
1465    }
1466    
1467    // ready
1468
return buffer.toString();
1469  }
1470  
1471  /**
1472   * Normalize flags. This is nessecary for the case-sensitivity flags
1473   * {@link Flags#F_CASE} and {@link Flags#F_NO_CASE}.
1474   * If neither <code>F_CASE</code> nor <code>F_NO_CASE</code> is set, <code>F_CASE</code>
1475   * is assumed. If both flags are set, <code>F_CASE</code> takes preceedence.
1476   *
1477   * @param flags not yet normalized flags
1478   * @param flagMask which flags should be handled
1479   * @return the normalized flags
1480   */

1481  private int normalizeFlags(int flags, int flagMask) {
1482    if ((flagMask & (Flags.F_CASE | Flags.F_NO_CASE)) == (Flags.F_CASE | Flags.F_NO_CASE)) {
1483      if ((flags & (Flags.F_CASE | Flags.F_NO_CASE)) == 0) {
1484        // none set: F_CASE is the default
1485
flags |= Flags.F_CASE;
1486      } else if ((flags & Flags.F_CASE) != 0) {
1487        // perhaps both set: F_CASE weights more
1488
flags &= ~Flags.F_NO_CASE;
1489      }
1490    }
1491    return flags;
1492  }
1493    
1494  /**
1495   * Checking a string parameter on null or emptiness. The method encapsulates
1496   * commonly used code (see {@link #addKeyword} or {@link #addSpecialSequence}
1497   * for example).
1498   *
1499   * @param arg the parameter to check
1500   * @param name a name for the <code>arg</code> parameter
1501   * @throws IllegalArgumentException if the given <code>arg</code> is null or empty
1502   */

1503  protected void checkArgument(String JavaDoc arg, String JavaDoc name) throws IllegalArgumentException JavaDoc {
1504    if (arg == null) {
1505      throw new ExtIllegalArgumentException("{0} is null.", new Object JavaDoc[] { name } );
1506    } else if (arg.length() <= 0) {
1507      throw new ExtIllegalArgumentException("{0} is empty.", new Object JavaDoc[] { name } );
1508    }
1509  }
1510  
1511  /**
1512   * Checking a {@link TokenizerProperty} parameter on null or missing nessecary
1513   * values. The method encapsulates commonly used code (see {@link #addProperty}
1514   * and {@link #removeProperty}).
1515   *
1516   * @param property the parameter to check
1517   * @throws IllegalArgumentException if the given <code>arg</code> is null or empty
1518   */

1519  protected void checkPropertyArgument(TokenizerProperty property) throws IllegalArgumentException JavaDoc {
1520    // check the parameter
1521
if (property == null) {
1522      throw new ExtIllegalArgumentException("Property is null.", null );
1523    } else if (property.getImages() == null) {
1524      throw new ExtIllegalArgumentException("No image(s) given in property.", null );
1525    } else if (property.getImages()[0] == null) {
1526      throw new ExtIllegalArgumentException("No (leading) image given in property.", null );
1527    }
1528  }
1529
1530  /**
1531   * The method fires the nessecary events when whitespace or separator sets
1532   * change.
1533   *
1534   * @param type token type
1535   * @param newValue the newly set value
1536   * @param oldValue the old value with case-sensitive handling
1537   */

1538  protected void handleEvent(
1539    int type,
1540    String JavaDoc newValue,
1541    String JavaDoc oldValue
1542  )
1543  {
1544    if (newValue != null && newValue.length() > 0) {
1545      if (oldValue == null) {
1546        notifyListeners(
1547          new TokenizerPropertyEvent(
1548                TokenizerPropertyEvent.PROPERTY_ADDED,
1549                new TokenizerProperty(type, new String JavaDoc[] { newValue } )));
1550      } else if ( ! oldValue.equals(newValue)) {
1551        notifyListeners(
1552          new TokenizerPropertyEvent(
1553                TokenizerPropertyEvent.PROPERTY_MODIFIED,
1554                new TokenizerProperty(type, new String JavaDoc[] { newValue } ),
1555                new TokenizerProperty(type, new String JavaDoc[] { oldValue } )));
1556      }
1557    } else if (oldValue != null && oldValue.length() > 0) {
1558      notifyListeners(
1559        new TokenizerPropertyEvent(
1560              TokenizerPropertyEvent.PROPERTY_REMOVED,
1561              new TokenizerProperty(type, new String JavaDoc[] { oldValue } )));
1562    }
1563  }
1564  
1565  /**
1566   * Notifying the registered listeners about a change in the properties. Listeners
1567   * are called in the order of their registration (see {@link #addTokenizerPropertyListener}).
1568   *
1569   * @param event the {@link TokenizerPropertyEvent} to communicate to the listeners
1570   */

1571  protected void notifyListeners(TokenizerPropertyEvent event) {
1572    Iterator JavaDoc iter = _listeners.iterator();
1573
1574    while (iter.hasNext()) {
1575      WeakReference JavaDoc ref = (WeakReference JavaDoc)iter.next();
1576      TokenizerPropertyListener listener = (TokenizerPropertyListener)ref.get();
1577
1578      if (listener == null) {
1579        // implicit cleanup of unused listeners
1580
iter.remove();
1581      } else {
1582        // call listener
1583
listener.propertyChanged(event);
1584      }
1585    }
1586  }
1587  
1588
1589  //---------------------------------------------------------------------------
1590
// Members
1591
//
1592

1593  /**
1594   * overall tokenizer flags.
1595   */

1596  protected int _flags = 0;
1597  
1598  /**
1599   * List of {@link TokenizerPropertyListener} instances.
1600   */

1601  private LinkedList JavaDoc _listeners = new LinkedList JavaDoc();
1602}
1603
Popular Tags