/* * RHQ Management Platform * Copyright (C) 2005-2008 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.enterprise.gui.common.tag; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import javax.servlet.http.HttpServletRequest; import com.sun.facelets.tag.AbstractTagLibrary; import org.rhq.core.clientapi.util.units.DateFormatter; import org.rhq.core.clientapi.util.units.FormattedNumber; import org.rhq.core.clientapi.util.units.ScaleConstants; import org.rhq.core.clientapi.util.units.UnitNumber; import org.rhq.core.clientapi.util.units.UnitsConstants; import org.rhq.core.clientapi.util.units.UnitsFormat; import org.rhq.core.domain.alert.AlertPriority; import org.rhq.core.domain.alert.notification.AlertNotification; import org.rhq.core.domain.auth.Subject; import org.rhq.core.domain.authz.Permission; import org.rhq.core.domain.common.EntityContext; import org.rhq.core.domain.configuration.ConfigurationUpdateStatus; import org.rhq.core.domain.event.EventSeverity; import org.rhq.core.domain.measurement.AvailabilityType; import org.rhq.core.domain.measurement.ui.MetricDisplaySummary; import org.rhq.core.domain.operation.OperationRequestStatus; import org.rhq.core.domain.resource.Resource; import org.rhq.core.domain.resource.ResourceType; import org.rhq.core.domain.resource.composite.ResourceFacets; import org.rhq.core.domain.resource.composite.ResourcePermission; import org.rhq.core.domain.resource.group.ResourceGroup; import org.rhq.core.gui.util.FacesContextUtility; import org.rhq.enterprise.gui.legacy.ParamConstants; import org.rhq.enterprise.gui.legacy.StringConstants; import org.rhq.enterprise.gui.legacy.WebUserPreferences; import org.rhq.enterprise.gui.legacy.util.RequestUtils; import org.rhq.enterprise.gui.util.EnterpriseFacesContextUtility; import org.rhq.enterprise.gui.util.WebUtility; import org.rhq.enterprise.server.authz.AuthorizationManagerLocal; import org.rhq.enterprise.server.plugin.pc.alert.AlertSender; import org.rhq.enterprise.server.plugin.pc.alert.AlertSenderPluginManager; import org.rhq.enterprise.server.resource.ResourceTypeManagerLocal; import org.rhq.enterprise.server.util.LookupUtil; /** * A Facelets tag library containing custom EL functions for use in RHQ GUI pages. * * *NOTE*: There are weird issues with Facelets function taglibs - * whenever possible, managed beans should be used instead. * * @author Ian Springer */ public class FunctionTagLibrary extends AbstractTagLibrary { private enum ElideMode { LEFT, RIGHT, MIDDLE } public static final String ELLIPSIS = "\u2026"; /** * Namespace used to import this library in Facelets pages */ public static final String NAMESPACE = "http://jboss.org/on/function"; /** * Current instance of library. */ public static final FunctionTagLibrary INSTANCE = new FunctionTagLibrary(); public FunctionTagLibrary() { super(NAMESPACE); try { Method[] methods = FunctionTagLibrary.class.getMethods(); for (Method method : methods) { if (Modifier.isStatic(method.getModifiers())) { this.addFunction(method.getName(), method); } } } catch (Exception e) { throw new RuntimeException(e); } } /** * Loads the Resource with the id specified via the 'id' query string parameter in the current request, and * sticks the Resource into the request context as the "Resource" attribute. */ public static void loadResource() { EnterpriseFacesContextUtility.getResource(); } /** * Returns a <code>ResourceFacets</code> object that represents the facets (measurement, configuration, etc.) that * are supported by the resource type with the specified id. Individual facets can be checked easily via EL, e.g.: * <code><c:set var="resourceFacets" value="${onf:getResourceFacets(Resource.resourceType.id)}"/> <c:if * test="${resourceFacets.measurement}"> ...</code> * * @param resourceTypeId a {@link org.rhq.core.domain.resource.ResourceType} id * * @return a <code>ResourceFacets</code> object for the resource type with the specified id */ public static ResourceFacets getResourceFacets(int resourceTypeId) { ResourceTypeManagerLocal resourceTypeManager = LookupUtil.getResourceTypeManager(); return resourceTypeManager.getResourceFacets(resourceTypeId); } public static ResourceFacets getFacets() { Resource resource = EnterpriseFacesContextUtility.getResource(); ResourceType resourceType = resource.getResourceType(); int resourceTypeId = resourceType.getId(); return getResourceFacets(resourceTypeId); } /** * Returns a <code>ResourcePermission</code> object for the resource associated with the current request. Individual * permissions can be checked easily via EL, e.g.: <code><c:set var="resourcePerm" * value="${onf:getResourcePermission()}"/> <c:if test="${resourcePerm.measure}"> ...</code> * * @return a <code>ResourcePermission</code> object for the resource with the specified id */ public static ResourcePermission getResourcePermission() { AuthorizationManagerLocal authorizationManager = LookupUtil.getAuthorizationManager(); Subject subject = EnterpriseFacesContextUtility.getSubject(); Resource resource = EnterpriseFacesContextUtility.getResource(); Set<Permission> resourcePerms = authorizationManager.getImplicitResourcePermissions(subject, resource.getId()); return new ResourcePermission(resourcePerms); } /** * Returns a <code>ResourcePermission</code> object for the group with the specified id. Individual permissions can * be checked easily via EL, e.g.: <code><c:set var="groupPerm" value="${onf:getGroupPermission(groupId)}"/> * <c:if test="${groupPerm.measure}"> ...</code> * * @param groupId a {@link ResourceGroup} id * * @return a <code>ResourcePermission</code> object for the group with the specified id */ public static ResourcePermission getGroupPermission(int groupId) { AuthorizationManagerLocal authorizationManager = LookupUtil.getAuthorizationManager(); Subject subject = EnterpriseFacesContextUtility.getSubject(); Set<Permission> groupPerms = authorizationManager.getImplicitGroupPermissions(subject, groupId); return new ResourcePermission(groupPerms); } /** * Formats the specified milliseconds-since-epoch timestamp as a String. * * @param timestamp a milliseconds-since-epoch timestamp * * @return a String representation of the timestamp * * @deprecated use <code>f:convertDateTime</code> tag instead */ @Deprecated public static String formatTimestamp(long timestamp) { // NOTE: The below code was snarfed from org.rhq.enterprise.gui.legacy.taglib.DateFormatter. UnitsConstants unit = UnitsConstants.UNIT_DATE; String key = StringConstants.UNIT_FORMAT_PREFIX_KEY + "epoch-millis"; String formatString = RequestUtils.message(FacesContextUtility.getRequest(), key); DateFormatter.DateSpecifics specs = new DateFormatter.DateSpecifics(); specs.setDateFormat(new SimpleDateFormat(formatString)); FormattedNumber fmtd = UnitsFormat.format(new UnitNumber(timestamp, unit, ScaleConstants.SCALE_MILLI), FacesContextUtility.getRequest().getLocale(), specs); return fmtd.toString(); } public static int sizeOf(Collection<?> collection) { if (collection == null) { return 0; } return collection.size(); } public static <T> int length(T[] collection) { if (collection == null) { return 0; } return collection.length; } public static WebUserPreferences getWebUserPreferences() { return EnterpriseFacesContextUtility.getWebUser().getWebPreferences(); } public static String contextFragmentURL() { EntityContext context = WebUtility.getEntityContext(); switch (context.type) { case Resource: return ParamConstants.RESOURCE_ID_PARAM + "=" + String.valueOf(context.resourceId); case ResourceGroup: return ParamConstants.GROUP_ID_PARAM + "=" + String.valueOf(context.groupId); case AutoGroup: return ParamConstants.PARENT_RESOURCE_ID_PARAM + "=" + String.valueOf(context.parentResourceId) + "&" + ParamConstants.RESOURCE_TYPE_ID_PARAM + "=" + String.valueOf(context.resourceTypeId); default: throw new IllegalArgumentException(context.getUnknownContextMessage()); } } /** * This method is akin to {@link #contextFragmentURL()} but produces a correct fragment * for the indicators chart action (/resource/common/monitor/visibility/IndicatorCharts.do). * * This legacy struts action expects a "ctype" parameter where the new UI uses "type". * * @return context fragment of the URL based on the current entity. */ public static String contextFragmentURLForIndicatorsChart() { EntityContext context = WebUtility.getEntityContext(); switch (context.type) { case AutoGroup: return ParamConstants.PARENT_RESOURCE_ID_PARAM + "=" + String.valueOf(context.parentResourceId) + "&" + ParamConstants.CHILD_RESOURCE_TYPE_ID_PARAM + "=" + String.valueOf(context.resourceTypeId); default: return contextFragmentURL(); } } public static Resource getResource(int resourceId) { Subject user = EnterpriseFacesContextUtility.getSubject(); return LookupUtil.getResourceManager().getResourceById(user, resourceId); } /** * Elides given string using an ellipsis character. * * The mode is one of "left", "right", "middle" (case insensitive). * * @see #elideStringCustom(String, int, String, String) */ public static String elideString(String str, int numChars, String mode) { return elideStringCustom(str, numChars, mode, ELLIPSIS); } /** * Elides given string using the specified ellipsis. * The mode is one of "left", "right", "middle" (case insensitive). * The resulting string has at most numChars characters. * * @param str the string to elide * @param numChars the length of the elided string * @param mode the elide mode * @param ellipsis the ellipsis string * @return the elided string */ public static String elideStringCustom(String str, int numChars, String mode, String ellipsis) { ElideMode eMode = Enum.valueOf(ElideMode.class, mode.toUpperCase()); return elideString(str, numChars, eMode, ellipsis); } private static String elideString(String str, int numChars, ElideMode mode, String ellipsis) { if (str == null) { throw new IllegalArgumentException("Cannot elide a null string"); } if (ellipsis == null) { throw new IllegalArgumentException("Ellipsis can't be null when eliding a string"); } if (numChars >= str.length()) { return str; } int ellipsisLength = ellipsis.length(); StringBuilder result = new StringBuilder(numChars); if (mode == ElideMode.LEFT) { result.append(ellipsis); result.append(str.substring(str.length() - numChars - ellipsisLength + 1, str.length())); } else if (mode == ElideMode.MIDDLE) { int firstHalf = (numChars - ellipsisLength) / 2; int secondHalf = firstHalf + ((numChars - ellipsisLength) % 2); result.append(str.substring(0, firstHalf)); result.append(ellipsis); result.append(str.substring(str.length() - secondHalf + 1, str.length())); } else if (mode == ElideMode.RIGHT) { result.append(str.substring(0, numChars - ellipsisLength + 1)); result.append(ellipsis); } return result.toString(); } private final static String AMP = "&"; public static String getChartURLParams(MetricDisplaySummary summary) { StringBuilder buffer = new StringBuilder(); buffer.append(contextFragmentURL()).append(AMP); buffer.append("imageWidth=647").append(AMP); buffer.append("imageHeight=100").append(AMP); buffer.append("schedId=").append(formatNullURLParams(summary.getScheduleId())).append(AMP); buffer.append("definitionId=").append(formatNullURLParams(summary.getDefinitionId())).append(AMP); buffer.append("measurementUnits=").append(formatNullURLParams(summary.getUnits())).append(AMP); buffer.append("now=").append(System.currentTimeMillis()); return buffer.toString(); } public static <T> List<T> getListFromMap(Map<String, T> map) { List<T> results = new ArrayList<T>(); results.addAll(map.values()); return results; } // either the object itself or its corresponding string representation can be null - handle both private static String formatNullURLParams(Object value) { String valueStr = (value == null ? null : value.toString()); return (valueStr == null ? "" : valueStr); } public static String getDefaultContextTabURL(EntityContext context) { if (context.type == EntityContext.Type.Resource) { return getDefaultResourceTabURL(); } else if (context.type == EntityContext.Type.ResourceGroup) { return "/rhq/group/monitor/graphs.xhtml"; } else if (context.type == EntityContext.Type.AutoGroup) { return "/rhq/autogroup/monitor/graphs.xhtml"; } else { throw new IllegalArgumentException("Do not support getting defaultTabURL for " + context); } } // needs to exist separately from getDefaultContextTabURL because only some facelets understand EntityContext public static String getDefaultResourceTabURL() { return "/rhq/resource/summary/overview.xhtml"; } public static String getDefaultGroupTabURL() { return "/rhq/group/inventory/view.xhtml"; } public static String getDefaultAutoGroupTabURL() { return "/rhq/autogroup/monitor/graphs.xhtml"; } public static String getAvailabilityURL(AvailabilityType type, int size) { if (size != 16 && size != 24) { throw new IllegalArgumentException("No availability icon for size " + size); } if (type == null) { return (size == 16) ? "/portal/images/icons/availability_grey_16.png" : "/portal/images/icons/availability_grey_24.png"; } else if (type == AvailabilityType.UP) { return (size == 16) ? "/portal/images/icons/availability_green_16.png" : "/portal/images/icons/availability_green_24.png"; } else if (type == AvailabilityType.DOWN) { return (size == 16) ? "/portal/images/icons/availability_red_16.png" : "/portal/images/icons/availability_red_24.png"; } else { throw new IllegalArgumentException("No icon for AvailabilityType[" + type + "]"); } } public static String getAlertPriorityURL(AlertPriority priority) { switch (priority) { case HIGH: return "/portal/images/icons/Flag_red_16.png"; case MEDIUM: return "/portal/images/icons/Flag_yellow_16.png"; case LOW: return "/portal/images/icons/Flag_blue_16.png"; default: throw new IllegalArgumentException("No icon for AlertPriority[" + priority + "]"); } } public static String getResourceConfigStatusURL(ConfigurationUpdateStatus status) { switch (status) { case SUCCESS: return "/portal/images/icons/Configure_ok_16.png"; case FAILURE: return "/portal/images/icons/Configure_failed_16.png"; case INPROGRESS: return "/portal/images/icons/Configure_16.png"; default: throw new IllegalArgumentException("No icon for ConfigurationUpdateStatus[" + status + "]"); } } public static String getOperationStatusURL(OperationRequestStatus status) { switch (status) { case SUCCESS: return "/portal/images/icons/Operation_ok_16.png"; case FAILURE: return "/portal/images/icons/Operation_failed_16.png"; case INPROGRESS: return "/portal/images/icons/Operation_16.png"; case CANCELED: return "/portal/images/icons/Operation_cancel_16.png"; default: throw new IllegalArgumentException("No icon for OperationRequestStatus[" + status + "]"); } } public static String getEventSeverityURL(EventSeverity severity, boolean grouped) { String color = null; switch (severity) { case DEBUG: color = "debug"; break; case INFO: color = "info"; break; case WARN: color = "warning"; break; case ERROR: color = "error"; break; case FATAL: color = "fatal"; break; default: throw new IllegalArgumentException("No icon for EventSeverity[" + severity + "]"); } String additional = (grouped ? "_multi" : ""); return "/portal/images/icons/Events_" + color + additional + "_16.png"; } public static String getAlertSenderConfigurationPreview(AlertNotification alertNotification) { AlertSenderPluginManager alertSenderPluginManager = LookupUtil.getAlertManager().getAlertPluginManager(); AlertSender sender = alertSenderPluginManager.getAlertSenderForNotification(alertNotification); return sender.previewConfiguration(); } public static boolean isIE6() { HttpServletRequest request = FacesContextUtility.getRequest(); String userAgent = request.getHeader("User-Agent").toLowerCase(); return (userAgent.indexOf("msie") != -1 && userAgent.indexOf("6.0") != -1); } }