KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > admin > meta > naming > 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.meta.naming;
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
32 import javax.management.MalformedObjectNameException JavaDoc;
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
49     /**
50         Default constructor for initialization purpose.
51     */

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

558             //boolean endsWithDelimiter = npString.endsWith(Tokens.kEscapedDelimiterString);
559

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

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