/*
* 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;
}
}