You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ma...@apache.org on 2010/07/08 17:23:25 UTC

svn commit: r961803 [1/2] - in /myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/menu: ./ GroupNode.java ImmutableGroupNode.java ImmutableItemNode.java ItemNode.java MenuNode.java MenuUtils.java

Author: matzew
Date: Thu Jul  8 15:23:24 2010
New Revision: 961803

URL: http://svn.apache.org/viewvc?rev=961803&view=rev
Log:
TRINIDAD-1836 - Define public apis for org.apache.myfaces.trinidadinternal.menu

moving some IMPL code to Trinidad API, since they are generally useful.

review on mailing was done by Trinidad contributor Venkata Guddanti

Added:
    myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/menu/
    myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/menu/GroupNode.java
    myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/menu/ImmutableGroupNode.java
    myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/menu/ImmutableItemNode.java
    myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/menu/ItemNode.java
    myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/menu/MenuNode.java
    myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/menu/MenuUtils.java

Added: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/menu/GroupNode.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/menu/GroupNode.java?rev=961803&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/menu/GroupNode.java (added)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/menu/GroupNode.java Thu Jul  8 15:23:24 2010
@@ -0,0 +1,241 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.myfaces.trinidad.menu;
+
+import java.lang.reflect.Array;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+
+/**
+ * Code specific to a Menu Model's GroupNode.
+ *
+ */
+
+public class GroupNode extends MenuNode
+{
+  /**
+    * Constructs a GroupNode
+    */
+  public GroupNode()
+  {
+    super();
+  }
+
+  /**
+    * Called by the Default ActionListener
+    * when a menu node is clicked/selected.
+    *
+    * @return String outcome or viewId used
+    *         during a POST for navigation.
+    */
+  @Override
+  public String doAction()
+  {
+    // Call the doAction method of my idref node
+    return getRefNode().doAction();
+  }
+
+  /**
+    * Get the Destination URL of a page for a
+    * GET.
+    *
+    * @return String URL of a page.
+    */
+  @Override
+  public String getDestination()
+  {
+    // Call the getDestination method of my idref node
+    return getRefNode().getDestination();
+  }
+
+  /**
+    * Sets the idref of the node.
+    *
+    * The value of this attribute is an "id" of another node
+    * This tells the pointing node where to obtain its viewId and
+    * takes precedence (and will replace) the pointing nodes viewId,
+    * if one exists.  This should point to a node of the same style,
+    * e.g. actionNode points to actionNode.
+    *
+    * @param idref - String name pointing to the "id" of another node
+    */
+  public void setIdRef(String idref)
+  {
+    _idref = idref;
+
+    // Create a list of idref's for easier access
+    if (_idref != null)
+      _makeIdRefList (idref);
+  }
+
+  /**
+    * Get the node whose id matches this node's
+    * idref attribute value.
+    *
+    * @return the MenuNode whose id matches this
+    *         node's idref attribute value.
+    */
+  @Override
+  public MenuNode getRefNode()
+  {
+    MenuNode refNode = null;
+
+    // create one if it does not exist
+    // should not happen, but can't hurt
+    if (_idrefList == null)
+    {
+      String idref = getIdRef();
+      _makeIdRefList(idref);
+    }
+
+    // Get idrefList
+    String[] idrefList = _getIdRefList();
+
+    // get group node's children
+    List<MenuNode> children = getChildren();
+
+    // Traverse the list. Do the following:
+    //    o get Node from Model's hashMap of nodes and ids
+    //    o check attributes (rendered, disabled, readOnly)
+    //    o if they are ok, return the node
+    for (int i=0; i < Array.getLength(idrefList); i++)
+    {
+      Iterator<MenuNode> childIter = children.iterator();
+
+      // All node "id" attribute values had the node's
+      // system hashcode id appended to the id when
+      // placed in the model's idNodeMap.
+      //
+      // Each id in the idreflist of a group node does
+      // NOT have this node sys id appended it to it
+      // and needs to or we won't find the group's
+      // ref node.
+      //
+      // Since group nodes can only point to one of
+      // its children, we iterate through them, get
+      // their sys id and append it to idref until
+      // we find a match (or not).
+      while (childIter.hasNext())
+      {
+        MenuNode childNode = childIter.next();
+        String modelId = childNode.getModelId();
+
+        // Need to append mode's sys id here to create a
+        // unique id.
+        String refNodeId = idrefList[i] + modelId;
+
+        refNode = (MenuNode) getRootModel().getNode(refNodeId);
+
+        // if nothing found, move on to the next child
+        if (refNode != null)
+         break;
+      }
+
+      if (refNode == null)
+        continue;
+
+      // Check the attributes of the found node
+      if (   !refNode.getRendered()
+          ||  refNode.getDisabled()
+          ||  refNode.getReadOnly()
+          || !refNode.getVisible()
+         )
+      {
+        refNode = null;
+        continue;
+      }
+
+      // Ok, we have a valid RefNode
+      break;
+    }
+
+    // If no valid node is found,
+    // log an error
+    if (refNode == null)
+    {
+        _LOG.severe("GroupNode " + getLabel() + " refers to no valid node.\n");
+        return null;
+    }
+
+    return refNode;
+  }
+
+  /**
+    * Get the id of the node referred to by
+    * the idref attribute of this node.
+    *
+    * @return String id of the node referred
+    *         to by the idref attribure of
+    *         this node.
+    */
+  public String getIdRef()
+  {
+    return _idref;
+  }
+  
+  public String[] getIdRefListProperty()
+  {
+    return _idrefList;
+  }
+
+  @Override
+  public MenuNode getThreadSafeCopy()
+  {
+    return new ImmutableGroupNode(this);
+  }
+  
+  /* =============================================================
+   * Private methods
+   * =============================================================*/
+
+  /**
+    * _getIdRefList. gets the list of idrefs for this node.
+    *
+    * @return String[] list of idrefs for this node.
+    */
+  private String[] _getIdRefList()
+  {
+    return _idrefList;
+  }
+
+  /**
+    * Make a list of idref entries from the nodes String
+    * of idref's.
+    *
+    * This should only be called from the node's setIdRef
+    * method.  So if it is called more than once (highly
+    * unlikely), simply empty out the previous contents.
+    *
+    * @param entries - String of String entries
+    *
+    */
+  private void _makeIdRefList (String entries)
+  {
+    _idrefList = entries.trim().split("\\s+");
+  }
+
+  private String   _idref     = null;
+  private String[] _idrefList = null;
+
+  private final static TrinidadLogger _LOG =
+       TrinidadLogger.createTrinidadLogger(GroupNode.class);
+}

Added: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/menu/ImmutableGroupNode.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/menu/ImmutableGroupNode.java?rev=961803&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/menu/ImmutableGroupNode.java (added)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/menu/ImmutableGroupNode.java Thu Jul  8 15:23:24 2010
@@ -0,0 +1,560 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.myfaces.trinidad.menu;
+
+import java.lang.reflect.Array;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+import org.apache.myfaces.trinidad.util.ContainerUtils;
+
+/**
+ * This class is a thread safe version of GroupNode class.
+ * It replicates most of the code in GroupNode but makes
+ * sure it does not modify state of the object.
+ * 
+ * Therefore multiple request threads can access the
+ * properties of the objects of this class,in a thread safe
+ * manner.
+ * 
+ * Please note that setters should not be called on objects
+ * of this class.Objects of this class are fully initialized
+ * on construction.
+ *
+ */
+public class ImmutableGroupNode extends GroupNode
+{
+  
+  public ImmutableGroupNode(GroupNode node)
+  {
+    _icon = node.getIconProperty();
+    _focusViewId = node.getFocusViewIdProperty();
+    _renderedStr = node.getRenderedProperty();
+    _disabledStr = node.getDisabledProperty();
+    _visibleStr = node.getVisibleProperty();
+    _readOnlyStr = node.getReadOnlyProperty();
+    _handlerId = node.getHandlerIdProperty();
+    _bundleKey = node.getBundleKeyProperty();
+    _bundleName = node.getBundleNameProperty();
+    _accessKey = node.getAccessKeyProperty();
+    _id = node.getIdProperty();
+    _modelId = node.getModelIdProperty();
+    _uniqueId = node.getUniqueIdProperty();
+    _labelAndAccessKey = node.getLabelAndAccessKeyProperty();
+    _defaultFocusPathStr = node.getDefaultFocusPathProperty();
+
+    // Root Menu model's Request Map Key
+    _rootModelKey = node.getRootModelKeyProperty();
+
+    _rootId = node.getRootIdProperty();
+    _label = node.getLabelProperty();
+    _idref = node.getIdRef();
+    _idrefList = node.getIdRefListProperty();
+  }
+  
+  
+  public String getIdRef()
+  {
+    return _idref;
+  }
+  
+  public MenuNode getRefNode()
+  {
+    MenuNode refNode = null;
+
+    
+    // Get idrefList
+    String[] idrefList = _idrefList;
+
+    // get group node's children
+    List<MenuNode> children = getChildren();
+
+    // Traverse the list. Do the following:
+    //    o get Node from Model's hashMap of nodes and ids
+    //    o check attributes (rendered, disabled, readOnly)
+    //    o if they are ok, return the node
+    for (int i=0; i < Array.getLength(idrefList); i++)
+    {
+      Iterator<MenuNode> childIter = children.iterator();
+
+      // All node "id" attribute values had the node's
+      // system hashcode id appended to the id when
+      // placed in the model's idNodeMap.
+      //
+      // Each id in the idreflist of a group node does
+      // NOT have this node sys id appended it to it
+      // and needs to or we won't find the group's
+      // ref node.
+      //
+      // Since group nodes can only point to one of
+      // its children, we iterate through them, get
+      // their sys id and append it to idref until
+      // we find a match (or not).
+      while (childIter.hasNext())
+      {
+        MenuNode childNode = childIter.next();
+        String modelId = childNode.getModelId();
+
+        // Need to append mode's sys id here to create a
+        // unique id.
+        String refNodeId = idrefList[i] + modelId;
+
+        refNode = (MenuNode) getRootModel().getNode(refNodeId);
+
+        // if nothing found, move on to the next child
+        if (refNode != null)
+         break;
+      }
+
+      if (refNode == null)
+        continue;
+
+      // Check the attributes of the found node
+      if (   !refNode.getRendered()
+          ||  refNode.getDisabled()
+          ||  refNode.getReadOnly()
+          || !refNode.getVisible()
+         )
+      {
+        refNode = null;
+        continue;
+      }
+
+      // Ok, we have a valid RefNode
+      break;
+    }
+
+    // If no valid node is found,
+    // log an error
+    if (refNode == null)
+    {
+        _LOG.severe("GroupNode " + getLabel() + " refers to no valid node.\n");
+        return null;
+    }
+
+    return refNode;
+  }
+
+  public final String getLabel()
+  {
+    if (_bundleKey != null && _bundleName != null)
+    {
+      // Load the resource bundle based on the locale of the
+      // current request. If the locale has not changed, this
+      // method just returns.
+      MenuUtils.loadBundle(_bundleName, _bundleKey + getHandlerId());
+    }
+
+    if (_label != null && ContainerUtils.isValueReference(_label))
+    {
+      // do not set _label to the evaluated EL.
+      // It may change at times in the EL.
+      return _evalElStr(_label);
+    }
+    if (_label == null && _labelAndAccessKey != null)
+    {
+      int ampIdx = 0;
+      String labelAndAccessKeyEval = null;
+      String labelAndAccessKey = _labelAndAccessKey;
+      String label;
+      if (ContainerUtils.isValueReference(labelAndAccessKey))
+      {
+        labelAndAccessKeyEval = _evalElStr(labelAndAccessKey);
+      } else
+      {
+        labelAndAccessKeyEval = labelAndAccessKey;
+      }
+
+      String accessKey;
+      if (labelAndAccessKeyEval == null ||
+          (ampIdx = labelAndAccessKeyEval.indexOf('&')) == -1)
+      {
+        // String is null or a label w/o an accesskey
+        label = labelAndAccessKeyEval;
+      } else if (ampIdx == (labelAndAccessKeyEval.length() - 1))
+      {
+        // & is last character, strip it.
+        label = labelAndAccessKeyEval.substring(0, ampIdx);
+      } else
+      {
+        // We have a string with an accessKey somewhere
+        char[] keyArray = labelAndAccessKeyEval.toCharArray();
+        int len = labelAndAccessKeyEval.length();
+        char[] keyArray2 = new char[len];
+        int i, j = 0;
+        boolean accessKeyFound = false;
+
+        for (i = 0, j = 0; i < len; i++, j++)
+        {
+          if (keyArray[i] == '&')
+          {
+            i++;
+
+            if (!accessKeyFound && keyArray[i] != '&')
+            {
+              // We have our accessKey
+              accessKey = labelAndAccessKeyEval.substring(i, i + 1);
+              accessKeyFound = true;
+            }
+          }
+
+          keyArray2[j] = keyArray[i];
+        }
+
+        String label1 = new String(keyArray2, 0, j);
+        label = label1;
+      }
+      return label;
+
+    }
+    return _label;
+  }
+
+  public final String getIcon()
+  {
+    return MenuUtils.evalString(_icon);
+  }
+
+  public final List<MenuNode> getChildren()
+  {
+    return _children;
+  }
+
+  public void setChildren(List<MenuNode> children)
+  {
+    _children = children;
+  }
+
+  public final String getFocusViewId()
+  {
+    return _focusViewId;
+  }
+
+  public final boolean getRendered()
+  {
+    boolean rendered = MenuUtils.evalBoolean(_renderedStr, true);
+    return rendered;
+  }
+
+  public final boolean getDisabled()
+  {
+    boolean disabled = MenuUtils.evalBoolean(_disabledStr, false);
+    return disabled;
+  }
+
+  public final boolean getVisible()
+  {
+    boolean visible = MenuUtils.evalBoolean(_visibleStr, true);
+    return visible;
+  }
+
+  public final boolean getReadOnly()
+  {
+    boolean readOnly = MenuUtils.evalBoolean(_readOnlyStr, false);
+    return readOnly;
+  }
+
+  protected final String getHandlerId()
+  {
+    return _handlerId;
+  }
+
+  public final String getBundleKey()
+  {
+    return _bundleKey;
+  }
+
+  public final String getBundleName()
+  {
+    return _bundleName;
+  }
+
+  
+
+  
+
+  public final char getAccessKey()
+  {
+    if (_accessKey == null && _labelAndAccessKey != null)
+    {
+      int ampIdx = 0;
+      String labelAndAccessKeyEval = null;
+      String labelAndAccessKey = _labelAndAccessKey;
+      String label;
+      if (ContainerUtils.isValueReference(labelAndAccessKey))
+      {
+        labelAndAccessKeyEval = _evalElStr(labelAndAccessKey);
+      } 
+      else
+      {
+        labelAndAccessKeyEval = labelAndAccessKey;
+      }
+
+      String accessKey = null;
+      if (labelAndAccessKeyEval == null ||
+          (ampIdx = labelAndAccessKeyEval.indexOf('&')) == -1)
+      {
+        // String is null or a label w/o an accesskey
+        label = labelAndAccessKeyEval;
+      } else if (ampIdx == (labelAndAccessKeyEval.length() - 1))
+      {
+        // & is last character, strip it.
+        label = labelAndAccessKeyEval.substring(0, ampIdx);
+      } else
+      {
+        // We have a string with an accessKey somewhere
+        char[] keyArray = labelAndAccessKeyEval.toCharArray();
+        int len = labelAndAccessKeyEval.length();
+        char[] keyArray2 = new char[len];
+        int i, j = 0;
+        boolean accessKeyFound = false;
+
+        for (i = 0, j = 0; i < len; i++, j++)
+        {
+          if (keyArray[i] == '&')
+          {
+            i++;
+
+            if (!accessKeyFound && keyArray[i] != '&')
+            {
+              // We have our accessKey
+              accessKey = labelAndAccessKeyEval.substring(i, i + 1);
+              accessKeyFound = true;
+            }
+          }
+
+          keyArray2[j] = keyArray[i];
+        }
+
+        String label1 = new String(keyArray2, 0, j);
+        label = label1;
+      }
+      return (accessKey != null)? accessKey.charAt(0):'\0';
+
+    }
+    else 
+    {
+      String accessKeyStr = MenuUtils.evalString(_accessKey);
+      if (accessKeyStr == null || accessKeyStr.length() > 1)
+        return '\0';
+      return accessKeyStr.charAt(0);
+    }
+    
+  }
+
+  public final String getLabelAndAccessKey()
+  {
+    if (_labelAndAccessKey != null)
+    {
+      int ampIdx = 0;
+      String labelAndAccessKeyEval = null;
+      String labelAndAccessKey = _labelAndAccessKey;
+      String label;
+      if (_bundleKey != null && _bundleName != null)
+      {
+        // Load the resource bundle based on the locale of the
+        // current request. If the locale has not changed, this
+        // method just returns.
+        MenuUtils.loadBundle(_bundleName, _bundleKey + getHandlerId());
+      }
+      if (ContainerUtils.isValueReference(labelAndAccessKey))
+      {
+        labelAndAccessKeyEval = _evalElStr(labelAndAccessKey);
+      } else
+      {
+        labelAndAccessKeyEval = labelAndAccessKey;
+      }
+
+      String accessKey = null;
+      if (labelAndAccessKeyEval == null ||
+          (ampIdx = labelAndAccessKeyEval.indexOf('&')) == -1)
+      {
+        // String is null or a label w/o an accesskey
+        label = labelAndAccessKeyEval;
+      } else if (ampIdx == (labelAndAccessKeyEval.length() - 1))
+      {
+        // & is last character, strip it.
+        label = labelAndAccessKeyEval.substring(0, ampIdx);
+      } else
+      {
+        // We have a string with an accessKey somewhere
+        char[] keyArray = labelAndAccessKeyEval.toCharArray();
+        int len = labelAndAccessKeyEval.length();
+        char[] keyArray2 = new char[len];
+        int i, j = 0;
+        boolean accessKeyFound = false;
+
+        for (i = 0, j = 0; i < len; i++, j++)
+        {
+          if (keyArray[i] == '&')
+          {
+            i++;
+
+            if (!accessKeyFound && keyArray[i] != '&')
+            {
+              // We have our accessKey
+              accessKey = labelAndAccessKeyEval.substring(i, i + 1);
+              accessKeyFound = true;
+            }
+          }
+
+          keyArray2[j] = keyArray[i];
+        }
+
+        String label1 = new String(keyArray2, 0, j);
+        label = label1;
+      }
+      if(accessKey == null)
+        return label;
+      
+      return _joinLabelAndAccessKey(label, accessKey);
+    }
+    return null;
+  }
+  public final String getId()
+  {
+    return _id;
+  }
+
+  public final String getModelId()
+  {
+    return _modelId;
+  }
+
+  public final String getUniqueId()
+  {
+    return _uniqueId;
+  }
+  
+  //TODO make this work
+//  public final String getLabelAndAccessKey()
+//  {
+//    String labelAndAcessKeyEval;
+//    if ( _labelAndAccessKey != null
+//        && ContainerUtils.isValueReference(_labelAndAccessKey)
+//       )
+//    {
+//       labelAndAcessKeyEval= _evalElStr(_labelAndAccessKey);
+//    }
+//    else
+//    {
+//      labelAndAcessKeyEval = _labelAndAccessKey;
+//    }
+//    
+//    
+//  }
+
+  public final boolean getDefaultFocusPath()
+  {
+    boolean defaultFocusPath =
+        MenuUtils.evalBoolean(_defaultFocusPathStr, false);
+    return defaultFocusPath;
+  }
+
+  public final String getRootModelKey()
+  {
+    return _rootModelKey;
+  }
+
+  public final int getRootId()
+  {
+    return _rootId;
+  }
+
+  private String _evalElStr(String str)
+  {
+    if (str == null)
+      return null;
+
+    String keystr =
+        MenuUtils.stringReplaceFirst(str.trim(), _bundleKey, _bundleKey +
+            getHandlerId());
+    String elVal = MenuUtils.getBoundValue(keystr, String.class);
+    return elVal;
+  }
+  
+  private String _joinLabelAndAccessKey(String label, String accessKey)
+  {
+    char[] keyArray = label.toCharArray();
+    int len = label.length();
+    int lentimes2 = len * 2;
+    char[] keyArray2 = new char[lentimes2];
+    int i, j = 0;
+    boolean accessKeyFound = false;
+
+    // find the first occurrence of a single Ampersand
+    for (i = 0, j = 0; i < len; i++, j++)
+    {
+      // AccessKey
+      if (keyArray[i] == accessKey.charAt(0) && !accessKeyFound)
+      {
+        keyArray2[j] = '&';
+        j++;
+        accessKeyFound = true;
+      }
+
+      keyArray2[j] = keyArray[i];
+
+      // Ampersand as regular character
+      // double it up.
+      if (keyArray[i] == '&')
+      {
+        j++;
+        keyArray2[j] = keyArray[i];
+      }
+    }
+
+    String combinedLabel = new String(keyArray2, 0, j);
+    return combinedLabel;
+  }
+
+  private final String _icon;
+  private List<MenuNode> _children = null;
+  private final String _focusViewId;
+  private final String _renderedStr;
+  private final String _disabledStr;
+  private final String _visibleStr;
+  private final String _readOnlyStr;
+  private final String _handlerId;
+  private final String _bundleKey;
+  private final String _bundleName;
+  private final String _accessKey;
+  private final String _id;
+  private final String _modelId;
+  private final String _labelAndAccessKey;
+  private final String _defaultFocusPathStr;
+  private final String _uniqueId;
+
+  // Root Menu model's Request Map Key
+  private final String _rootModelKey;
+
+  private final int _rootId;
+
+  
+
+  private final String _label;
+  
+  
+  private final String   _idref ;
+  private final String[] _idrefList ;
+
+  private final static TrinidadLogger _LOG =
+    TrinidadLogger.createTrinidadLogger(ImmutableGroupNode.class);
+}

Added: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/menu/ImmutableItemNode.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/menu/ImmutableItemNode.java?rev=961803&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/menu/ImmutableItemNode.java (added)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/menu/ImmutableItemNode.java Thu Jul  8 15:23:24 2010
@@ -0,0 +1,632 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.myfaces.trinidad.menu;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.el.ELContext;
+import javax.el.ExpressionFactory;
+import javax.el.MethodExpression;
+import javax.faces.context.FacesContext;
+import javax.faces.event.ActionEvent;
+
+import org.apache.myfaces.trinidad.util.ContainerUtils;
+
+/**
+ * This class is a thread safe version of ItemNode class.
+ * It replicates most of the code in ItemNode but makes
+ * sure it does not modify state of the object.
+ * 
+ * Therefore multiple request threads can access the
+ * properties of the objects of this class,in a thread safe
+ * manner.
+ * 
+ * Please note that setters should not be called on objects
+ * of this class.Objects of this class are fully initialized
+ * on construction.
+ *
+ */
+public class ImmutableItemNode extends ItemNode
+{
+  
+  public ImmutableItemNode(ItemNode node)
+  {
+    _icon = node.getIconProperty();
+    _focusViewId = node.getFocusViewIdProperty();
+    _renderedStr = node.getRenderedProperty();
+    _disabledStr = node.getDisabledProperty();
+    _visibleStr = node.getVisibleProperty();
+    _readOnlyStr = node.getReadOnlyProperty();
+    _handlerId = node.getHandlerIdProperty();
+    _bundleKey = node.getBundleKeyProperty();
+    _bundleName = node.getBundleNameProperty();
+    _accessKey = node.getAccessKeyProperty();
+    _id = node.getIdProperty();
+    _modelId = node.getModelIdProperty();
+    _uniqueId = node.getUniqueIdProperty();
+    _labelAndAccessKey = node.getLabelAndAccessKeyProperty();
+    _defaultFocusPathStr = node.getDefaultFocusPathProperty();
+
+    // Root Menu model's Request Map Key
+    _rootModelKey = node.getRootModelKeyProperty();
+
+    _rootId = node.getRootIdProperty();
+
+    _customPropList = node.getCustomPropListProperty();
+
+    _destination = node.getDestinationProperty();
+    _targetFrame = node.getTargetFrameProperty();
+    _action = node.getActionProperty();
+    _actionListener = node.getActionListenerProperty();
+    _launchListener = node.getLaunchListenerProperty();
+    _returnListener = node.getReturnListenerProperty();
+    _immediateStr = node.getImmediateProperty();
+    _useWindowStr = node.getUseWindowProperty();
+    _windowHeightStr = node.getWindowHeightProperty();
+    _windowWidthStr = node.getWindowWidthProperty();
+
+    _label = node.getLabelProperty();
+  }
+
+  public final Map<String, String> getCustomPropList()
+  {
+    return _customPropList;
+  }
+
+  public final String getDestination()
+  {
+
+    String value = _destination;
+
+    // Could be EL expression
+    if (value != null && ContainerUtils.isValueReference(value))
+    {
+      // Value of action is EL method binding, so we
+      // need to evaluate it
+      value = MenuUtils.getBoundValue(value, String.class);
+    }
+
+    // Appending nodeId to URL so that we can identify the node
+    // when getFocusRowKey() is called on the model.
+    return value != null ? value + "?nodeId=" + getUniqueId() : value;
+
+  }
+
+  public final String getTargetFrame()
+  {
+    String value = _targetFrame;
+
+    // Could be EL expression
+    if (value != null && ContainerUtils.isValueReference(value))
+    {
+      // Value of destination is EL value binding, so we
+      // need to evaluate it
+      value = MenuUtils.getBoundValue(value, String.class);
+    }
+
+    return value;
+  }
+
+  public final String getActionListener()
+  {
+    String value = _actionListener;
+
+    // Could be EL expression
+    if (value != null && ContainerUtils.isValueReference(value))
+    {
+      // Value of action is EL method binding, so we
+      // need to evaluate it
+      value = MenuUtils.getBoundValue(value, String.class);
+    }
+
+    return value;
+  }
+
+  public final String getLaunchListener()
+  {
+
+    String value = _launchListener;
+
+    // Could be EL expression
+    if (value != null && ContainerUtils.isValueReference(value))
+    {
+      // Value of action is EL method binding, so we
+      // need to evaluate it
+      value = MenuUtils.getBoundValue(value, String.class);
+    }
+
+    return value;
+  }
+
+  public final String getReturnListener()
+  {
+    String value = _returnListener;
+
+    // Could be EL expression
+    if (value != null && ContainerUtils.isValueReference(value))
+    {
+      // Value of action is EL method binding, so we
+      // need to evaluate it
+      value = MenuUtils.getBoundValue(value, String.class);
+    }
+
+    return value;
+
+  }
+
+  public final boolean getImmediate()
+  {
+    boolean immediate = MenuUtils.evalBoolean(_immediateStr, false);
+    return immediate;
+  }
+
+  public final boolean getUseWindow()
+  {
+    boolean useWindow = MenuUtils.evalBoolean(_useWindowStr, false);
+    return useWindow;
+  }
+
+  public final int getWindowHeight()
+  {
+    int windowHeight = MenuUtils.evalInt(_windowHeightStr);
+    return windowHeight;
+  }
+
+  public final int getWindowWidth()
+  {
+    int windowWidth = MenuUtils.evalInt(_windowWidthStr);
+    return windowWidth;
+  }
+
+  public final String getLabel()
+  {
+    if (_bundleKey != null && _bundleName != null)
+    {
+      // Load the resource bundle based on the locale of the
+      // current request. If the locale has not changed, this
+      // method just returns.
+      MenuUtils.loadBundle(_bundleName, _bundleKey + getHandlerId());
+    }
+
+    if (_label != null && ContainerUtils.isValueReference(_label))
+    {
+      // do not set _label to the evaluated EL.
+      // It may change at times in the EL.
+      return _evalElStr(_label);
+    }
+    if (_label == null && _labelAndAccessKey != null)
+    {
+      int ampIdx = 0;
+      String labelAndAccessKeyEval = null;
+      String labelAndAccessKey = _labelAndAccessKey;
+      String label;
+      if (ContainerUtils.isValueReference(labelAndAccessKey))
+      {
+        labelAndAccessKeyEval = _evalElStr(labelAndAccessKey);
+      } else
+      {
+        labelAndAccessKeyEval = labelAndAccessKey;
+      }
+
+      String accessKey;
+      if (labelAndAccessKeyEval == null ||
+          (ampIdx = labelAndAccessKeyEval.indexOf('&')) == -1)
+      {
+        // String is null or a label w/o an accesskey
+        label = labelAndAccessKeyEval;
+      } else if (ampIdx == (labelAndAccessKeyEval.length() - 1))
+      {
+        // & is last character, strip it.
+        label = labelAndAccessKeyEval.substring(0, ampIdx);
+      } else
+      {
+        // We have a string with an accessKey somewhere
+        char[] keyArray = labelAndAccessKeyEval.toCharArray();
+        int len = labelAndAccessKeyEval.length();
+        char[] keyArray2 = new char[len];
+        int i, j = 0;
+        boolean accessKeyFound = false;
+
+        for (i = 0, j = 0; i < len; i++, j++)
+        {
+          if (keyArray[i] == '&')
+          {
+            i++;
+
+            if (!accessKeyFound && keyArray[i] != '&')
+            {
+              // We have our accessKey
+              accessKey = labelAndAccessKeyEval.substring(i, i + 1);
+              accessKeyFound = true;
+            }
+          }
+
+          keyArray2[j] = keyArray[i];
+        }
+
+        String label1 = new String(keyArray2, 0, j);
+        label = label1;
+      }
+      return label;
+
+    }
+    return _label;
+  }
+
+  public final String getIcon()
+  {
+    return MenuUtils.evalString(_icon);
+  }
+
+  public final List<MenuNode> getChildren()
+  {
+    return _children;
+  }
+
+  public void setChildren(List<MenuNode> children)
+  {
+    _children = children;
+  }
+
+  public final String getFocusViewId()
+  {
+    return _focusViewId;
+  }
+
+  public final boolean getRendered()
+  {
+    boolean rendered = MenuUtils.evalBoolean(_renderedStr, true);
+    return rendered;
+  }
+
+  public final boolean getDisabled()
+  {
+    boolean disabled = MenuUtils.evalBoolean(_disabledStr, false);
+    return disabled;
+  }
+
+  public final boolean getVisible()
+  {
+    boolean visible = MenuUtils.evalBoolean(_visibleStr, true);
+    return visible;
+  }
+
+  public final boolean getReadOnly()
+  {
+    boolean readOnly = MenuUtils.evalBoolean(_readOnlyStr, false);
+    return readOnly;
+  }
+
+  protected final String getHandlerId()
+  {
+    return _handlerId;
+  }
+
+  public final String getBundleKey()
+  {
+    return _bundleKey;
+  }
+
+  public final String getBundleName()
+  {
+    return _bundleName;
+  }
+
+  public void actionListener(ActionEvent event)
+  {
+    String value = _actionListener;
+    if (value != null)
+    {
+      FacesContext facesContext = FacesContext.getCurrentInstance();
+      ExpressionFactory expressionFactory =
+          facesContext.getApplication().getExpressionFactory();
+      ELContext context = facesContext.getELContext();
+
+      MethodExpression methodExpression =
+          expressionFactory.createMethodExpression(context, value, Void.TYPE,
+              new Class<?>[]
+              { ActionEvent.class });
+      methodExpression.invoke(context, new Object[]
+      { event });
+    }
+
+  }
+
+  public String doAction()
+  {
+    String value = _action;
+
+    if (value != null)
+    {
+      FacesContext facesContext = FacesContext.getCurrentInstance();
+      ExpressionFactory expressionFactory =
+          facesContext.getApplication().getExpressionFactory();
+      ELContext context = facesContext.getELContext();
+      MethodExpression methodExpression =
+          expressionFactory.createMethodExpression(context, value,
+              String.class, new Class<?>[]
+              {});
+      value = (String) methodExpression.invoke(context, null);
+    }
+
+    // Post me as the selected Node for the request
+    postSelectedNode(this);
+
+    return value;
+  }
+
+  public final char getAccessKey()
+  {
+    if (_accessKey == null && _labelAndAccessKey != null)
+    {
+      int ampIdx = 0;
+      String labelAndAccessKeyEval = null;
+      String labelAndAccessKey = _labelAndAccessKey;
+      String label;
+      if (ContainerUtils.isValueReference(labelAndAccessKey))
+      {
+        labelAndAccessKeyEval = _evalElStr(labelAndAccessKey);
+      } 
+      else
+      {
+        labelAndAccessKeyEval = labelAndAccessKey;
+      }
+
+      String accessKey = null;
+      if (labelAndAccessKeyEval == null ||
+          (ampIdx = labelAndAccessKeyEval.indexOf('&')) == -1)
+      {
+        // String is null or a label w/o an accesskey
+        label = labelAndAccessKeyEval;
+      } else if (ampIdx == (labelAndAccessKeyEval.length() - 1))
+      {
+        // & is last character, strip it.
+        label = labelAndAccessKeyEval.substring(0, ampIdx);
+      } else
+      {
+        // We have a string with an accessKey somewhere
+        char[] keyArray = labelAndAccessKeyEval.toCharArray();
+        int len = labelAndAccessKeyEval.length();
+        char[] keyArray2 = new char[len];
+        int i, j = 0;
+        boolean accessKeyFound = false;
+
+        for (i = 0, j = 0; i < len; i++, j++)
+        {
+          if (keyArray[i] == '&')
+          {
+            i++;
+
+            if (!accessKeyFound && keyArray[i] != '&')
+            {
+              // We have our accessKey
+              accessKey = labelAndAccessKeyEval.substring(i, i + 1);
+              accessKeyFound = true;
+            }
+          }
+
+          keyArray2[j] = keyArray[i];
+        }
+
+        String label1 = new String(keyArray2, 0, j);
+        label = label1;
+      }
+      return (accessKey != null)? accessKey.charAt(0):'\0';
+
+    }
+    else 
+    {
+      String accessKeyStr = MenuUtils.evalString(_accessKey);
+      if (accessKeyStr == null || accessKeyStr.length() > 1)
+        return '\0';
+      return accessKeyStr.charAt(0);
+    }
+    
+  }
+
+  public final String getId()
+  {
+    return _id;
+  }
+
+  public final String getModelId()
+  {
+    return _modelId;
+  }
+
+  public final String getUniqueId()
+  {
+    return _uniqueId;
+  }
+  
+  public final String getLabelAndAccessKey()
+  {
+    String labelAndAcessKeyEval;
+    if (_labelAndAccessKey != null)
+    {
+      int ampIdx = 0;
+      String labelAndAccessKeyEval = null;
+      String labelAndAccessKey = _labelAndAccessKey;
+      String label;
+      if (_bundleKey != null && _bundleName != null)
+      {
+        // Load the resource bundle based on the locale of the
+        // current request. If the locale has not changed, this
+        // method just returns.
+        MenuUtils.loadBundle(_bundleName, _bundleKey + getHandlerId());
+      }
+      if (ContainerUtils.isValueReference(labelAndAccessKey))
+      {
+        labelAndAccessKeyEval = _evalElStr(labelAndAccessKey);
+      } else
+      {
+        labelAndAccessKeyEval = labelAndAccessKey;
+      }
+
+      String accessKey = null;
+      if (labelAndAccessKeyEval == null ||
+          (ampIdx = labelAndAccessKeyEval.indexOf('&')) == -1)
+      {
+        // String is null or a label w/o an accesskey
+        label = labelAndAccessKeyEval;
+      } else if (ampIdx == (labelAndAccessKeyEval.length() - 1))
+      {
+        // & is last character, strip it.
+        label = labelAndAccessKeyEval.substring(0, ampIdx);
+      } else
+      {
+        // We have a string with an accessKey somewhere
+        char[] keyArray = labelAndAccessKeyEval.toCharArray();
+        int len = labelAndAccessKeyEval.length();
+        char[] keyArray2 = new char[len];
+        int i, j = 0;
+        boolean accessKeyFound = false;
+
+        for (i = 0, j = 0; i < len; i++, j++)
+        {
+          if (keyArray[i] == '&')
+          {
+            i++;
+
+            if (!accessKeyFound && keyArray[i] != '&')
+            {
+              // We have our accessKey
+              accessKey = labelAndAccessKeyEval.substring(i, i + 1);
+              accessKeyFound = true;
+            }
+          }
+
+          keyArray2[j] = keyArray[i];
+        }
+
+        String label1 = new String(keyArray2, 0, j);
+        label = label1;
+      }
+      // https://issues.apache.org/jira/browse/TRINIDAD-1588
+      if (accessKey == null) {
+          return label;
+      }
+      return _joinLabelAndAccessKey(label, accessKey);
+    }
+    return null;
+  }
+
+  public final boolean getDefaultFocusPath()
+  {
+    boolean defaultFocusPath =
+        MenuUtils.evalBoolean(_defaultFocusPathStr, false);
+    return defaultFocusPath;
+  }
+
+  public final String getRootModelKey()
+  {
+    return _rootModelKey;
+  }
+
+  public final int getRootId()
+  {
+    return _rootId;
+  }
+
+  private String _evalElStr(String str)
+  {
+    if (str == null)
+      return null;
+
+    String keystr =
+        MenuUtils.stringReplaceFirst(str.trim(), _bundleKey, _bundleKey +
+            getHandlerId());
+    String elVal = MenuUtils.getBoundValue(keystr, String.class);
+    return elVal;
+  }
+
+  private String _joinLabelAndAccessKey(String label, String accessKey)
+  {
+    char[] keyArray = label.toCharArray();
+    int len = label.length();
+    int lentimes2 = len * 2;
+    char[] keyArray2 = new char[lentimes2];
+    int i, j = 0;
+    boolean accessKeyFound = false;
+
+    // find the first occurrence of a single Ampersand
+    for (i = 0, j = 0; i < len; i++, j++)
+    {
+      // AccessKey
+      if (keyArray[i] == accessKey.charAt(0) && !accessKeyFound)
+      {
+        keyArray2[j] = '&';
+        j++;
+        accessKeyFound = true;
+      }
+
+      keyArray2[j] = keyArray[i];
+
+      // Ampersand as regular character
+      // double it up.
+      if (keyArray[i] == '&')
+      {
+        j++;
+        keyArray2[j] = keyArray[i];
+      }
+    }
+
+    String combinedLabel = new String(keyArray2, 0, j);
+    return combinedLabel;
+  }
+
+  private final String _icon;
+  private List<MenuNode> _children = null;
+  private final String _focusViewId;
+  private final String _renderedStr;
+  private final String _disabledStr;
+  private final String _visibleStr;
+  private final String _readOnlyStr;
+  private final String _handlerId;
+  private final String _bundleKey;
+  private final String _bundleName;
+  private final String _accessKey;
+  private final String _id;
+  private final String _modelId;
+  private final String _labelAndAccessKey;
+  private final String _defaultFocusPathStr;
+  private final String _uniqueId;
+
+  // Root Menu model's Request Map Key
+  private final String _rootModelKey;
+
+  private final int _rootId;
+
+  private final Map<String, String> _customPropList;
+
+  private final String _destination;
+  private final String _targetFrame;
+  private final String _action;
+  private final String _actionListener;
+  private final String _launchListener;
+  private final String _returnListener;
+  private final String _immediateStr;
+  private final String _useWindowStr;
+  private final String _windowHeightStr;
+  private final String _windowWidthStr;
+
+  private final String _label;
+
+}

Added: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/menu/ItemNode.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/menu/ItemNode.java?rev=961803&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/menu/ItemNode.java (added)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/menu/ItemNode.java Thu Jul  8 15:23:24 2010
@@ -0,0 +1,543 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.myfaces.trinidad.menu;
+
+import java.util.Map;
+
+import javax.el.ELContext;
+import javax.el.ExpressionFactory;
+import javax.el.MethodExpression;
+import javax.faces.context.FacesContext;
+import javax.faces.event.ActionEvent;
+
+import org.apache.myfaces.trinidad.util.ContainerUtils;
+
+/**
+ * Code specific to a Menu Model's ItemNode.
+ *     
+ */
+
+public class ItemNode extends MenuNode
+{
+  /**
+    * Constructs an ItemNode
+    */
+  public ItemNode()
+  {
+    super();
+  }
+  
+  /**
+    * Sets the action of the node.  This is obtained from the menu
+    * metadata file and is the string value of the "action" 
+    * property.
+    * 
+    * @param action - the string value of the ItemNode's "action" property.
+    */
+
+  public void setAction(String action)
+  {
+    _action = action;
+  }  
+  
+  /**
+    * Gets the value of the node's action property.  The action attr value
+    * could be one of 2 things:
+    * 1) An EL expression
+    * 2) An outcome referencing a navigation rule in the faces_config file.
+    * 
+    * Since this method is called only when an ItemNode is clicked, the model 
+    * is notified that this node is the currently selected node.
+    * 
+    * @return String value of the ItemNode's "action" property.
+    */
+  @Override
+  public String doAction()
+  {
+    String value = _action;
+
+    if (value != null)
+    {
+      FacesContext facesContext = FacesContext.getCurrentInstance();
+      ExpressionFactory expressionFactory =
+          facesContext.getApplication().getExpressionFactory();
+      ELContext context = facesContext.getELContext();
+      MethodExpression methodExpression =
+          expressionFactory.createMethodExpression(context, value,
+              String.class, new Class<?>[]
+              {});
+      value = (String) methodExpression.invoke(context, null);
+    }
+
+    // Post me as the selected Node for the request
+    postSelectedNode(this);
+
+    return value;
+  }
+
+  /**
+    * setActionListener - sets the value of the Menu Node's actionListener
+    * atribute.
+    * 
+    * @param actionListener - El expression method reference to an 
+    * action listener
+    */
+  public void setActionListener(String actionListener)
+  {
+    _actionListener = actionListener;
+  }  
+  
+  /**
+    * getActionListener - gets the value of the Menu Node's actionListener
+    * attribute.
+    * 
+    * @return String  - method reference to an 
+    * action listener
+    */
+  public String getActionListener()
+  {
+    String value = _actionListener;
+
+    // Could be EL expression
+    if (   value != null
+        && ContainerUtils.isValueReference(value)
+       )
+    {
+      // Value of action is EL method binding, so we 
+      // need to evaluate it
+      value = MenuUtils.getBoundValue(value, String.class);
+      setActionListener(value);
+    }
+
+    return value;
+  }
+  
+  public void actionListener(ActionEvent event)
+  {
+    String value = _actionListener;
+    if (value != null)
+    {
+      FacesContext facesContext = FacesContext.getCurrentInstance();
+      ExpressionFactory expressionFactory =
+          facesContext.getApplication().getExpressionFactory();
+      ELContext context = facesContext.getELContext();
+
+      MethodExpression methodExpression =
+          expressionFactory.createMethodExpression(context, value, Void.TYPE,
+              new Class<?>[]
+              { ActionEvent.class });
+      methodExpression.invoke(context, new Object[]{ event });
+    }
+
+  }
+  
+  /**
+    * setLaunchListener - sets the value of the Menu Node's launchListener
+    * atribute.
+    * 
+    * @param launchListener - El expression method reference to a 
+    * launch listener
+    */
+  public void setLaunchListener(String launchListener)
+  {
+    _launchListener = launchListener;
+  }  
+  
+  /**
+    * getLaunchListener - gets the value of the Menu Node's launchListener
+    * attribute.
+    * 
+    * @return String  - method reference to an 
+    * launch listener
+    */
+  public String getLaunchListener()
+  {
+    String value = _launchListener;
+
+    // Could be EL expression
+    if (   value != null
+        && ContainerUtils.isValueReference(value)
+       )
+    {
+      // Value of action is EL method binding, so we 
+      // need to evaluate it
+      value = MenuUtils.getBoundValue(value, String.class);
+      setLaunchListener(value);
+    }
+
+    return value;
+  }
+  
+  /**
+    * setReturnListener - sets the value of the Menu Node's returnListener
+    * atribute.
+    * 
+    * @param returnListener - El expression method reference to a 
+    * return listener
+    */
+  public void setReturnListener(String returnListener)
+  {
+    _returnListener = returnListener;
+  }  
+  
+  /**
+    * getReturnListener - gets the value of the Menu Node's returnListener
+    * attribute.
+    * 
+    * @return String  - method reference to an 
+    * return listener
+    */
+  public String getReturnListener()
+  {
+    String value = _returnListener;
+
+    // Could be EL expression
+    if (   value != null
+        && ContainerUtils.isValueReference(value)
+       )
+    {
+      // Value of action is EL method binding, so we 
+      // need to evaluate it
+      value = MenuUtils.getBoundValue(value, String.class);
+      setReturnListener(value);
+    }
+
+    return value;
+  }
+  
+  /**
+    * Sets the immediate attribute of the menu item.  
+    *  
+    * @param immediate - boolean indicating whether or not data validation - 
+    * client-side or server-side - should take place when 
+    * events are generated by this component. 
+    */
+  public void setImmediate(boolean immediate)
+  {
+    _immediateStr = immediate ? "true" : "false";
+  }
+
+  /**
+    * Sets the immediate attribute of the menu item.  
+    * 
+    * @param immediateStr - string representing a boolean value
+    * or an EL expression
+    */
+  public void setImmediate(String immediateStr)
+  {
+    _immediateStr = immediateStr;
+  }
+      
+  /**
+    * Gets the immediate attribute of the menu item.  
+    *
+    * @return boolean - indicating whether or not data validation - 
+    * client-side or server-side - should take place when events 
+    * are generated by this component. 
+    */
+  public boolean getImmediate()
+  {
+    boolean immediate = MenuUtils.evalBoolean(_immediateStr, false);
+    return immediate;
+  }
+      
+  /**
+    * Sets the useWindow attribute of the menu item.  
+    *  
+    * @param useWindow - boolean indicating whether
+    * or not to use a new window when launching dialogs. 
+    */
+  public void setUseWindow(boolean useWindow)
+  {
+    _useWindowStr = useWindow ? "true" : "false";
+  }
+
+  /**
+    * Sets the useWindow attribute of the menu item.  
+    * 
+    * @param useWindowStr - string representing a boolean value or
+    * an EL Expression
+    */
+  public void setUseWindow(String useWindowStr)
+  {
+    _useWindowStr = useWindowStr;
+  }
+      
+  /**
+    * Gets the useWindow attribute of the menu item.  
+    *
+    * @return boolean - indicating whether
+    * or not to use a new window when launching dialogs. 
+    */
+  public boolean getUseWindow()
+  {
+    boolean useWindow = MenuUtils.evalBoolean(_useWindowStr, false);
+    return useWindow;
+  }
+      
+  /**
+    * Sets the windowHeight attribute of the menu item.  
+    *  
+    * @param windowHeight - int height of the window, if 
+    * this command is used to launch a window.
+    */
+  public void setWindowHeight(int windowHeight)
+  {
+    _windowHeightStr = Integer.toString(windowHeight);
+  }
+
+  /**
+    * Sets the windowHeight attribute of the menu item.  
+    *  
+    * @param windowHeightStr - String Height of the window, if 
+    * this command is used to launch a window. Could be an
+    * EL expression
+    */
+  public void setWindowHeight(String windowHeightStr)
+  {
+    _windowHeightStr = windowHeightStr;
+  }
+
+  /**
+    * Gets the windowHeight attribute of the menu item.  
+    *
+    * @return int height of the window, if 
+    * this command is used to launch a window. 
+    */
+  public int getWindowHeight()
+  {
+    int windowHeight = MenuUtils.evalInt(_windowHeightStr);
+    return windowHeight;
+  }
+      
+  /**
+    * Sets the windowWidth attribute of the menu item.  
+    *  
+    * @param windowWidth - int width of the window, if 
+    * this command is used to launch a window.
+    */
+  public void setWindowWidth(int windowWidth)
+  {
+    _windowWidthStr = Integer.toString(windowWidth);
+  }
+
+  /**
+    * Sets the windowWidth attribute of the menu item.  
+    *  
+    * @param windowWidthStr - String width of the window, if 
+    * this command is used to launch a window. Could be an
+    * EL expression
+    */
+  public void setWindowWidth(String windowWidthStr)
+  {
+    _windowWidthStr = windowWidthStr;
+  }
+
+  /**
+    * Gets the windowWidth attribute of the menu item.  
+    *
+    * @return int width of the window, if 
+    * this command is used to launch a window. 
+    */
+  public int getWindowWidth()
+  {
+    int windowWidth = MenuUtils.evalInt(_windowWidthStr);
+    return windowWidth;
+  }
+
+  /**
+    * Sets the destination of the node.  
+    * 
+    * This is obtained from the metadata file and is the string
+    * value of the "destination" property.
+    *
+    * @param destination - either a URI or an EL method binding expression.
+    */
+  public void setDestination(String destination)
+  {
+    _destination = destination;
+  }  
+  
+  /**
+    * Gets the value of the node's destination property.
+    * The destination attr value could be one of 2 things:
+    * 1) a uri
+    * 2) An EL expression
+    * 
+    * So that the model can identify this node as the currently selected
+    * node, the node's id is appended to the destination as a parameter
+    * that is picked up when the getFocusRowKey() method of the model 
+    * is called to get the focus path.
+    * 
+    * @return destination - the String value of the destinationNode's
+    *                       "destination" property.
+    */
+  @Override
+  public String getDestination()
+  {
+    String value = _destination;
+      
+    // Could be EL expression
+    if (   value != null
+        && ContainerUtils.isValueReference(value)
+       ) 
+    {
+      // Value of action is EL method binding, so we 
+      // need to evaluate it
+      value = MenuUtils.getBoundValue(value, String.class);
+    }
+
+    // Appending nodeId to URL so that we can identify the node
+    // when getFocusRowKey() is called on the model.
+    return value != null ? value + "?nodeId=" + getUniqueId() : value;
+  }
+  
+  /**
+   * setTargetFrame - sets the value of the Destination Node's
+   * targetFrame attribute
+   * 
+   * @param targetFrame - the target frame for the goCommandMenuItem.
+   */
+  public void setTargetFrame(String targetFrame) 
+  {
+    _targetFrame = targetFrame; 
+  }
+
+  /**
+   * getTargetFrame - gets the value of the Destination Node's
+   * targetFrame attribute
+   * 
+   * @return the target frame for the goCommandMenuItem.
+   */
+  public String getTargetFrame()
+  {
+    String value = _targetFrame;
+    
+    // Could be EL expression
+    if (   value != null
+        && ContainerUtils.isValueReference(value)
+       )
+    {
+      // Value of destination is EL value binding, so we 
+      // need to evaluate it
+      value = MenuUtils.getBoundValue(value, String.class);
+      setTargetFrame(value);
+    }
+     
+    return value;
+  }
+  
+  /**
+   * Get the Attributes containing the custom attributes on this node. This 
+   * needs to be public so that the menu model can get them.
+   * 
+   * @return Attributes list containing the custom attributes on this node
+   */
+  public Map<String, String> getCustomPropList()
+  {
+    return _customPropList;
+  }
+  
+  
+  public final Map<String, String> getCustomPropListProperty()
+  {
+    return _customPropList;
+  }
+
+  public final String getDestinationProperty()
+  {
+    return _destination;
+  }
+
+  public final String getTargetFrameProperty()
+  {
+    return _targetFrame;
+  }
+
+  public final String getActionProperty()
+  {
+    return _action;
+  }
+
+  public final String getActionListenerProperty()
+  {
+    return _actionListener;
+  }
+
+  public final String getLaunchListenerProperty()
+  {
+    return _launchListener;
+  }
+
+  public final String getReturnListenerProperty()
+  {
+    return _returnListener;
+  }
+
+  public final String getImmediateProperty()
+  {
+    return _immediateStr;
+  }
+
+  public final String getUseWindowProperty()
+  {
+    return _useWindowStr;
+  }
+
+  public final String getWindowHeightProperty()
+  {
+    return _windowHeightStr;
+  }
+
+  public final String getWindowWidthProperty()
+  {
+    return _windowWidthStr;
+  }
+  /**
+   * Set the list of custom attributes.
+   * 
+   * @param attrMap Map of attibute name/values for this node
+   * from MenuContentHandlerImpl
+   */
+  public void setCustomPropList(Map<String, String> attrMap)
+  {
+    _customPropList = attrMap;
+  }
+  
+  public MenuNode getThreadSafeCopy()
+  {
+    return new ImmutableItemNode(this);
+  }
+  
+  // Map for Custom attributes (properties)
+  private Map<String, String> _customPropList = null;
+  
+  private String _destination     = null;
+  private String _targetFrame     = null;   
+  private String _action          = null;
+  private String _actionListener  = null;
+  private String _launchListener  = null;
+  private String _returnListener  = null;
+  private String _immediateStr    = null;
+  private String _useWindowStr    = null;
+  private String _windowHeightStr = null;
+  private String _windowWidthStr  = null;
+  
+ 
+}

Added: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/menu/MenuNode.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/menu/MenuNode.java?rev=961803&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/menu/MenuNode.java (added)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/menu/MenuNode.java Thu Jul  8 15:23:24 2010
@@ -0,0 +1,901 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.myfaces.trinidad.menu;
+
+import java.util.List;
+
+import java.util.Map;
+
+import javax.faces.context.FacesContext;
+
+import org.apache.myfaces.trinidad.model.XMLMenuModel;
+import org.apache.myfaces.trinidad.util.ContainerUtils;
+
+/**
+ * Code generic to a Menu Nodes of the menu model.
+ *
+ * IMPORTANT NOTE: even internally, values that support EL expressions
+ * should use the "get" methods to obtain values.
+ *
+ */
+
+public class MenuNode
+{
+  /**
+    * Constructs a MenuNode
+    */
+  public MenuNode()
+  {
+  }
+
+  /**
+    * Set the menu item's label.
+    *
+    * @param label - String name shown in the menu item
+    */
+  public void setLabel(String label)
+  {
+    _label = label;
+  }
+
+  /**
+    * Get the menu item's label
+    *
+    * This could either be a string value set directly in
+    * the metadata or an EL expression string. In the case
+    * of an EL expression, we need to get its bound value.
+    *
+    * @return label as a String
+    */
+  public String getLabel()
+  {
+    if (_bundleKey != null && _bundleName != null)
+    {
+      // Load the resource bundle based on the locale of the
+      // current request.  If the locale has not changed, this
+      // method just returns.
+      MenuUtils.loadBundle(_bundleName, _bundleKey + getHandlerId());
+    }
+
+    if (   _label != null
+        && ContainerUtils.isValueReference(_label)
+       )
+    {
+      // do not set _label to the evaluated EL.
+      // It may change at times in the EL.
+      return _evalElStr(_label);
+    }
+    return _label;
+  }
+
+  /**
+    * Set the icon used by the menu item.
+    *
+    * @param icon - the String URI to the icon.
+    */
+  public void setIcon(String icon)
+  {
+    _icon = icon;
+  }
+
+  /**
+    * Get the icon used by the menu item
+    * This could either be a string value set directly in
+    * the metadata or an EL expression string. In the case
+    * of an EL expression, we need to get its bound value.
+    *
+    * @return icon - the String URI to the icon.
+    */
+  public String getIcon()
+  {
+    return MenuUtils.evalString(_icon);
+  }
+
+  /**
+    * Sets the rendered attribute of the menu item.
+    * If false, menu item will not appear.
+    *
+    * @param rendered - boolean that toggles the visible state of the XMLMenuModel
+    * item.
+    */
+  public void setRendered(boolean rendered)
+  {
+    _renderedStr = rendered ? "true" : "false";
+  }
+
+  /**
+    * Gets the rendered attribute of the menu item.
+    * If false, menu item will not appear.
+    *
+    * @return boolean indicating whether or not the menu item is visible.
+    */
+  public boolean getRendered()
+  {
+    boolean rendered = MenuUtils.evalBoolean(_renderedStr, true);
+    return rendered;
+  }
+
+  /**
+    * Sets the disabled attribute of the menu item.
+    * If true, menu item will not appear greyed-out and clicking
+    * on it will have no effect
+    *
+    * @param disabled - boolean that toggles the enabled/disabled state of the
+    * menu item.
+    */
+  public void setDisabled(boolean disabled)
+  {
+    _disabledStr = disabled ? "true" : "false";
+  }
+
+  /**
+    * Gets the disabled attribute of the menu item.
+    * If true, menu item will not appear greyed-out and clicking
+    * on it will have no effect
+    *
+    * @return boolean indicating whether or not the menu item is disabled.
+    */
+  public boolean getDisabled()
+  {
+    boolean disabled = MenuUtils.evalBoolean(_disabledStr, false);
+    return disabled;
+  }
+
+  /**
+    * Sets the visible attribute of the menu item.
+    * If false, menu item will not appear
+    *
+    * @param visible - boolean that toggles the visible state of the
+    * menu item.
+    */
+  public void setVisible(boolean visible)
+  {
+    _visibleStr = visible ? "true" : "false";
+  }
+
+  /**
+    * Gets the visible attribute of the menu item.
+    * If false, menu item will not appear
+    *
+    * @return boolean indicating whether or not the menu item is visible.
+    */
+  public boolean getVisible()
+  {
+    boolean visible = MenuUtils.evalBoolean(_visibleStr, true);
+    return visible;
+  }
+
+  /**
+    * Sets the defaultFocusPath attribute of the menu item.
+    *
+    * @param defaultFocusPath - boolean that tells the XMLMenuModel model that
+    * the focus path to this node should be used in cases where the focus path
+    * is not determinable by the XMLMenuModel model.
+    */
+  public void setDefaultFocusPath(boolean defaultFocusPath)
+  {
+    _defaultFocusPathStr = defaultFocusPath ? "true" : "false";
+  }
+
+  /**
+    * Gets the defaultFocusPath attribute of the menu item.
+    *
+    * @return boolean indicating whether or not this is the focus path to use,
+    * by default, in cases where there are duplicate paths to this node and
+    * the focus path is not determinable by the XMLMenuModel model.
+    */
+  public boolean getDefaultFocusPath()
+  {
+    boolean defaultFocusPath = MenuUtils.evalBoolean(_defaultFocusPathStr,
+                                                     false);
+    return defaultFocusPath;
+  }
+
+  /**
+    * Get the List of menu item's children.
+    *
+    * @return List of menu item's children
+    */
+  public List<MenuNode> getChildren()
+  {
+    return _children;
+  }
+
+  /**
+    * Set the List of menu item's children.
+    *
+    * @param children - List of MenuNode children for this MenuNode
+    */
+  public void setChildren(List<MenuNode> children)
+  {
+    _children = children;
+  }
+  
+
+  /**
+    * Gets the readOnly state of the node.
+    *
+    * @return the node's readOnly state as a boolean.
+    */
+  public boolean getReadOnly()
+  {
+    boolean readOnly = MenuUtils.evalBoolean(_readOnlyStr, false);
+    return readOnly;
+  }
+
+  /**
+    * Sets the the value of the readOnly attribute of the node.
+    *
+    * @param readOnly - boolean setting readOnly state of the node
+    */
+  public void setReadOnly(boolean readOnly)
+  {
+    _readOnlyStr = readOnly ? "true" : "false";
+  }
+
+  /**
+  * Sets the value of the node's focusViewId property.
+  *
+  * @param focusViewId - string value of the Node's "focusViewId" property.
+  */
+  public void setFocusViewId(String focusViewId)
+  {
+    _focusViewId = focusViewId;
+  }
+
+  /**
+  * Gets the value of the node's focusViewId property.
+  *
+  * @return string - the value of the Node's "focusViewId" property.
+  */
+  public String getFocusViewId()
+  {
+    return _focusViewId;
+  }
+
+  /**
+    * Sets the rendered attribute of the menu item.
+    * If false, menu item will not appear.
+    *
+    * Called only from MenuContentHandlerImpl during parsing of metadata.
+    *
+    * @param renderedStr - string representing a boolean value
+    */
+  public void setRendered(String renderedStr)
+  {
+    _renderedStr = renderedStr;
+  }
+
+  /**
+    * Sets the disabled attribute of the menu item.
+    * If false, menu item will appear in a disabled state.
+    *
+    * @param disabledStr - string representing a boolean value or
+    * an EL Expression
+    */
+  public void setDisabled(String disabledStr)
+  {
+    _disabledStr = disabledStr;
+  }
+
+  /**
+    * Sets the readOnly attribute of the menu item.
+    * If false, menu item will appear in a readOnly state.
+    *
+    * @param readOnlyStr - string representing a boolean value or EL
+    * expression.
+    */
+  public void setReadOnly(String readOnlyStr)
+  {
+    _readOnlyStr = readOnlyStr;
+  }
+
+  /**
+    * Sets the visible attribute of the menu item.
+    * If false, menu item will not appear.
+    *
+    * @param visibleStr - string representing a boolean value or
+    * an EL Expression
+    */
+  public void setVisible(String visibleStr)
+  {
+    _visibleStr = visibleStr;
+  }
+
+  /**
+    * Sets the defaultFocusPath attribute of the menu item.
+    *
+    * Called only from MenuContentHandlerImpl during parsing of metadata.
+    *
+    * @param defaultFocusPathStr - string representing a boolean value
+    */
+  public void setDefaultFocusPath(String defaultFocusPathStr)
+  {
+    _defaultFocusPathStr = defaultFocusPathStr;
+  }
+
+  /**
+   * setAccessKey - Takes either a single character String or
+   * an EL expression and sets the value of the accessKey attribute
+   * of the node.
+   *
+   * @param accessKey - Single character String or EL expression
+   * representing the label's access key.
+   */
+  public void setAccessKey (String accessKey)
+  {
+    if (   accessKey != null
+        && ContainerUtils.isValueReference(accessKey)
+       )
+    {
+       // EL Expression
+      _accessKey = accessKey;
+    }
+    else
+    {
+      // accessKey cannot be more than one character
+      if (accessKey != null && accessKey.length() > 1)
+        return;
+
+      _accessKey = accessKey;
+    }
+  }
+
+  /**
+   * setAccessKey - Takes a single character and sets the value of the
+   * accessKey attribute of the node.
+   *
+   * @param accessKey - Single character label access key.
+   */
+  public void setAccessKey (char accessKey)
+  {
+      char[] charArray = {'\0'};
+
+      charArray[0] = accessKey;
+      _accessKey = String.copyValueOf(charArray);
+  }
+
+  /**
+   * getAccessKey - get the label's accessKey as a char.
+   *
+   * @return the access key of the label as a char.
+   */
+  public char getAccessKey()
+  {
+    String accessKeyStr = MenuUtils.evalString(_accessKey);
+
+    if (accessKeyStr == null || accessKeyStr.length() > 1)
+      return '\0';
+
+    return accessKeyStr.charAt(0);
+  }
+
+  /**
+   * setLabelAndAccessKey - Takes either an EL expression or a
+   * String representing the label and accessKey together, and
+   * sets the label and the accessKey separately.
+   *
+   * @param labelAndAccessKey - either and EL Expression or
+   * a String representing the label and accessKey together.
+   */
+  public void setLabelAndAccessKey(String labelAndAccessKey)
+  {
+    int ampIdx = 0;
+    _labelAndAccessKeyEL = false;
+
+    // if EL expression, set it and the label to the same thing
+    if (   labelAndAccessKey != null
+        && ContainerUtils.isValueReference(labelAndAccessKey)
+       )
+    {
+      _labelAndAccessKey   = labelAndAccessKey;
+      _labelAndAccessKeyEL = true;
+      _accessKey = null;
+    }
+    else if (   labelAndAccessKey == null
+             || (ampIdx = labelAndAccessKey.indexOf('&')) == -1
+            )
+    {
+      // String is null or a label w/o an accesskey
+      _label = labelAndAccessKey;
+      _accessKey = null;
+    }
+    else if (ampIdx == (labelAndAccessKey.length() - 1))
+    {
+      // & is last character, strip it.
+      _label = labelAndAccessKey.substring(0, ampIdx);
+      _accessKey = null;
+    }
+    else
+    {
+       // We have a string with an accessKey somewhere
+       _splitLabelAndAccessKey(labelAndAccessKey);
+    }
+  }
+
+  /**
+   * getLabelAndAccessKey - get the label and accessKey together
+   * in a single string.
+   *
+   * @return a String containing (representing) the label and accessKey
+   * together.
+   */
+  public String getLabelAndAccessKey()
+  {
+    // If labelAndAccessKey is an EL expression
+    // we get it and process it, set the label
+    // and the accessKey, null out labelAndAccessKey
+    // and set labelAndAccessKeyEL to false
+    if (_labelAndAccessKeyEL)
+    {
+      _labelAndAccessKey = _evalElStr(_labelAndAccessKey);
+      setLabelAndAccessKey(_labelAndAccessKey);
+      _labelAndAccessKey = null;
+      _labelAndAccessKeyEL = false;
+    }
+    // Now it is a simple string, so we have already
+    // set the label and accessKey.  We get both the
+    // label and accessKey, construct a labelAndAccessKey
+    // and return it.
+    String label = getLabel(); // This is a simple string
+
+    if (_accessKey == null)
+      return label; // String is just the label
+
+    return _joinLabelAndAccessKey(label, _accessKey);
+  }
+
+  /**
+   * setId - sets the id of the node.
+   *
+   * @param id - the identifier for the node component
+   */
+  public void setId (String id)
+  {
+    _id = id;
+  }
+
+  /**
+   * getId - gets the metadata id of the node.
+   *
+   * @return - String identifier for the node component.
+   */
+  public String getId()
+  {
+    return _id;
+  }
+
+  /*===========================================================================
+   * getRefNode(), doAction(), & getDestination() are never called.  They
+   * are just here so that the same methods in itemNode.java and GroupNode.java
+   * will compile.
+   * ==========================================================================
+   */
+  /**
+   * Get the node whose id matches this node's
+   * idref attribute value.
+   *
+   * @return the MenuNode whose id matches this
+   *         node's idref attribute value.
+   */
+  public MenuNode getRefNode()
+  {
+    return this;
+  }
+
+  /**
+   * Called by the Default ActionListener
+   * when a menu node is clicked/selected.
+   *
+   * @return String outcome or viewId used
+   *         during a POST for navigation.
+   */
+  public String doAction()
+  {
+    // Call the doAction method of my idref node
+    return getRefNode().doAction();
+  }
+
+  /**
+   * Get the Destination URL of a page for a
+   * GET.
+   *
+   * @return String URL of a page.
+   */
+  public String getDestination()
+  {
+    // Call the doAction method of my idref node
+    return getRefNode().getDestination();
+  }
+
+  /**
+   * Get the top-level, root menu model Request Map Key.
+   *
+   * @return root, top-level XMLMenuModel's Request Map Key.
+   */
+  public String getRootModelKey()
+  {
+    return _rootModelKey;
+  }
+
+  /**
+   * Sets the root menu Model's Request map key.
+   * <p>
+   * This is always only the top-level, root model's Request map key.
+   * We do this because the MenuContentHandlerImpl and nodes need to be able
+   * to call into the root model to:
+   * <ul>
+   * <li>notify them root menu model of the currently selected node on a POST
+   * <li>group node needs to find its referenced item node.
+   * </ul>
+   *
+   * @param rootModelKey - String the root, top-level menu model's Request
+   *        map key.
+   */
+  public void setRootModelKey(String rootModelKey)
+  {
+    _rootModelKey = rootModelKey;
+  }
+
+  /**
+   * Gets the local (shared node's) menu Model's Request map key.
+   */
+  public String getModelId()
+  {
+    return _modelId;
+  }
+
+  /**
+   * Sets the local (shared node's) menu Model's Request map key.
+   * <p>
+   * This is appended to the node's id to create a unique id.
+   *
+   * @param rootModelKey - String the local (shared node's) menu
+   *        Model's Request map key.
+   */
+  public void setModelId(String modelId)
+  {
+    _modelId = modelId;
+  }
+
+  public int getRootId()
+  {
+    return _rootId;
+  }
+  public void setRootId(int id)
+  {
+    _rootId = id;
+  }
+
+  
+  public final String getLabelProperty()
+  {
+    return _label;
+  }
+
+  public final String getIconProperty()
+  {
+    return _icon;
+  }
+
+  public final List<MenuNode> getChildrenProperty()
+  {
+    return _children;
+  }
+
+  public final String getFocusViewIdProperty()
+  {
+    return _focusViewId;
+  }
+
+  public final String getRenderedProperty()
+  {
+    return _renderedStr;
+  }
+
+  public final String getDisabledProperty()
+  {
+    return _disabledStr;
+  }
+
+  public final String getVisibleProperty()
+  {
+    return _visibleStr;
+  }
+
+  public final String getReadOnlyProperty()
+  {
+    return _readOnlyStr;
+  }
+
+  public final String getHandlerIdProperty()
+  {
+    return _handlerId;
+  }
+
+  public final String getBundleKeyProperty()
+  {
+    return _bundleKey;
+  }
+
+  public final String getBundleNameProperty()
+  {
+    return _bundleName;
+  }
+
+  public final String getAccessKeyProperty()
+  {
+    return _accessKey;
+  }
+
+  public final String getIdProperty()
+  {
+    return _id;
+  }
+
+  public final String getModelIdProperty()
+  {
+    return _modelId;
+  }
+
+  public final String getUniqueIdProperty()
+  {
+    return getIdProperty() + getModelIdProperty();
+  }
+
+  
+  public final String getLabelAndAccessKeyProperty()
+  {
+    return _labelAndAccessKey;
+  }
+
+  public final String getDefaultFocusPathProperty()
+  {
+    return _defaultFocusPathStr;
+  }
+
+  public final String getRootModelKeyProperty()
+  {
+    return _rootModelKey;
+  }
+
+  public final int getRootIdProperty()
+  {
+    return _rootId;
+  }
+  
+  /**
+   * setResBundleKey - sets the name of the resource bundle used in
+   * obtaining the node's label text. Used, along with the handerId,
+   * to identify and get a string from the proper resource bundle.
+   *
+   * @param bundleKey - String name of the resource bundle.
+   */
+  public void setResBundleKey(String bundleKey)
+  {
+    _bundleKey = bundleKey;
+  }
+
+  /**
+   * setResBundleKey - sets the name of the resource bundle used in
+   * obtaining the node's label text. Used, along with the handerId,
+   * to identify and get a string from the proper resource bundle.
+   *
+   * @param bundleName - String name of the resource bundle.
+   */
+  public void setResBundleName(String bundleName)
+  {
+    _bundleName = bundleName;
+  }
+
+  /**
+   * setHandlerId - sets the MenuContentHandlerImpl's handlerId on the node.
+   * Used, along with the bundleKey, to identify and get a string from the
+   * proper resource bundle.
+   *
+   * @param handlerId String uniquely identifying the specific
+   *        MenuContentHandlerImpl that created this node.
+   */
+  public void setHandlerId(String handlerId)
+  {
+    _handlerId = handlerId;
+  }
+
+  /**
+   * Notifies the root model that this node has been selected on a POST
+   *
+   * @param selectedNode - The currently selected menu item.
+   */
+  protected void postSelectedNode(MenuNode selectedNode)
+  {
+    getRootModel().setCurrentlyPostedNode(selectedNode);
+  }
+
+  /**
+   * getUniqueId - gets the unique id of the node.
+   *
+   * @return - String identifier for the node component.
+   */
+  public String getUniqueId()
+  {
+    // This must be made unique so that we do not have duplicates
+    // in the idNodeMap on the menu's tree.
+    return _id + _modelId;
+  }
+
+  /**
+   * Set the MenuContentHandlerImpl's id.
+   *
+   * @return String object id of the MenuContentHandlerImpl
+   */
+  protected String getHandlerId()
+  {
+    return _handlerId;
+  }
+
+  /**
+   * Get the top-level, root menu model, which contains
+   * the entire menu tree.
+   *
+   * @return root, top-level XMLMenuModel
+   */
+  @SuppressWarnings("unchecked")
+  protected XMLMenuModel getRootModel()
+  {
+    FacesContext facesContext = FacesContext.getCurrentInstance();
+    Map<String, Object> requestMap =
+      facesContext.getExternalContext().getRequestMap();
+
+    Map map =  (Map) requestMap.get(getRootModelKey());
+    XMLMenuModel model = (XMLMenuModel) map.get(getRootId());
+    return model;
+  }
+
+  /**
+   * Construct a thread safe version
+   * of this object and return it.
+   * @return a thread safe copy of this object. 
+   */
+  public MenuNode getThreadSafeCopy()
+  {
+    return null;
+  }
+  /**
+   * _joinLabelAndAccessKey - takes a string label and string accessKey
+   * and combines them into a single labelAndAccessKey string.
+   *
+   * @param label - String with node's label.
+   * @param accessKey - One character String which is the label's accessKey.
+   * @return
+   */
+  private String _joinLabelAndAccessKey(String label, String accessKey)
+  {
+    char[] keyArray  = label.toCharArray();
+    int len          = label.length();
+    int lentimes2    = len*2;
+    char[] keyArray2 = new char[lentimes2];
+    int i, j = 0;
+    boolean accessKeyFound = false;
+
+    // find the first occurrence of a single Ampersand
+    for (i=0, j=0; i < len; i++, j++)
+    {
+      // AccessKey
+      if (   keyArray[i] == accessKey.charAt(0)
+          && !accessKeyFound
+         )
+      {
+        keyArray2[j] = '&';
+        j++;
+        accessKeyFound = true;
+      }
+
+      keyArray2[j] = keyArray[i];
+
+      // Ampersand as regular character
+      // double it up.
+      if (keyArray[i] == '&')
+      {
+        j++;
+        keyArray2[j] = keyArray[i];
+      }
+    }
+
+    String combinedLabel = new String(keyArray2, 0, j);
+    return combinedLabel;
+  }
+
+  /**
+   * _splitLabelAndAccessKey - takes a string containing a label
+   * and an accessKey and breaks separates it and sets the label
+   * and the accessKey separately.
+   *
+   * @param labelAndAccessKey - String holding both a label and
+   * accessKey.
+   */
+  private void _splitLabelAndAccessKey(String labelAndAccessKey)
+  {
+    char[] keyArray  = labelAndAccessKey.toCharArray();
+    int len = labelAndAccessKey.length();
+    char[] keyArray2 = new char[len];
+    int i, j = 0;
+    boolean accessKeyFound = false;
+
+    for (i=0, j=0; i < len ; i++, j++)
+    {
+      if (keyArray[i] == '&')
+      {
+         i++;
+
+         if (!accessKeyFound && keyArray[i] != '&')
+         {
+           // We have our accessKey
+           _accessKey = labelAndAccessKey.substring(i, i+1);
+           accessKeyFound = true;
+         }
+      }
+
+      keyArray2[j] = keyArray[i];
+    }
+
+    String label = new String(keyArray2, 0, j);
+    _label = label;
+  }
+
+  /**
+   * _evalElStr - Evaluate an EL expression string.
+   *
+   * @param str - the EL expression
+   * @return the bound value of the El expression as a String
+   */
+  private String _evalElStr(String str)
+  {
+    if (str == null)
+      return null;
+
+    String keystr = MenuUtils.stringReplaceFirst(str.trim(), _bundleKey,
+                                                 _bundleKey + getHandlerId());
+    String elVal = MenuUtils.getBoundValue(keystr, String.class);
+    return elVal;
+  }
+
+  private String         _label       = null;
+  private String         _icon        = null;
+  private List<MenuNode> _children    = null;
+  private String         _focusViewId = null;
+  private String         _renderedStr = null;
+  private String         _disabledStr = null;
+  private String         _visibleStr  = null;
+  private String         _readOnlyStr = null;
+  private String         _handlerId   = null;
+  private String         _bundleKey   = null;
+  private String         _bundleName  = null;
+  private String         _accessKey   = null;
+  private String         _id          = null;
+  private String         _modelId     = null;
+  private boolean        _labelAndAccessKeyEL = false;
+  private String         _labelAndAccessKey   = null;
+  private String         _defaultFocusPathStr = null;
+
+  // Root Menu model's Request Map Key
+  private String _rootModelKey  = null;
+  
+  private int _rootId;
+
+}