/* * RHQ Management Platform * Copyright (C) 2005-2014 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ package org.rhq.coregui.client.inventory.resource.detail; import static org.rhq.coregui.client.components.form.DateFilterItem.adjustTimeToEndOfDay; import static org.rhq.coregui.client.components.form.DateFilterItem.adjustTimeToStartOfDay; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.datepicker.client.CalendarUtil; import com.smartgwt.client.data.DSRequest; import com.smartgwt.client.data.DSResponse; import com.smartgwt.client.data.Record; import com.smartgwt.client.types.ListGridFieldType; import com.smartgwt.client.types.SortDirection; import com.smartgwt.client.widgets.Canvas; 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.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 org.rhq.core.domain.criteria.Criteria; import org.rhq.core.domain.resource.CreateResourceHistory; import org.rhq.core.domain.resource.CreateResourceStatus; import org.rhq.core.domain.resource.DeleteResourceHistory; import org.rhq.core.domain.resource.DeleteResourceStatus; import org.rhq.core.domain.resource.composite.ResourceComposite; 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.ImageManager; import org.rhq.coregui.client.components.form.DateFilterItem; import org.rhq.coregui.client.components.table.Table; import org.rhq.coregui.client.components.table.TimestampCellFormatter; import org.rhq.coregui.client.components.view.ViewName; import org.rhq.coregui.client.gwt.GWTServiceLookup; import org.rhq.coregui.client.util.RPCDataSource; import org.rhq.coregui.client.util.async.Command; import org.rhq.coregui.client.util.async.CountDownLatch; /** * @author John Mazzitelli */ public class ChildHistoryView extends Table<ChildHistoryView.DataSource> { public static final ViewName VIEW_ID = new ViewName("ChildHistory", MSG.view_tabs_common_child_history()); public static final String CHILD_CREATED_ICON = ImageManager.getChildCreateIcon(); public static final String CHILD_DELETED_ICON = ImageManager.getChildDeleteIcon(); private final ResourceComposite resourceComposite; private DateFilterItem startDateFilter; private DateFilterItem endDateFilter; public ChildHistoryView(ResourceComposite resourceComposite) { super(VIEW_ID.getTitle()); this.resourceComposite = resourceComposite; setDataSource(new DataSource()); } @Override protected void configureTableFilters() { endDateFilter = new DateFilterItem(DateFilterItem.END_DATE_FILTER, MSG.filter_to_date()); Date date = new Date(); endDateFilter.setValue(date); startDateFilter = new DateFilterItem(DateFilterItem.START_DATE_FILTER, MSG.filter_from_date()); CalendarUtil.addMonthsToDate(date, -1); startDateFilter.setValue(date); if (isShowFilterForm()) { setFilterFormItems(startDateFilter, endDateFilter); } } @Override protected void configureTable() { ListGridField idField = new ListGridField(DataSource.Field.ID, MSG.common_title_id()); idField.setWidth(75); ListGridField typeField = new ListGridField(DataSource.Field.TYPE, MSG.common_title_type()); typeField.setWidth(75); typeField.setType(ListGridFieldType.ICON); HashMap<String, String> typeIcons = new HashMap<String, String>(2); typeIcons.put(DataSource.TYPE_CREATE, CHILD_CREATED_ICON); typeIcons.put(DataSource.TYPE_DELETE, CHILD_DELETED_ICON); typeField.setValueIcons(typeIcons); typeField.setShowHover(true); typeField.setHoverCustomizer(new HoverCustomizer() { public String hoverHTML(Object value, ListGridRecord record, int rowNum, int colNum) { String type = record.getAttribute(DataSource.Field.TYPE); if (DataSource.TYPE_CREATE.equals(type)) { return MSG.view_resource_inventory_childhistory_createdChild(); } else if (DataSource.TYPE_DELETE.equals(type)) { return MSG.view_resource_inventory_childhistory_deletedChild(); } else { return "?"; // should never happen } } }); ListGridField createdField = new ListGridField(DataSource.Field.CREATED_DATE, MSG.common_title_dateCreated()); TimestampCellFormatter.prepareDateField(createdField); ListGridField modifiedField = new ListGridField(DataSource.Field.LAST_MODIFIED_TIME, MSG.common_title_lastUpdated()); TimestampCellFormatter.prepareDateField(modifiedField); ListGridField subjectField = new ListGridField(DataSource.Field.SUBJECT_NAME, MSG.common_title_user()); ListGridField statusField = new ListGridField(DataSource.Field.STATUS, MSG.common_title_status()); statusField.setCellFormatter(new CellFormatter() { public String format(Object value, ListGridRecord record, int rowNum, int colNum) { String type = record.getAttribute(DataSource.Field.TYPE); if (DataSource.TYPE_CREATE.equals(type)) { switch (CreateResourceStatus.valueOf(value.toString())) { case SUCCESS: return MSG.common_status_success(); case FAILURE: return MSG.common_status_failed(); case IN_PROGRESS: return MSG.common_status_inprogress(); case INVALID_ARTIFACT: return MSG.view_resource_inventory_childhistory_status_invalidArtifact(); case INVALID_CONFIGURATION: return MSG.view_resource_inventory_childhistory_status_invalidConfig(); case TIMED_OUT: return MSG.widget_resourceFactoryWizard_timeoutFailure(); } } else if (DataSource.TYPE_DELETE.equals(type)) { switch (DeleteResourceStatus.valueOf(value.toString())) { case SUCCESS: return MSG.common_status_success(); case FAILURE: return MSG.common_status_failed(); case IN_PROGRESS: return MSG.common_status_inprogress(); case TIMED_OUT: return MSG.common_status_timedOut(); } } return "?"; // should never happen } }); setListGridFields(idField, typeField, createdField, modifiedField, subjectField, statusField); // Add a double click handler to show the details for the selected row. // Notice this goes against our normal UI design. I would normally have used TableSection // and have the details canvas created via the getDetails API. // This would make our details view bookmarkable. However, the old design of the create/delete // history makes determining what entity to use via an ID is not possible (the create/delete // history is split into two tables). So, I'll just pop up the audit details in a dialog window. setListGridDoubleClickHandler(new DoubleClickHandler() { public void onDoubleClick(DoubleClickEvent event) { ListGrid listGrid = (ListGrid) event.getSource(); ListGridRecord[] selectedRows = listGrid.getSelectedRecords(); if (selectedRows != null && selectedRows.length == 1) { String typeString = selectedRows[0].getAttribute(DataSource.Field.TYPE); ChildHistoryDetails detailsView = null; if (DataSource.TYPE_CREATE.equals(typeString)) { CreateResourceHistory history = (CreateResourceHistory) selectedRows[0] .getAttributeAsObject(DataSource.Field.OBJECT); detailsView = new ChildHistoryDetails(history); } else if (DataSource.TYPE_DELETE.equals(typeString)) { DeleteResourceHistory history = (DeleteResourceHistory) selectedRows[0] .getAttributeAsObject(DataSource.Field.OBJECT); detailsView = new ChildHistoryDetails(history); } new DetailsWindow(detailsView).show(); } } }); ListGrid listGrid = getListGrid(); listGrid.setSortField(DataSource.Field.CREATED_DATE); listGrid.setSortDirection(SortDirection.DESCENDING); } class DataSource extends RPCDataSource<Object, Criteria> { public static final String TYPE_CREATE = "create"; public static final String TYPE_DELETE = "delete"; public class Field { public static final String ID = "id"; public static final String CREATED_DATE = "createdDate"; public static final String LAST_MODIFIED_TIME = "lastModifiedDate"; public static final String SUBJECT_NAME = "subjectName"; public static final String STATUS = "status"; // name of either [Create,Delete]ResourceStatus public static final String TYPE = "historyType"; // will be either TYPE_CREATE or TYPE_DELETE public static final String OBJECT = "object"; } /** * Given a record, returns either the CreateResourceHistory or the DeleteResourceHistory entity object * that the record represents. * * @param from a record that represents either a create or delete resource history item * @return the create/delete resource history item */ @Override public Object copyValues(Record from) { return from.getAttributeAsObject(Field.OBJECT); } /** * Given either a CreateResourceHistory or a DeleteResourceHistory entity object, * returns its record representation. * * @param from a create or delete resource history item * @return the record that represents the given history item */ @Override public ListGridRecord copyValues(Object from) { ListGridRecord record = new ListGridRecord(); record.setAttribute(Field.OBJECT, from); if (from instanceof CreateResourceHistory) { CreateResourceHistory history = (CreateResourceHistory) from; record.setAttribute(Field.TYPE, TYPE_CREATE); record.setAttribute(Field.ID, history.getId()); record.setAttribute(Field.SUBJECT_NAME, history.getSubjectName()); record.setAttribute(Field.CREATED_DATE, history.getCreatedDate()); record.setAttribute(Field.LAST_MODIFIED_TIME, history.getLastModifiedDate()); record.setAttribute(Field.STATUS, history.getStatus().name()); } else if (from instanceof DeleteResourceHistory) { DeleteResourceHistory history = (DeleteResourceHistory) from; record.setAttribute(Field.TYPE, TYPE_DELETE); record.setAttribute(Field.ID, history.getId()); record.setAttribute(Field.SUBJECT_NAME, history.getSubjectName()); record.setAttribute(Field.CREATED_DATE, history.getCreatedDate()); record.setAttribute(Field.LAST_MODIFIED_TIME, history.getLastModifiedDate()); record.setAttribute(Field.STATUS, history.getStatus().name()); } else { CoreGUI.getErrorHandler().handleError("invalid child history type: " + from.getClass()); // should never occur } return record; } @Override protected void executeFetch(final DSRequest request, final DSResponse response, Criteria criteria) { Date startDate, endDate; try { startDate = startDateFilter.getValueAsDate(); endDate = endDateFilter.getValueAsDate(); } catch (Exception e) { // Value parsed is not a date processResults(request, response, Collections.emptyList()); return; } if (startDate == null || endDate == null) { processResults(request, response, Collections.emptyList()); return; } long start = adjustTimeToStartOfDay(startDate).getTime(); long end = adjustTimeToEndOfDay(endDate).getTime(); final List<Object> fullList = new ArrayList<Object>(); final CountDownLatch latch = CountDownLatch.create(2, new Command() { @Override public void execute() { processResults(request, response, fullList); } }); GWTServiceLookup.getResourceService().findCreateChildResourceHistory( resourceComposite.getResource().getId(), start, end, PageControl.getUnlimitedInstance(), new AsyncCallback<PageList<CreateResourceHistory>>() { @Override public void onSuccess(final PageList<CreateResourceHistory> createList) { fullList.addAll(createList); latch.countDown(); } @Override public void onFailure(Throwable caught) { CoreGUI.getErrorHandler().handleError("Failed to load child create history", caught); latch.countDown(); } }); GWTServiceLookup.getResourceService().findDeleteChildResourceHistory( resourceComposite.getResource().getId(), start, end, PageControl.getUnlimitedInstance(), new AsyncCallback<PageList<DeleteResourceHistory>>() { @Override public void onSuccess(final PageList<DeleteResourceHistory> deleteList) { fullList.addAll(deleteList); latch.countDown(); } @Override public void onFailure(Throwable caught) { CoreGUI.getErrorHandler().handleError("Failed to load child delete history", caught); latch.countDown(); } }); } private void processResults(DSRequest request, DSResponse response, List<Object> fullList) { ListGridRecord[] records = buildRecords(fullList); response.setData(records); processResponse(request.getRequestId(), response); } @Override protected Criteria getFetchCriteria(DSRequest request) { return null; // using special server side API to get the create/delete histories, no criteria involved } } class DetailsWindow extends Window { public DetailsWindow(Canvas canvas) { super(); setTitle(MSG.common_title_details()); setShowMinimizeButton(false); setShowMaximizeButton(true); setIsModal(true); setShowModalMask(true); setWidth(600); setHeight(400); setAutoCenter(true); setShowResizer(true); setCanDragResize(true); centerInPage(); addCloseClickHandler(new CloseClickHandler() { public void onCloseClick(CloseClickEvent event) { markForDestroy(); } }); if (canvas != null) { addItem(canvas); } } } }