KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > admin > common > NameParser


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 package com.sun.enterprise.admin.common;
25
26 import java.util.Iterator JavaDoc;
27 import java.util.Vector JavaDoc;
28 import java.util.Stack JavaDoc;
29 import java.util.EmptyStackException JavaDoc;
30
31 // i18n import
32
import com.sun.enterprise.admin.util.SOMLocalStringsManager;
33
34 /**
35     A Class that parses the given Character String as per NameSpace Grammar.
36     Implemented using a StringBuffer of valid tokens. Uses a two pass technique in
37     which first pass does all the validity checks and second pass actually
38     segragates the given String into a collection of NameParts delimited by
39     the delimiter character from Tokens class.
40     @see Tokens
41 */

42
43 public class NameParser
44 {
45     private String JavaDoc mString = null;
46     private Vector JavaDoc mNameParts = null;
47
48     // i18n SOMLocalStringsManager
49
private static SOMLocalStringsManager localizedStrMgr =
50         SOMLocalStringsManager.getManager( NameParser.class );
51
52     /**
53         Default constructor for initialization purpose.
54     */

55
56     public NameParser()
57     {
58         mNameParts = new Vector JavaDoc();
59     }
60
61
62     /**
63         A method in the public interface of this class which initializes
64         the parsing process.
65         <p>
66         @param the string to be parsed. Should be non null.
67         <p>
68         @throws MalformedNameException, if the string is not per grammer
69     */

70
71     public void parseIt(String JavaDoc parseString) throws MalformedNameException
72     {
73         //ArgChecker.check(parseString != null, "null string to parse");
74
mString = parseString;
75         parseStringForNameParts();
76         parseNameParts();
77         if(! isWildcardCharValid())
78         {
79
80             String JavaDoc msg = localizedStrMgr.getString( "admin.common.invalid_wild-card_char_placement" );
81             throw new MalformedNameException( msg );
82         }
83     }
84
85
86     /**
87         Returns the iterator for all the name-parts, for the parsed string.
88         Guaranteed to return a non null iterator even if there are no elements
89         in it.
90
91         @return iterator to iterate through the string representations of
92                 name-parts of a name string
93     */

94
95     public Iterator JavaDoc getParts()
96     {
97         return ( mNameParts.iterator() );
98     }
99
100
101     
102     private String JavaDoc removeEscapes(String JavaDoc str)
103     {
104         int idx;
105         while((idx=str.indexOf(Tokens.kEscapeChar))>=0)
106             if(idx==0)
107                 str = str.substring(1);
108             else
109                 str = str.substring(0, idx)+str.substring(idx+1);
110         return str;
111                
112     }
113     /**
114         Segregates the string to be parsed into the vector of name-parts.
115         Each Name-part is delimited by a delimiter character defined in
116         the Tokens class. This method while segregating the name-parts,
117         determines whether any scanned single character is valid.
118
119         @throws MalformedNameException if the namestring is invalid
120     */

121     private void parseStringForNameParts() throws MalformedNameException
122     {
123         int counter = 0;
124         int begin = counter;
125         String JavaDoc nameString = null;
126
127         while(counter < mString.length())
128         {
129             char parseChar = mString.charAt(counter);
130             if(isValidChar(parseChar))
131             {
132                 boolean gotDelimiter = isDelimiterChar(mString, counter);
133                 if(gotDelimiter)
134                 {
135                     nameString = mString.substring(begin, counter);
136                     begin = counter + 1;
137                     mNameParts.addElement(removeEscapes(nameString));
138                     //Debug.println("a name string: " + nameString);
139
}
140             }
141             else
142             {
143                 String JavaDoc msg = localizedStrMgr.getString( "admin.common.invalid_char_encountered", new String JavaDoc( parseChar + "" ) );
144                 throw new MalformedNameException( msg );
145             }
146             counter++;
147         }
148         nameString = mString.substring(begin);
149         mNameParts.addElement(removeEscapes(nameString));
150         //Debug.println("a name string: " + nameString);
151
}
152
153
154     /**
155         Method to parse each individual name-part in the name.
156
157         @throws MalformedNameException if any name-part is invalid.
158     */

159
160     private void parseNameParts() throws MalformedNameException
161     {
162         Iterator JavaDoc partsIter = getParts();
163         boolean canReduce = false;
164
165         while(partsIter.hasNext())
166         {
167             String JavaDoc aNamePartString = (String JavaDoc) partsIter.next();
168             canReduce = reduceNamePart(aNamePartString);
169             if(! canReduce)
170             {
171                 String JavaDoc msg = localizedStrMgr.getString( "admin.common.invalid_name", mString );
172                 throw new MalformedNameException( msg );
173             }
174         }
175     }
176
177
178     /**
179         Determines whether the wild-card character is per grammar.
180         A wild-card character is permissible in name, if and only if
181         <li>
182             it is a name-part which has no other char with it &&
183         <li>
184             it is the last name-part.
185         <p>
186         It is valid to have no wildcard character at all.
187     */

188
189     private boolean isWildcardCharValid()
190     {
191         boolean isWildcardCharValid = true;
192         String JavaDoc starString = new String JavaDoc(new char[]{Tokens.kWildCardChar});
193
194         /*
195             if Any name-part contains wild-card char, then that name-part
196             should be the only thing that name-part.
197         */

198         for(int i = 0 ; i < mNameParts.size(); i++)
199         {
200             String JavaDoc aPart = (String JavaDoc) mNameParts.elementAt(i);
201             if(aPart.indexOf(Tokens.kWildCardChar) != -1 &&
202                ! aPart.equals(starString))
203             {
204                 isWildcardCharValid = false;
205                 break;
206             }
207         }
208         
209         return isWildcardCharValid;
210     }
211
212     /**
213         Determines whether given character is valid as a single character.
214
215         @returns true if argument is valid character, false otherwise
216     */

217
218     private boolean isValidChar(char aChar)
219     {
220         return ( Character.isLetter(aChar) ||
221                  Character.isDigit(aChar) ||
222                  this.isPermissibleChar(aChar)||
223                  this.isSpecialChar(aChar)
224                 );
225
226     }
227
228
229     /**
230         There are certain characters that are neither letters nor digits but are
231         allowed in names and this method determines whether the given character
232         is such a permissible special character.
233         <p>
234         @param a character
235         @return true if the argument is allowed special character, false otherwise
236     */

237
238     private boolean isPermissibleChar(char aChar)
239     {
240         boolean isPermissibleChar = false;
241
242         if (aChar == Tokens.kSubScriptBeginnerChar ||
243             aChar == Tokens.kSubScriptEnderChar ||
244             aChar == Tokens.kDelimiterChar ||
245             aChar == Tokens.kEscapeChar ||
246             aChar == Tokens.kWildCardChar)
247         {
248             isPermissibleChar = true;
249         }
250         return isPermissibleChar;
251     }
252
253
254     /**
255         Determines whether the given character is one of Tokens.kSpecialsString.
256
257         @return true if the character is special, false otherwise
258     */

259
260     private boolean isSpecialChar(char aChar)
261     {
262         return ( Tokens.kSpecialsString.indexOf(aChar) != -1 );
263     }
264
265
266     /**
267         Returns if given character is a non-zero digit (1..9)
268     */

269
270     private boolean isNonZeroDigit(char aChar)
271     {
272         return ( Tokens.kNonZeroDigitsString.indexOf(aChar) != -1 );
273     }
274
275
276     /**
277         The actual method that does parsing and determines whether the
278         sequence of characters in given string is according
279         to the grammar.
280     */

281
282     private boolean reduceNamePart(String JavaDoc npString)
283     {
284         boolean canReduce = true;
285
286         if (isSubscriptPresent(npString))
287         {
288             canReduce = isSubscriptValid(npString);
289         }
290         if (canReduce)
291         {
292             String JavaDoc subscriptLessString = removeSubscript(npString);
293             canReduce = isSubscriptLessStringValid(subscriptLessString);
294         }
295         return ( canReduce );
296     }
297
298
299     /**
300         A method to determine whether character at given position in given
301         string is Tokens.kDelimiterChar && is acting as a delimiter.
302         <p>
303         A Tokens.kDelimiterChar is delimiter if and only if it is
304         <it> not escaped </it> with Tokens.kEscapeChar just before it.
305         <p>
306         @param aString and the position of a character which needs to be tested
307             for being delimiter
308         @param position integer position that denotes a delimiter character
309         @return boolean true if such character is delimiter, false otherwise
310     */

311
312     private boolean isDelimiterChar(String JavaDoc aString, int position)
313     {
314         boolean isDelim = false;
315
316         //Assert.assertRange(position, -1, aString.length(), "invalid position");
317

318         if(aString.charAt(position) == Tokens.kDelimiterChar)
319         {
320             if(position == 0 ||
321                aString.charAt(position - 1) != Tokens.kEscapeChar
322                )
323             {
324                 isDelim = true;
325             }
326         }
327         return ( isDelim );
328     }
329
330
331     /**
332         A method to determine whether given string reprensents a valid
333         index. An index is invalid if either of the following is true
334         <li> it is negative, OR
335         <li> it is zero and length of the string is more than 1, OR
336         <li> it is greater than zero and its first digit is 0
337         <p>
338         In all other cases the string represents a valid index.
339
340         @param index string representing the index
341     */

342
343     private boolean isValidIndexString(String JavaDoc index)
344     {
345         boolean isValidIndex = true;
346
347         if (index != null && index.length() > 0)
348         {
349             try
350             {
351                 int intValue = Integer.parseInt(index);
352                 if((intValue == 0 && index.length() != 1) ||
353                    (intValue > 0 && index.charAt(0) == Tokens.kZeroDigitChar) ||
354                    (intValue < 0)
355                    )
356                 {
357                     isValidIndex = false;
358                 }
359             }
360             catch(NumberFormatException JavaDoc e)
361             {
362                 //ExceptionUtil.ignoreException(e);
363
isValidIndex = false;
364             }
365         }
366         else
367         {
368             isValidIndex = false;
369         }
370
371         return ( isValidIndex );
372     }
373
374
375     /**
376         Determines whether any subscript character (Tokens.kSubscriptBeginnerChar)
377         or (Tokens.kSubscriptEnderChar) is present.
378
379         @param npString the string to be tested for subscript characters
380
381         @return true if argument contains either subscript character, false otherwise
382     */

383
384     private boolean isSubscriptPresent(String JavaDoc npString)
385     {
386         boolean subscriptPresent = false;
387
388         if(npString.indexOf(Tokens.kSubScriptBeginnerChar) != -1 ||
389            npString.indexOf(Tokens.kSubScriptEnderChar) != -1
390            )
391         {
392             subscriptPresent = true;
393         }
394         return ( subscriptPresent );
395     }
396
397
398     /**
399         Checks whether the string present inside []
400         can be a valid index.
401         Only non-negative integers are valid with some exceptions. e.g. 32 is a
402         valid index, but 03 or 004 is not.
403         <p>
404         In other words this method does following checks:
405         <li>
406             The subscript characters are ordered in given string
407             #isSubscriptOrdered(java.lang.String)
408         <li>
409             The contents of string between first index of Tokens.kSubscriptBeginnerChar and
410             Tokens.kSubScriptEnderChar evaluates to a permissible integer value.
411             #isValidIndexString(java.lang.String)
412         <li>
413             if there is a subscript, it is always at the end of the string, as
414             abc[5]d is invalid.
415         <p>
416
417         @param npString any string
418         @return true if the string contains a valid subscript, false otherwise
419     */

420
421     private boolean isSubscriptValid(String JavaDoc npString)
422     {
423         boolean subscriptValid = true;
424
425         boolean subscriptOrdered = isSubscriptOrdered(npString);
426         if(subscriptOrdered)
427         {
428             int leftPos = npString.indexOf(Tokens.kSubScriptBeginnerChar);
429             int rightPos = npString.lastIndexOf(Tokens.kSubScriptEnderChar);
430
431             String JavaDoc indexString = npString.substring(leftPos + 1, rightPos);
432             if(! isValidIndexString(indexString))
433             {
434                 subscriptValid = false;
435             }
436             boolean lastCharIsRightSquareBracket =
437                 npString.charAt(npString.length() - 1) == Tokens.kSubScriptEnderChar;
438
439             if(! lastCharIsRightSquareBracket)
440             {
441                 subscriptValid = false;
442             }
443         }
444         else
445         {
446             subscriptValid = false;
447         }
448
449         return ( subscriptValid );
450     }
451
452     /**
453         Simple stack based implementation to test whether the subscripts
454         are in order. e.g. [], [][], [[]] are all valid orders and ][, [[], []]
455         are all invalid orders.
456         <p>
457         Note that if the string passed does not contain
458         any subscript character i.e. a string without '[' or ']', then this
459         method returns false.
460
461         @param npString any string
462         @return true if the subscripts are ordered, false otherwise
463     */

464
465     private boolean isSubscriptOrdered(String JavaDoc npString)
466     {
467         boolean subscriptOrdered = true;
468         int index = 0;
469         Stack JavaDoc charStack = new Stack JavaDoc();
470
471         if(isSubscriptPresent(npString))
472         {
473             while(index < npString.length())
474             {
475                 char ch = npString.charAt(index);
476                 if(ch == Tokens.kSubScriptBeginnerChar)
477                 {
478                     charStack.push(new Character JavaDoc(ch));
479                 }
480                 else if(ch == Tokens.kSubScriptEnderChar)
481                 {
482                     if(! charStack.empty())
483                     {
484                         Character JavaDoc poppedChar = (Character JavaDoc)charStack.pop();
485                         if(poppedChar.charValue() != Tokens.kSubScriptBeginnerChar)
486                         {
487                             subscriptOrdered = false;
488                             break;
489                         }
490                     }
491                     else
492                     {
493                         subscriptOrdered = false;
494                         break;
495                     }
496                 }
497                 index++;
498             }
499             if(! charStack.empty())
500             {
501                 subscriptOrdered = false;
502             }
503         }
504         else
505         {
506             subscriptOrdered = false;
507         }
508
509         return ( subscriptOrdered );
510     }
511
512     /**
513         Returns a string that contains anything in given string upto first
514         index of Tokens.SubscriptBeginnerChar(that character excluded). If at all
515         this method gets called, it should be made sure that the subscript
516         characters are ordered, as this method does not make that check.
517
518         @param npString a String
519         @return a string that contains subset of given string upto Tokens.SubscriptBeginnerChar.
520             Returns null if null string is passed. Returns null string for "[]".
521             Returns the same string if no subscript characters are present.
522     */

523
524     private String JavaDoc removeSubscript(String JavaDoc npString)
525     {
526         String JavaDoc subscriptLessString = null;
527         int leftIndex = npString.indexOf(Tokens.kSubScriptBeginnerChar);
528
529         if (npString != null || npString.length() > 0)
530         {
531             if(leftIndex != -1)
532             {
533                 subscriptLessString = npString.substring(0, leftIndex);
534             }
535             else
536             {
537                 subscriptLessString = npString;
538             }
539         }
540         return ( subscriptLessString );
541     }
542
543
544     /**
545         A method to validate the string that contains no subscript characters,
546         i.e. a String that contains neither Tokens.kSubscriptBeginnerChar nor
547         Tokens.kSubscriptEnderChar.
548         <p>
549         @return true if any subscript character is present in given string, false
550             otherwise
551     */

552
553     private boolean isSubscriptLessStringValid(String JavaDoc npString)
554     {
555         boolean remStringValid = false;
556
557         if(npString != null && npString.length() > 0)
558         {
559             //boolean noMoreDotsPresent = (npString.indexOf(Tokens.kMoreEscapedDelimitersString) == -1);
560

561             //boolean endsWithDelimiter = npString.endsWith(Tokens.kEscapedDelimiterString);
562

563             boolean onlyDelimiterEscaped = isOnlyDelimiterEscaped(npString);
564             boolean containsEscape = npString.indexOf(Tokens.kEscapeChar) != -1;
565             boolean isEscapeValid = ! containsEscape ||
566                                                 containsEscape && onlyDelimiterEscaped;
567
568             boolean noMoreStars = npString.indexOf(Tokens.kMoreWildCardsString) == -1;
569
570             if( isEscapeValid &&
571                 noMoreStars
572               )
573             {
574                 remStringValid = true;
575             }
576         }
577         return ( remStringValid );
578     }
579
580
581     /**
582         Checks whether all the escape characters escape only delimiters.
583         Method returns true if and only if
584         <li> string contains at least one escape character &&
585         <li> all escape charactrs are always followed by a delimiter character.
586         <p>
587         Returns false, in all other cases.
588         <p>
589         @param npString any string
590         @return true if all the delimiters are escaped, false otherwise
591     */

592
593     private boolean isOnlyDelimiterEscaped(String JavaDoc npString)
594     {
595         boolean onlyDelimiterEscaped = true;
596
597         if(npString != null && npString.length() > 0)
598         {
599             int index = 0;
600             int strlength = npString.length();
601
602             while(index < strlength)
603             {
604                 char ch = npString.charAt(index);
605                 if(ch == Tokens.kEscapeChar)
606                 {
607                     int nextIndex = index + 1;
608                     if (nextIndex >= strlength ||
609                         npString.charAt(nextIndex) != Tokens.kDelimiterChar)
610                     {
611                         onlyDelimiterEscaped = false;
612                         break; // no need to continue as at least one occurrance found
613
}
614                 }
615                 index++;
616             }
617         }
618         else
619         {
620             onlyDelimiterEscaped = false;
621         }
622         return ( onlyDelimiterEscaped );
623     }
624
625 }
626
Popular Tags