View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.trinidad.menu;
20  
21  import java.lang.reflect.Array;
22  import java.util.Iterator;
23  import java.util.List;
24  
25  import org.apache.myfaces.trinidad.logging.TrinidadLogger;
26  import org.apache.myfaces.trinidad.util.ContainerUtils;
27  
28  /**
29   * This class is a thread safe version of GroupNode class.
30   * It replicates most of the code in GroupNode but makes
31   * sure it does not modify state of the object.
32   * 
33   * Therefore multiple request threads can access the
34   * properties of the objects of this class,in a thread safe
35   * manner.
36   * 
37   * Please note that setters should not be called on objects
38   * of this class.Objects of this class are fully initialized
39   * on construction.
40   *
41   */
42  public class ImmutableGroupNode extends GroupNode
43  {
44    
45    public ImmutableGroupNode(GroupNode node)
46    {
47      _icon = node.getIconProperty();
48      _focusViewId = node.getFocusViewIdProperty();
49      _renderedStr = node.getRenderedProperty();
50      _disabledStr = node.getDisabledProperty();
51      _visibleStr = node.getVisibleProperty();
52      _readOnlyStr = node.getReadOnlyProperty();
53      _handlerId = node.getHandlerIdProperty();
54      _bundleKey = node.getBundleKeyProperty();
55      _bundleName = node.getBundleNameProperty();
56      _accessKey = node.getAccessKeyProperty();
57      _id = node.getIdProperty();
58      _modelId = node.getModelIdProperty();
59      _uniqueId = node.getUniqueIdProperty();
60      _labelAndAccessKey = node.getLabelAndAccessKeyProperty();
61      _defaultFocusPathStr = node.getDefaultFocusPathProperty();
62  
63      // Root Menu model's Request Map Key
64      _rootModelKey = node.getRootModelKeyProperty();
65  
66      _rootId = node.getRootIdProperty();
67      _label = node.getLabelProperty();
68      _idref = node.getIdRef();
69      _idrefList = node.getIdRefListProperty();
70    }
71    
72    
73    public String getIdRef()
74    {
75      return _idref;
76    }
77    
78    public MenuNode getRefNode()
79    {
80      MenuNode refNode = null;
81  
82      
83      // Get idrefList
84      String[] idrefList = _idrefList;
85  
86      // get group node's children
87      List<MenuNode> children = getChildren();
88  
89      // Traverse the list. Do the following:
90      //    o get Node from Model's hashMap of nodes and ids
91      //    o check attributes (rendered, disabled, readOnly)
92      //    o if they are ok, return the node
93      for (int i=0; i < Array.getLength(idrefList); i++)
94      {
95        Iterator<MenuNode> childIter = children.iterator();
96  
97        // All node "id" attribute values had the node's
98        // system hashcode id appended to the id when
99        // placed in the model's idNodeMap.
100       //
101       // Each id in the idreflist of a group node does
102       // NOT have this node sys id appended it to it
103       // and needs to or we won't find the group's
104       // ref node.
105       //
106       // Since group nodes can only point to one of
107       // its children, we iterate through them, get
108       // their sys id and append it to idref until
109       // we find a match (or not).
110       while (childIter.hasNext())
111       {
112         MenuNode childNode = childIter.next();
113         String modelId = childNode.getModelId();
114 
115         // Need to append mode's sys id here to create a
116         // unique id.
117         String refNodeId = idrefList[i] + modelId;
118 
119         refNode = (MenuNode) getRootModel().getNode(refNodeId);
120 
121         // if nothing found, move on to the next child
122         if (refNode != null)
123          break;
124       }
125 
126       if (refNode == null)
127         continue;
128 
129       // Check the attributes of the found node
130       if (   !refNode.getRendered()
131           ||  refNode.getDisabled()
132           ||  refNode.getReadOnly()
133           || !refNode.getVisible()
134          )
135       {
136         refNode = null;
137         continue;
138       }
139 
140       // Ok, we have a valid RefNode
141       break;
142     }
143 
144     // If no valid node is found,
145     // log an error
146     if (refNode == null)
147     {
148         _LOG.severe("GroupNode " + getLabel() + " refers to no valid node.\n");
149         return null;
150     }
151 
152     return refNode;
153   }
154 
155   public final String getLabel()
156   {
157     if (_bundleKey != null && _bundleName != null)
158     {
159       // Load the resource bundle based on the locale of the
160       // current request. If the locale has not changed, this
161       // method just returns.
162       MenuUtils.loadBundle(_bundleName, _bundleKey + getHandlerId());
163     }
164 
165     if (_label != null && ContainerUtils.isValueReference(_label))
166     {
167       // do not set _label to the evaluated EL.
168       // It may change at times in the EL.
169       return _evalElStr(_label);
170     }
171     if (_label == null && _labelAndAccessKey != null)
172     {
173       int ampIdx = 0;
174       String labelAndAccessKeyEval = null;
175       String labelAndAccessKey = _labelAndAccessKey;
176       String label;
177       if (ContainerUtils.isValueReference(labelAndAccessKey))
178       {
179         labelAndAccessKeyEval = _evalElStr(labelAndAccessKey);
180       } else
181       {
182         labelAndAccessKeyEval = labelAndAccessKey;
183       }
184 
185       String accessKey;
186       if (labelAndAccessKeyEval == null ||
187           (ampIdx = labelAndAccessKeyEval.indexOf('&')) == -1)
188       {
189         // String is null or a label w/o an accesskey
190         label = labelAndAccessKeyEval;
191       } else if (ampIdx == (labelAndAccessKeyEval.length() - 1))
192       {
193         // & is last character, strip it.
194         label = labelAndAccessKeyEval.substring(0, ampIdx);
195       } else
196       {
197         // We have a string with an accessKey somewhere
198         char[] keyArray = labelAndAccessKeyEval.toCharArray();
199         int len = labelAndAccessKeyEval.length();
200         char[] keyArray2 = new char[len];
201         int i, j = 0;
202         boolean accessKeyFound = false;
203 
204         for (i = 0, j = 0; i < len; i++, j++)
205         {
206           if (keyArray[i] == '&')
207           {
208             i++;
209 
210             if (!accessKeyFound && keyArray[i] != '&')
211             {
212               // We have our accessKey
213               accessKey = labelAndAccessKeyEval.substring(i, i + 1);
214               accessKeyFound = true;
215             }
216           }
217 
218           keyArray2[j] = keyArray[i];
219         }
220 
221         String label1 = new String(keyArray2, 0, j);
222         label = label1;
223       }
224       return label;
225 
226     }
227     return _label;
228   }
229 
230   public final String getIcon()
231   {
232     return MenuUtils.evalString(_icon);
233   }
234 
235   public final List<MenuNode> getChildren()
236   {
237     return _children;
238   }
239 
240   public void setChildren(List<MenuNode> children)
241   {
242     _children = children;
243   }
244 
245   public final String getFocusViewId()
246   {
247     return _focusViewId;
248   }
249 
250   public final boolean getRendered()
251   {
252     boolean rendered = MenuUtils.evalBoolean(_renderedStr, true);
253     return rendered;
254   }
255 
256   public final boolean getDisabled()
257   {
258     boolean disabled = MenuUtils.evalBoolean(_disabledStr, false);
259     return disabled;
260   }
261 
262   public final boolean getVisible()
263   {
264     boolean visible = MenuUtils.evalBoolean(_visibleStr, true);
265     return visible;
266   }
267 
268   public final boolean getReadOnly()
269   {
270     boolean readOnly = MenuUtils.evalBoolean(_readOnlyStr, false);
271     return readOnly;
272   }
273 
274   protected final String getHandlerId()
275   {
276     return _handlerId;
277   }
278 
279   public final String getBundleKey()
280   {
281     return _bundleKey;
282   }
283 
284   public final String getBundleName()
285   {
286     return _bundleName;
287   }
288 
289   
290 
291   
292 
293   public final char getAccessKey()
294   {
295     if (_accessKey == null && _labelAndAccessKey != null)
296     {
297       int ampIdx = 0;
298       String labelAndAccessKeyEval = null;
299       String labelAndAccessKey = _labelAndAccessKey;
300       String label;
301       if (ContainerUtils.isValueReference(labelAndAccessKey))
302       {
303         labelAndAccessKeyEval = _evalElStr(labelAndAccessKey);
304       } 
305       else
306       {
307         labelAndAccessKeyEval = labelAndAccessKey;
308       }
309 
310       String accessKey = null;
311       if (labelAndAccessKeyEval == null ||
312           (ampIdx = labelAndAccessKeyEval.indexOf('&')) == -1)
313       {
314         // String is null or a label w/o an accesskey
315         label = labelAndAccessKeyEval;
316       } else if (ampIdx == (labelAndAccessKeyEval.length() - 1))
317       {
318         // & is last character, strip it.
319         label = labelAndAccessKeyEval.substring(0, ampIdx);
320       } else
321       {
322         // We have a string with an accessKey somewhere
323         char[] keyArray = labelAndAccessKeyEval.toCharArray();
324         int len = labelAndAccessKeyEval.length();
325         char[] keyArray2 = new char[len];
326         int i, j = 0;
327         boolean accessKeyFound = false;
328 
329         for (i = 0, j = 0; i < len; i++, j++)
330         {
331           if (keyArray[i] == '&')
332           {
333             i++;
334 
335             if (!accessKeyFound && keyArray[i] != '&')
336             {
337               // We have our accessKey
338               accessKey = labelAndAccessKeyEval.substring(i, i + 1);
339               accessKeyFound = true;
340             }
341           }
342 
343           keyArray2[j] = keyArray[i];
344         }
345 
346         String label1 = new String(keyArray2, 0, j);
347         label = label1;
348       }
349       return (accessKey != null)? accessKey.charAt(0):'\0';
350 
351     }
352     else 
353     {
354       String accessKeyStr = MenuUtils.evalString(_accessKey);
355       if (accessKeyStr == null || accessKeyStr.length() > 1)
356         return '\0';
357       return accessKeyStr.charAt(0);
358     }
359     
360   }
361 
362   public final String getLabelAndAccessKey()
363   {
364     if (_labelAndAccessKey != null)
365     {
366       int ampIdx = 0;
367       String labelAndAccessKeyEval = null;
368       String labelAndAccessKey = _labelAndAccessKey;
369       String label;
370       if (_bundleKey != null && _bundleName != null)
371       {
372         // Load the resource bundle based on the locale of the
373         // current request. If the locale has not changed, this
374         // method just returns.
375         MenuUtils.loadBundle(_bundleName, _bundleKey + getHandlerId());
376       }
377       if (ContainerUtils.isValueReference(labelAndAccessKey))
378       {
379         labelAndAccessKeyEval = _evalElStr(labelAndAccessKey);
380       } else
381       {
382         labelAndAccessKeyEval = labelAndAccessKey;
383       }
384 
385       String accessKey = null;
386       if (labelAndAccessKeyEval == null ||
387           (ampIdx = labelAndAccessKeyEval.indexOf('&')) == -1)
388       {
389         // String is null or a label w/o an accesskey
390         label = labelAndAccessKeyEval;
391       } else if (ampIdx == (labelAndAccessKeyEval.length() - 1))
392       {
393         // & is last character, strip it.
394         label = labelAndAccessKeyEval.substring(0, ampIdx);
395       } else
396       {
397         // We have a string with an accessKey somewhere
398         char[] keyArray = labelAndAccessKeyEval.toCharArray();
399         int len = labelAndAccessKeyEval.length();
400         char[] keyArray2 = new char[len];
401         int i, j = 0;
402         boolean accessKeyFound = false;
403 
404         for (i = 0, j = 0; i < len; i++, j++)
405         {
406           if (keyArray[i] == '&')
407           {
408             i++;
409 
410             if (!accessKeyFound && keyArray[i] != '&')
411             {
412               // We have our accessKey
413               accessKey = labelAndAccessKeyEval.substring(i, i + 1);
414               accessKeyFound = true;
415             }
416           }
417 
418           keyArray2[j] = keyArray[i];
419         }
420 
421         String label1 = new String(keyArray2, 0, j);
422         label = label1;
423       }
424       if(accessKey == null)
425         return label;
426       
427       return _joinLabelAndAccessKey(label, accessKey);
428     }
429     return null;
430   }
431   public final String getId()
432   {
433     return _id;
434   }
435 
436   public final String getModelId()
437   {
438     return _modelId;
439   }
440 
441   public final String getUniqueId()
442   {
443     return _uniqueId;
444   }
445   
446   //TODO make this work
447 //  public final String getLabelAndAccessKey()
448 //  {
449 //    String labelAndAcessKeyEval;
450 //    if ( _labelAndAccessKey != null
451 //        && ContainerUtils.isValueReference(_labelAndAccessKey)
452 //       )
453 //    {
454 //       labelAndAcessKeyEval= _evalElStr(_labelAndAccessKey);
455 //    }
456 //    else
457 //    {
458 //      labelAndAcessKeyEval = _labelAndAccessKey;
459 //    }
460 //    
461 //    
462 //  }
463 
464   public final boolean getDefaultFocusPath()
465   {
466     boolean defaultFocusPath =
467         MenuUtils.evalBoolean(_defaultFocusPathStr, false);
468     return defaultFocusPath;
469   }
470 
471   public final String getRootModelKey()
472   {
473     return _rootModelKey;
474   }
475 
476   public final int getRootId()
477   {
478     return _rootId;
479   }
480 
481   private String _evalElStr(String str)
482   {
483     if (str == null)
484       return null;
485 
486     String keystr =
487         MenuUtils.stringReplaceFirst(str.trim(), _bundleKey, _bundleKey +
488             getHandlerId());
489     String elVal = MenuUtils.getBoundValue(keystr, String.class);
490     return elVal;
491   }
492   
493   private String _joinLabelAndAccessKey(String label, String accessKey)
494   {
495     char[] keyArray = label.toCharArray();
496     int len = label.length();
497     int lentimes2 = len * 2;
498     char[] keyArray2 = new char[lentimes2];
499     int i, j = 0;
500     boolean accessKeyFound = false;
501 
502     // find the first occurrence of a single Ampersand
503     for (i = 0, j = 0; i < len; i++, j++)
504     {
505       // AccessKey
506       if (keyArray[i] == accessKey.charAt(0) && !accessKeyFound)
507       {
508         keyArray2[j] = '&';
509         j++;
510         accessKeyFound = true;
511       }
512 
513       keyArray2[j] = keyArray[i];
514 
515       // Ampersand as regular character
516       // double it up.
517       if (keyArray[i] == '&')
518       {
519         j++;
520         keyArray2[j] = keyArray[i];
521       }
522     }
523 
524     String combinedLabel = new String(keyArray2, 0, j);
525     return combinedLabel;
526   }
527 
528   private final String _icon;
529   private List<MenuNode> _children = null;
530   private final String _focusViewId;
531   private final String _renderedStr;
532   private final String _disabledStr;
533   private final String _visibleStr;
534   private final String _readOnlyStr;
535   private final String _handlerId;
536   private final String _bundleKey;
537   private final String _bundleName;
538   private final String _accessKey;
539   private final String _id;
540   private final String _modelId;
541   private final String _labelAndAccessKey;
542   private final String _defaultFocusPathStr;
543   private final String _uniqueId;
544 
545   // Root Menu model's Request Map Key
546   private final String _rootModelKey;
547 
548   private final int _rootId;
549 
550   
551 
552   private final String _label;
553   
554   
555   private final String   _idref ;
556   private final String[] _idrefList ;
557 
558   private final static TrinidadLogger _LOG =
559     TrinidadLogger.createTrinidadLogger(ImmutableGroupNode.class);
560 }