KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > tools > jsfext > el > PermissionChecker


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 package com.sun.enterprise.tools.jsfext.el;
24
25 import com.sun.enterprise.tools.jsfext.layout.descriptor.LayoutElement;
26
27 import java.util.ArrayList JavaDoc;
28 import java.util.EmptyStackException JavaDoc;
29 import java.util.HashMap JavaDoc;
30 import java.util.Iterator JavaDoc;
31 import java.util.List JavaDoc;
32 import java.util.Map JavaDoc;
33 import java.util.Stack JavaDoc;
34
35 import javax.faces.component.UIComponent;
36
37
38 /**
39  * <p> This class evaluates a Boolean equation. The supported functions /
40  * operators are:</p>
41  *
42  * <ul><li>$&lt;type&gt;{&lt;key&gt;} -- To read a value according to
43  * &lt;type&gt; using &lt;key&gt; (See:
44  * {@link VariableResolver}). (null is
45  * interpretted as false, non boolean values (besides the string
46  * "false") are interpretted to mean true) </li>
47  * <li>'(' and ')' can be used to override order of operation </li>
48  * <li>'!' negate a boolean value </li>
49  * <li>'|' logical OR </li>
50  * <li>'&amp;' logical AND </li>
51  * <li>'=' String equals </li>
52  * <li>'&lt;' less than between 2 Integers</li>
53  * <li>'&gt;' greater than between 2 Integers</li>
54  * <li>'%' modulus of 2 Integers</li>
55  * </ul>
56  *
57  *
58  * <p> Operator Precedence (for infix notation) is:</p>
59  *
60  * <ul><li> () -- Highest </li>
61  * <li> ! </li>
62  * <li> % </li>
63  * <li> &amp; </li>
64  * <li> | </li>
65  * <li> &lt; and &gt; </li>
66  * <li> = </li>
67  * </ul>
68  *
69  * @see VariableResolver
70  *
71  * @author Ken Paulsen (ken.paulsen@sun.com)
72  */

73 public class PermissionChecker {
74
75     /**
76      * This is the constructor method that is required to create this object.
77      */

78     public PermissionChecker(LayoutElement desc, UIComponent component, String JavaDoc infixStr) {
79     setLayoutElement(desc);
80     setUIComponent(component);
81     setInfix(stripWhiteSpace(infixStr));
82     }
83
84
85     /**
86      * <p>This method sets the LayoutElement that is associated with the 'if'
87      * check being evaluated. This is not normally needed, it is only needed
88      * if the 'if' check contains an expression which requires a
89      * LayoutElement to be properly evaluated.</p>
90      */

91     protected void setUIComponent(UIComponent component) {
92     _component = component;
93     }
94
95
96     /**
97      * <p>Retreives the LayoutElement associated with this PermissionChecker
98      * (only needed in cases where a expression requires a LayoutElement for
99      * evaluation).</p>
100      */

101     public UIComponent getUIComponent() {
102     return _component;
103     }
104
105
106     /**
107      * <p>This method sets the LayoutElement that is associated with the 'if'
108      * check being evaluated. This is not normally needed, it is only needed
109      * if the 'if' check contains an expression which requires a
110      * LayoutElement to be properly evaluated.</p>
111      */

112     protected void setLayoutElement(LayoutElement desc) {
113     _desc = desc;
114     }
115
116
117     /**
118      * <p>Retreives the LayoutElement associated with this PermissionChecker
119      * (only needed in cases where a expression requires a LayoutElement for
120      * evaluation).</p>
121      */

122     public LayoutElement getLayoutElement() {
123     return _desc;
124     }
125
126
127     /**
128      * <p> This method returns the precedence of the given operator. This
129      * only applies to infix notation (of course) and is needed to
130      * correctly order the operators when converting to postfix.</p>
131      *
132      * <ul><li> ! (not) has the highest precedence</li>
133      * <li> % (modulus)</li>
134      * <li> &amp; (and)</li>
135      * <li> | (or)</li>
136      * <li> &lt; (less than) and &gt; (greater than)</li>
137      * <li> = (equals)</li>
138      * </ul>
139      *
140      * <p> Of course '(' and ')' can be used to override the order of
141      * operations in infix notation.</p>
142      *
143      * @param op The operator to evaluate.
144      *
145      * @return A number that can be used to compare its precedence.
146      */

147     private static int getPrecedence(char op) {
148     switch (op) {
149         case LEFT_PAREN:
150         return 1;
151         case RIGHT_PAREN:
152         return 999;
153         case EQUALS_OPERATOR:
154         return 2;
155         case LESS_THAN_OPERATOR:
156         case MORE_THAN_OPERATOR:
157         return 4;
158         case OR_OPERATOR:
159         return 8;
160         case AND_OPERATOR:
161         return 16;
162         case MODULUS_OPERATOR:
163         return 32;
164         case NOT_OPERATOR:
165         return 64;
166     }
167     return 1;
168     }
169
170     /**
171      * <p> This method replaces all "true" / "false" strings w/ 't'/'f'. It
172      * converts the String into a char[]. It replaces all user defined
173      * functions w/ 'F' and places a Function in a list per the registered
174      * user-defined function. All other strings are converted to an 'F'
175      * and a StringFunction is added to the function list.</p>
176      */

177     protected char[] preProcessString(String JavaDoc source) {
178     char[] arr = source.toCharArray();
179     int sourceLen = arr.length;
180     int destLen = 0;
181     String JavaDoc str = null;
182
183     // Loop through the String, char by char
184
for (int idx = 0; idx < sourceLen; idx++) {
185         switch (arr[idx]) {
186         case POST_TRUE:
187         case POST_TRUE_CAP:
188             if (((idx + TRUE.length()) <= sourceLen)
189             && TRUE.equalsIgnoreCase(
190                 new String JavaDoc(arr, idx, TRUE.length()))) {
191             arr[destLen++] = POST_TRUE;
192             idx += TRUE.length() - 1;
193             } else {
194             idx = storeFunction(arr, idx);
195             arr[destLen++] = FUNCTION_MARKER;
196             }
197             break;
198         case POST_FALSE:
199         case POST_FALSE_CAP:
200             if (((idx + FALSE.length()) <= sourceLen)
201             && FALSE.equalsIgnoreCase(
202                 new String JavaDoc(arr, idx, FALSE.length()))) {
203             arr[destLen++] = POST_FALSE;
204             idx += FALSE.length() - 1;
205             } else {
206             idx = storeFunction(arr, idx);
207             arr[destLen++] = FUNCTION_MARKER;
208             }
209             break;
210         case OR_OPERATOR:
211         case EQUALS_OPERATOR:
212         case LESS_THAN_OPERATOR:
213         case MORE_THAN_OPERATOR:
214         case MODULUS_OPERATOR:
215         case AND_OPERATOR:
216         case NOT_OPERATOR:
217         case LEFT_PAREN:
218         case RIGHT_PAREN:
219             arr[destLen++] = arr[idx];
220             break;
221         default:
222             idx = storeFunction(arr, idx);
223             arr[destLen++] = FUNCTION_MARKER;
224         }
225     }
226     char[] dest = new char[destLen];
227     for (int idx = 0; idx < destLen; idx++) {
228         dest[idx] = arr[idx];
229     }
230     return dest;
231     }
232
233
234     /**
235      * <p> This method searches for "$...{...}" in given string and replaces
236      * them with FUNCTION_MARKER's. It adds a Function to the
237      * _tmpFunctionStack for each of these so that it can be inserted in
238      * the proper place during preProcessing. If the "${}" evaluates to
239      * (null), it is replaced with false (BooleanFunction); if it evalutes
240      * to "false", it also will use a false BooleanFunction. In all other
241      * cases, it will be replaced with a StringFunction which evaluates t
242      * true.</p>
243     protected String substituteVariables(String string) {
244 // FIXME: Consider reworking this to be an inline substitution... since nested
245 // FIXME: $()'s aren't supported, a single-pass forward replacement may
246 // FIXME: simplify this.
247     int stringLen = string.length();
248     int startTokenLen = VariableResolver.SUB_START.length();
249     int delimLen = VariableResolver.SUB_TYPE_DELIM.length();
250     int endTokenLen = VariableResolver.SUB_END.length();
251     int endIndex, delimIndex;
252     int parenSemi;
253     char firstEndChar = VariableResolver.SUB_END.charAt(0);
254     char firstDelimChar = VariableResolver.SUB_TYPE_DELIM.charAt(0);
255     char currChar;
256     Object obj = null;
257
258     // Temporary Function List (functions here will be inserted correctly
259     // during preProcessing)
260     _tmpFunctionStack = new Stack();
261     Stack tmpStack = new Stack();
262     _currTmpFunction = 0;
263
264     // Iterate through the String backwards looking for substitutions
265     for (int startIndex = string.indexOf(VariableResolver.SUB_START);
266          startIndex != -1;
267          startIndex = string.indexOf(VariableResolver.SUB_START, startIndex+1)) {
268
269         // Find make sure we have a typeDelim
270         delimIndex = string.indexOf(VariableResolver.SUB_TYPE_DELIM, startIndex+startTokenLen);
271         if (delimIndex == -1) {
272         continue;
273         }
274
275         // Next find the end token
276         parenSemi = 0;
277         endIndex = -1;
278         for (int curr = delimIndex+delimLen; curr<stringLen; ) {
279         currChar = string.charAt(curr);
280         if ((currChar == firstDelimChar) && VariableResolver.SUB_TYPE_DELIM.equals(string.substring(curr, curr+delimLen))) {
281             parenSemi++;
282             curr += delimLen;
283             continue;
284         }
285         if ((currChar == firstEndChar) && VariableResolver.SUB_END.equals(string.substring(curr, curr+endTokenLen))) {
286             parenSemi--;
287             if (parenSemi < 0) {
288             endIndex = curr;
289             break;
290             }
291             curr += endTokenLen;
292             continue;
293         }
294         curr++;
295         }
296         if (endIndex == -1) {
297         continue;
298         }
299
300         // increment the endIndex to point just after it
301         endIndex += endTokenLen;
302
303         // We found a match! Create a StringFunction
304         obj = new StringFunction(string.substring(startIndex, endIndex));
305
306         // Add the function
307         tmpStack.push(obj);
308
309         // Make new string
310         string = string.substring(0, startIndex) + // Before replacement
311              FUNCTION_MARKER + // Replacement
312              string.substring(endIndex); // After
313     }
314
315     // Flip Stack (b/c we search forward to help eval ${} correctly
316     while (!tmpStack.empty()) {
317         _tmpFunctionStack.push(tmpStack.pop());
318     }
319
320     // Return the (new) string
321     return string;
322     }
323      */

324
325
326     /**
327      * <p> This method looks at the given char array starting at index and
328      * continues until an operator (or end of String) is encountered. It
329      * then uses this string to lookup a registered function (if any), it
330      * stores that function (with parameters)... or if the function is
331      * not found, it registers a "String function" (which always returns
332      * true).</p>
333      */

334     protected int storeFunction(char[] arr, int idx) {
335     // Find string...
336
int start = idx;
337     int len = arr.length;
338     while ((idx < len) && !isOperator(arr[idx])) {
339         idx++;
340     }
341
342     // Create String...
343
String JavaDoc str = new String JavaDoc(arr, start, idx - start);
344
345     // Check to see if it is a registered function...
346
Function function = getFunction(str);
347     if (function != null) {
348         // Find the left paren...
349
int left = idx;
350         if ((left >= len) || (arr[left] != LEFT_PAREN)) {
351         throw new RuntimeException JavaDoc("Function '" + str
352             + "' is expected to have a '" + LEFT_PAREN
353             + "' immediately following it. Equation: '"
354             + new String JavaDoc(arr) + "'.");
355         }
356
357         ArrayList JavaDoc arguments = new ArrayList JavaDoc();
358
359         // Find the right Paren...
360
while ((++idx < len) && (arr[idx] != RIGHT_PAREN)) {
361         if (arr[idx] == ARGUMENT_SEPARATOR) {
362             left++;
363             arguments.add(new String JavaDoc(arr, left, idx - left));
364             left = idx;
365         }
366         }
367
368         // Make sure we don't have ()
369
left++;
370         if (idx > left) {
371         arguments.add(new String JavaDoc(arr, left, idx - left));
372         }
373
374         // Set the arguments...
375
function.setArguments(arguments);
376     } else {
377         // Not a registered function...
378
idx--; // In this case, there are no ()'s to consume, backup 1
379
if ((str.charAt(0) == FUNCTION_MARKER) && (str.length() == 1)
380             && !_tmpFunctionStack.empty()) {
381         // We have a function added during the subtitute() phase
382
function = (Function) _tmpFunctionStack.pop();
383         } else {
384         // Create a StringFunction
385
function = new StringFunction(str);
386         }
387     }
388
389     // Add the function to the function list
390
_functionList.add(function);
391
392     // Return the number of characters that we consumed...
393
return idx;
394     }
395
396
397     /**
398      * <p> This method is a factory method for constructing a new function
399      * based on the function name passed in. The function must be
400      * registered prior to invoking this method.</p>
401      */

402     protected static Function getFunction(String JavaDoc functionName) {
403     // Get the Function class
404
Class JavaDoc functionClass = (Class JavaDoc) _functions.get(functionName);
405     if (functionClass == null) {
406         return null;
407     }
408
409     // Create a new instance
410
Function function = null;
411     try {
412         function = (Function) functionClass.newInstance();
413     } catch (Exception JavaDoc ex) {
414         throw new RuntimeException JavaDoc("Unable to instantiate '"
415             + functionClass.getName() + "' for '"
416             + functionName + "'", ex);
417     }
418
419     // Return the instance
420
return function;
421     }
422
423
424     /**
425      * <p> This method allows arbitrary functions to be registered. Function
426      * names should only contain letters or numbers, other characters or
427      * whitespace may cause problems. No checking is done to ensure this,
428      * however.</p>
429      *
430      * <p> Functions will be expressed in an equation as follows:</p>
431      *
432      * <ul><li>function_name(param1,param2)</li></ul>
433      *
434      * <p> Function parameters also should only contain alpha-numeric
435      * characters.</p>
436      *
437      * <p> Functions must implement PermissionChecker.Function interface</p>
438      */

439     public static void registerFunction(String JavaDoc functionName, Class JavaDoc function) {
440     if (function == null) {
441         _functions.remove(functionName);
442     }
443     if (!Function.class.isAssignableFrom(function)) {
444         throw new RuntimeException JavaDoc("'" + function.getName()
445         + "' must implement '" + Function.class.getName() + "'");
446     }
447     _functions.put(functionName, function);
448     }
449
450
451     /**
452      * <p> This method returns true if the given character is a valid
453      * operator.</p>
454      */

455     public static boolean isOperator(char ch) {
456     switch (ch) {
457         case LEFT_PAREN:
458         case RIGHT_PAREN:
459         case EQUALS_OPERATOR:
460         case LESS_THAN_OPERATOR:
461         case MORE_THAN_OPERATOR:
462         case MODULUS_OPERATOR:
463         case OR_OPERATOR:
464         case AND_OPERATOR:
465         case NOT_OPERATOR:
466 // case AT_OPERATOR:
467
// case POUND_OPERATOR:
468
// case DOLLAR_OPERATOR:
469
// case UP_OPERATOR:
470
// case STAR_OPERATOR:
471
// case TILDA_OPERATOR:
472
// case ARGUMENT_SEPARATOR:
473
return true;
474     }
475     return false;
476     }
477
478
479     /**
480      * <p> This method calculates the postfix representation of the infix
481      * equation passed in. It returns the postfix equation as a
482      * char[].</p>
483      *
484      * @param infixStr The infix representation of the equation.
485      *
486      * @return postfix representation of the equation as a char[] (the f()'s
487      * are removed and stored in _functionList).
488      */

489     protected char [] generatePostfix(String JavaDoc infixStr) {
490     // Reset the _functionList
491
_functionList = new ArrayList JavaDoc();
492
493     // Convert string to our parsable format
494
char[] result = preProcessString(infixStr);
495 //System.out.println("DEBUG: Initial String: '"+infixStr+"'");
496
//System.out.println("DEBUG: After Pre-process: '"+new String(result)+"'");
497
int resultLen = result.length;
498     int postIdx = 0;
499     int precedence = 0;
500     Stack JavaDoc opStack = new Stack JavaDoc();
501
502     // Put f()'s directly into result, push operators into right order
503
for (int idx = 0; idx < resultLen; idx++) {
504         switch(result[idx]) {
505         case FUNCTION_MARKER:
506         case POST_TRUE:
507         case POST_FALSE:
508             result[postIdx++] = result[idx];
509             break;
510         case LEFT_PAREN:
511             opStack.push(new Character JavaDoc(LEFT_PAREN));
512             break;
513         case RIGHT_PAREN:
514             while (!opStack.empty()
515                 && (((Character JavaDoc) opStack.peek()).charValue()
516                 != LEFT_PAREN)) {
517             result[postIdx++] =
518                 ((Character JavaDoc) opStack.pop()).charValue();
519             }
520             if (!opStack.empty()) {
521             // Throw away the LEFT_PAREN that should still be there
522
opStack.pop();
523             }
524             break;
525         default:
526             // clear stuff
527
precedence = getPrecedence(result[idx]);
528             while (!opStack.empty()
529                 && (getPrecedence(((Character JavaDoc) opStack.peek()).
530                     charValue()) >= precedence)) {
531             result[postIdx++] =
532                 ((Character JavaDoc) opStack.pop()).charValue();
533             }
534
535             /* Put it on the stack */
536             opStack.push(new Character JavaDoc(result[idx]));
537             break;
538         }
539     }
540
541     // empty the rest of the stack to the result
542
while (!opStack.empty()) {
543         result[postIdx++] = ((Character JavaDoc) opStack.pop()).charValue();
544     }
545     // Copy the result to the postfixStr
546
char[] postfixStr = new char[postIdx];
547     for (int idx = 0; idx < postIdx; idx++) {
548         postfixStr[idx] = result[idx];
549     }
550 //System.out.println("DEBUG: Postfix String: '"+new String(postfixStr)+"'");
551
return postfixStr;
552     }
553
554
555     /**
556      * <p> This method is invoked to determine if the equation evaluates to
557      * true or false.</p>
558      */

559     public boolean hasPermission() {
560     char[] postfixArr = getPostfixArr();
561     int len = postfixArr.length;
562     Stack JavaDoc result = new Stack JavaDoc();
563     result.push(FALSE_BOOLEAN_FUNCTION); // Default to false
564
boolean val1, val2;
565     Iterator JavaDoc it = _functionList.iterator();
566     Function func = null;
567
568     // Iterate through the postfix array
569
for (int idx = 0; idx < len; idx++) {
570         switch (postfixArr[idx]) {
571         case POST_TRUE:
572             result.push(TRUE_BOOLEAN_FUNCTION);
573             break;
574         case POST_FALSE:
575             result.push(FALSE_BOOLEAN_FUNCTION);
576             break;
577         case FUNCTION_MARKER:
578             if (!it.hasNext()) {
579             throw new RuntimeException JavaDoc("Unable to evaluate: '"
580                 + toString() + "' -- found function marker "
581                 + "w/o cooresponding function!");
582             }
583             result.push(it.next());
584             break;
585         case EQUALS_OPERATOR:
586             try {
587             // Allow reg expression matching
588
String JavaDoc matchStr = result.pop().toString();
589             val1 = result.pop().toString().matches(matchStr);
590             } catch (EmptyStackException JavaDoc ex) {
591             throw new RuntimeException JavaDoc("Unable to evaluate: '"
592                 + toString() + "'.", ex);
593             }
594             result.push(val1 ?
595                 TRUE_BOOLEAN_FUNCTION : FALSE_BOOLEAN_FUNCTION);
596             break;
597         case LESS_THAN_OPERATOR:
598             try {
599             // The stack reverses the order, so check greater than
600
val1 = Integer.parseInt(result.pop().toString())
601                 > Integer.parseInt(result.pop().toString());
602             } catch (EmptyStackException JavaDoc ex) {
603             throw new RuntimeException JavaDoc("Unable to evaluate: '"
604                 + toString() + "'.", ex);
605             }
606             result.push(val1 ?
607                 TRUE_BOOLEAN_FUNCTION : FALSE_BOOLEAN_FUNCTION);
608             break;
609         case MORE_THAN_OPERATOR:
610             try {
611             // The stack reverses the order, so check greater than
612
val1 = Integer.parseInt(result.pop().toString())
613                 < Integer.parseInt(result.pop().toString());
614             } catch (EmptyStackException JavaDoc ex) {
615             throw new RuntimeException JavaDoc("Unable to evaluate: '"
616                 + toString() + "'.", ex);
617             }
618             result.push(val1 ?
619                 TRUE_BOOLEAN_FUNCTION : FALSE_BOOLEAN_FUNCTION);
620             break;
621         case MODULUS_OPERATOR:
622             try {
623             // The stack reverses the order...
624
int modNumber =
625                 Integer.parseInt(result.pop().toString());
626             int num = Integer.parseInt(result.pop().toString());
627             result.push(new StringFunction("" + (num % modNumber)));
628             } catch (EmptyStackException JavaDoc ex) {
629             throw new RuntimeException JavaDoc("Unable to evaluate: '"
630                 + toString() + "'.", ex);
631             }
632             break;
633         case OR_OPERATOR:
634             try {
635             val1 = ((Function) result.pop()).evaluate();
636             val2 = ((Function) result.pop()).evaluate();
637             } catch (EmptyStackException JavaDoc ex) {
638             throw new RuntimeException JavaDoc("Unable to evaluate: '"
639                 + toString() + "'.", ex);
640             }
641             result.push((val1 || val2) ?
642                 TRUE_BOOLEAN_FUNCTION : FALSE_BOOLEAN_FUNCTION);
643             break;
644         case AND_OPERATOR:
645             try {
646             val1 = ((Function) result.pop()).evaluate();
647             val2 = ((Function) result.pop()).evaluate();
648             } catch (EmptyStackException JavaDoc ex) {
649             throw new RuntimeException JavaDoc("Unable to evaluate: '"
650                 + toString() + "'.", ex);
651             }
652             result.push((val1 && val2) ?
653                 TRUE_BOOLEAN_FUNCTION : FALSE_BOOLEAN_FUNCTION);
654             break;
655         case NOT_OPERATOR:
656             try {
657             val1 = ((Function) result.pop()).evaluate();
658             } catch (EmptyStackException JavaDoc ex) {
659             throw new RuntimeException JavaDoc("Unable to evaluate: '"
660                 + toString() + "'.", ex);
661             }
662             result.push((!val1) ?
663                 TRUE_BOOLEAN_FUNCTION : FALSE_BOOLEAN_FUNCTION);
664             break;
665         }
666     }
667
668     // Return the only element on the stack (hopefully)
669
try {
670         val1 = ((Function) result.pop()).evaluate();
671     } catch (EmptyStackException JavaDoc ex) {
672         throw new RuntimeException JavaDoc("Unable to evaluate: '"
673             + toString() + "'.", ex);
674     }
675     if (!result.empty()) {
676         result.pop(); // We added a false that wasn't needed
677
if (!result.empty()) {
678         throw new RuntimeException JavaDoc("Unable to evaluate: '"
679             + toString() + "' -- values left on the stack.");
680         }
681     }
682     return val1;
683     }
684
685
686     /**
687      * <p> This method returns the infix representation of the equation, in
688      * other words: the original String passed in.</p>
689      */

690     public String JavaDoc getInfix() {
691     return _infixStr;
692     }
693
694
695     /**
696      * <p> This method sets the equation and forces a re-evaluation of the
697      * equation. It returns the postfix representation of the
698      * equation.</p>
699      *
700      * @param equation The infix equation to use.
701      *
702      */

703     public void setInfix(String JavaDoc equation) {
704     _infixStr = equation;
705     setPostfixArr(generatePostfix(equation));
706     }
707
708
709     /**
710      * <p> Getter for the post fix array. If it is currently null, an empty
711      * <code>char[]</code> array will be returned.</p>
712      */

713     protected char [] getPostfixArr() {
714     if (_postfixArr == null) {
715         _postfixArr = new char[] {' '};
716     }
717     return _postfixArr;
718     }
719
720
721     /**
722      * <p> Setter for the postfix array of chars.</p>
723      */

724     protected void setPostfixArr(char[] postfix) {
725     _postfixArr = postfix;
726     }
727
728
729     /**
730      * <p> This method provides access to a <code>String</code> representation
731      * of the postfix equation held by this <code>Object</code>.</p>
732      */

733     public String JavaDoc getPostfix() {
734     if (getPostfixArr() == null) {
735         return "";
736     }
737     return new String JavaDoc(getPostfixArr());
738     }
739
740
741     /**
742      * <p> Displays the infix and postfix version of the equation.</p>
743      */

744     public String JavaDoc toString() {
745     return _infixStr + " = " + toString(getPostfixArr());
746     }
747
748
749     /**
750      * <p> This toString(...) method generates just the postfix
751      * representation of the equation. The postfix notation is stored as
752      * a char[] and it has the functions removed from the char[]. This
753      * method iterates through the char[] and generates a String with the
754      * functions put back into the equation.</p>
755      *
756      * @param post The char[] representation of the postfix equation.
757      */

758     private String JavaDoc toString(char[] post) {
759     int len = post.length;
760     StringBuffer JavaDoc result = new StringBuffer JavaDoc("");
761     Iterator JavaDoc it = _functionList.iterator();
762
763     for (int idx = 0; idx < len; idx++) {
764         switch (post[idx]) {
765         case POST_TRUE:
766             result.append(TRUE);
767             break;
768         case POST_FALSE:
769             result.append(FALSE);
770             break;
771         case FUNCTION_MARKER:
772             result.append(((Function) it.next()).toString());
773             break;
774         default:
775             result.append(post[idx]);
776         }
777     }
778
779     return result.toString();
780     }
781
782
783     /**
784      * <p> This method removes all whitespace from the given String.</p>
785      */

786     public static String JavaDoc stripWhiteSpace(String JavaDoc input) {
787     char[] arr = input.toCharArray();
788     int len = arr.length;
789     int destLen = 0;
790
791     // Loop through the array skipping whitespace
792
for (int idx = 0; idx < len; idx++) {
793         if (Character.isWhitespace(arr[idx])) {
794         continue;
795         }
796         arr[destLen++] = arr[idx];
797     }
798
799     // Return the result
800
return new String JavaDoc(arr, 0, destLen);
801     }
802
803
804
805
806     /**
807      * <p> This class must be implemented by all user defined Functions.</p>
808      *
809      * <p> In addition to these methods, a toString() should be implemented
810      * that reconstructs the original format of the function (i.e.
811      * function_name(arg1,arg2...)).</p>
812      */

813     public static interface Function {
814
815     /**
816      * <p> This method returns the List of arguments.</p>
817      */

818     public List JavaDoc getArguments();
819
820     /**
821      * <p> This method is invoked be the PermissionChecker to set the
822      * arguments.</p>
823      */

824     public void setArguments(List JavaDoc args);
825
826     /**
827      * <p> This method is invoked by the PermissionCheck to evaluate the
828      * function to true or false.</p>
829      */

830     public boolean evaluate();
831     }
832
833     /**
834      * <p> <code>StringFunction</code> implements <code>Function</code> and
835      * serves as the default function. This function is special in that
836      * it is NEVER registered and is the only function that SHOULD NOT be
837      * followed by ()'s. This function will process embedded expressions
838      * and evaulate to false if the entire string evaulates to null.
839      * Otherwise it will return true. This <code>Function</code> ignores
840      * all arguments (arguments only apply if it is registered, which
841      * shouldn't be the case anyway).</p>
842      */

843     protected class StringFunction implements PermissionChecker.Function {
844
845     /**
846      * Constructor.
847      *
848      * @param value The expression to evaluate.
849      */

850     public StringFunction(String JavaDoc value) {
851         _value = value;
852     }
853
854     /**
855      * Not used.
856      */

857     public List JavaDoc getArguments() {
858         return null;
859     }
860
861     /**
862      * Not used.
863      */

864     public void setArguments(List JavaDoc args) {
865     }
866
867     /**
868      * <p> Determine if the value of the <code>Function</code> is
869      * <code>true</code> or <code>false</code>.</p>
870      */

871     public boolean evaluate() {
872         Object JavaDoc obj = getEvaluatedValue();
873         if (obj == null) {
874         return false;
875         }
876         obj = obj.toString();
877         if (obj.equals("")) {
878         return false;
879         }
880         if (((String JavaDoc) obj).equalsIgnoreCase("false")) {
881         return false;
882         }
883         return true;
884     }
885
886     /**
887      * <p> This methis uses the {@link VariableResolver} to evaluate the
888      * String and returns the result.</p>
889      */

890     public Object JavaDoc getEvaluatedValue() {
891          return VariableResolver.resolveVariables(getLayoutElement(),
892         getUIComponent(), _value);
893     }
894
895     /**
896      * <p> This implementation of <code>toString()</code> returns the
897      * evaluated value, except when the value is <code>(null)</code>
898      * in which case it returns the empty string ("").</p>
899      */

900     public String JavaDoc toString() {
901         Object JavaDoc obj = getEvaluatedValue();
902         if (obj == null) {
903         return "";
904         }
905         return obj.toString();
906     }
907
908     private String JavaDoc _value;
909     }
910
911     /**
912      * <p> <code>BooleanFunction</code> is either <code>true</code> or
913      * <code>false</code>. It is used internally by
914      * <code>PermissionChecker</code> and is not needed outside
915      * <code>PermissionChecker</code> since the Strings "true" or "false"
916      * used in an equation are sufficient.</p>
917      */

918     protected static class BooleanFunction implements PermissionChecker.Function {
919
920     /**
921      * <p> Constructor (defaults to false).</p>
922      */

923     public BooleanFunction() {
924     }
925
926     /**
927      * <p> Constructor.</p>
928      */

929     public BooleanFunction(boolean value) {
930         _value = value;
931     }
932
933     /**
934      * <p> Not used.</p>
935      */

936     public List JavaDoc getArguments() {
937         return null;
938     }
939
940     /**
941      * <p> Not used.</p>
942      */

943     public void setArguments(List JavaDoc args) {
944     }
945
946     /**
947      * <p> Return the value of the <code>Function</code>;
948      * <code>true</code> or <code>false</code>.</p>
949      */

950     public boolean evaluate() {
951         return _value;
952     }
953
954     /**
955      * <p> This implementation prints the <code>String</code> "true" or
956      * "false" based on the stored value.</p>
957      */

958     public String JavaDoc toString() {
959         return _value ? "true" : "false";
960     }
961
962     private boolean _value = false;
963     }
964
965
966     /**
967      * <p> This is here to provide some test cases. It only tests the
968      * conversion to postfix notation.</p>
969      */

970     public static void main(String JavaDoc[] args) {
971     PermissionChecker checker;
972     if (args.length > 0) {
973         for (int count = 0; count < args.length; count++) {
974         checker = new PermissionChecker(null, null, args[count]);
975         System.out.println("Output:\n" + checker.toString() + " (" + checker.hasPermission() + ")");
976         }
977     } else {
978         boolean success = true;
979         checker = new PermissionChecker(null, null, "true |false");
980         System.out.println("Output:\n" + checker.toString() + " (" + checker.hasPermission() + ")");
981         if (!checker.toString().equals("true|false = truefalse|")) {
982         System.out.println("\tFAILED!");
983         System.out.println("Should have been:\n" + "true|false = truefalse|");
984         success = false;
985         }
986         if (!checker.hasPermission()) {
987         System.out.println("\tFAILED!");
988         System.out.println("hasPermission(" + checker.toString(checker.getPostfixArr()) + ") returned the wrong result!");
989         success = false;
990         }
991
992         checker = new PermissionChecker(null, null, "true&(false|true)");
993         System.out.println("Output:\n" + checker.toString() + " (" + checker.hasPermission() + ")");
994         if (!checker.toString().equals("true&(false|true) = truefalsetrue|&")) {
995         System.out.println("\tFAILED!");
996         System.out.println("Should have been:\n" + "true&(false|true) = truefalsetrue|&");
997         success = false;
998         }
999         if (!checker.hasPermission()) {
1000        System.out.println("\tFAILED!");
1001        System.out.println("hasPermission(" + checker.toString(checker.getPostfixArr()) + ") returned the wrong result!");
1002        success = false;
1003        }
1004
1005        checker = new PermissionChecker(null, null, "true&false|true");
1006        System.out.println("Output:\n" + checker.toString() + " (" + checker.hasPermission() + ")");
1007        if (!checker.toString().equals("true&false|true = truefalse&true|")) {
1008        System.out.println("\tFAILED!");
1009        System.out.println("Should have been:\n" + "true&false|true = truefalse&true|");
1010        success = false;
1011        }
1012        if (!checker.hasPermission()) {
1013        System.out.println("\tFAILED!");
1014        System.out.println("hasPermission(" + checker.toString(checker.getPostfixArr()) + ") returned the wrong result!");
1015        success = false;
1016        }
1017
1018        checker = new PermissionChecker(null, null, "true&true|false&true");
1019        System.out.println("Output:\n" + checker.toString() + " (" + checker.hasPermission() + ")");
1020        if (!checker.toString().equals("true&true|false&true = truetrue&falsetrue&|")) {
1021        System.out.println("\tFAILED!");
1022        System.out.println("Should have been:\n" + "true&true|false&true = truetrue&falsetrue&|");
1023        success = false;
1024        }
1025        if (!checker.hasPermission()) {
1026        System.out.println("\tFAILED!");
1027        System.out.println("hasPermission(" + checker.toString(checker.getPostfixArr()) + ") returned the wrong result!");
1028        success = false;
1029        }
1030
1031        checker = new PermissionChecker(null, null, "!true|false&!(false|true)");
1032        System.out.println("Output:\n" + checker.toString() + " (" + checker.hasPermission() + ")");
1033        if (!checker.toString().equals("!true|false&!(false|true) = true!falsefalsetrue|!&|")) {
1034        System.out.println("\tFAILED!");
1035        System.out.println("Should have been:\n" + "!true|false&!(false|true) = true!falsefalsetrue|!&|");
1036        success = false;
1037        }
1038        if (checker.hasPermission()) {
1039        System.out.println("\tFAILED!");
1040        System.out.println("hasPermission(" + checker.toString(checker.getPostfixArr()) + ") returned the wrong result!");
1041        success = false;
1042        }
1043
1044        checker = new PermissionChecker(null, null, "!(!(true&!true)|!(false|false))|(true|false)&true");
1045        System.out.println("Output:\n" + checker.toString() + " (" + checker.hasPermission() + ")");
1046        if (!checker.toString().equals("!(!(true&!true)|!(false|false))|(true|false)&true = truetrue!&!falsefalse|!|!truefalse|true&|")) {
1047
1048        System.out.println("\tFAILED!");
1049        System.out.println("Should have been:\n" + "!(!(true&!true)|!(false|false))|(true|false)&true = truetrue!&!falsefalse|!|!truefalse|true&|");
1050        success = false;
1051        }
1052        if (!checker.hasPermission()) {
1053        System.out.println("\tFAILED!");
1054        System.out.println("hasPermission(" + checker.toString(checker.getPostfixArr()) + ") returned the wrong result!");
1055        success = false;
1056        }
1057
1058        // Test '='
1059
checker = new PermissionChecker(null, null, "false =false");
1060        System.out.println("Output:\n" + checker.toString() + " (" + checker.hasPermission() + ")");
1061        if (!checker.toString().equals("false=false = falsefalse=")) {
1062        System.out.println("\tFAILED!");
1063        System.out.println("Should have been:\n" + "false=false = falsefalse=");
1064        success = false;
1065        }
1066        if (!checker.hasPermission()) {
1067        System.out.println("\tFAILED!");
1068        System.out.println("hasPermission(" + checker.toString(checker.getPostfixArr()) + ") returned the wrong result!");
1069        success = false;
1070        }
1071
1072        checker = new PermissionChecker(null, null, " test= me ");
1073        System.out.println("Output:\n" + checker.toString() + " (" + checker.hasPermission() + ")");
1074        if (!checker.toString().equals("test=me = testme=")) {
1075        System.out.println("\tFAILED!");
1076        System.out.println("Should have been:\n" + "test=me = testme=");
1077        success = false;
1078        }
1079        if (checker.hasPermission()) {
1080        System.out.println("\tFAILED!");
1081        System.out.println("hasPermission(" + checker.toString(checker.getPostfixArr()) + ") returned the wrong result!");
1082        success = false;
1083        }
1084
1085        checker = new PermissionChecker(null, null, " this should work=thisshouldwork");
1086        System.out.println("Output:\n" + checker.toString() + " (" + checker.hasPermission() + ")");
1087        if (!checker.toString().equals("thisshouldwork=thisshouldwork = thisshouldworkthisshouldwork=")) {
1088        System.out.println("\tFAILED!");
1089        System.out.println("Should have been:\n" + "thisshouldwork=thisshouldwork = thisshouldworkthisshouldwork=");
1090        success = false;
1091        }
1092        if (!checker.hasPermission()) {
1093        System.out.println("\tFAILED!");
1094        System.out.println("hasPermission(" + checker.toString(checker.getPostfixArr()) + ") returned the wrong result!");
1095        success = false;
1096        }
1097
1098        checker = new PermissionChecker(null, null, "false|ab=true");
1099        System.out.println("Output:\n" + checker.toString() + " (" + checker.hasPermission() + ")");
1100        if (!checker.toString().equals("false|ab=true = falseab|true=")) {
1101        System.out.println("\tFAILED!");
1102        System.out.println("Should have been:\n" + "false|ab=true = falseab|true=");
1103        success = false;
1104        }
1105        if (!checker.hasPermission()) {
1106        System.out.println("\tFAILED!");
1107        System.out.println("hasPermission(" + checker.toString(checker.getPostfixArr()) + ") returned the wrong result!");
1108        success = false;
1109        }
1110
1111        checker = new PermissionChecker(null, null, "false|(ab=true)");
1112        System.out.println("Output:\n" + checker.toString() + " (" + checker.hasPermission() + ")");
1113        if (!checker.toString().equals("false|(ab=true) = falseabtrue=|")) {
1114        System.out.println("\tFAILED!");
1115        System.out.println("Should have been:\n" + "false|ab=true = falseab|true=");
1116        success = false;
1117        }
1118        if (checker.hasPermission()) {
1119        System.out.println("\tFAILED!");
1120        System.out.println("hasPermission(" + checker.toString(checker.getPostfixArr()) + ") returned the wrong result!");
1121        success = false;
1122        }
1123
1124        checker = new PermissionChecker(null, null, "false|(ab=ab)");
1125        System.out.println("Output:\n" + checker.toString() + " (" + checker.hasPermission() + ")");
1126        if (!checker.toString().equals("false|(ab=ab) = falseabab=|")) {
1127        System.out.println("\tFAILED!");
1128        System.out.println("Should have been:\n" + "false|ab=true = falseab|true=");
1129        success = false;
1130        }
1131        if (!checker.hasPermission()) {
1132        System.out.println("\tFAILED!");
1133        System.out.println("hasPermission(" + checker.toString(checker.getPostfixArr()) + ") returned the wrong result!");
1134        success = false;
1135        }
1136
1137        checker = new PermissionChecker(null, null, "!");
1138        System.out.println("Output:\n" + checker.toString() + " (" + checker.hasPermission() + ")");
1139        if (!checker.toString().equals("! = !")) {
1140        System.out.println("\tFAILED!");
1141        System.out.println("Should have been:\n" + "! = !");
1142        success = false;
1143        }
1144        if (!checker.hasPermission()) {
1145        System.out.println("\tFAILED!");
1146        System.out.println("hasPermission(" + checker.toString(checker.getPostfixArr()) + ") returned the wrong result!");
1147        success = false;
1148        }
1149
1150        checker = new PermissionChecker(null, null, "");
1151        System.out.println("Output:\n" + checker.toString() + " (" + checker.hasPermission() + ")");
1152        if (!checker.toString().equals(" = ")) {
1153        System.out.println("\tFAILED!");
1154        System.out.println("Should have been:\n" + " = ");
1155        success = false;
1156        }
1157        if (checker.hasPermission()) {
1158        System.out.println("\tFAILED!");
1159        System.out.println("hasPermission(" + checker.toString(checker.getPostfixArr()) + ") returned the wrong result!");
1160        success = false;
1161        }
1162
1163        checker = new PermissionChecker(null, null, "!$escape{}");
1164        System.out.println("Output:\n" + checker.toString() + " (" + checker.hasPermission() + ")");
1165        if (!checker.toString().equals("!$escape{} = !")) {
1166        System.out.println("\tFAILED!");
1167        System.out.println("Should have been:\n" + "! = !");
1168        success = false;
1169        }
1170        if (!checker.hasPermission()) {
1171        System.out.println("\tFAILED!");
1172        System.out.println("hasPermission(" + checker.toString(checker.getPostfixArr()) + ") returned the wrong result!");
1173        success = false;
1174        }
1175
1176        checker = new PermissionChecker(null, null, "$escape{}");
1177        System.out.println("Output:\n" + checker.toString() + " (" + checker.hasPermission() + ")");
1178        if (!checker.toString().equals("$escape{} = ")) {
1179        System.out.println("\tFAILED!");
1180        System.out.println("Should have been:\n" + " = ");
1181        success = false;
1182        }
1183        if (checker.hasPermission()) {
1184        System.out.println("\tFAILED!");
1185        System.out.println("hasPermission(" + checker.toString(checker.getPostfixArr()) + ") returned the wrong result!");
1186        success = false;
1187        }
1188
1189        if (success) {
1190        System.out.println("\n\tALL TESTS PASSED!");
1191        } else {
1192        System.out.println("\n\tNOT ALL TESTS PASSED!");
1193        }
1194    }
1195    }
1196
1197
1198    /**
1199     * <p> This variable represents a "false" BooleanFunction.</p>
1200     */

1201    public static final BooleanFunction FALSE_BOOLEAN_FUNCTION =
1202    new BooleanFunction(false);
1203
1204    /**
1205     * <p> This variable represents a "true" BooleanFunction.</p>
1206     */

1207    public static final BooleanFunction TRUE_BOOLEAN_FUNCTION =
1208    new BooleanFunction(true);
1209
1210
1211    protected static final char POST_TRUE = 't';
1212    protected static final char POST_FALSE = 'f';
1213    protected static final char POST_TRUE_CAP = 'T';
1214    protected static final char POST_FALSE_CAP = 'F';
1215
1216    public static final String JavaDoc TRUE = "true";
1217    public static final String JavaDoc FALSE = "false";
1218
1219    // Function representation in postfix String
1220
public static final char FUNCTION_MARKER = 'F';
1221
1222    // Operator constants
1223
public static final char LEFT_PAREN = '(';
1224    public static final char RIGHT_PAREN = ')';
1225    public static final char EQUALS_OPERATOR = '=';
1226    public static final char OR_OPERATOR = '|';
1227    public static final char AND_OPERATOR = '&';
1228    public static final char NOT_OPERATOR = '!';
1229    public static final char LESS_THAN_OPERATOR = '<';
1230    public static final char MORE_THAN_OPERATOR = '>';
1231    public static final char MODULUS_OPERATOR = '%';
1232
1233    // The COMMA separates function arguments... not really an operator
1234
public static final char ARGUMENT_SEPARATOR = ',';
1235
1236    // Reserved operators, although not currently used...
1237
/*
1238 * These may be added eventually
1239 *
1240 * public static final char AT_OPERATOR = '@';
1241 * public static final char POUND_OPERATOR = '#';
1242 * public static final char DOLLAR_OPERATOR = '$';
1243 * public static final char UP_OPERATOR = '^';
1244 * public static final char STAR_OPERATOR = '*';
1245 * public static final char TILDA_OPERATOR = '~';
1246 */

1247
1248    /**
1249     * <p> This holds the infix equation.</p>
1250     */

1251    private String JavaDoc _infixStr = null;
1252
1253    /**
1254     * <p> This holds the postfix equation.</p>
1255     */

1256    private char[] _postfixArr = null;
1257
1258    /**
1259     * <p> This is a Map of Class objects which are user-registered
1260     * functions.</p>
1261     */

1262    private static Map JavaDoc _functions = new HashMap JavaDoc();
1263
1264    /**
1265     * <p> This List holds the actual Function objects that correspond to the
1266     * 'F' markers in the postfix string.</p>
1267     */

1268    private List JavaDoc _functionList = null;
1269
1270    /**
1271     * <p> This List of functions maintains variableSubstitution Functions
1272     * which happen out-of-order. They will be pulled from this list as
1273     * placed into the actual _functionList when the are encountered
1274     * during the preProcessing.</p>
1275     */

1276    private Stack JavaDoc _tmpFunctionStack = null;
1277    private LayoutElement _desc = null;
1278    private UIComponent _component = null;
1279}
1280
Popular Tags