public void startElement()

in trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/MenuContentHandlerImpl.java [146:360]


  public void startElement(String nameSpaceUri, String localElemName,
                           String qualifiedElemName, Attributes attrList)
    throws SAXException
  {
    super.startElement(nameSpaceUri, localElemName, qualifiedElemName,
                       attrList);

    if (_ROOT_NODE.equals(qualifiedElemName))
    {
      // Unless both of these are specified, don't attempt to load
      // the resource bundle.
      String resBundle    = attrList.getValue(_RES_BUNDLE_ATTR);
      String resBundleKey = attrList.getValue(_VAR_ATTR);

      if (   (resBundle != null    && !"".equals(resBundle))
          && (resBundleKey != null && !"".equals(resBundleKey))
         )
      {
        // Load the resource Bundle.
        // Ensure the bundle key is unique by appending the
        // handler Id.
        MenuUtils.loadBundle(resBundle, resBundleKey + getHandlerId());
        _resBundleKey  = resBundleKey;
        _resBundleName = resBundle;
      }
    }
    else
    {
      // Either itemNode, destinationNode, or groupNode
      boolean isNonSharedNode = (   _ITEM_NODE.equals(qualifiedElemName)
                                 || _GROUP_NODE.equals(qualifiedElemName)
                                );

      if (isNonSharedNode)
      {
        _currentNodeStyle = (  _ITEM_NODE.equals(qualifiedElemName)
                             ? MenuConstants.NODE_STYLE_ITEM
                             : MenuConstants.NODE_STYLE_GROUP
                            );
        _nodeDepth++;

        if ((_skipDepth >= 0) && (_nodeDepth > _skipDepth))
        {
          // This sub-tree is being skipped, so just return
          return;
        }

        if (_menuNodes.size() < _nodeDepth)
        {
          _menuNodes.add(new ArrayList<MenuNode>());
        }

        _attrMap = _getMapFromList(attrList);

        // Create either an itemNode or groupNode.
        MenuNode menuNode = _createMenuNode();

        if (menuNode == null)
        {
          // No menu item is created, so note that we are
          // now skipping the subtree
          _skipDepth = _nodeDepth;
        }
        else
        {
          if (   (_resBundleName != null && !"".equals(_resBundleName))
              && (_resBundleKey  != null && !"".equals(_resBundleKey))
             )
          {
            menuNode.setResBundleKey(_resBundleKey);
            menuNode.setResBundleName(_resBundleName);
          }

          // Set the node's MenuContentHandlerImpl id so that when
          // the node's getLabel() method is called, we can
          // use the handlerId to insert into the label
          // if it is an EL expression.
          menuNode.setHandlerId(getHandlerId());

          // Set the root model on the node so we can call into
          // the root model from the node to populate its
          // idNodeMap (See XMLMenuModel.java)
          menuNode.setRootModelKey(getRootModelKey());

          // 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.setModelId(getModelId());

          // menu nodes need to know how to refer
          // back to the specific xml menu model
          // so that they can mutate them.
          FacesContext facesContext = FacesContext.getCurrentInstance();
          Map<String, Object> requestMap =
            facesContext.getExternalContext().getRequestMap();
          if(!requestMap.containsKey(XMLMenuModel.SHARED_MODEL_INDICATOR_KEY))
            menuNode.setRootId( (getId() ) );
          else
            menuNode.setRootId((Integer) requestMap.get(XMLMenuModel.SHARED_MODEL_INDICATOR_KEY));

          List<MenuNode> list = _menuNodes.get(_nodeDepth-1);
          list.add(menuNode.getThreadSafeCopy());
        }
      }
      else if (_SHARED_NODE.equals(qualifiedElemName))
      {
        _nodeDepth++;

        // SharedNode's "ref" property points to another submenu's metadata,
        // and thus a new model, which we build here.  Note: this will
        // recursively call into this MenuContentHandlerImpl when parsing the
        // submenu's metadata.
        String expr = attrList.getValue(_REF_ATTR);
        
        // push this only when we are root model
        FacesContext facesContext = FacesContext.getCurrentInstance();
        Map<String, Object> requestMap =
          facesContext.getExternalContext().getRequestMap();
        Integer recurseLevel = (Integer) requestMap.get(_RECURSE_COUNTER);
        if(recurseLevel == null) 
          recurseLevel = 0;
        if(recurseLevel == 0)
          requestMap.put(XMLMenuModel.SHARED_MODEL_INDICATOR_KEY, this.getId());
        
        recurseLevel++;
        requestMap.put(_RECURSE_COUNTER, recurseLevel);
        

        // Need to push several items onto the stack now as we recurse
        // into another menu model.
        _saveModelData();

        // Create the sub menu model specified in the sharedNode
        XMLMenuModel menuModel = (XMLMenuModel)MenuUtils.getBoundValue(expr,
                                                              Object.class);


        // Now must pop the values cause we are back to the parent
        // model.
        _restoreModelData();
        
        recurseLevel = (Integer) requestMap.get(_RECURSE_COUNTER);
        recurseLevel --;
        requestMap.put(_RECURSE_COUNTER, recurseLevel);
        
        if(recurseLevel == 0)
          requestMap.remove(XMLMenuModel.SHARED_MODEL_INDICATOR_KEY);
        

        // Name of the managed bean that is the sub menu XMLMenuModel.
        String modelStr = expr.substring(expr.indexOf('{')+1,
                                         expr.indexOf('}'));

        // There are 2 ways that a Model can be invalid:
        // 1) Something such as a missing managed bean definition
        //    for the submenu model causes the creation of the
        //    XMLMenuModel for the submenu to fail. This will result
        //    in menuModel being NULL.
        // 2) Some kind of parsing error in its metadata.  If a node
        //    type is invalid, an exception will be thrown (see below)
        //    and caught in getTreeModel().  This will result in a
        //    null submenu list the following SAXException will also
        //    be logged.
        if (menuModel != null)
        {
          Object         subMenuObj  = menuModel.getWrappedData();
          List<MenuNode> subMenuList = null;

          if (subMenuObj instanceof ChildPropertyTreeModel)
          {
            subMenuList =
              (List<MenuNode>)((ChildPropertyTreeModel)subMenuObj).getWrappedData();
          }

          if (subMenuList != null)
          {
            // SharedNode could be the first child
            // So we need a new list for the children
            if (_menuNodes.size() < _nodeDepth)
            {
              _menuNodes.add(new ArrayList<MenuNode>());
            }

            List<MenuNode> list = _menuNodes.get(_nodeDepth-1);
            list.addAll(subMenuList);
          }
          else
          {
            // Let it go through but log it.  This way the rest of
            // the Tree gets built and this submenu is skipped.
            SAXException npe =
              new SAXException("Shared Node Model not created for " + modelStr);
          }
        }
        else
        {
          // Let it go through but log it.  This way the rest of
          // the Tree gets built and this submenu is skipped.
          NullPointerException npe =
            new NullPointerException("Shared Node Model not created for "
              + modelStr + ". Check for the existence of the corresponding "
              + "managed bean in your config files.");

          _LOG.severe (npe.getMessage(), npe);
        }
      }
      else
      {
        // Throw an Exception for any node that is not of type
        // menu, itemNode, groupNode, or sharedNode.  This will get
        // caught in getTreeModel()
        throw new SAXException("Invalid Node type: " + localElemName);
      }
    }
  }