/*
* RHQ Management Platform
* Copyright (C) 2011 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, version 2, as
* published by the Free Software Foundation, and/or the GNU Lesser
* General Public License, version 2.1, also 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 and the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* and the GNU Lesser 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.report;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.smartgwt.client.data.DSRequest;
import com.smartgwt.client.data.DSResponse;
import com.smartgwt.client.data.DataSourceField;
import com.smartgwt.client.data.Record;
import com.smartgwt.client.data.fields.DataSourceTextField;
import com.smartgwt.client.widgets.events.DoubleClickEvent;
import com.smartgwt.client.widgets.events.DoubleClickHandler;
import com.smartgwt.client.widgets.grid.CellFormatter;
import com.smartgwt.client.widgets.grid.HoverCustomizer;
import com.smartgwt.client.widgets.grid.ListGrid;
import com.smartgwt.client.widgets.grid.ListGridField;
import com.smartgwt.client.widgets.grid.ListGridRecord;
import com.smartgwt.client.widgets.grid.events.RecordClickEvent;
import com.smartgwt.client.widgets.grid.events.RecordClickHandler;
import org.rhq.core.domain.alert.AlertDefinition;
import org.rhq.core.domain.common.EntityContext;
import org.rhq.core.domain.criteria.AlertDefinitionCriteria;
import org.rhq.core.domain.criteria.ResourceCriteria;
import org.rhq.core.domain.resource.Resource;
import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.domain.util.PageControl;
import org.rhq.core.domain.util.PageList;
import org.rhq.coregui.client.CoreGUI;
import org.rhq.coregui.client.IconEnum;
import org.rhq.coregui.client.LinkManager;
import org.rhq.coregui.client.admin.templates.AlertDefinitionTemplateTypeView;
import org.rhq.coregui.client.alert.definitions.AbstractAlertDefinitionsDataSource;
import org.rhq.coregui.client.components.ReportExporter;
import org.rhq.coregui.client.components.table.AbstractTableAction;
import org.rhq.coregui.client.components.table.Table;
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.inventory.resource.AncestryUtil;
import org.rhq.coregui.client.inventory.resource.type.ResourceTypeRepository;
import org.rhq.coregui.client.inventory.resource.type.ResourceTypeRepository.TypesLoadedCallback;
import org.rhq.coregui.client.util.StringUtility;
import org.rhq.coregui.client.util.enhanced.EnhancedIButton.ButtonColor;
/**
* A tabular report that shows alert definitions on all resources in inventory.
*
* @author John Mazzitelli
*/
public class AlertDefinitionReportView extends Table<AlertDefinitionReportView.DataSource> implements HasViewName {
public static final ViewName VIEW_ID = new ViewName("AlertDefinitions", MSG.view_reports_alertDefinitions(),
IconEnum.ALERT_DEFINITIONS);
public AlertDefinitionReportView() {
super();
setDataSource(new DataSource());
}
@Override
protected void configureTable() {
super.configureTable();
ListGrid listGrid = getListGrid();
ArrayList<ListGridField> fields = getDataSource().getListGridFields();
listGrid.setFields(fields.toArray(new ListGridField[fields.size()]));
setListGridDoubleClickHandler(new DoubleClickHandler() {
@Override
public void onDoubleClick(DoubleClickEvent event) {
ListGrid lg = (ListGrid) event.getSource();
ListGridRecord selected = lg.getSelectedRecord();
if (selected != null) {
AlertDefinition alertDef = getDataSource().copyValues(selected);
int resourceId = alertDef.getResource().getId();
int alertDefId = alertDef.getId();
String link = LinkManager.getSubsystemAlertDefinitionLink(resourceId, alertDefId);
CoreGUI.goToView(link);
}
}
});
addExportAction();
}
private void addExportAction() {
addTableAction("Export", MSG.common_button_reports_export(), ButtonColor.BLUE, new AbstractTableAction() {
@Override
public boolean isEnabled(ListGridRecord[] selection) {
return enableIfRecordsExist(getListGrid());
}
@Override
public void executeAction(ListGridRecord[] selection, Object actionValue) {
ReportExporter exporter = ReportExporter.createStandardExporter("alertDefinitions");
exporter.export();
refreshTableInfo();
}
});
}
@Override
public ViewName getViewName() {
return VIEW_ID;
}
class DataSource extends AbstractAlertDefinitionsDataSource {
private static final String FIELD_PARENT = "parent";
private static final String FIELD_RESOURCE = "resource";
@Override
protected AlertDefinitionCriteria getFetchCriteria(DSRequest request) {
AlertDefinitionCriteria criteria = new AlertDefinitionCriteria();
criteria.addFilterResourceOnly(true); // guarantees that all alert defs we get will have a non-null Resource object
criteria.setPageControl(getPageControl(request));
criteria.fetchResource(true);
criteria.fetchGroupAlertDefinition(true);
return criteria;
}
@Override
protected String getSortFieldForColumn(String columnName) {
if (AncestryUtil.RESOURCE_ANCESTRY.equals(columnName)) {
return "resource.ancestry";
}
if (FIELD_PARENT.equals(columnName)) {
return "parentId";
}
return super.getSortFieldForColumn(columnName);
}
@Override
protected AlertDefinitionCriteria getSimpleCriteriaForAll() {
AlertDefinitionCriteria criteria = new AlertDefinitionCriteria();
criteria.addFilterResourceOnly(true);
criteria.setPageControl(PageControl.getUnlimitedInstance());
return criteria;
}
@Override
public ArrayList<ListGridField> getListGridFields() {
ArrayList<ListGridField> fields = super.getListGridFields();
// hide the created/modified fields, we don't need to show them by default
// add cell formatter on the name field so we can make it a link
for (ListGridField field : fields) {
String fieldName = field.getName();
if (fieldName.equals(FIELD_CTIME) || fieldName.equals(FIELD_MTIME)) {
field.setHidden(true);
} else if (fieldName.equals(FIELD_NAME)) {
field.setCellFormatter(new CellFormatter() {
@Override
public String format(Object value, ListGridRecord record, int rowNum, int colNum) {
AlertDefinition alertDef = copyValues(record);
int resourceId = alertDef.getResource().getId();
int alertDefId = alertDef.getId();
String link = LinkManager.getSubsystemAlertDefinitionLink(resourceId, alertDefId);
return "<a href=\"" + link + "\">" + StringUtility.escapeHtml(alertDef.getName()) + "</a>";
}
});
}
}
// add more columns
ListGridField parentField = new ListGridField(FIELD_PARENT, MSG.view_alerts_field_parent());
parentField.setWidth(100);
parentField.setShowHover(true);
parentField.setHoverCustomizer(new HoverCustomizer() {
@Override
public String hoverHTML(Object value, ListGridRecord record, int rowNum, int colNum) {
if (record.getAttribute(FIELD_PARENT) != null) {
return MSG.view_reports_alertDefinitions_parentHover();
}
return MSG.common_val_na();
}
});
parentField.addRecordClickHandler(new RecordClickHandler() {
@Override
public void onRecordClick(RecordClickEvent event) {
// we only do something if we really have a parent.
// if we have a template parent, we have to get the resource's type and go to the template page for that type
// if we have a group parent, we can directly go to the group's alert def page
Record record = event.getRecord();
AlertDefinition alertDef = copyValues(record);
if (alertDef.getParentId() != null && alertDef.getParentId().intValue() > 0) {
final Integer templateId = alertDef.getParentId().intValue();
final Integer resourceId = alertDef.getResource().getId();
ResourceCriteria resCriteria = new ResourceCriteria();
resCriteria.addFilterId(resourceId);
resCriteria.fetchResourceType(true);
GWTServiceLookup.getResourceService().findResourcesByCriteria(resCriteria,
new AsyncCallback<PageList<Resource>>() {
@Override
public void onSuccess(PageList<Resource> result) {
if (result == null || result.size() != 1) {
CoreGUI.getErrorHandler().handleError(
MSG.view_reports_alertDefinitions_resTypeLoadError());
} else {
int typeId = result.get(0).getResourceType().getId();
CoreGUI.goToView(LinkManager.getAdminTemplatesEditLink(
AlertDefinitionTemplateTypeView.VIEW_ID.getName(), typeId)
+ "/"
+ templateId);
}
}
@Override
public void onFailure(Throwable caught) {
CoreGUI.getErrorHandler().handleError(
MSG.view_reports_alertDefinitions_resTypeLoadError(), caught);
}
});
} else if (alertDef.getParentId() != null && alertDef.getParentId() == 0) {
// handle "View Group Definition"
int resourceId = alertDef.getResource().getId();
int alertDefId = alertDef.getId();
CoreGUI.goToView(LinkManager.getSubsystemAlertDefinitionLink(resourceId, alertDefId));
} else if (alertDef.getGroupAlertDefinition() != null) {
AlertDefinition groupAlertDef = alertDef.getGroupAlertDefinition();
CoreGUI.goToView(LinkManager.getEntityTabLink(EntityContext.forGroup(groupAlertDef.getGroup()),
"Alert", "Definitions") + "/" + groupAlertDef.getId());
}
}
});
fields.add(parentField);
ListGridField resourceField = new ListGridField(FIELD_RESOURCE, MSG.common_title_resource());
resourceField.setCellFormatter(new CellFormatter() {
public String format(Object value, ListGridRecord listGridRecord, int i, int i1) {
String url = LinkManager.getResourceLink(listGridRecord.getAttributeAsInt(AncestryUtil.RESOURCE_ID));
return LinkManager.getHref(url, StringUtility.escapeHtml(value.toString()));
}
});
resourceField.setShowHover(true);
resourceField.setHoverCustomizer(new HoverCustomizer() {
public String hoverHTML(Object value, ListGridRecord listGridRecord, int rowNum, int colNum) {
return AncestryUtil.getResourceHoverHTML(listGridRecord, 0);
}
});
fields.add(resourceField);
ListGridField ancestryField = AncestryUtil.setupAncestryListGridField();
fields.add(ancestryField);
return fields;
}
@Override
public ListGridRecord copyValues(AlertDefinition from) {
// in order to support sorting our list grid on the parent and resource columns,
// we have to assign these to something that is sortable
ListGridRecord record = super.copyValues(from);
Resource resource = from.getResource();
record.setAttribute(FIELD_RESOURCE, resource.getName());
Integer parentId = from.getParentId(); // a valid non-zero number means the alert def came from a template
AlertDefinition groupAlertDefinition = from.getGroupAlertDefinition();
if (parentId != null && parentId.intValue() > 0) {
record.setAttribute(FIELD_PARENT, "<b>" + MSG.view_alert_definition_for_type() + "</b>");
} else if (groupAlertDefinition != null) {
record.setAttribute(FIELD_PARENT, "<b>" + MSG.view_alert_definition_for_group() + "</b>");
}
// for ancestry handling
record.setAttribute(AncestryUtil.RESOURCE_ID, resource.getId());
record.setAttribute(AncestryUtil.RESOURCE_NAME, resource.getName());
record.setAttribute(AncestryUtil.RESOURCE_ANCESTRY, resource.getAncestry());
record.setAttribute(AncestryUtil.RESOURCE_TYPE_ID, resource.getResourceType().getId());
return record;
}
@Override
protected List<DataSourceField> addDataSourceFields() {
List<DataSourceField> fields = super.addDataSourceFields();
// hide the created/modified fields, we don't need to show them by default
for (DataSourceField field : fields) {
String fieldName = field.getName();
if (fieldName.equals(FIELD_CTIME) || fieldName.equals(FIELD_MTIME)) {
field.setHidden(true);
}
}
// add more columns
DataSourceField resourceField = new DataSourceTextField(FIELD_RESOURCE);
fields.add(resourceField);
DataSourceField parentField = new DataSourceTextField(FIELD_RESOURCE);
fields.add(parentField);
return fields;
}
/**
* Additional processing to support a cross-resource view)
* @param result
* @param response
* @param request
*/
protected void dataRetrieved(final PageList<AlertDefinition> result, final DSResponse response,
final DSRequest request) {
HashSet<Integer> typesSet = new HashSet<Integer>();
HashSet<String> ancestries = new HashSet<String>();
for (AlertDefinition alertDefinition : result) {
Resource resource = alertDefinition.getResource();
if (null != resource) {
typesSet.add(resource.getResourceType().getId());
ancestries.add(resource.getAncestry());
}
}
// In addition to the types of the result resources, get the types of their ancestry
typesSet.addAll(AncestryUtil.getAncestryTypeIds(ancestries));
ResourceTypeRepository typeRepo = ResourceTypeRepository.Cache.getInstance();
typeRepo.getResourceTypes(typesSet.toArray(new Integer[typesSet.size()]), new TypesLoadedCallback() {
public void onTypesLoaded(Map<Integer, ResourceType> types) {
// SmartGWT has issues storing a Map as a ListGridRecord attribute. Wrap it in a pojo.
AncestryUtil.MapWrapper typesWrapper = new AncestryUtil.MapWrapper(types);
Record[] records = buildRecords(result);
for (Record record : records) {
// To avoid a lot of unnecessary String construction, be lazy about building ancestry hover text.
// Store the types map off the records so we can build a detailed hover string as needed.
record.setAttribute(AncestryUtil.RESOURCE_ANCESTRY_TYPES, typesWrapper);
// Build the decoded ancestry Strings now for display
record.setAttribute(AncestryUtil.RESOURCE_ANCESTRY_VALUE, AncestryUtil.getAncestryValue(record));
}
response.setData(records);
response.setTotalRows(result.getTotalSize()); // for paging to work we have to specify size of full result set
processResponse(request.getRequestId(), response);
}
});
}
}
}