/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development * and Distribution License("CDDL") (collectively, the "License"). You * may not use this file except in compliance with the License. You can obtain * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific * language governing permissions and limitations under the License. * * When distributing the software, include this License Header Notice in each * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt. * Sun designates this particular file as subject to the "Classpath" exception * as provided by Sun in the GPL Version 2 section of the License file that * accompanied this code. If applicable, add the following below the License * Header, with the fields enclosed by brackets [] replaced by your own * identifying information: "Portions Copyrighted [year] * [name of copyright owner]" * * Contributor(s): * * If you wish your version of this file to be governed by only the CDDL or * only the GPL Version 2, indicate your decision by adding "[Contributor] * elects to include this software in this distribution under the [CDDL or GPL * Version 2] license." If you don't indicate a single choice of license, a * recipient has the option to distribute your version of this file under * either the CDDL, the GPL Version 2 or to extend the choice of license to * its licensees as provided above. However, if you add GPL Version 2 code * and therefore, elected the GPL Version 2 license, then the option applies * only if the new code is made subject to such option by the copyright * holder. */ package com.sun.enterprise.tools.admingui.tree; import com.sun.enterprise.tools.admingui.util.JMXUtil; import com.sun.enterprise.tools.admingui.util.GuiUtil; import com.sun.jsftemplating.component.ComponentUtil; import com.sun.jsftemplating.component.factory.tree.TreeAdaptor; import com.sun.jsftemplating.component.factory.tree.TreeAdaptorBase; import com.sun.jsftemplating.util.Util; import com.sun.jsftemplating.layout.descriptors.LayoutComponent; import com.sun.jsftemplating.layout.event.CommandActionListener; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import javax.faces.component.ActionSource; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.management.ObjectName; /** *

The MBeanTreeAdaptor implementation must have a * public static MBeanTreeAdaptor getInstance(FacesContext, * LayoutComponent, UIComponent) method in order to get access to * an instance of the MBeanTreeAdaptor instance.

* *

This class is used by DynamicTreeNodeFactory.

* * @author Ken Paulsen (ken.paulsen@sun.com) */ public class MBeanTreeAdaptor extends TreeAdaptorBase { /** *

This constructor is not used.

*/ private MBeanTreeAdaptor() { } /** *

This constructor saves the LayoutComponent descriptor * and the UIComponent associated with this * TreeAdaptor. This constructor is used by the * getInstance() method.

*/ protected MBeanTreeAdaptor(LayoutComponent desc, UIComponent parent) { super(desc, parent); } /** *

This method provides access to an MBeanTreeAdaptor * instance. Each time it is invoked, it returns a new instance.

*/ public static TreeAdaptor getInstance(FacesContext ctx, LayoutComponent desc, UIComponent parent) { return new MBeanTreeAdaptor(desc, parent); } /** *

This method is called shortly after * {@link #getInstance(FacesContext, LayoutComponent, UIComponent)}. * It provides a place for post-creation initialization to take * occur.

*/ public void init() { // Get the FacesContext FacesContext ctx = FacesContext.getCurrentInstance(); // This is the descriptor for this dynamic TreeNode, it contains all // information (options) necessary for this Adaptor LayoutComponent desc = getLayoutComponent(); // The parent UIComponent UIComponent parent = getParentUIComponent(); // Get the Object Name Object val = desc.getEvaluatedOption(ctx, "objectName", parent); if (val == null) { throw new IllegalArgumentException( "'objectName' must be specified!"); } _objectName = (String) val; // Get the Method Name val = desc.getEvaluatedOption(ctx, "methodName", parent); if (val == null) { throw new IllegalArgumentException( "'methodName' must be specified!"); } _methodName = (String) val; // Get Parameters _paramsArray = null; val = desc.getEvaluatedOption(ctx, "parameters", parent); if (val != null) { if (val instanceof List) { _paramsArray = ((List) val).toArray(); } else { _paramsArray = new Object[] {val}; } } // Get Parameter Types _paramTypesArray = null; val = desc.getEvaluatedOption(ctx, "paramTypes", parent); if (val != null) { if (val instanceof String) { _paramTypesArray = new String[] {(String) val}; } else if (val instanceof List) { _paramTypesArray = (String []) ((List) val).toArray(new String[0]); } else { throw new IllegalArgumentException( "'paramTypes' must be a String or a List of types!"); } } // Get the attribute name for the text (optional) _nameAtt = (String) desc.getEvaluatedOption( ctx, "attributeName", parent); if (_nameAtt != null) { _nameAtt = _nameAtt.trim(); if (_nameAtt.length() == 0) { _nameAtt = null; } } // Get the method name for the text (optional) _nameMethod = (String) desc.getEvaluatedOption( ctx, "attrNameMethod", parent); if (_nameMethod != null) { _nameMethod = _nameMethod.trim(); if (_nameMethod.length() == 0) { _nameMethod = null; } } /* FIXME: See "DynamicTreeNode.java -- The code in getChildObjectNames should be FIXME: broken up between this method and the next (getChildTreeNodeObjects). FIXME: This file should only deal w/ the normal MBean use case. WebServices FIXME: should be handled via WebServiceTreeAdaptor (to be written). */ // The following method should set the "key" to the node containing all // the children... the children will also have keys which must be // retrievable by the next method (getChildTreeNodeObjects)... these // "keys" will be used by the rest of the methods in this file for // getting information about the TreeNode that should be built. String ignored = (String) desc.getEvaluatedOption(ctx, "ignored", parent); if ( ignored == null || "false".equals(ignored)){ setTreeNodeObject(_objectName); }else{ setTreeNodeObject(null); } } /** *

Returns child TreeNodes for the given * TreeNode 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); } _children = (Object []) JMXUtil.invoke( _objectName, _methodName, _paramsArray, _paramTypesArray); // 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; } } else { // Currently multiple levels are not implemented return null; } return _children != null ? Arrays.asList((Object[])_children):null; } /** *

This method returns the "options" that should be supplied to the * factory that creates the TreeNode for the given tree * node model object.

* *

Some useful options for the standard TreeNode * component include:

* *

* *

See Tree / TreeNode component documentation for more details.

*/ public Map getFactoryOptions(Object nodeObject) { if (nodeObject == null) { return null; } LayoutComponent desc = getLayoutComponent(); Map props = new HashMap(); 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 // FIXME: There was a check near here (in DynamicTreeNode.updateKids(...) for // FIXME: isChildValid... figure out how we want to expose an "exludes" list // FIXME: or filter to make this more generalized. if (nodeObject instanceof ObjectName) { if (_nameAtt != null) { setProperty(props, "text", (String) JMXUtil.getAttribute( (ObjectName) nodeObject, _nameAtt)); } else if (_nameMethod != null) { // This is for monitoring MBeans, they don't have a name // attr, but perhaps a getName() method. setProperty(props, "text", (String) JMXUtil.invoke( (ObjectName) nodeObject, _nameMethod, null, null)); } if (!props.containsKey("text")) { // fallback to the object name setProperty(props, "text", nodeObject.toString()); } } else if (nodeObject instanceof String) { setProperty(props, "text", (String) nodeObject); /* FIXME: This is from line #108 - 109 of DynamicTreeNode.java: node.setAttribute("webServiceKey", webServiceKeyMap.get(name)); node.setAttribute("webServiceName", name); */ } 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", desc.getOption("childImageURL")); setProperty(props, "target", desc.getOption("childTarget")); setProperty(props, "action", desc.getOption("childAction")); String tt = (String) desc.getOption("targetConfigName"); if (!GuiUtil.isEmpty(tt)){ setProperty(props, "targetConfigName", tt); } String check = (String) desc.getOption("checkAdminServer"); if (!GuiUtil.isEmpty(check)){ String serverName = (String) props.get("text"); if (serverName.equals("server")){ setProperty(props, "text", "server (Admin Server)"); setProperty(props, "serverName", "server"); }else setProperty(props, "serverName", serverName); } // 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; } /** *

Helper method for setting Properties while avoiding NPE's.

*/ void setProperty(Map props, String key, Object value) { if (value != null) { props.put(key, value); } } /** *

This method returns the id for the given tree node * model object.

*/ public String getId(Object nodeObject) { if (nodeObject == null) { return "nullNodeObject"; } if (nodeObject.toString().equals(_objectName)) { // Top level can use the ID of the LayoutComponent return getLayoutComponent().getId( FacesContext.getCurrentInstance(), getParentUIComponent()); } return genId(nodeObject.toString()); } /** *

This method generates an ID that is safe for JSF for the given * String. It does not guarantee that the id is unique, it is the * responsibility of the caller to pass in a String that will result * in a UID. All non-ascii characters will be stripped.

* * @param uid A non-null String. */ private String genId(String uid) { char [] chArr = uid.toCharArray(); int len = chArr.length; int newIdx = 0; String prefix = ""; // Make sure the first char is ! a number or a '-' if ((chArr[0] == '-') || Character.isDigit(chArr[0])) { prefix = "_"; } for (int idx=0; idx This method returns any facets that should be applied to the * TreeNode (comp). Useful facets for the sun * TreeNode component are: "content" and "image".

* *

Facets that already exist on comp, or facets that * are directly added to comp do not need to be returned * from this method.

* *

This implementation directly adds a "content" and "image" facet and * returns null from this method.

* * @param comp The tree node UIComponent. * @param nodeObject The (model) object representing the tree node. */ public Map getFacets(UIComponent comp, Object nodeObject) { if (nodeObject == null){ return null; } if (nodeObject.toString().equals(_objectName)) { return null; } Properties props = new Properties(); LayoutComponent desc = this.getLayoutComponent(); // Check to see if a childActionListener was added // NOTE: This is not needed when a "command" event is used. In the // case of a CommandEvent an ActionListener will be // automatically registered by the ComponentFactoryBase class // during "setOptions()". Also, setting a childActionListener // here should not stop "command" handlers from being invoked. setProperty(props, "actionListener", desc.getOption("childActionListener")); // Also se the target and text... setProperty(props, "target", desc.getOption("childTarget")); // FIXME: Add support for other hyperlink properties?? // Create Hyperlink // NOTE: Last attribute "content" will be the facet named used. UIComponent imageLink = ComponentUtil.getChild( comp, "imagelink", "com.sun.jsftemplating.component.factory.sun.ImageHyperlinkFactory", props, "image"); // We don't want the imageHyperlink to have the following property, so // set it after creating it setProperty(props, "text", comp.getAttributes().get("text")); UIComponent link = ComponentUtil.getChild( comp, "link", "com.sun.jsftemplating.component.factory.sun.HyperlinkFactory", props, "content"); // Check to see if we have a childURL, evalute it here (after component // is created, before rendered) so we can use the link itself to define // the URL. This has proven to be useful... Object val = desc.getOption("childURL"); if (val != null) { val = desc.resolveValue( FacesContext.getCurrentInstance(), link, val); // FIXME: Debug starting here... print out what it thinkt's it's value is for childURL. link.getAttributes().put("url", val); imageLink.getAttributes().put("url", val); } // Set the image URL val = desc.getOption("childImageURL"); if (val != null) { imageLink.getAttributes().put("imageURL", desc. resolveValue(FacesContext.getCurrentInstance(), link, val)); } // Set href's handlers... // We do it this way rather than earlier b/c the factory will not // recognize this as a property, it requires it to be defined in the // LayoutComponent as a handler. So we must do this manually like // this. List handlers = desc.getHandlers("childCommand"); if (handlers != null) { link.getAttributes().put("command", handlers); imageLink.getAttributes().put("command", handlers); // This adds the required action listener to proces the commands // This is needed here b/c the factory has already executed -- the // factory is normally the place where this is added (iff there is // at least one command handler). ((ActionSource) link).addActionListener( CommandActionListener.getInstance()); ((ActionSource) imageLink).addActionListener( CommandActionListener.getInstance()); } // We already added the facet, return null... return null; } /** *

Advanced framework feature which provides better handling for * things such as expanding TreeNodes, beforeEncode, and other * events.

* *

This method should return a Map of List * of Handler objects. Each List in the * Map should be registered under a key that cooresponds * to to the "event" in which the Handlers should be * invoked.

*/ public Map getHandlersByType(UIComponent comp, Object nodeObject) { /* These handlers apply to the TreeNode not the Hyperlink */ /* LayoutComponent lc = this.getLayoutComponent(); List list = lc.getHandlers("childCommand"); if (list != null) { Map m = new HashMap(); m.put("command", list); return m; } */ return null; } /** *

This method returns the UIComponent factory class * implementation that should be used to create a * TreeNode for the given tree node model object.

This method provides a means use different TreeNodeFactories, currently we are using the default which is defined in the superclass, if needed we can change this. public String getFactoryClass(Object nodeObject) { return "com.sun.enterprise.tools.jsfext.component.factory.basic.TreeNodeFactory"; } */ /** * The MBean object name. */ private String _methodName = null; /** * The MBean object name. */ String _objectName = null; /** * The MBean method parameters. */ private Object[] _paramsArray = null; /** * The MBean method parameter types. */ private String[] _paramTypesArray= null; /** * The name of the attribute which describes the TreeNode name. */ private String _nameAtt = null; /** * The name of the method which describes the TreeNode name. */ private String _nameMethod = null; /** * This sub-nodes of the top-level Node. */ Object[] _children = null; }