/** Returns child <code>TreeNode</code>s for the given <code>TreeNode</code> model Object. */
  public List getChildTreeNodeObjects(Object nodeObject) {
    if (nodeObject == null) {
      return null;
    }
    // if (nodeObject.toString().equals(_objectName)) {
    // In this implementation _objectName represents the top-level,
    // we need to find its children here
    // if (_children != null) {
    //    return Arrays.asList((Object[])_children);
    // }

    String context = "";
    if (nodeObject instanceof NameClassPair) {

      context = (String) ((NameClassPair) nodeObject).getName();
      _nodeClass = (String) ((NameClassPair) nodeObject).getClassName();
    }

    List transformed = new ArrayList();
    try {
      ArrayList result =
          (ArrayList)
              JMXUtil.getMBeanServer()
                  .invoke(
                      new ObjectName(_objectName),
                      "getNames",
                      new String[] {context},
                      new String[] {"java.lang.String"});
      for (int i = 0; i < result.size(); i++) {
        NameClassPair pair = (NameClassPair) result.get(i);
        String nm = pair.getName();
        String prepend = context.equals("") ? "" : context + "/";
        pair.setName(prepend + pair.getName());
        transformed.add(pair);
      }
      _children = transformed.toArray(new Object[0]);

      // Ok, we got the result, provide an event in case we want to
      // do some filtering
      FacesContext ctx = FacesContext.getCurrentInstance();
      Object retVal =
          getLayoutComponent()
              .dispatchHandlers(
                  ctx,
                  FilterTreeEvent.EVENT_TYPE,
                  new FilterTreeEvent(getParentUIComponent(), _children));
      if ((retVal != null) && (retVal instanceof Object[])) {
        // We have a return value, use it instead of the original list
        _children = (Object[]) retVal;
      }
    } catch (Exception ex) {
      // Ignore exception since there are no children
      _children = null;
    }

    return _children != null ? Arrays.asList((Object[]) _children) : null;
  }
  /**
   * This method returns the "options" that should be supplied to the factory that creates the
   * <code>TreeNode</code> for the given tree node model object.
   *
   * <p>Some useful options for the standard <code>TreeNode</code> component include:
   *
   * <p>
   *
   * <ul>
   *   <li>text
   *   <li>url
   *   <li>imageURL
   *   <li>target
   *   <li>action
   *   <li>
   *   <li>actionListener
   *   <li>expanded
   * </ul>
   *
   * <p>See Tree / TreeNode component documentation for more details.
   */
  public Map<String, Object> getFactoryOptions(Object nodeObject) {
    if (nodeObject == null) {
      return null;
    }

    LayoutComponent desc = getLayoutComponent();
    Map<String, Object> props = new HashMap<String, Object>();
    if (nodeObject.toString().equals(_objectName)) {
      // This case deals with the top node.

      // NOTE: All supported options must be handled here,
      //		otherwise they'll be ignored.
      // NOTE: Options will be evaluated later, do not eval here.
      setProperty(props, "text", desc.getOption("text"));
      setProperty(props, "url", desc.getOption("url"));
      setProperty(props, "imageURL", desc.getOption("imageURL"));
      setProperty(props, "target", desc.getOption("target"));
      setProperty(props, "action", desc.getOption("action"));

      // NOTE: Although actionListener is supported, LH currently
      //	     implements this to be the ActionListener of the "turner"
      //	     which is inconsistent with "action".  We should make use
      //	     of the "Handler" feature which provides a "toggle"
      //	     CommandEvent.
      setProperty(props, "actionListener", desc.getOption("actionListener"));
      setProperty(props, "expanded", desc.getOption("expanded"));
    } else {
      // This case deals with the children

      // NOTE: All supported options must be handled here,
      // otherwise they'll be ignored
      _childImage = "../.." + _childImageFolder;
      if (nodeObject instanceof NameClassPair) {
        String context = (String) ((NameClassPair) nodeObject).getName();
        setProperty(props, "text", context);
        setProperty(props, "nodeClass", (String) ((NameClassPair) nodeObject).getClassName());
        try {
          ArrayList result =
              (ArrayList)
                  JMXUtil.getMBeanServer()
                      .invoke(
                          new ObjectName(_objectName),
                          "getNames",
                          new String[] {context},
                          new String[] {"java.lang.String"});
        } catch (Exception ex) {
          // Ignore exception since there are no children.
          _childImage = "../.." + _childImageDocument;
        }

      } else {
        throw new RuntimeException(
            "'"
                + nodeObject
                + "' Illegal type ("
                + nodeObject.getClass().getName()
                + ") for tree processing");
      }

      // Finish setting the child properties
      setProperty(props, "url", desc.getOption("childURL"));
      setProperty(props, "imageURL", _childImage);
      setProperty(props, "target", desc.getOption("childTarget"));
      setProperty(props, "action", desc.getOption("childAction"));
      // We are using "childActionListener" for the hyperlink, not the TreeNode
      //	    setProperty(props, "actionListener", desc.getOption("childActionListener"));
      setProperty(props, "expanded", desc.getOption("childExpanded"));
    }

    // Return the options
    return props;
  }