/* * RHQ Management Platform * Copyright (C) 2005-2010 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.alert.definitions; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; 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.types.Overflow; import com.smartgwt.client.widgets.Window; import com.smartgwt.client.widgets.events.CloseClickEvent; import com.smartgwt.client.widgets.events.CloseClickHandler; import com.smartgwt.client.widgets.form.fields.SelectItem; import com.smartgwt.client.widgets.grid.ListGridRecord; import org.rhq.core.domain.alert.AlertCondition; import org.rhq.core.domain.criteria.Criteria; import org.rhq.core.domain.drift.DriftDefinitionTemplate; import org.rhq.core.domain.measurement.MeasurementDefinition; import org.rhq.core.domain.resource.ResourceType; import org.rhq.coregui.client.alert.AlertFormatUtility; import org.rhq.coregui.client.components.table.AbstractTableAction; import org.rhq.coregui.client.components.table.Table; import org.rhq.coregui.client.components.table.TableActionEnablement; import org.rhq.coregui.client.inventory.resource.type.ResourceTypeRepository; import org.rhq.coregui.client.inventory.resource.type.ResourceTypeRepository.MetadataType; import org.rhq.coregui.client.util.RPCDataSource; import org.rhq.coregui.client.util.enhanced.EnhancedIButton.ButtonColor; import org.rhq.coregui.client.util.enhanced.EnhancedVLayout; /** * @author John Mazzitelli */ public class ConditionsEditor extends EnhancedVLayout { private final ResourceType resourceType; private HashSet<AlertCondition> conditions; private Map<Integer, AlertCondition> modifiedConditions; private Table<ConditionDataSource> table; private final SelectItem conditionExpression; private boolean updated; public ConditionsEditor(SelectItem conditionExpression, ResourceType resourceType, HashSet<AlertCondition> conditions) { super(); this.conditionExpression = conditionExpression; this.resourceType = resourceType; this.updated = false; setConditions(conditions); modifiedConditions = new HashMap<Integer, AlertCondition>(); } /** * Returns the conditions that this editor currently has in memory. * This will never be <code>null</code>. This collection serves for new * or deleted conditions. * * @return conditions set that was possibly edited by the user */ public HashSet<AlertCondition> getConditions() { return conditions; } /** * Returns the conditions that this editor currently has in memory. * This will never be <code>null</code>. This collection holds modified * existing conditions. * * @return modifiedConditions map of modified conditions that exist in the db, key is id */ public Map<Integer, AlertCondition> getModifiedConditions() { return modifiedConditions; } public void setConditions(Set<AlertCondition> set) { conditions = new HashSet<AlertCondition>(); // make our own copy modifiedConditions = new HashMap<Integer, AlertCondition>(conditions.size()); //reset changes if (set != null) { // we need to make sure we have the full measurement definition, including the units. // this is so we can display the condition values with the proper units. If an alert // condition is a measurement condition, but the measurement definition isn't the full // definition, look up the full definition from the resource type and use it. for (AlertCondition alertCondition : set) { MeasurementDefinition measDef = alertCondition.getMeasurementDefinition(); if (measDef != null) { if (measDef.getUnits() == null) { MeasurementDefinition fullMeasDef = findMeasurementDefinition(measDef.getId()); if (fullMeasDef != null) { alertCondition.setMeasurementDefinition(fullMeasDef); } } } } conditions.addAll(set); } if (table != null) { table.refresh(); } } private MeasurementDefinition findMeasurementDefinition(int measurementDefinitionId) { Set<MeasurementDefinition> measDefs = this.resourceType.getMetricDefinitions(); if (measDefs != null) { for (MeasurementDefinition measDef : measDefs) { if (measDef.getId() == measurementDefinitionId) { return measDef; } } } return null; } @Override protected void onInit() { super.onInit(); table = new ConditionsTable(); addMember(table); } public void setEditable(boolean editable) { table.setTableActionDisableOverride(!editable); } public boolean isUpdated() { return updated; } public void setUpdated(boolean updated) { this.updated = updated; } public boolean isConditionInternallyUpdated() { return !modifiedConditions.isEmpty(); } private class ConditionsTable extends Table<ConditionDataSource> { private ConditionsTable() { super(); setShowHeader(false); final ConditionDataSource dataSource = new ConditionDataSource(); setDataSource(dataSource); } @Override protected void configureTable() { addTableAction(MSG.common_button_add(), null, ButtonColor.BLUE, new AbstractTableAction() { public void executeAction(ListGridRecord[] selection, Object actionValue) { showConditionEditor(null); } }); table.addTableAction(MSG.common_button_delete(), MSG .view_alert_definition_condition_editor_delete_confirm(), ButtonColor.RED, new AbstractTableAction( TableActionEnablement.ANY) { public void executeAction(ListGridRecord[] selection, Object actionValue) { for (ListGridRecord record : selection) { AlertCondition condition = getDataSource().copyValues(record); conditions.remove(condition); modifiedConditions.remove(condition); updated = true; } refresh(); } }); table.addTableAction(MSG.view_alert_definition_editCondition(), null, ButtonColor.GRAY, new AbstractTableAction(TableActionEnablement.SINGLE) { public void executeAction(ListGridRecord[] selection, Object actionValue) { AlertCondition condition = getDataSource().copyValues(selection[0]); showConditionEditor(condition); } }); } private void showConditionEditor(final AlertCondition existingCondition) { // we need the drift definition templates (if there are any) so we know if we should offer drift conditions as an option ResourceTypeRepository.Cache.getInstance() .getResourceTypes(resourceType.getId(), EnumSet.of(MetadataType.driftDefinitionTemplates, MetadataType.events, MetadataType.resourceConfigurationDefinition), new ResourceTypeRepository.TypeLoadedCallback() { @Override public void onTypesLoaded(ResourceType type) { // the resource type repo caches types - so if this resource type was already cached prior // to the conditions editor component created (which it probably was) then we are getting the same // exact instance that we had before (resourceType). When this happens, great! Our resourceType // instance will have its drift definition templates populated. But, I'm being paranoid. If somehow // we have a resourceType that is different than the type being passed to us, we need to copy // the drift definition. if (type != resourceType) { // paranoia, unsure if this is needed but clear out any old drift definition still hanging around if (resourceType.getDriftDefinitionTemplates() != null) { resourceType.getDriftDefinitionTemplates().clear(); } // if the newly loaded resource type supports drift, put it in our type object if (type.getDriftDefinitionTemplates() != null) { for (DriftDefinitionTemplate template : type.getDriftDefinitionTemplates()) { resourceType.addDriftDefinitionTemplate(template); } } } final Window winModal = new Window(); winModal.setTitle(existingCondition == null ? MSG .view_alert_common_tab_conditions_modal_title() : MSG .view_alert_common_tab_conditions_modalEdit_title()); winModal.setOverflow(Overflow.VISIBLE); winModal.setShowMinimizeButton(false); winModal.setIsModal(true); winModal.setShowModalMask(true); winModal.setAutoSize(true); winModal.setAutoCenter(true); winModal.centerInPage(); winModal.addCloseClickHandler(new CloseClickHandler() { @Override public void onCloseClick(CloseClickEvent event) { winModal.markForDestroy(); refreshTableInfo(); } }); final int numConditions = conditions.size(); final ConditionEditor newConditionEditor = new ConditionEditor(conditions, modifiedConditions, ConditionsEditor.this.conditionExpression, ConditionsEditor.this.resourceType, existingCondition, new Runnable() { @Override public void run() { updated = updated || numConditions != conditions.size() || isConditionInternallyUpdated(); winModal.markForDestroy(); refresh(); } }); winModal.addItem(newConditionEditor); winModal.show(); } }); } } private class ConditionDataSource extends RPCDataSource<AlertCondition, Criteria> { private static final String FIELD_OBJECT = "obj"; private static final String FIELD_CONDITION = "condition"; public ConditionDataSource() { super(); List<DataSourceField> fields = addDataSourceFields(); addFields(fields); } @Override protected List<DataSourceField> addDataSourceFields() { List<DataSourceField> fields = super.addDataSourceFields(); DataSourceTextField conditionField = new DataSourceTextField(FIELD_CONDITION, MSG.view_alert_common_tab_conditions_text()); fields.add(conditionField); return fields; } @Override public AlertCondition copyValues(Record from) { return (AlertCondition) from.getAttributeAsObject(FIELD_OBJECT); } @Override public ListGridRecord copyValues(AlertCondition from) { ListGridRecord record = new ListGridRecord(); record.setAttribute(FIELD_CONDITION, AlertFormatUtility.formatAlertConditionForDisplay(from)); record.setAttribute(FIELD_OBJECT, from); return record; } @Override protected void executeFetch(DSRequest request, DSResponse response, Criteria unused) { response.setData(buildRecords(conditions)); processResponse(request.getRequestId(), response); } @Override protected Criteria getFetchCriteria(DSRequest request) { // we don't use criterias for this datasource, just return null return null; } } }