/*
* NOTE: This copyright does *not* cover user programs that use HQ
* program services by normal system calls through the application
* program interfaces provided as part of the Hyperic Plug-in Development
* Kit or the Hyperic Client Development Kit - this is merely considered
* normal use of the program, and does *not* fall under the heading of
* "derived work".
*
* Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
* This file is part of HQ.
*
* HQ is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License as
* published by the Free Software Foundation. This program is distributed
* in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*/
package org.hyperic.hq.ui.taglib;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperic.hq.appdef.shared.AppdefEntityConstants;
import org.hyperic.hq.appdef.shared.AppdefEntityID;
import org.hyperic.hq.appdef.shared.AppdefEntityNotFoundException;
import org.hyperic.hq.auth.shared.SessionNotFoundException;
import org.hyperic.hq.auth.shared.SessionTimeoutException;
import org.hyperic.hq.authz.shared.PermissionException;
import org.hyperic.hq.bizapp.shared.AppdefBoss;
import org.hyperic.hq.bizapp.shared.uibeans.ResourceTreeNode;
import org.hyperic.hq.context.Bootstrap;
import org.hyperic.hq.ui.Constants;
import org.hyperic.hq.ui.beans.ImageMapRectAreaBean;
import org.hyperic.hq.ui.exception.ParameterNotFoundException;
import org.hyperic.hq.ui.servlet.NavMapImageServlet;
import org.hyperic.hq.ui.util.RequestUtils;
import org.hyperic.image.widget.ResourceTree;
import org.hyperic.util.data.IResourceTreeNode;
import org.hyperic.util.timer.StopWatch;
/**
* <p>
* A JSP tag that will retrieve a tree of all resources connected to the current
* resource and store it in the session. The "treeVar" request attribute will
* hold the name of the session attribute holding the ResourceTree data.
* </p>
*
* <p>
* Whatever is set as the areasVar will be set as request attribute holding the
* image map <area> beans. The number of image map <area> beans will
* be stored in the request under whatever wasareasSizeVar was set as.
* </p>
*
*/
public class NavMapTag extends TagSupport {
private static final long serialVersionUID = 1L;
private static Log log = LogFactory.getLog(NavMapTag.class.getName());
private static final int MAX_HEIGHT = 600;
private String areasVar;
private String areasSizeVar;
private Integer imageWidth;
/**
* Set the name of the request attribute that should hold the list of
* ImageMapRectAreaBean objects.
*
* @param var
* the name of the request attribute
*/
public void setAreasVar(String areasVar) {
this.areasVar = areasVar;
}
/**
* Set the name of the request attribute that should hold the size of the
* list of ImageMapRectAreaBean objects.
*
* @param sizeVar
* the name of the request attribute
*/
public void setAreasSizeVar(String areasSizeVar) {
this.areasSizeVar = areasSizeVar;
}
/**
* Set the width of the navigation map image.
*
* @param imageWidth
* the name of the request attribute
*/
public void setImageWidth(Integer imageWidth) {
this.imageWidth = imageWidth;
}
public Integer getImageWidth() {
return imageWidth;
}
/**
* Process the tag, generating appropriate HTML.
*
* @exception JspException
* if any errors occur
*/
public final int doStartTag() throws JspException {
final boolean debug = log.isDebugEnabled();
StopWatch watch = new StopWatch();
HttpServletRequest request = (HttpServletRequest) pageContext
.getRequest();
// first try to get the resource ids as eids, then as rid / type
AppdefEntityID[] eids = null;
try {
eids = RequestUtils.getEntityIds(request);
} catch (ParameterNotFoundException e) {
// either an auto-group of platforms or an individual resource
try {
eids = new AppdefEntityID[] { RequestUtils.getEntityId(request) };
} catch (ParameterNotFoundException pnfe) {
// auto-group of platforms
eids = null;
}
}
Integer ctype = null;
if (eids != null && eids.length > 0) {
switch (eids[0].getType()) {
case AppdefEntityConstants.APPDEF_TYPE_GROUP:
case AppdefEntityConstants.APPDEF_TYPE_APPLICATION:
ctype = null;
break;
default:
ctype = RequestUtils.getIntParameter(request,
Constants.CHILD_RESOURCE_TYPE_ID_PARAM, null);
}
}
Integer autogrouptype = RequestUtils.getIntParameter(request,
Constants.AUTOGROUP_TYPE_ID_PARAM, null);
if (autogrouptype != null) {
ctype = autogrouptype;
}
// The tree variable for the session will be computed from the
// eids, ctype and current timestamp.
StringBuffer tvBuf = new StringBuffer("resourceTree_").append(
System.currentTimeMillis()).append('_');
if (null != eids) {
for (int i = 0; i < eids.length; ++i) {
tvBuf.append(eids[i].getAppdefKey()).append('_');
}
}
if (null != ctype) {
tvBuf.append('_').append(ctype);
}
String treeVar = tvBuf.toString();
request.setAttribute(NavMapImageServlet.TREE_VAR_PARAM, treeVar);
Integer imageWidth = getImageWidth();
try {
ResourceTree tree = _getResourceTree(eids, ctype, imageWidth
.intValue());
request.getSession().setAttribute(treeVar, tree);
List<ImageMapRectAreaBean> areas = _getAreasForTree(tree);
request.setAttribute(areasVar, areas);
request.setAttribute(areasSizeVar, new Integer(areas.size()));
} catch (Exception e) {
if(debug) {
log.debug("Error while getting tree.", e);
}
throw new JspException(e);
}
if (debug) {
log.debug("NavMapTag.doStartTag: " + watch);
}
return SKIP_BODY;
}
private List<ImageMapRectAreaBean> _getAreasForTree(ResourceTree tree) {
IResourceTreeNode[][] levels = tree.getLevels();
List<ImageMapRectAreaBean> areas = new ArrayList<ImageMapRectAreaBean>();
for (int i = 0; i < levels.length; ++i) {
for (int j = 0; j < levels[i].length; ++j) {
ResourceTreeNode node = (ResourceTreeNode) levels[i][j];
_addAreasForTreeNode(node, areas);
}
}
return areas;
}
private void _addAreasForTreeNode(ResourceTreeNode node,
List<ImageMapRectAreaBean> areas) {
// Create <area> tag for parent node. If the rectangle is
// null, we won't create an <area> tag for it.
Rectangle[] rects = node.getRectangles();
if (null != rects) {
for (int i = 0; i < rects.length; ++i) {
int x2 = (int) (rects[i].x + rects[i].width);
int y2 = (int) (rects[i].y + rects[i].height);
if (node.getType() == org.hyperic.util.data.IResourceTreeNode.AUTO_GROUP) {
areas.add(new ImageMapRectAreaBean((int) rects[i].x,
(int) rects[i].y, x2, y2, node.getEntityIds(), node
.getCtype(), node.getName(),
// fix for autogroups
node.getREntityId().getType() + ":"
+ node.getCtype()));
} else if (node.hasCtype()) {
areas.add(new ImageMapRectAreaBean((int) rects[i].x,
(int) rects[i].y, x2, y2, node.getEntityIds(), node
.getCtype(), node.getName()));
} else {
areas.add(new ImageMapRectAreaBean((int) rects[i].x,
(int) rects[i].y, x2, y2, node.getEntityIds(), node
.getName()));
}
}
}
// Create <area> tags for child nodes.
IResourceTreeNode[] children = (IResourceTreeNode[]) node
.getUpChildren();
if (null != children) {
for (int i = 0; i < children.length; ++i) {
ResourceTreeNode cnode = (ResourceTreeNode) children[i];
_addAreasForTreeNode(cnode, areas);
}
}
children = (IResourceTreeNode[]) node.getDownChildren();
if (null != children) {
for (int i = 0; i < children.length; ++i) {
ResourceTreeNode cnode = (ResourceTreeNode) children[i];
_addAreasForTreeNode(cnode, areas);
}
}
}
private ResourceTree _getResourceTree(AppdefEntityID[] eids, Integer ctype,
int imageWidth) throws ServletException, SessionNotFoundException,
SessionTimeoutException, AppdefEntityNotFoundException,
PermissionException, RemoteException {
HttpServletRequest request = (HttpServletRequest) pageContext
.getRequest();
ServletContext ctx = pageContext.getServletContext();
int sessionId = RequestUtils.getSessionId(request).intValue();
AppdefBoss ab = Bootstrap.getBean(AppdefBoss.class);
ResourceTree tree = new ResourceTree(imageWidth);
ResourceTreeNode[] data = null;
if (null == ctype) {
data = ab.getNavMapData(sessionId, eids[0]);
} else {
data = ab.getNavMapData(sessionId, eids, ctype.intValue());
}
if (data != null) {
tree.addLevel(data);
}
// We must call getImage() here because it initializes the
// tree such that the coordinates for the nodes can be
// computed. A NullPointerException will result if getImage()
// has not been called before calculateCoordinates().
tree.getImage();
tree.calculateCoordinates();
// Ask the tree for the image dimensions and check them against
// the max width and height parameters. If we're not within range
// then auto-group any promotable nodes.
Dimension dim = tree.getImageSize();
if (dim.getHeight() > MAX_HEIGHT) {
tree = new ResourceTree(imageWidth);
ResourceTreeNode.autoGroupData(data);
tree.addLevel(data);
tree.getImage();
tree.calculateCoordinates();
}
return tree;
}
public int doEndTag() throws JspException {
release();
return EVAL_PAGE;
}
public void release() {
areasVar = null;
areasSizeVar = null;
super.release();
}
}