/* * RHQ Management Platform * Copyright (C) 2005-2014 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, * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ package org.rhq.coregui.client.alert; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import com.google.gwt.user.client.History; import com.google.gwt.user.client.rpc.AsyncCallback; import com.smartgwt.client.data.Criteria; import com.smartgwt.client.data.Record; import com.smartgwt.client.data.ResultSet; import com.smartgwt.client.data.SortSpecifier; import com.smartgwt.client.types.SortDirection; import com.smartgwt.client.widgets.Canvas; import com.smartgwt.client.widgets.form.fields.PickerIcon; import com.smartgwt.client.widgets.form.fields.SelectItem; import com.smartgwt.client.widgets.form.fields.SpacerItem; import com.smartgwt.client.widgets.form.fields.TextItem; import com.smartgwt.client.widgets.form.fields.events.FormItemClickHandler; import com.smartgwt.client.widgets.form.fields.events.FormItemIconClickEvent; import com.smartgwt.client.widgets.grid.ListGrid; import com.smartgwt.client.widgets.grid.ListGridField; import com.smartgwt.client.widgets.grid.ListGridRecord; import org.rhq.core.domain.alert.AlertFilter; import org.rhq.core.domain.alert.AlertPriority; import org.rhq.core.domain.authz.Permission; import org.rhq.core.domain.common.EntityContext; import org.rhq.core.domain.criteria.AlertCriteria; import org.rhq.coregui.client.CoreGUI; import org.rhq.coregui.client.IconEnum; import org.rhq.coregui.client.ImageManager; import org.rhq.coregui.client.components.form.DateFilterItem; import org.rhq.coregui.client.components.form.EnumSelectItem; import org.rhq.coregui.client.components.table.RecordExtractor; import org.rhq.coregui.client.components.table.ResourceAuthorizedTableAction; import org.rhq.coregui.client.components.table.TableAction; import org.rhq.coregui.client.components.table.TableActionEnablement; import org.rhq.coregui.client.components.table.TableSection; import org.rhq.coregui.client.components.view.HasViewName; import org.rhq.coregui.client.components.view.ViewName; import org.rhq.coregui.client.gwt.GWTServiceLookup; import org.rhq.coregui.client.util.enhanced.EnhancedIButton.ButtonColor; import org.rhq.coregui.client.util.message.Message; /** * A view that displays a paginated table of fired {@link org.rhq.core.domain.alert.Alert alert}s, along with the * ability to filter those alerts, sort those alerts, double-click a row to view full details an alert, and perform * various operations on the the alerts: delete selected, delete all from source, ack selected, ack all from source. * This view fully respects the user's authorization, and will not allow operations on the alerts unless the user is * either the inventory manager or has MANAGE_ALERTS permission on every resource corresponding to the alerts being * operated on. * * @author Joseph Marques * @author Ian Springer * @author Heiko W. Rupp * @author John Mazzitelli */ public class AlertHistoryView extends TableSection<AlertDataSource> implements HasViewName { public static final ViewName SUBSYSTEM_VIEW_ID = new ViewName("RecentAlerts", MSG.common_title_recent_alerts(), IconEnum.RECENT_ALERTS); private static SortSpecifier DEFAULT_SORT_SPECIFIER = new SortSpecifier(AlertCriteria.SORT_FIELD_CTIME, SortDirection.DESCENDING); private static final Criteria INITIAL_CRITERIA = new Criteria(); protected SelectItem priorityFilter; protected SelectItem alertFilter; protected DateFilterItem startDateFilter; protected DateFilterItem endDateFilter; protected TextItem alertNameFilter; private EntityContext context; private boolean hasWriteAccess; private boolean showNewDefinitionButton = true; static { AlertPriority[] priorityValues = AlertPriority.values(); String[] priorityNames = new String[priorityValues.length]; for (int i = 0, priorityValuesLength = priorityValues.length; i < priorityValuesLength; i++) { priorityNames[i] = priorityValues[i].name(); } INITIAL_CRITERIA.addCriteria(AlertDataSource.FILTER_PRIORITIES, priorityNames); } // for subsystem views public AlertHistoryView() { this(SUBSYSTEM_VIEW_ID.getTitle(), EntityContext.forSubsystemView(), false); } public AlertHistoryView(String tableTitle, EntityContext entityContext) { this(tableTitle, entityContext, false); } protected AlertHistoryView(String tableTitle, EntityContext context, boolean hasWriteAccess) { super(tableTitle, INITIAL_CRITERIA, new SortSpecifier[] { DEFAULT_SORT_SPECIFIER }); this.context = context; this.hasWriteAccess = hasWriteAccess; setInitialCriteriaFixed(false); setDataSource(new AlertDataSource(context)); } public AlertHistoryView(String tableTitle, int[] resourceIds) { super(tableTitle, new SortSpecifier[] { DEFAULT_SORT_SPECIFIER }); Criteria initialCriteria = new Criteria(); AlertPriority[] priorityValues = AlertPriority.values(); String[] priorityNames = new String[priorityValues.length]; for (int i = 0, priorityValuesLength = priorityValues.length; i < priorityValuesLength; i++) { priorityNames[i] = priorityValues[i].name(); } initialCriteria.addCriteria(AlertDataSource.FILTER_PRIORITIES, priorityNames); initialCriteria.setAttribute("resourceIds", resourceIds); setInitialCriteria(initialCriteria); this.context = new EntityContext(); this.context.type = EntityContext.Type.SubsystemView; this.hasWriteAccess = true; setDataSource(new AlertDataSource(context)); } @Override protected void configureTableFilters() { LinkedHashMap<String, String> priorities = new LinkedHashMap<String, String>(3); priorities.put(AlertPriority.HIGH.name(), MSG.common_alert_high()); priorities.put(AlertPriority.MEDIUM.name(), MSG.common_alert_medium()); priorities.put(AlertPriority.LOW.name(), MSG.common_alert_low()); LinkedHashMap<String, String> priorityIcons = new LinkedHashMap<String, String>(3); priorityIcons.put(AlertPriority.HIGH.name(), ImageManager.getAlertIcon(AlertPriority.HIGH)); priorityIcons.put(AlertPriority.MEDIUM.name(), ImageManager.getAlertIcon(AlertPriority.MEDIUM)); priorityIcons.put(AlertPriority.LOW.name(), ImageManager.getAlertIcon(AlertPriority.LOW)); priorityFilter = new EnumSelectItem(AlertDataSource.FILTER_PRIORITIES, MSG.view_alerts_table_filter_priority(), AlertPriority.class, priorities, priorityIcons); LinkedHashMap<String, String> filters = new LinkedHashMap<String, String>(3); filters.put(AlertFilter.ACKNOWLEDGED_STATUS.name(), MSG.common_alert_filter_acknowledged_status()); filters.put(AlertFilter.RECOVERED_STATUS.name(), MSG.common_alert_filter_recovered_status()); filters.put(AlertFilter.RECOVERY_TYPE.name(), MSG.common_alert_filter_recovery_type()); alertFilter = new EnumSelectItem(AlertDataSource.FILTER_STATUS, MSG.view_alerts_table_filter_options(), AlertFilter.class, filters, null); // The default is to select everything in EnumSelectItem helper class. Not so for filters. alertFilter.setValues(null); startDateFilter = new DateFilterItem(DateFilterItem.START_DATE_FILTER, MSG.filter_from_date()); endDateFilter = new DateFilterItem(DateFilterItem.END_DATE_FILTER, MSG.filter_to_date()); alertNameFilter = new TextItem(AlertDataSource.FILTER_NAME, MSG.common_title_name()); alertNameFilter.setWrapTitle(false); alertNameFilter.setValue(""); PickerIcon refreshFilter = new PickerIcon(PickerIcon.CLEAR, new FormItemClickHandler() { public void onFormItemClick(FormItemIconClickEvent event) { alertNameFilter.clearValue(); } }); alertNameFilter.setIcons(refreshFilter); alertNameFilter.setIconPrompt("Resets the alert name filter."); SpacerItem spacerItem = new SpacerItem(); spacerItem.setColSpan(2); if (isShowFilterForm()) { setFilterFormItems(priorityFilter, startDateFilter, alertFilter, endDateFilter, alertNameFilter); } } @Override protected void configureTable() { ArrayList<ListGridField> dataSourceFields = getDataSource().getListGridFields(); getListGrid().setFields(dataSourceFields.toArray(new ListGridField[dataSourceFields.size()])); setupTableInteractions(this.hasWriteAccess); super.configureTable(); } @Override protected String getDetailsLinkColumnName() { return AlertCriteria.SORT_FIELD_CTIME; } /** * Subclasses can override this to indicate they do not support * deleting all alerts or acknowledging all alerts. Portlet subclasses * that only trim their views to the top N alerts can override this to * return false so they don't delete or acknowledge alerts that aren't displayed * to the user. * * @return this default implementation returns true */ protected boolean canSupportDeleteAndAcknowledgeAll() { return true; } protected void setupTableInteractions(final boolean hasWriteAccess) { addTableAction(MSG.common_button_ack(), MSG.view_alerts_ack_confirm(), ButtonColor.BLUE, new ResourceAuthorizedTableAction(AlertHistoryView.this, TableActionEnablement.ANY, (hasWriteAccess ? null : Permission.MANAGE_ALERTS), new RecordExtractor<Integer>() { public Collection<Integer> extract(Record[] records) { List<Integer> result = new ArrayList<Integer>(records.length); for (Record record : records) { result.add(record.getAttributeAsInt("resourceId")); } return result; } }) { public void executeAction(ListGridRecord[] selection, Object actionValue) { acknowledge(selection); } }); if (canSupportDeleteAndAcknowledgeAll()) { addTableAction(MSG.common_button_ack_all(), MSG.view_alerts_ack_confirm_all(), new TableAction() { public boolean isEnabled(ListGridRecord[] selection) { ListGrid grid = getListGrid(); ResultSet resultSet = (null != grid) ? grid.getResultSet() : null; return (hasWriteAccess && grid != null && resultSet != null && !resultSet.isEmpty()); } public void executeAction(ListGridRecord[] selection, Object actionValue) { acknowledgeAll(); } }); } addTableAction(MSG.common_button_delete(), MSG.view_alerts_delete_confirm(), ButtonColor.RED, new ResourceAuthorizedTableAction(AlertHistoryView.this, TableActionEnablement.ANY, (hasWriteAccess ? null : Permission.MANAGE_ALERTS), new RecordExtractor<Integer>() { public Collection<Integer> extract(Record[] records) { List<Integer> result = new ArrayList<Integer>(records.length); for (Record record : records) { result.add(record.getAttributeAsInt("resourceId")); } return result; } }) { public void executeAction(ListGridRecord[] selection, Object actionValue) { delete(selection); } }); if (canSupportDeleteAndAcknowledgeAll()) { addTableAction(MSG.common_button_delete_all(), MSG.view_alerts_delete_confirm_all(), ButtonColor.RED, new TableAction() { public boolean isEnabled(ListGridRecord[] selection) { ListGrid grid = getListGrid(); ResultSet resultSet = (null != grid) ? grid.getResultSet() : null; return (hasWriteAccess && grid != null && resultSet != null && !resultSet.isEmpty()); } public void executeAction(ListGridRecord[] selection, Object actionValue) { deleteAll(); } }); } if (!context.isSubsystemView() && showNewDefinitionButton) { addTableAction(MSG.common_button_new() + " " + MSG.common_title_definition(), ButtonColor.BLUE, new TableAction() { public boolean isEnabled(ListGridRecord[] selection) { // todo: this.permissions.isAlert() return hasWriteAccess; } public void executeAction(ListGridRecord[] selection, Object actionValue) { // CoreGUI.goToView(LinkManager.getEntityTabLink(context, "Alerts", "Definitions/0")); // the above doesn't work because EntityContext doesn't know if it is autogroup or not // -> using the relative URL hack String oldurl = History.getToken(); String lastChunk = oldurl.substring(oldurl.lastIndexOf("/") + 1); if ("Activity".equals(lastChunk)) { oldurl = oldurl.substring(0, oldurl.lastIndexOf("/")); oldurl = oldurl.substring(0, oldurl.lastIndexOf("/")) + "/Alerts"; } else if ("History".equals(lastChunk)) { oldurl = oldurl.substring(0, oldurl.lastIndexOf("/")); } else { try { Integer.parseInt(lastChunk); oldurl += "/Alerts"; } catch (NumberFormatException nfe) { // do nothing } } if ("Alerts".equals(oldurl.substring(oldurl.lastIndexOf("/") + 1))) { String newUrl = oldurl + "/Definitions/0"; CoreGUI.goToView(newUrl); } } }); } } protected void delete(ListGridRecord[] records) { final int[] alertIds = new int[records.length]; for (int i = 0, selectionLength = records.length; i < selectionLength; i++) { ListGridRecord record = records[i]; Integer alertId = record.getAttributeAsInt("id"); alertIds[i] = alertId; } GWTServiceLookup.getAlertService().deleteAlerts(alertIds, new AsyncCallback<Integer>() { public void onSuccess(Integer resultCount) { CoreGUI.getMessageCenter().notify( new Message(MSG.view_alerts_delete_success(String.valueOf(resultCount)), Message.Severity.Info)); refresh(true); } public void onFailure(Throwable caught) { CoreGUI.getErrorHandler() .handleError(MSG.view_alerts_delete_failure(Arrays.toString(alertIds)), caught); refreshTableInfo(); } }); } protected void deleteAll() { int rpcTimeout = 10000 + getListGrid().getTotalRows(); GWTServiceLookup.getAlertService(rpcTimeout).deleteAlertsByContext(context, new AsyncCallback<Integer>() { public void onSuccess(Integer resultCount) { CoreGUI.getMessageCenter().notify( new Message(MSG.view_alerts_delete_success(String.valueOf(resultCount)), Message.Severity.Info)); refresh(true); } public void onFailure(Throwable caught) { CoreGUI.getErrorHandler().handleError(MSG.view_alerts_delete_failure_all(), caught); refreshTableInfo(); } }); } public void acknowledge(ListGridRecord[] records) { final int[] alertIds = new int[records.length]; for (int i = 0, selectionLength = records.length; i < selectionLength; i++) { ListGridRecord record = records[i]; Integer alertId = record.getAttributeAsInt("id"); alertIds[i] = alertId; } GWTServiceLookup.getAlertService().acknowledgeAlerts(alertIds, new AsyncCallback<Integer>() { public void onSuccess(Integer resultCount) { CoreGUI.getMessageCenter().notify( new Message(MSG.view_alerts_ack_success(String.valueOf(resultCount)), Message.Severity.Info)); refresh(); } public void onFailure(Throwable caught) { CoreGUI.getErrorHandler().handleError(MSG.view_alerts_ack_failure(Arrays.toString(alertIds)), caught); refreshTableInfo(); } }); } protected void acknowledgeAll() { int rpcTimeout = 10000 + getListGrid().getTotalRows(); GWTServiceLookup.getAlertService(rpcTimeout).acknowledgeAlertsByContext(context, new AsyncCallback<Integer>() { public void onSuccess(Integer resultCount) { CoreGUI.getMessageCenter().notify( new Message(MSG.view_alerts_ack_success(String.valueOf(resultCount)), Message.Severity.Info)); refresh(); } public void onFailure(Throwable caught) { CoreGUI.getErrorHandler().handleError(MSG.view_alerts_ack_failure_all(), caught); refreshTableInfo(); } }); } @Override public Canvas getDetailsView(Integer alertId) { return AlertDetailsView.getInstance(); } public EntityContext getContext() { return context; } @Override public ViewName getViewName() { return SUBSYSTEM_VIEW_ID; } public void setShowNewDefinitionButton(boolean showNewDefinitionButton) { this.showNewDefinitionButton = showNewDefinitionButton; } }