/* * RHQ Management Platform * Copyright (C) 2005-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 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.coregui.client.inventory.resource.detail.configuration; import java.util.ArrayList; import java.util.Date; import java.util.List; import com.smartgwt.client.data.DSRequest; import com.smartgwt.client.data.DataSourceField; import com.smartgwt.client.data.Record; import com.smartgwt.client.data.fields.DataSourceIntegerField; import com.smartgwt.client.types.Alignment; import com.smartgwt.client.types.ListGridFieldType; import com.smartgwt.client.widgets.Canvas; import com.smartgwt.client.widgets.grid.CellFormatter; import com.smartgwt.client.widgets.grid.HoverCustomizer; 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.configuration.AbstractConfigurationUpdate; import org.rhq.core.domain.configuration.AbstractResourceConfigurationUpdate; import org.rhq.core.domain.configuration.ConfigurationUpdateStatus; import org.rhq.core.domain.criteria.AbstractResourceConfigurationUpdateCriteria; import org.rhq.core.domain.resource.Resource; import org.rhq.core.domain.util.PageControl; import org.rhq.core.domain.util.PageOrdering; import org.rhq.coregui.client.ErrorMessageWindow; import org.rhq.coregui.client.LinkManager; import org.rhq.coregui.client.components.table.TimestampCellFormatter; import org.rhq.coregui.client.gwt.ConfigurationGWTServiceAsync; import org.rhq.coregui.client.gwt.GWTServiceLookup; import org.rhq.coregui.client.inventory.resource.AncestryUtil; import org.rhq.coregui.client.util.RPCDataSource; /** * A superclass data source that loads information about all the plugin/resource configuration changes that happened * for a resource or across all inventory. * * @author Greg Hinkle * @author John Mazzitelli */ public abstract class AbstractConfigurationHistoryDataSource<T extends AbstractResourceConfigurationUpdate, C extends AbstractResourceConfigurationUpdateCriteria> extends RPCDataSource<T, C> { public static abstract class Field { public static final String ID = "id"; public static final String CREATED_TIME = "createdTime"; public static final String STATUS = "status"; public static final String SUBJECT = "subjectName"; public static final String CONFIGURATION = "configuration"; public static final String GROUP_CONFIG_UPDATE_ID = "groupConfigUpdateId"; public static final String GROUP_ID = "groupId"; // will only be non-null if group config update id is non-null public static final String DURATION = "duration"; public static final String ERROR_MESSAGE = "errorMessage"; public static final String MODIFIED_TIME = "modifiedTime"; public static final String CURRENT_CONFIG = "currentConfig"; // will be true if the history item represents the current config public static final String OBJECT = "object"; // the full entity object is stored in this attribute } public static abstract class CriteriaField { public static final String RESOURCE_ID = "resourceId"; public static final String IDS = "ids"; } public static abstract class RequestProperty { public static final String FETCH_CONFIGURATION = "fetchConfiguration"; } // Specify 60s timeout to compensate for Configurations being fetched for all of the config updates. // TODO (ips, 08/31/11): Remove this once fetching of Configurations has been disabled. private ConfigurationGWTServiceAsync configurationService = GWTServiceLookup.getConfigurationService(60 * 1000); protected ConfigurationGWTServiceAsync getConfigurationService() { return this.configurationService; } public AbstractConfigurationHistoryDataSource() { super(); List<DataSourceField> fields = addDataSourceFields(); addFields(fields); } protected String getStatusHtmlString(Record record) { String html = null; AbstractConfigurationUpdate obj = (AbstractConfigurationUpdate) record.getAttributeAsObject(Field.OBJECT); switch (obj.getStatus()) { case SUCCESS: { html = MSG.view_configurationHistoryList_table_statusSuccess(); break; } case INPROGRESS: { html = "<p>" + MSG.view_configurationHistoryList_table_statusInprogress() + "</p>"; break; } case NOCHANGE: { html = MSG.view_configurationHistoryList_table_statusNochange(); break; } case FAILURE: { html = obj.getErrorMessage(); if (html == null) { html = "<p>" + MSG.view_configurationHistoryList_table_statusFailure() + "</p>"; } else { if (html.length() > 80) { // this was probably an error stack trace, snip it so the tooltip isn't too big html = "<pre>" + html.substring(0, 80) + "...</pre><p>" + MSG.view_configurationHistoryList_table_clickStatusIcon() + "</p>"; } else { html = "<pre>" + html + "</pre>"; } } break; } } return html; } /** * Views that use this data source can call this method to get a list of fields * that can be used in a list grid to show the data for this data source. * * @param includeResourceFields if true, the list of fields that are returned will * include fields to show individual resource data. * Pass in false if you are only collecting data on a * single resource, since you don't need every row to * show the same data on the same resource. * @return fields */ public ArrayList<ListGridField> getListGridFields(boolean includeResourceFields) { ArrayList<ListGridField> fields = new ArrayList<ListGridField>(); ListGridField idField = new ListGridField(Field.ID, MSG.common_title_version()); idField.setShowHover(true); idField.setHoverCustomizer(new HoverCustomizer() { @Override public String hoverHTML(Object value, ListGridRecord record, int rowNum, int colNum) { if (Boolean.parseBoolean(record.getAttribute(Field.CURRENT_CONFIG))) { return MSG.dataSource_configurationHistory_currentConfig(); } return null; } }); fields.add(idField); ListGridField submittedTimeField = new ListGridField(Field.CREATED_TIME, MSG .dataSource_configurationHistory_dateSubmitted()); submittedTimeField.setType(ListGridFieldType.DATE); TimestampCellFormatter.prepareDateField(submittedTimeField); fields.add(submittedTimeField); ListGridField completedTimeField = new ListGridField(Field.MODIFIED_TIME, MSG .dataSource_configurationHistory_dateCompleted()); completedTimeField.setType(ListGridFieldType.DATE); TimestampCellFormatter.prepareDateField(completedTimeField); fields.add(completedTimeField); ListGridField statusField = new ListGridField(Field.STATUS, MSG.common_title_status()); statusField.setAlign(Alignment.CENTER); statusField.setCellFormatter(new CellFormatter() { public String format(Object value, ListGridRecord listGridRecord, int i, int i1) { ConfigurationUpdateStatus status = ConfigurationUpdateStatus.valueOf(value.toString()); return Canvas.imgHTML(getConfigurationUpdateStatusIcon(status), 16, 16); } }); statusField.setShowHover(true); statusField.setHoverCustomizer(new HoverCustomizer() { @Override public String hoverHTML(Object value, ListGridRecord record, int rowNum, int colNum) { String html = getStatusHtmlString(record); return html; } }); statusField.addRecordClickHandler(new RecordClickHandler() { @Override public void onRecordClick(RecordClickEvent event) { String err = event.getRecord().getAttribute(Field.ERROR_MESSAGE); if (err != null && err.length() > 0) { err = "<pre>" + err + "</pre>"; new ErrorMessageWindow(MSG.common_severity_error(), err).show(); } } }); fields.add(statusField); ListGridField subjectField = new ListGridField(Field.SUBJECT, MSG.common_title_user()); fields.add(subjectField); ListGridField updateTypeField = new ListGridField(Field.GROUP_CONFIG_UPDATE_ID, MSG .dataSource_configurationHistory_updateType()); updateTypeField.setCellFormatter(new CellFormatter() { @Override public String format(Object value, ListGridRecord record, int rowNum, int colNum) { if (value == null) { return MSG.dataSource_configurationHistory_updateType_individual(); } Integer groupId = record.getAttributeAsInt(Field.GROUP_ID); return "<a href=\"" + getGroupConfigurationUpdateHistoryLink(groupId, (Number) value) + "\">" + MSG.dataSource_configurationHistory_updateType_group() + "</a>"; } }); fields.add(updateTypeField); // determine the widths of our columns if (includeResourceFields) { ListGridField resourceNameField = new ListGridField(AncestryUtil.RESOURCE_NAME, MSG.common_title_resource()); resourceNameField.setCellFormatter(new CellFormatter() { public String format(Object o, ListGridRecord listGridRecord, int i, int i1) { String url = LinkManager .getResourceLink(listGridRecord.getAttributeAsInt(AncestryUtil.RESOURCE_ID)); return LinkManager.getHref(url, o.toString()); } }); resourceNameField.setShowHover(true); resourceNameField.setHoverCustomizer(new HoverCustomizer() { public String hoverHTML(Object value, ListGridRecord listGridRecord, int rowNum, int colNum) { return AncestryUtil.getResourceHoverHTML(listGridRecord, 0); } }); fields.add(resourceNameField); ListGridField ancestryField = AncestryUtil.setupAncestryListGridField(); fields.add(ancestryField); idField.setWidth("10%"); submittedTimeField.setWidth(150); completedTimeField.setWidth(150); statusField.setWidth("10%"); subjectField.setWidth("10%"); updateTypeField.setWidth("10%"); resourceNameField.setWidth("30%"); ancestryField.setWidth("*"); } else { idField.setWidth("10%"); submittedTimeField.setWidth("20%"); completedTimeField.setWidth("20%"); statusField.setWidth("10%"); subjectField.setWidth("10%"); updateTypeField.setWidth("*"); } return fields; } @Override protected List<DataSourceField> addDataSourceFields() { List<DataSourceField> fields = super.addDataSourceFields(); DataSourceIntegerField idField = new DataSourceIntegerField(Field.ID, MSG.common_title_version()); idField.setPrimaryKey(true); fields.add(idField); return fields; } @SuppressWarnings("unchecked") @Override public T copyValues(Record from) { return (T) from.getAttributeAsObject(Field.OBJECT); } @Override public ListGridRecord copyValues(T from) { ListGridRecord record = new ListGridRecord(); record.setAttribute(Field.ID, from.getId()); record.setAttribute(Field.SUBJECT, from.getSubjectName()); record.setAttribute(Field.STATUS, from.getStatus().name()); record.setAttribute(Field.CONFIGURATION, from.getConfiguration()); record.setAttribute(Field.DURATION, from.getDuration()); record.setAttribute(Field.ERROR_MESSAGE, from.getErrorMessage()); record.setAttribute(Field.CREATED_TIME, new Date(from.getCreatedTime())); // if it is still in progress, the modified time (which we label as "date completed") is meaningless since it isn't completed yet if (from.getStatus() != ConfigurationUpdateStatus.INPROGRESS) { record.setAttribute(Field.MODIFIED_TIME, new Date(from.getModifiedTime())); } if (from.getAbstractGroupConfigurationUpdate() != null) { record.setAttribute(Field.GROUP_CONFIG_UPDATE_ID, from.getAbstractGroupConfigurationUpdate().getId()); record.setAttribute(Field.GROUP_ID, from.getAbstractGroupConfigurationUpdate().getGroup().getId()); // note group must be eagerly loaded here } // for ancestry handling Resource resource = from.getResource(); 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()); record.setAttribute(Field.OBJECT, from); return record; } @Override protected String getSortFieldForColumn(String columnName) { if (Field.GROUP_CONFIG_UPDATE_ID.equals(columnName)) { return "groupConfigurationUpdate.id"; } if (AncestryUtil.RESOURCE_ANCESTRY.equals(columnName)) { return "resource.ancestry"; } return super.getSortFieldForColumn(columnName); } protected abstract String getConfigurationUpdateStatusIcon(ConfigurationUpdateStatus status); protected abstract String getGroupConfigurationUpdateHistoryLink(Integer groupId, Number value); protected abstract C createFetchCriteria(); @Override protected C getFetchCriteria(DSRequest request) { C criteria = createFetchCriteria(); PageControl pageControl = getPageControl(request); pageControl.addDefaultOrderingField(Field.ID, PageOrdering.DESC); criteria.setPageControl(pageControl); List<Integer> ids = getFilter(request, CriteriaField.IDS, List.class); if (ids != null) { criteria.addFilterIds(ids.toArray(new Integer[0])); } Boolean fetchConfiguration = request.getAttributeAsBoolean(RequestProperty.FETCH_CONFIGURATION); if (fetchConfiguration != null && fetchConfiguration) { criteria.fetchConfiguration(true); } return criteria; } }