/*
* RHQ Management Platform
* Copyright 2011, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* 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.drift;
import java.util.ArrayList;
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.Record;
import com.smartgwt.client.data.SortSpecifier;
import com.smartgwt.client.rpc.RPCResponse;
import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.Autofit;
import com.smartgwt.client.types.ExpansionMode;
import com.smartgwt.client.types.ListGridFieldType;
import com.smartgwt.client.types.Overflow;
import com.smartgwt.client.types.SortDirection;
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.ListGrid;
import com.smartgwt.client.widgets.grid.ListGridField;
import com.smartgwt.client.widgets.grid.ListGridRecord;
import com.smartgwt.client.widgets.layout.Layout;
import org.rhq.core.domain.common.EntityContext;
import org.rhq.core.domain.criteria.DriftDefinitionCriteria;
import org.rhq.core.domain.drift.DriftCategory;
import org.rhq.core.domain.drift.DriftComplianceStatus;
import org.rhq.core.domain.drift.DriftDefinition;
import org.rhq.core.domain.resource.Resource;
import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.domain.util.PageList;
import org.rhq.core.domain.util.ResourceTypeUtility;
import org.rhq.coregui.client.CoreGUI;
import org.rhq.coregui.client.ImageManager;
import org.rhq.coregui.client.LinkManager;
import org.rhq.coregui.client.ViewPath;
import org.rhq.coregui.client.admin.templates.DriftDefinitionTemplateTypeView;
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.components.table.TableSection;
import org.rhq.coregui.client.drift.wizard.DriftAddDefinitionWizard;
import org.rhq.coregui.client.gwt.GWTServiceLookup;
import org.rhq.coregui.client.inventory.resource.AncestryUtil;
import org.rhq.coregui.client.util.RPCDataSource;
import org.rhq.coregui.client.util.enhanced.EnhancedIButton.ButtonColor;
import org.rhq.coregui.client.util.message.Message;
/**
* A list view that displays a paginated table of {@link org.rhq.core.domain.drift.DriftDefinitionTemplate}s. It
* offers various options on the list like filtering (maybe) and sorting, add new/delete. Double-click drills
* down to the detail view of the underlying Config. Rows expand to reveal the drift definitions derived from
* the template. This view fully respects the user's authorization, and will not allow actions on the templates
* unless the user is either the inventory manager or has MANAGE_DRIFT permission.
*
* @author Jay Shaughnessy
*/
public class DriftDefinitionTemplatesView extends TableSection<DriftDefinitionTemplateDataSource> {
private static SortSpecifier DEFAULT_SORT_SPECIFIER = new SortSpecifier(
DriftDefinitionTemplateDataSource.ATTR_NAME, SortDirection.ASCENDING);
private ResourceType type;
private boolean hasWriteAccess;
private DriftDefinitionTemplateDataSource dataSource;
private boolean useSnapshotDetailsView;
private String snapshotDriftDetailsId;
static {
DriftCategory[] categoryValues = DriftCategory.values();
String[] categoryNames = new String[categoryValues.length];
int i = 0;
for (DriftCategory c : categoryValues) {
categoryNames[i++] = c.name();
}
// Add any INITIAL_CRITERIA here (non currently)
}
// for subsystem views
public DriftDefinitionTemplatesView(ResourceType type, boolean hasWriteAccess) {
this(getTitle(type), type, hasWriteAccess);
}
protected DriftDefinitionTemplatesView(String tableTitle, ResourceType type, boolean hasWriteAccess) {
super(tableTitle, null, new SortSpecifier[] { DEFAULT_SORT_SPECIFIER });
this.type = type;
this.hasWriteAccess = hasWriteAccess;
setDataSource(getDataSource());
}
@Override
public DriftDefinitionTemplateDataSource getDataSource() {
if (null == this.dataSource) {
this.dataSource = new DriftDefinitionTemplateDataSource(type.getId());
}
return this.dataSource;
}
@Override
protected ListGrid createListGrid() {
return new DriftDefinitionTemplatesListGrid();
}
public static String getTitle(ResourceType type) {
return DriftDefinitionTemplateTypeView.VIEW_ID.getTitle() + " [" + ResourceTypeUtility.displayName(type) + "]";
}
@Override
protected void configureTableFilters() {
// currently no table filters
}
@Override
protected void configureTable() {
ArrayList<ListGridField> dataSourceFields = getDataSource().getListGridFields();
getListGrid().setFields(dataSourceFields.toArray(new ListGridField[dataSourceFields.size()]));
setupTableInteractions(this.hasWriteAccess);
super.configureTable();
}
private void setupTableInteractions(final boolean hasWriteAccess) {
TableActionEnablement addEnablement = hasWriteAccess ? TableActionEnablement.ALWAYS
: TableActionEnablement.NEVER;
TableActionEnablement deleteEnablement = hasWriteAccess ? TableActionEnablement.ANY
: TableActionEnablement.NEVER;
addTableAction(MSG.common_button_new(), ButtonColor.BLUE, new AbstractTableAction(addEnablement) {
public void executeAction(ListGridRecord[] selection, Object actionValue) {
add();
}
});
addTableAction(MSG.common_button_delete(), MSG.view_drift_confirm_deleteTemplate(), ButtonColor.RED, new AbstractTableAction(
deleteEnablement) {
boolean result = false;
@Override
public boolean isEnabled(ListGridRecord[] selection) {
if (super.isEnabled(selection)) {
for (ListGridRecord record : selection) {
if (!record.getAttributeAsBoolean(DriftDefinitionTemplateDataSource.ATTR_IS_USER_DEFINED)
.booleanValue()) {
return false;
}
}
result = true;
}
return result;
}
public void executeAction(ListGridRecord[] selection, Object actionValue) {
delete(selection);
}
});
}
private void add() {
DriftAddDefinitionWizard.showWizard(EntityContext.forTemplate(type.getId()), this);
// we can refresh the table buttons immediately since the wizard is a dialog, the
// user can't access enabled buttons anyway.
DriftDefinitionTemplatesView.this.refreshTableInfo();
}
private void delete(final ListGridRecord[] records) {
int[] templateIds = new int[records.length];
for (int i = 0; i < records.length; ++i) {
templateIds[i] = Integer.parseInt(records[i].getAttribute(DriftDefinitionTemplateDataSource.ATTR_ID));
}
GWTServiceLookup.getDriftService().deleteDriftDefinitionTemplates(templateIds, new AsyncCallback<Void>() {
@Override
public void onFailure(Throwable caught) {
CoreGUI.getErrorHandler().handleError(MSG.view_drift_failure_deleteTemplates(), caught);
DriftDefinitionTemplatesView.this.refresh();
}
@Override
public void onSuccess(Void result) {
CoreGUI.getMessageCenter().notify(
new Message(MSG.view_drift_success_deleteTemplate(Integer.toString(records.length)),
Message.Severity.Info));
DriftDefinitionTemplatesView.this.refresh();
}
});
}
@Override
public void renderView(ViewPath viewPath) {
// we have two detail views for drift def templates, the config editor and the pinned snapshot. Figure out which
// one we're dealing with. The default is the editor.
if (!viewPath.isEnd()) {
this.useSnapshotDetailsView = !viewPath.isNextEnd() && "Snapshot".equals(viewPath.getNext().getPath());
snapshotDriftDetailsId = null;
if (viewPath.viewsLeft() > 1) {
snapshotDriftDetailsId = viewPath.getViewForIndex(viewPath.getCurrentIndex() + 2).getPath()
.substring("0id_".length());
}
}
super.renderView(viewPath);
}
@Override
public Canvas getDetailsView(Integer driftTemplateId) {
if (this.useSnapshotDetailsView) {
if (null == snapshotDriftDetailsId) {
return new DriftDefinitionTemplateSnapshotView(driftTemplateId);
}
return new DriftDetailsView(snapshotDriftDetailsId);
}
return new DriftDefinitionTemplateEditView(driftTemplateId, hasWriteAccess);
}
/**
* The expandable list grid
*/
private class DriftDefinitionTemplatesListGrid extends ListGrid {
public DriftDefinitionTemplatesListGrid() {
super();
setCanExpandRecords(true);
setCanExpandMultipleRecords(true);
setExpansionMode(ExpansionMode.RELATED);
}
@Override
protected Canvas getExpansionComponent(ListGridRecord record) {
int templateId = record.getAttributeAsInt(DriftDefinitionTemplateDataSource.ATTR_ID);
String templateName = record.getAttribute(DriftDefinitionTemplateDataSource.ATTR_NAME);
return new TemplateDefinitionsView(templateId);
}
}
/**
* The expanded row table view of definitions derived from the template
*/
public class TemplateDefinitionsView extends Table<TemplateDefinitionsView.TemplateDefinitionsDataSource> {
private int templateId;
private TemplateDefinitionsDataSource dataSource;
public TemplateDefinitionsView(int templateId) {
super(null, true);
this.templateId = templateId;
setShowFilterForm(false);
setShowHeader(false);
setShowFooter(false);
setDataSource(getDataSource());
}
@Override
public TemplateDefinitionsDataSource getDataSource() {
if (null == dataSource) {
dataSource = new TemplateDefinitionsDataSource();
}
return dataSource;
}
@Override
protected void configureTable() {
ArrayList<ListGridField> dataSourceFields = getDataSource().getListGridFields();
getListGrid().setFields(dataSourceFields.toArray(new ListGridField[dataSourceFields.size()]));
super.configureTable();
}
@Override
protected void configureTableContents(Layout contents) {
contents.setWidth100();
contents.setHeight100();
contents.setOverflow(Overflow.VISIBLE);
}
@Override
protected ListGrid createListGrid() {
return new TemplateDefinitionsListGrid();
}
@Override
protected void configureListGrid(ListGrid grid) {
grid.setDefaultHeight(1);
grid.setAutoFitData(Autofit.VERTICAL);
}
/**
* The definitions list grid
*/
private class TemplateDefinitionsListGrid extends ListGrid {
public TemplateDefinitionsListGrid() {
super();
}
}
public class TemplateDefinitionsDataSource extends RPCDataSource<DriftDefinition, DriftDefinitionCriteria> {
public TemplateDefinitionsDataSource() {
addDataSourceFields();
}
public ArrayList<ListGridField> getListGridFields() {
ArrayList<ListGridField> fields = new ArrayList<ListGridField>(6);
ListGridField nameField = new ListGridField(DriftDefinitionDataSource.ATTR_NAME,
MSG.common_title_name());
nameField.setCellFormatter(new CellFormatter() {
public String format(Object o, ListGridRecord listGridRecord, int i, int i1) {
Integer resourceId = listGridRecord.getAttributeAsInt(AncestryUtil.RESOURCE_ID);
Integer driftDefId = listGridRecord.getAttributeAsInt("id");
String url = LinkManager.getDriftDefinitionCarouselLink(resourceId, driftDefId);
return LinkManager.getHref(url, o.toString());
}
});
fields.add(nameField);
ListGridField descriptionField = new ListGridField(DriftDefinitionDataSource.ATTR_DESCRIPTION,
MSG.common_title_description());
fields.add(descriptionField);
ListGridField attachedField = new ListGridField(DriftDefinitionDataSource.ATTR_ATTACHED,
MSG.view_drift_table_attached());
fields.add(attachedField);
ListGridField enabledField = new ListGridField(DriftDefinitionDataSource.ATTR_IS_ENABLED_ICON,
MSG.common_title_enabled());
enabledField.setType(ListGridFieldType.IMAGE);
enabledField.setAlign(Alignment.CENTER);
fields.add(enabledField);
ListGridField inComplianceField = new ListGridField(DriftDefinitionDataSource.ATTR_COMPLIANCE_ICON,
MSG.common_title_in_compliance());
inComplianceField.setType(ListGridFieldType.IMAGE);
inComplianceField.setAlign(Alignment.CENTER);
inComplianceField.setShowHover(true);
inComplianceField.setHoverCustomizer(new HoverCustomizer() {
@Override
public String hoverHTML(Object o, ListGridRecord record, int row, int column) {
int complianceCode = record.getAttributeAsInt(DriftDefinitionDataSource.ATTR_COMPLIANCE);
DriftComplianceStatus complianceStatus = DriftComplianceStatus.fromCode(complianceCode);
switch (complianceStatus) {
case OUT_OF_COMPLIANCE_NO_BASEDIR:
return MSG.view_drift_table_hover_outOfCompliance_noBaseDir();
case OUT_OF_COMPLIANCE_DRIFT:
return MSG.view_drift_table_hover_outOfCompliance_drift();
default:
return "";
}
}
});
fields.add(inComplianceField);
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) {
Integer resourceId = listGridRecord.getAttributeAsInt(AncestryUtil.RESOURCE_ID);
String url = LinkManager.getResourceLink(resourceId);
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);
nameField.setWidth("15%");
descriptionField.setWidth("25%");
attachedField.setWidth(70);
enabledField.setWidth(60);
inComplianceField.setWidth(100);
resourceNameField.setWidth("20%");
ancestryField.setWidth("*");
return fields;
}
@Override
protected void executeFetch(final DSRequest request, final DSResponse response,
DriftDefinitionCriteria criteria) {
GWTServiceLookup.getDriftService().findDriftDefinitionsByCriteria(criteria,
new AsyncCallback<PageList<DriftDefinition>>() {
public void onFailure(Throwable caught) {
CoreGUI.getErrorHandler().handleError(MSG.view_drift_failure_load(), caught);
response.setStatus(RPCResponse.STATUS_FAILURE);
processResponse(request.getRequestId(), response);
}
public void onSuccess(final PageList<DriftDefinition> result) {
response.setData(buildRecords(result));
response.setTotalRows(result.getTotalSize());
processResponse(request.getRequestId(), response);
}
});
}
@Override
protected DriftDefinitionCriteria getFetchCriteria(DSRequest request) {
DriftDefinitionCriteria criteria = new DriftDefinitionCriteria();
criteria.addFilterTemplateId(templateId);
criteria.fetchResource(true);
return criteria;
}
@Override
public DriftDefinition copyValues(Record from) {
return null;
}
@Override
public ListGridRecord copyValues(DriftDefinition from) {
ListGridRecord record = new ListGridRecord();
record.setAttribute(DriftDefinitionDataSource.ATTR_ID, from.getId());
record.setAttribute(DriftDefinitionDataSource.ATTR_NAME, from.getName());
record.setAttribute(DriftDefinitionDataSource.ATTR_DESCRIPTION, from.getDescription());
record.setAttribute(DriftDefinitionDataSource.ATTR_IS_ENABLED, String.valueOf(from.isEnabled()));
record.setAttribute(DriftDefinitionDataSource.ATTR_IS_ENABLED_ICON,
ImageManager.getAvailabilityIcon(from.isEnabled()));
record.setAttribute(DriftDefinitionDataSource.ATTR_COMPLIANCE, from.getComplianceStatus().ordinal());
record
.setAttribute(DriftDefinitionDataSource.ATTR_COMPLIANCE_ICON, ImageManager.getAvailabilityIcon(from
.getComplianceStatus() == DriftComplianceStatus.IN_COMPLIANCE));
record.setAttribute(DriftDefinitionDataSource.ATTR_ATTACHED, from.isAttached() ? MSG.common_val_yes()
: MSG.common_val_no());
// 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());
return record;
}
}
}
}