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 2008/08/19 07:56:49 UTC

svn commit: r686962 - in /myfaces/trinidad/trunk_1.2.x: trinidad-api/src/main/java/org/apache/myfaces/trinidad/model/ trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/

Author: matzew
Date: Mon Aug 18 22:56:49 2008
New Revision: 686962

URL: http://svn.apache.org/viewvc?rev=686962&view=rev
Log:
TRINIDAD-1183 - Allows any node in the whole menu tree to be obtained through its "id", unique or not.

Thanks to Gary kind for his patch.

Modified:
    myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/model/XMLMenuModel.java
    myfaces/trinidad/trunk_1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/GroupNode.java
    myfaces/trinidad/trunk_1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/MenuContentHandlerImpl.java
    myfaces/trinidad/trunk_1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/MenuNode.java

Modified: myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/model/XMLMenuModel.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/model/XMLMenuModel.java?rev=686962&r1=686961&r2=686962&view=diff
==============================================================================
--- myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/model/XMLMenuModel.java (original)
+++ myfaces/trinidad/trunk_1.2.x/trinidad-api/src/main/java/org/apache/myfaces/trinidad/model/XMLMenuModel.java Mon Aug 18 22:56:49 2008
@@ -6,9 +6,9 @@
  *  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
@@ -50,7 +50,7 @@
  * but not a mix of beans and maps.
  * o The viewId of a node can be null, but if set it must be unique.
  * o The tree cannot be mutable.
- * </ul> 
+ * </ul>
  * <p>
  * The getFocusRowKey method
  * <ul>
@@ -58,10 +58,10 @@
  * FacesContext.getCurrentInstance().getViewRoot().getViewId()
  * o compares the current viewId with the viewId's in the viewIdFocusPathMap
  * that was built by traversing the tree when the model was created.
- * o returns the focus path to the node with the current viewId or null if the 
+ * o returns the focus path to the node with the current viewId or null if the
  * current viewId can't be found.
- * o in the case where a viewId has multiple focus paths, the currently 
- * selected node is used as a key into the nodeFocusPathMap to return the 
+ * o in the case where a viewId has multiple focus paths, the currently
+ * selected node is used as a key into the nodeFocusPathMap to return the
  * correct focus path.
  * </ul>
  * <p>
@@ -82,51 +82,51 @@
  *  &lt;/managed-bean&gt;
  * </pre>
  *
- * 
+ *
  */
 
 /*
  * Three hashmaps are also created in order to be able to resolve cases where
  * multiple menu items cause navigation to the same viewId.  All 3 of these maps
- * are created after the metadata is parsed and the tree is built, in the 
- * MenuContentHandlerImpl. 
- * 
- * o The first hashMap is called the viewIdFocusPathMap and is built by 
- * traversing the tree when the model is created.  Each node's focusViewId is 
- * obtained and used as the key to an entry in the viewIdHashMap.  An ArrayList 
- * is used as the entry's value and each item in the ArrayList is a node's 
- * rowkey from the tree. This allows us to have duplicate rowkeys for a single 
- * focusViewId which translates to a menu that contains multiple items pointing 
- * to the same page. In general, each entry will have an ArrayList of rowkeys 
+ * are created after the metadata is parsed and the tree is built, in the
+ * MenuContentHandlerImpl.
+ *
+ * o The first hashMap is called the viewIdFocusPathMap and is built by
+ * traversing the tree when the model is created.  Each node's focusViewId is
+ * obtained and used as the key to an entry in the viewIdHashMap.  An ArrayList
+ * is used as the entry's value and each item in the ArrayList is a node's
+ * rowkey from the tree. This allows us to have duplicate rowkeys for a single
+ * focusViewId which translates to a menu that contains multiple items pointing
+ * to the same page. In general, each entry will have an ArrayList of rowkeys
  * with only 1 rowkey, AKA focus path.
- * o The second hashMap is called the nodeFocusPathMap and is built at the 
- * same time the viewIdHashMap is built. Each entry's key is the actual node and 
+ * o The second hashMap is called the nodeFocusPathMap and is built at the
+ * same time the viewIdHashMap is built. Each entry's key is the actual node and
  * the value is the row key.  Since the model keeps track of the currently
- * selected menu node, this hashmap can be used to resolve viewId's with 
+ * selected menu node, this hashmap can be used to resolve viewId's with
  * multiple focus paths.  Since we have the currently selected node, we just
  * use this hashMap to get its focus path.
  * o The third hashMap is called idNodeMap and is built at the same time as the
  * previous maps.  This map is populated by having each entry contain the node's
- * id as the key and the actual node as the value.  In order to keep track of 
- * the currently selected node in the case of a GET, the node's id is appended 
- * to the request URL as a parameter.  The currently selected node's id is 
- * picked up and this map is used to get the actual node that is currently 
+ * id as the key and the actual node as the value.  In order to keep track of
+ * the currently selected node in the case of a GET, the node's id is appended
+ * to the request URL as a parameter.  The currently selected node's id is
+ * picked up and this map is used to get the actual node that is currently
  * selected.
  *
- * Keeping track of the currently selected menu item/node.  
- * 
+ * Keeping track of the currently selected menu item/node.
+ *
  * If an itemNode in the metadata uses its "action" attribute, a POST is done
  * and the node's "doAction" method is called when the menu item is clicked. At
- * that time, the model is notified through its setCurrentlyPostedNode() method, 
+ * that time, the model is notified through its setCurrentlyPostedNode() method,
  * where the current node is set and the request method is set to POST.
- * 
+ *
  * If an itemNode in the metadata uses its "destination" attribute, a GET is
  * done.  Nothing is called on the model when the menu item is clicked.  However
  * at the time the page is rendered the "getDestination" method for all nodes
  * using the "destination" attribute is called.  At this point
  * we append the node's id to the value of the destination attribute URL, as
- * a parameter, and return it. So when getFocusRowKey() is called, we get the 
- * request the node's parameter matching the currently selected node's id.  
+ * a parameter, and return it. So when getFocusRowKey() is called, we get the
+ * request the node's parameter matching the currently selected node's id.
  * Using the node id, we find the matching node in the idNodeMap and voila, we
  * have the currently selected node!
  */
@@ -136,12 +136,13 @@
   public XMLMenuModel()
   {
     super();
+    _modelId = Integer.valueOf(System.identityHashCode(this)).toString();
   }
-  
+
   /**
    * setSource - specifies the XML metadata and creates
    * the XML Menu Model.
-   * 
+   *
    * @param menuMetadataUri - String URI to the XML metadata.
    */
   public void setSource(String menuMetadataUri)
@@ -156,14 +157,14 @@
   /**
    * Makes the TreeModel part of the menu model.  Also creates the
    * _viewIdFocusPathMap, _nodeFocusPathMap, and idNodeMaps.
-   * 
+   *
    * @param data The Tree Model instance
    */
-  @Override  
+  @Override
   public void setWrappedData(Object data)
   {
     super.setWrappedData(data);
-    
+
     // The only thing the child menu models are needed for are their
     // menuLists, which get incorporated into the Root Model's tree.
     // There is no need to create the hashmaps or anything
@@ -176,10 +177,10 @@
       _idNodeMap          = _contentHandler.getIdNodeMap(_mdSource);
     }
   }
-  
+
   /**
-   * Returns the rowKey to the current viewId, or in the case of where the 
-   * model has nodes with duplicate viewId's and one is encountered, we 
+   * Returns the rowKey to the current viewId, or in the case of where the
+   * model has nodes with duplicate viewId's and one is encountered, we
    * return the rowKey of the currently selected node.
    * <p>
    *
@@ -189,24 +190,24 @@
    * FacesContext.getCurrentInstance().getViewRoot().getViewId()
    * <li>compares the current viewId with the viewId's in the viewIdFocusPathMap
    * that was built by traversing the tree when the model was created.
-   * <li>returns the focus path to the node with the current viewId or null if 
+   * <li>returns the focus path to the node with the current viewId or null if
    * the current viewId can't be found.
-   * <li>in the case where a viewId has multiple focus paths, the currently 
-   * selected node is used as a key into the nodeFocusPathMap to return the 
+   * <li>in the case where a viewId has multiple focus paths, the currently
+   * selected node is used as a key into the nodeFocusPathMap to return the
    * correct focus path.
    * </ul>
-   * 
-   * @return  the rowKey to the node with the current viewId or null if the 
-   * current viewId can't be found. 
+   *
+   * @return  the rowKey to the node with the current viewId or null if the
+   * current viewId can't be found.
    */
   @SuppressWarnings("unchecked")
-  @Override  
+  @Override
   public Object getFocusRowKey()
   {
     Object focusPath        = null;
     String currentViewId    = _getCurrentViewId();
     FacesContext context    = FacesContext.getCurrentInstance();
-    
+
     // getFocusRowKey() is called multiple times during the Process Validations
     // Phase and again during the Render Response Phase during each Request.
     // During each phase, as described below, the same viewId is passed in. To
@@ -215,27 +216,27 @@
     // below.
     //
     // ** Process Validations Phase:
-    // During the Process Validations Phase, the prevViewId is initially 
+    // During the Process Validations Phase, the prevViewId is initially
     // null (gets set to this at the start of each Request). The first time
     // getFocusRowKey is called, the currentViewId is that of the node we are
     // navigating "from" during the Request.  This is stored in prevViewId.
     // Because the currentViewId is not equal to the prevViewId,
     // the node is looked up, its focus path stored in prevFocusPath, and the
-    // focus path is returned. On subsequent calls during the Process 
+    // focus path is returned. On subsequent calls during the Process
     // Validations Phase, the currentViewId is always that of the "from" node,
-    // the currentViewId is equal to the prevViewId, and so we simply 
+    // the currentViewId is equal to the prevViewId, and so we simply
     // return prevFocusPath.
     //
     // ** Render Response Phase:
-    // During the Render Response Phase, the prevViewId is initially 
-    // that of the "from" node. The first time getFocusRowKey is called 
-    // the currentViewId is that of the node we are navigating "to" during 
+    // During the Render Response Phase, the prevViewId is initially
+    // that of the "from" node. The first time getFocusRowKey is called
+    // the currentViewId is that of the node we are navigating "to" during
     // the Request.  This is stored in prevViewId.
     // Because the currentViewId is not equal to the prevViewId,
     // the node is looked up, its focus path stored in prevFocusPath, and the
-    // focus path is returned. On subsequent calls during the Render 
+    // focus path is returned. On subsequent calls during the Render
     // Response Phase, the currentViewId is always that of the "to" node,
-    // the currentViewId is equal to the prevViewId, and so we simply 
+    // the currentViewId is equal to the prevViewId, and so we simply
     // return prevFocusPath.
     //
     // IMPORTANT: Code that returns the correct focus path for duplicate nodes
@@ -243,10 +244,10 @@
     //
     if ((_prevViewId != null) && _prevViewId.equals(currentViewId))
       return _prevFocusPath;
-    
+
     // Initializations
     _prevViewId    = currentViewId;
-    
+
     // How did we get to this page?
     // 1) Clicked on a menu item with its action attribute set.  This does
     //    a POST.
@@ -255,28 +256,28 @@
     // 3) Navigation to a viewId within our model but done from outside the
     //    model.  Examples, button, text link, etc.
     //
-    
+
     // Case 1: POST method.  Current Node has already been set and so has the
     // request method.  The doAction() method of the clicked node calls
     // the setCurrentlyPostedNode() method of this model, which sets both. So
     // we have nothing to do in this case.
-    
+
     if (_getRequestMethod() != _METHOD_POST)
     {
-      // Case 2: GET method.  We have hung the selected node's id off the 
-      // request's URL, which enables us to get the selected node and also 
+      // Case 2: GET method.  We have hung the selected node's id off the
+      // request's URL, which enables us to get the selected node and also
       // to know that the request method is GET.
-      Map<String, String> paramMap = 
+      Map<String, String> paramMap =
         context.getExternalContext().getRequestParameterMap();
-      String nodeId = paramMap.get(_NODE_ID_PROPERTY);
-      
-      if (nodeId != null)
+      String UrlNodeId = paramMap.get(_NODE_ID_PROPERTY);
+
+      if (UrlNodeId != null)
       {
-        _setCurrentlySelectedNode(getNode(nodeId));
+        _setCurrentlySelectedNode(_getNodeFromURLParams(UrlNodeId));
         _setRequestMethod(_METHOD_GET);
       }
     }
-    
+
     // Case 3: Navigation to a page within the model from an outside
     // method, e.g. button, link text, etc.  In this case we set the
     // currently selected node to null.  This tells us to get the 0th
@@ -287,13 +288,13 @@
     {
       _setCurrentlySelectedNode(null);
     }
-    
+
     // Get the matching focus path ArrayList for the currentViewId.
     // This is an ArrayList because our map allows nodes with the same
     // viewId, that is, different focus paths to the same viewId.
-    ArrayList<Object> fpArrayList = 
+    ArrayList<Object> fpArrayList =
      (ArrayList<Object>) _viewIdFocusPathMap.get(currentViewId);
-    
+
     if (fpArrayList != null)
     {
       if (_prevRequestNode != null)
@@ -304,7 +305,7 @@
         // use the node.  If we don't do this, the wrong focus path
         // could be returned from the _viewIdFocusPathMap.
         focusPath = _nodeFocusPathMap.get(_prevRequestNode);
-        
+
         // Reset it to null
         _prevRequestNode = null;
       }
@@ -312,16 +313,16 @@
       {
         // Get the currently selected node
         Object currentNode = _getCurrentlySelectedNode();
-        
+
         if (fpArrayList.size() == 1 || currentNode == null)
         {
           // For fpArrayLists with multiple focusPaths,
-          // the 0th entry in the fpArrayList carries the 
+          // the 0th entry in the fpArrayList carries the
           // focusPath of the node with its defaultFocusPath
           // attribute set to "true", if there is one.  If
           // not, the 0th element is the default.
           focusPath = fpArrayList.get(0);
-          
+
           // Not a duplicate node so set this to null
           _prevRequestNode = null;
         }
@@ -330,7 +331,7 @@
           // This will be a duplicate node, meaning it navigates to the
           // the same page as at least one other node in the tree.
           focusPath = _nodeFocusPathMap.get(currentNode);
-          
+
           // Save this node for the next request.  Otherwise, the
           // next Request will go into previous part of this conditional
           // and return (possibly) the wrong focus path during the
@@ -342,8 +343,8 @@
 
     // Save all pertinent information
     _prevFocusPath = focusPath;
-    
-    // Reset this to _METHOD_NONE so we will know when 
+
+    // Reset this to _METHOD_NONE so we will know when
     // Navigation to a viewId within our model has been
     // done from outside the model, e.g. link, button.
     // If this is not done, the current request method
@@ -359,7 +360,7 @@
 
   /**
    * Gets the URI to the XML menu metadata.
-   * 
+   *
    * @return String URI to the XML menu metadata.
    */
   public String getSource()
@@ -371,8 +372,8 @@
    * Sets the boolean value that determines whether or not to create
    * nodes whose rendered attribute value is false.  The default
    * value is false.
-   * 
-   * This is set through a managed property of the XMLMenuModel 
+   *
+   * This is set through a managed property of the XMLMenuModel
    * managed bean -- typically in the faces-config.xml file for
    * a faces application.
    */
@@ -380,15 +381,15 @@
   {
     _createHiddenNodes = createHiddenNodes;
   }
-  
+
   /**
    * Gets the boolean value that determines whether or not to create
    * nodes whose rendered attribute value is false.  The default
    * value is false.
-   * 
+   *
    * This is called by the contentHandler when parsing the XML metadata
    * for each node.
-   * 
+   *
    * @return the boolean value that determines whether or not to create
    * nodes whose rendered attribute value is false.
    */
@@ -396,24 +397,24 @@
   {
     return _createHiddenNodes;
   }
-  
+
 
   /**
-   * Maps the focusPath returned when the viewId is newViewId 
+   * Maps the focusPath returned when the viewId is newViewId
    * to the focusPath returned when the viewId is aliasedViewId.
    * This allows view id's not in the treeModel to be mapped
    * to a focusPath.
-   * 
+   *
    * @param newViewId the view id to add a focus path for.
-   * @param aliasedViewId the view id to use to get the focusPath to use 
+   * @param aliasedViewId the view id to use to get the focusPath to use
    *        for newViewId.
    */
   @SuppressWarnings("unchecked")
   public void addViewId(String newViewId, String aliasedViewId)
-  { 
-    List<Object> focusPath = 
+  {
+    List<Object> focusPath =
       _viewIdFocusPathMap.get(aliasedViewId);
-      
+
     if (focusPath != null)
     {
       _viewIdFocusPathMap.put(newViewId, focusPath);
@@ -421,19 +422,19 @@
   }
 
   /**
-   * Sets the currently selected node and the request method.  
+   * Sets the currently selected node and the request method.
    * This is called by a selected node's doAction method.  This
    * menu node must have had its "action" attribute set, thus the
    * method is POST.
-   * 
+   *
    * @param currentNode  The currently selected node in the menu
    */
-  public void setCurrentlyPostedNode(Object currentNode)  
+  public void setCurrentlyPostedNode(Object currentNode)
   {
     _setCurrentlySelectedNode(currentNode);
     _setRequestMethod(_METHOD_POST);
 
-    
+
     // Do this in the case where a menu item is selected
     // that has the same viewId as the previous menu item
     // that is selected.  If not, the test at the beginning
@@ -444,27 +445,33 @@
   }
 
   /**
-   * Get a the MenuNode corresponding to the key "id" from the 
+   * Get a the MenuNode corresponding to the key "id" from the
    * node id hashmap.
-   * 
+   *
    * @param id - String node id key for the hashmap entry.
-   * @return The MenuNode that corresponds to id.
+   * @return The Node Object that corresponds to id.
    */
   public Object getNode (String id)
   {
+    XMLMenuModel rootModel = _getRootModel();
+    Map<String, Object> idNodeMap = rootModel._getIdNodeMap();
+
+    if (idNodeMap == null)
+      return null;
+
     // This needs to be public because the nodes call into this map
-    return _idNodeMap.get(id);
+    return idNodeMap.get(id + _getModelId());
   }
 
   /**
-   * Gets the list of custom properties from the node 
+   * Gets the list of custom properties from the node
    * and returns the value of propName.  Node must be an itemNode.
    * If it is not an itemNode, the node will not have any custom
    * properties and null will be returned.
-   * 
+   *
    * @param node Object used to get its list of custom properties
    * @param propName String name of the property whose value is desired
-   * 
+   *
    * @return Object value of propName for Object node.
    */
   @SuppressWarnings("unchecked")
@@ -472,18 +479,18 @@
   {
     if (node == null)
       return null;
-      
+
     FacesContext context = FacesContext.getCurrentInstance();
     ELContext elContext  = context.getELContext();
     ELResolver resolver  = elContext.getELResolver();
     String value         = null;
-    
+
     try
     {
-      Map<String, String> propMap = 
+      Map<String, String> propMap =
         (Map<String, String>) resolver.getValue(elContext,
                                                 node, _CUSTOM_ATTR_LIST);
-        
+
       // Need to check to see if propMap is null.  If there are
       // no custom properties for this itemNode, there will be
       // no propMap.  See MenuContentHandler._createItemNode().
@@ -496,10 +503,10 @@
     {
       // if the node is not an itemNode, the node
       // has no custom properties, so we simply
-      // return null 
+      // return null
       return null;
     }
-    
+
     // If it is an EL expression, we must evaluate it
     // and return its value
     if (   value != null
@@ -507,7 +514,7 @@
        )
      {
        Object elValue = null;
-       
+
        try
        {
          elValue = context.getApplication().evaluateExpressionGet(context,
@@ -522,13 +529,13 @@
        }
        return elValue;
      }
-     
+
     return value;
   }
 
   /**
    * getStream - Opens an InputStream to the provided URI.
-   * 
+   *
    * @param uri - String uri to a data source.
    * @return InputStream to the data source.
    */
@@ -539,7 +546,7 @@
     // And it is called by the MenuContentHandlerImpl.
     try
     {
-      // Open the metadata  
+      // Open the metadata
       FacesContext context = FacesContext.getCurrentInstance();
       URL url = context.getExternalContext().getResource(uri);
       return url.openStream();
@@ -549,7 +556,7 @@
       _LOG.severe("OPEN_URI_EXCEPTION", uri);
       _LOG.severe(ex);
       return null;
-    }    
+    }
   }
 
   /**
@@ -571,15 +578,33 @@
   /* ====================================================================
    * Private Methods
    * ==================================================================== */
-   
+
+  private  Map<String, Object> _getIdNodeMap()
+  {
+    return (this == _getRootModel()) ? _idNodeMap : null;
+  }
+
+  /**
+   * Get a the MenuNode corresponding to the key "id" from the
+   * node id hashmap.
+   *
+   * @param id - String node id key for the hashmap entry.
+   * @return The MenuNode that corresponds to id.
+   */
+  private Object _getNodeFromURLParams (String urlNodeId)
+  {
+    // This needs to be public because the nodes call into this map
+    return _idNodeMap.get(urlNodeId);
+  }
+
   /**
     * Creates a menu model based on the menu metadata Uri.
     * This is accomplished by:
     * <ol>
     * <li> Get the MenuContentHandlerImpl through the Services API.
-    * <li> Set the root model and current model on the content handler, which, 
+    * <li> Set the root model and current model on the content handler, which,
     * in turn, sets the models on each of the nodes.
-    * <li> Parse the metadata.  This calls into the MenuContentHandler's 
+    * <li> Parse the metadata.  This calls into the MenuContentHandler's
     * startElement and endElement methods, where a List of nodes and a TreeModel
     * are created, along with the 3 hashMaps needed by the Model.</li>
     * <li> Use the TreeModel to create the XMLMenuModel.</li>
@@ -590,23 +615,23 @@
     try
     {
       if (_contentHandler == null)
-      {        
-        List<MenuContentHandler> services = 
+      {
+        List<MenuContentHandler> services =
           ClassLoaderUtils.getServices(_MENUCONTENTHANDLER_SERVICE);
-         
+
         if (services.isEmpty())
         {
           throw new IllegalStateException(_LOG.getMessage(
             "NO_MENUCONTENTHANDLER_REGISTERED"));
         }
-        
+
         _contentHandler = services.get(0);
         if (_contentHandler == null)
         {
           throw new NullPointerException();
         }
       }
-      
+
       // Set the root, top-level menu model's URI on the contentHandler.
       // In this model, the menu content handler and nodes need to have
       // access to the model's data structures and to notify the model
@@ -616,8 +641,8 @@
       // Set the local model (model created by a sharedNode) on the
       // contentHandler so that nodes can get back to their local model
       // if necessary.
-      _setModelUri(_contentHandler);
-      
+      _setModelId(_contentHandler);
+
       TreeModel treeModel = _contentHandler.getTreeModel(_mdSource);
       setWrappedData(treeModel);
     }
@@ -630,81 +655,92 @@
   }
 
   /**
-   * _setRootModelKey - sets the top-level, menu model's Key on the 
+   * _setRootModelKey - sets the top-level, menu model's Key on the
    * menu content handler. This is so nodes will only operate
-   * on the top-level, root model. 
-   * 
+   * on the top-level, root model.
+   *
    */
   @SuppressWarnings("unchecked")
   private void _setRootModelKey(MenuContentHandler contentHandler)
   {
     if (_getRootModel() == null)
-    {      
+    {
       // Put the root model on the Request Map so that it
-      // Can be picked up by the nodes to call back into the 
+      // Can be picked up by the nodes to call back into the
       // root model
       FacesContext facesContext = FacesContext.getCurrentInstance();
-      Map<String, Object> requestMap = 
+      Map<String, Object> requestMap =
         facesContext.getExternalContext().getRequestMap();
-      
+
       requestMap.put(_ROOT_MODEL_KEY, this);
-      
+
       // Set the key to the root model on the content
       // handler so that it can then be set on each of the nodes
       contentHandler.setRootModelKey(_ROOT_MODEL_KEY);
     }
   }
-  
+
   /**
    * Returns the root menu model.
-   * 
+   *
    * @return XMLMenuModel the root menu model.
    */
   @SuppressWarnings("unchecked")
   private XMLMenuModel _getRootModel()
   {
     FacesContext facesContext = FacesContext.getCurrentInstance();
-    Map<String, Object> requestMap = 
+    Map<String, Object> requestMap =
       facesContext.getExternalContext().getRequestMap();
     return (XMLMenuModel) requestMap.get(_ROOT_MODEL_KEY);
   }
-  
+
+
   /**
-   * _setModelUri - sets the local, menu model's Uri on the 
-   * menu content handler.  
+   * _getModelId - gets the local, menu model's Sys Id.
+   *
+   * @return String the model's System Id.
+   */
+  private String _getModelId()
+  {
+    return _modelId;
+  }
+
+  /**
+   * _setModelId - sets the local, menu model's id on the
+   * menu content handler.
    */
   @SuppressWarnings("unchecked")
-  private void _setModelUri(MenuContentHandler contentHandler)
+  private void _setModelId(MenuContentHandler contentHandler)
   {
-    String localUri = _mdSource;
-    
+    String modelId = _getModelId();
+
     // Put the local model on the Request Map so that it
-    // Can be picked up by the nodes to call back into the 
+    // Can be picked up by the nodes to call back into the
     // local model
     FacesContext facesContext = FacesContext.getCurrentInstance();
-    Map<String, Object> requestMap = 
+    Map<String, Object> requestMap =
       facesContext.getExternalContext().getRequestMap();
-    
-    requestMap.put(localUri, this);
-    
-    // Set the key (_localUri) to the local model on the content
+
+    requestMap.put(modelId, this);
+
+    // Set the key (modelId) to the local model on the content
     // handler so that it can then be set on each of the nodes
-    contentHandler.setModelUri(localUri);
+    contentHandler.setModelId(modelId);
   }
-  
+
   /**
    * Returns the current viewId.
-   * 
-   * @return  the current viewId or null if the current viewId can't be found 
+   *
+   * @return  the current viewId or null if the current viewId can't be found
    */
-  
+
   private String _getCurrentViewId()
-  {    
-    String currentViewId = 
-        FacesContext.getCurrentInstance().getViewRoot().getViewId();  
-                   
+  {
+    String currentViewId =
+        FacesContext.getCurrentInstance().getViewRoot().getViewId();
+
     return currentViewId;
-  }  
+  }
 
   /**
    * Gets the currently selected node in the menu
@@ -713,10 +749,10 @@
   {
     return _currentNode;
   }
-  
+
   /**
    * Sets the currently selected node.
-   * 
+   *
    * @param currentNode.  The currently selected node in the menu.
    */
   private void _setCurrentlySelectedNode(Object currentNode)
@@ -726,14 +762,14 @@
 
   /**
    * Sets the request method
-   * 
+   *
    * @param method
    */
   private void _setRequestMethod(String method)
   {
     _requestMethod = method;
   }
-  
+
   /**
    * Get the request method
    */
@@ -746,19 +782,19 @@
    * Public inner interface for the menu content handler
    * implementation
    * ================================================================ */
-   
+
   /*
    * Interface corresponding to the MenuContentHandlerImpl
-   * in org.apache.myfaces.trinidadinternal.menu.   This is used to achieve 
-   * separation between the api (trinidad) and the implementation 
-   * (trinidadinternal). It is only used by the XMLMenuModel, thus it is 
+   * in org.apache.myfaces.trinidadinternal.menu.   This is used to achieve
+   * separation between the api (trinidad) and the implementation
+   * (trinidadinternal). It is only used by the XMLMenuModel, thus it is
    * an internal interface.
    */
-  public interface MenuContentHandler 
+  public interface MenuContentHandler
   {
     /**
       * Get the TreeModel built while parsing metadata.
-      * 
+      *
       * @param uri String mapkey to a (possibly) treeModel cached on
       *        the MenuContentHandlerImpl.
       * @return TreeModel.
@@ -766,59 +802,60 @@
     public TreeModel getTreeModel(String uri);
 
     /**
-      * Sets the root model's request map key on the ContentHandler so 
+      * Sets the root model's request map key on the ContentHandler so
       * that the nodes can get back to their root model
       * through the request map.
       */
     public void setRootModelKey(String key);
-    
+
     /**
-      * Sets the local, sharedNode model's Uri on the ContentHandler so that
+      * Sets the local, sharedNode model's Model id on the ContentHandler so that
       * the local model can be gotten to, if necessary.
       */
-    public void setModelUri(String uri);
+    public void setModelId(String modelId);
 
     /**
      * Get the Model's idNodeMap
-     * 
+     *
      * @return the Model's idNodeMap
      */
     public Map<String, Object> getIdNodeMap(Object modelKey);
 
     /**
      * Get the Model's nodeFocusPathMap
-     * 
+     *
      * @return the Model's nodeFocusPathMap
      */
     public Map<Object, List<Object>> getNodeFocusPathMap(Object modelKey);
 
     /**
      * Get the Model's viewIdFocusPathMap
-     * 
+     *
      * @return the Model's viewIdFocusPathMap
      */
     public Map<String, List<Object>> getViewIdFocusPathMap(Object modelKey);
   }
-     
+
   private Object  _currentNode       = null;
   private Object  _prevFocusPath     = null;
   private String  _prevViewId        = null;
   private String  _requestMethod     = _METHOD_NONE;
   private String  _mdSource          = null;
   private boolean _createHiddenNodes = false;
+  private String  _modelId           = null;
 
   private Map<String, List<Object>> _viewIdFocusPathMap;
   private Map<Object, List<Object>> _nodeFocusPathMap;
   private Map<String, Object>       _idNodeMap;
 
   static private MenuContentHandler _contentHandler  = null;
-  
+
   // Only set this if _currentNode is a duplicate
   static private Object             _prevRequestNode = null;
-  
-  static private final String _ROOT_MODEL_KEY = 
+
+  static private final String _ROOT_MODEL_KEY =
     "org.apache.myfaces.trinidad.model.XMLMenuModel.__root_menu__";
-  
+
   static private final String _NODE_ID_PROPERTY     = "nodeId";
   static private final String _METHOD_GET           = "get";
   static private final String _METHOD_POST          = "post";
@@ -826,8 +863,8 @@
   static private final String _CUSTOM_ATTR_LIST     = "customPropList";
   static private final String _MENUCONTENTHANDLER_SERVICE =
             "org.apache.myfaces.trinidad.model.XMLMenuModel$MenuContentHandler";
-            
-  static private final TrinidadLogger _LOG = 
+
+  static private final TrinidadLogger _LOG =
          TrinidadLogger.createTrinidadLogger(XMLMenuModel.class);
   private static final long serialVersionUID = 1L;
 }

Modified: myfaces/trinidad/trunk_1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/GroupNode.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk_1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/GroupNode.java?rev=686962&r1=686961&r2=686962&view=diff
==============================================================================
--- myfaces/trinidad/trunk_1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/GroupNode.java (original)
+++ myfaces/trinidad/trunk_1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/GroupNode.java Mon Aug 18 22:56:49 2008
@@ -6,9 +6,9 @@
  *  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
@@ -27,7 +27,7 @@
 
 /**
  * Code specific to a Menu Model's GroupNode.
- *     
+ *
  */
 
 public class GroupNode extends MenuNode
@@ -39,11 +39,11 @@
   {
     super();
   }
-  
+
   /**
-    * Called by the Default ActionListener 
+    * Called by the Default ActionListener
     * when a menu node is clicked/selected.
-    * 
+    *
     * @return String outcome or viewId used
     *         during a POST for navigation.
     */
@@ -53,11 +53,11 @@
     // 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
@@ -66,31 +66,31 @@
     // Call the getDestination method of my idref node
     return getRefNode().getDestination();
   }
-  
+
   /**
-    * Sets the idref of the node.  
-    * 
+    * 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 
+    * 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.  
-    * 
+    * 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.
     */
@@ -98,27 +98,27 @@
   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);       
+      _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    
+    //    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
@@ -126,33 +126,33 @@
       // 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 
+      // 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 
+      // 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 nodeSysId = childNode.getNodeSysId();
-        
+        String modelId = childNode.getModelId();
+
         // Need to append mode's sys id here to create a
         // unique id.
-        String refNodeId = idrefList[i] + nodeSysId;
-        
+        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()
@@ -163,27 +163,27 @@
         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 
+    * Get the id of the node referred to by
     * the idref attribute of this node.
-    * 
-    * @return String id of the node referred 
+    *
+    * @return String id of the node referred
     *         to by the idref attribure of
     *         this node.
     */
@@ -195,36 +195,36 @@
   /* =============================================================
    * 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 
+    * 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 = 
+  private final static TrinidadLogger _LOG =
        TrinidadLogger.createTrinidadLogger(GroupNode.class);
 }

Modified: myfaces/trinidad/trunk_1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/MenuContentHandlerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk_1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/MenuContentHandlerImpl.java?rev=686962&r1=686961&r2=686962&view=diff
==============================================================================
--- myfaces/trinidad/trunk_1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/MenuContentHandlerImpl.java (original)
+++ myfaces/trinidad/trunk_1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/MenuContentHandlerImpl.java Mon Aug 18 22:56:49 2008
@@ -232,7 +232,7 @@
           // Set the local model (created when parsing a sharedNode)
           // on the node in case the node needs to get back to its
           // local model.
-          // menuNode.setModel(getModel());
+          menuNode.setModelId(getModelId());
 
           List<MenuNode> list = _menuNodes.get(_nodeDepth-1);
           list.add(menuNode);
@@ -595,7 +595,7 @@
     Map<String, Object> requestMap =
       facesContext.getExternalContext().getRequestMap();
 
-    return (XMLMenuModel) requestMap.get(getModelUri());
+    return (XMLMenuModel) requestMap.get(getModelId());
   }
 
   /**
@@ -603,19 +603,19 @@
    *
    * @return sharedNode's XMLMenuModel Uri
    */
-  public String getModelUri()
+  public String getModelId()
   {
-    return _localModelUri;
+    return _localModelId;
   }
 
   /**
-   * Sets the local (sharedNode's) menu Model's Uri.
+   * Sets the local (sharedNode's) menu Model's System Id.
    *
-   * @param localModelUri - String the root, top-level menu model's Uri.
+   * @param localModelId - String the root, top-level menu model's Uri.
    */
-  public void setModelUri(String localModelUri)
+  public void setModelId(String localModelId)
   {
-    _localModelUri = localModelUri;
+    _localModelId = localModelId;
   }
 
   /**
@@ -850,7 +850,7 @@
       );
 
     String mapTreeKeySave    = _currentTreeModelMapKey;
-    String localModelUriSave = _localModelUri;
+    String localModelIdSave = _localModelId;
     String handlerId         = _handlerId;
     String resBundleName     = _resBundleName;
     String resBundleKey      = _resBundleKey;
@@ -858,7 +858,7 @@
     _saveDataStack.push(menuNodesSave);
     _saveDataStack.push(menuListSave);
     _saveDataStack.push(mapTreeKeySave);
-    _saveDataStack.push(localModelUriSave);
+    _saveDataStack.push(localModelIdSave);
     _saveDataStack.push(handlerId);
     _saveDataStack.push(resBundleName);
     _saveDataStack.push(resBundleKey);
@@ -879,7 +879,7 @@
     _resBundleKey           = (String) _saveDataStack.pop();
     _resBundleName          = (String) _saveDataStack.pop();
     _handlerId              = (String) _saveDataStack.pop();
-    _localModelUri          = (String) _saveDataStack.pop();
+    _localModelId          = (String) _saveDataStack.pop();
     _currentTreeModelMapKey = (String) _saveDataStack.pop();
     _menuList               = (ArrayList<MenuNode>) _saveDataStack.pop();
     _menuNodes              = (ArrayList<List<MenuNode>>) _saveDataStack.pop();
@@ -1018,7 +1018,7 @@
 
 
   // Local (shared) Menu models Uri
-  private String _localModelUri = null;
+  private String _localModelId = null;
 
   // Root Menu model's Session map key
   private String _rootModelKey  = null;

Modified: myfaces/trinidad/trunk_1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/MenuNode.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk_1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/MenuNode.java?rev=686962&r1=686961&r2=686962&view=diff
==============================================================================
--- myfaces/trinidad/trunk_1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/MenuNode.java (original)
+++ myfaces/trinidad/trunk_1.2.x/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/MenuNode.java Mon Aug 18 22:56:49 2008
@@ -6,9 +6,9 @@
  *  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
@@ -42,39 +42,38 @@
     */
   public MenuNode()
   {
-    _nodeSysId = Integer.valueOf(System.identityHashCode(this)).toString();
   }
-  
+
   /**
     * 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 
+    *
+    * 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 
+      // 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 
+
+    if (   _label != null
         && UIComponentTag.isValueReference(_label)
        )
     {
@@ -87,20 +86,20 @@
 
   /**
     * 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 
+    * 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()
@@ -109,9 +108,9 @@
   }
 
   /**
-    * Sets the rendered attribute of the menu item.  
+    * 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.
     */
@@ -121,7 +120,7 @@
   }
 
   /**
-    * Gets the rendered attribute of the menu item.  
+    * 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.
@@ -131,12 +130,12 @@
     boolean rendered = MenuUtils.evalBoolean(_renderedStr, true);
     return rendered;
   }
-      
+
   /**
-    * Sets the disabled attribute of the menu item.  
+    * 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.
     */
@@ -146,7 +145,7 @@
   }
 
   /**
-    * Gets the disabled attribute of the menu item.  
+    * 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
     *
@@ -157,11 +156,11 @@
     boolean disabled = MenuUtils.evalBoolean(_disabledStr, false);
     return disabled;
   }
-      
+
   /**
-    * Sets the visible attribute of the menu item.  
+    * 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.
     */
@@ -171,7 +170,7 @@
   }
 
   /**
-    * Gets the visible attribute of the menu item.  
+    * 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.
@@ -181,10 +180,10 @@
     boolean visible = MenuUtils.evalBoolean(_visibleStr, true);
     return visible;
   }
-      
+
   /**
-    * Sets the defaultFocusPath attribute of the menu item.  
-    * 
+    * 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.
@@ -195,7 +194,7 @@
   }
 
   /**
-    * Gets the defaultFocusPath attribute of the menu item.  
+    * 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
@@ -203,34 +202,34 @@
     */
   public boolean getDefaultFocusPath()
   {
-    boolean defaultFocusPath = MenuUtils.evalBoolean(_defaultFocusPathStr, 
+    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.  
-    *  
+    * Gets the readOnly state of the node.
+    *
     * @return the node's readOnly state as a boolean.
     */
   public boolean getReadOnly()
@@ -240,8 +239,8 @@
   }
 
   /**
-    * Sets the the value of the readOnly attribute of the node.  
-    * 
+    * 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)
@@ -251,41 +250,41 @@
 
   /**
   * 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.  
-    * 
+    * 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.  
-    * 
+    * 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
     */
@@ -293,11 +292,11 @@
   {
     _disabledStr = disabledStr;
   }
-      
+
   /**
-    * Sets the readOnly attribute of the menu item.  
-    * If false, menu item will appear in a readOnly state.  
-    * 
+    * 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.
     */
@@ -307,9 +306,9 @@
   }
 
   /**
-    * Sets the visible attribute of the menu item.  
-    * If false, menu item will not appear.  
-    * 
+    * 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
     */
@@ -317,30 +316,30 @@
   {
     _visibleStr = visibleStr;
   }
-      
+
   /**
-    * Sets the defaultFocusPath attribute of the menu item.  
-    * 
+    * 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 
+    if (   accessKey != null
         && UIComponentTag.isValueReference(accessKey)
        )
     {
@@ -358,39 +357,39 @@
   }
 
   /**
-   * setAccessKey - Takes a single character and sets the value of the 
+   * 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 
+   * 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.
    */
@@ -398,7 +397,7 @@
   {
     int ampIdx = 0;
     _labelAndAccessKeyEL = false;
-    
+
     // if EL expression, set it and the label to the same thing
     if (   labelAndAccessKey != null
         && UIComponentTag.isValueReference(labelAndAccessKey)
@@ -428,18 +427,18 @@
        _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 
+    // we get it and process it, set the label
     // and the accessKey, null out labelAndAccessKey
     // and set labelAndAccessKeyEL to false
     if (_labelAndAccessKeyEL)
@@ -457,23 +456,23 @@
 
     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()
@@ -490,7 +489,7 @@
   /**
    * Get the node whose id matches this node's
    * idref attribute value.
-   * 
+   *
    * @return the MenuNode whose id matches this
    *         node's idref attribute value.
    */
@@ -498,11 +497,11 @@
   {
     return this;
   }
-  
+
   /**
-   * Called by the Default ActionListener 
+   * Called by the Default ActionListener
    * when a menu node is clicked/selected.
-   * 
+   *
    * @return String outcome or viewId used
    *         during a POST for navigation.
    */
@@ -511,11 +510,11 @@
     // 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()
@@ -523,28 +522,28 @@
     // 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 
+   * 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.
    */
@@ -554,10 +553,31 @@
   }
 
   /**
-   * setResBundleKey - sets the name of the resource bundle used in 
-   * obtaining the node's label text. Used, along with the handerId, 
+   * 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;
+  }
+
+  /**
+   * 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.
    */
   protected void setResBundleKey(String bundleKey)
@@ -566,10 +586,10 @@
   }
 
   /**
-   * setResBundleKey - sets the name of the resource bundle used in 
-   * obtaining the node's label text. Used, along with the handerId, 
+   * 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.
    */
   protected void setResBundleName(String bundleName)
@@ -579,10 +599,10 @@
 
   /**
    * setHandlerId - sets the MenuContentHandlerImpl's handlerId on the node.
-   * Used, along with the bundleKey, to identify and get a string from the 
+   * Used, along with the bundleKey, to identify and get a string from the
    * proper resource bundle.
-   * 
-   * @param handlerId String uniquely identifying the specific 
+   *
+   * @param handlerId String uniquely identifying the specific
    *        MenuContentHandlerImpl that created this node.
    */
   protected void setHandlerId(String handlerId)
@@ -592,7 +612,7 @@
 
   /**
    * 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)
@@ -602,60 +622,47 @@
 
   /**
    * getUniqueId - gets the unique id of the node.
-   * 
+   *
    * @return - String identifier for the node component.
    */
   protected String getUniqueId()
   {
-    // This must be made unique so that we do not have duplicates 
-    // in the idNodeMap on the menu's tree.      
-    return _id + _nodeSysId;
+    // 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;
   }
-  
-  /**
-   * Set the Menu Node's System id.
-   * 
-   * This is appended to the node's id in getUniqueId() to 
-   * ensure that each node's id is unique.
-   * 
-   * @return String object System id of the node.
-   */
-  protected String getNodeSysId()
-  {
-    return _nodeSysId;
-  }
-  
+
   /**
    * 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 = 
+    Map<String, Object> requestMap =
       facesContext.getExternalContext().getRequestMap();
-    
+
     XMLMenuModel model =  (XMLMenuModel) requestMap.get(getRootModelKey());
     return model;
   }
-  
+
   /**
    * _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
@@ -668,7 +675,7 @@
     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++)
     {
@@ -681,18 +688,18 @@
         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;
   }
@@ -701,8 +708,8 @@
    * _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 
+   *
+   * @param labelAndAccessKey - String holding both a label and
    * accessKey.
    */
   private void _splitLabelAndAccessKey(String labelAndAccessKey)
@@ -712,31 +719,31 @@
     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
    */
@@ -744,13 +751,13 @@
   {
     if (str == null)
       return null;
-    
+
     String keystr = MenuUtils.stringReplaceFirst(str.trim(), _bundleKey,
                                                  _bundleKey + getHandlerId());
     String elVal = MenuUtils.getBoundValue(keystr, String.class);
-    return elVal;       
+    return elVal;
   }
-  
+
   private String         _label       = null;
   private String         _icon        = null;
   private List<MenuNode> _children    = null;
@@ -764,11 +771,11 @@
   private String         _bundleName  = null;
   private String         _accessKey   = null;
   private String         _id          = null;
-  private String         _nodeSysId   = 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;
-} 
+}