package org.rhq.coregui.client.dashboard.portlets.recent.operations;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import com.google.gwt.user.client.Timer;
import com.smartgwt.client.data.DSRequest;
import com.smartgwt.client.data.DSResponse;
import com.smartgwt.client.types.Overflow;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.HTMLFlow;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.events.SubmitValuesEvent;
import com.smartgwt.client.widgets.form.events.SubmitValuesHandler;
import com.smartgwt.client.widgets.form.fields.CheckboxItem;
import com.smartgwt.client.widgets.form.fields.FormItem;
import com.smartgwt.client.widgets.form.fields.SelectItem;
import org.rhq.core.domain.authz.Permission;
import org.rhq.core.domain.common.EntityContext;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.domain.criteria.ResourceOperationHistoryCriteria;
import org.rhq.core.domain.dashboard.DashboardPortlet;
import org.rhq.core.domain.operation.OperationRequestStatus;
import org.rhq.core.domain.operation.ResourceOperationHistory;
import org.rhq.core.domain.resource.composite.ResourcePermission;
import org.rhq.core.domain.util.OrderingField;
import org.rhq.core.domain.util.PageControl;
import org.rhq.core.domain.util.PageList;
import org.rhq.core.domain.util.PageOrdering;
import org.rhq.coregui.client.LinkManager;
import org.rhq.coregui.client.components.measurement.CustomConfigMeasurementRangeEditor;
import org.rhq.coregui.client.dashboard.AutoRefreshPortlet;
import org.rhq.coregui.client.dashboard.AutoRefreshUtil;
import org.rhq.coregui.client.dashboard.CustomSettingsPortlet;
import org.rhq.coregui.client.dashboard.PortletWindow;
import org.rhq.coregui.client.dashboard.portlets.PortletConfigurationEditorComponent;
import org.rhq.coregui.client.dashboard.portlets.PortletConfigurationEditorComponent.Constant;
import org.rhq.coregui.client.operation.OperationHistoryDataSource;
import org.rhq.coregui.client.operation.OperationHistoryView;
import org.rhq.coregui.client.util.MeasurementUtility;
import org.rhq.coregui.client.util.enhanced.EnhancedVLayout;
/**
* A base class for deriving recent resource operations portlets for different entity contexts. In this way the
* basic plumbing is shared, giving a consistent behavior and configuration for the concrete portlets.
*
* @author Jay Shaughnessy
* @author Simeon Pinder
*/
public abstract class AbstractOperationHistoryPortlet extends OperationHistoryView implements CustomSettingsPortlet,
AutoRefreshPortlet {
// set on initial configuration, the window for this portlet view.
private PortletWindow portletWindow;
private OperationHistoryPortletDataSource dataSource;
private Boolean hasControlPermission;
// autorefresh timer
private Timer refreshTimer;
private String baseViewPath;
public AbstractOperationHistoryPortlet(EntityContext entityContext) {
super(null, entityContext);
this.baseViewPath = LinkManager.getEntityTabLink(getContext(), "Operations", "History");
setShowFilterForm(false); //disable filter form for portlet
setOverflow(Overflow.VISIBLE);
setShowFooterRefresh(false); //disable footer refresh button as redundant for portlets
setShowHeader(false);//disable header for portlets
}
public Timer getRefreshTimer() {
return refreshTimer;
}
public void setRefreshTimer(Timer refreshTimer) {
this.refreshTimer = refreshTimer;
}
public PortletWindow getPortletWindow() {
return portletWindow;
}
@Override
public OperationHistoryPortletDataSource getDataSource() {
if (null == this.dataSource) {
this.dataSource = new OperationHistoryPortletDataSource(getContext());
}
return this.dataSource;
}
@Override
protected String getBasePath() {
return this.baseViewPath;
}
@Override
public Canvas getHelpCanvas() {
return new HTMLFlow(MSG.view_portlet_help_operations_criteria());
}
@Override
public void configure(PortletWindow portletWindow, DashboardPortlet storedPortlet) {
// the portletWindow does not change, so we can hold onto it locally
if (null == this.portletWindow && null != portletWindow) {
this.portletWindow = portletWindow;
}
// if there is no configuration there is nothing to set
if ((null == storedPortlet) || (null == storedPortlet.getConfiguration())) {
return;
}
Configuration config = storedPortlet.getConfiguration();
// not sure I love the fact that this common portlet config assigns some irrelevant/unused config props,
// may be better to prune the common set and add the specific properties locally in this method
for (String key : PortletConfigurationEditorComponent.CONFIG_PROPERTY_INITIALIZATION.keySet()) {
if (config.getSimple(key) == null) {
config.put(new PropertySimple(key, PortletConfigurationEditorComponent.CONFIG_PROPERTY_INITIALIZATION
.get(key)));
}
}
getDataSource().setConfiguration(config);
}
@Override
public DynamicForm getCustomSettingsForm() {
DynamicForm customSettingsForm = new DynamicForm();
EnhancedVLayout page = new EnhancedVLayout();
DynamicForm filterForm = new DynamicForm();
filterForm.setMargin(5);
final DashboardPortlet storedPortlet = this.portletWindow.getStoredPortlet();
final Configuration portletConfig = storedPortlet.getConfiguration();
// operation history status selector
final SelectItem operationStatusSelector = PortletConfigurationEditorComponent
.getOperationStatusEditor(portletConfig);
// result count selector
final SelectItem resultCountSelector = PortletConfigurationEditorComponent.getResultCountEditor(portletConfig);
// range selector
final CustomConfigMeasurementRangeEditor measurementRangeEditor = PortletConfigurationEditorComponent
.getMeasurementRangeEditor(portletConfig);
filterForm.setItems(operationStatusSelector, resultCountSelector);
//submit handler
customSettingsForm.addSubmitValuesHandler(new SubmitValuesHandler() {
@Override
public void onSubmitValues(SubmitValuesEvent event) {
// operation status
String selectedValue = (null == operationStatusSelector.getValue()) ? "" : operationStatusSelector
.getValue().toString();
if ((selectedValue.trim().isEmpty())
|| (selectedValue.split(",").length == OperationRequestStatus.values().length)) {
selectedValue = Constant.OPERATION_STATUS_DEFAULT;
}
portletConfig.put(new PropertySimple(Constant.OPERATION_STATUS, selectedValue));
// result count
selectedValue = resultCountSelector.getValue().toString();
if (selectedValue.trim().isEmpty()) {
selectedValue = Constant.RESULT_COUNT_DEFAULT;
}
portletConfig.put(new PropertySimple(Constant.RESULT_COUNT, selectedValue));
// time range settings
saveMeasurementRangeEditorSettings(measurementRangeEditor, portletConfig);
// persist and reload portlet
storedPortlet.setConfiguration(portletConfig);
configure(portletWindow, storedPortlet);
//apply latest settings to the visible result set
refresh();
}
});
page.addMember(measurementRangeEditor);
page.addMember(filterForm);
customSettingsForm.addChild(page);
return customSettingsForm;
}
/**
* Takes the current value of the widget and persists it into the configuration object passed in.
*
* @param measurementRangeEditor
* @param portletConfig
* returns populated configuration object.
*/
private void saveMeasurementRangeEditorSettings(final CustomConfigMeasurementRangeEditor measurementRangeEditor,
Configuration portletConfig) {
String selectedValue = null;
if ((measurementRangeEditor != null) && (portletConfig != null)) {
//time range filter. Check for enabled and then persist property. Dealing with compound widget.
FormItem item = measurementRangeEditor.getItem(CustomConfigMeasurementRangeEditor.ENABLE_RANGE_ITEM);
CheckboxItem itemC = (CheckboxItem) item;
boolean persistTimeRangeSettings = itemC.getValueAsBoolean();
if (persistTimeRangeSettings) {//retrieve values and persist
selectedValue = String.valueOf(itemC.getValueAsBoolean());
if (!selectedValue.trim().isEmpty()) {//then call
portletConfig.put(new PropertySimple(Constant.METRIC_RANGE_ENABLE, selectedValue));
}
//time advanced time filter enabled.
boolean isAdvanceTimeSetting = false;
selectedValue = String.valueOf(measurementRangeEditor.isAdvanced());
if ((selectedValue != null) && (!selectedValue.trim().isEmpty())) {
portletConfig.put(new PropertySimple(Constant.METRIC_RANGE_BEGIN_END_FLAG, selectedValue));
isAdvanceTimeSetting = Boolean.valueOf(selectedValue);
}
//time frame
List<Long> begEnd = measurementRangeEditor.getBeginEndTimes();
if (isAdvanceTimeSetting) {//advanced settings
portletConfig.put(new PropertySimple(Constant.METRIC_RANGE, (begEnd.get(0) + "," + begEnd.get(1))));
} else {
//save not advanced time range
portletConfig.put(new PropertySimple(Constant.METRIC_RANGE_LASTN, measurementRangeEditor
.getMetricRangePreferences().lastN));
portletConfig.put(new PropertySimple(Constant.METRIC_RANGE_UNIT, measurementRangeEditor
.getMetricRangePreferences().unit));
}
} else {//if disabled, reset time defaults
portletConfig.put(new PropertySimple(Constant.METRIC_RANGE_ENABLE, false));
portletConfig.put(new PropertySimple(Constant.METRIC_RANGE_BEGIN_END_FLAG, false));
List<Long> rangeArray = MeasurementUtility.calculateTimeFrame(
Integer.valueOf(Constant.METRIC_RANGE_LASTN_DEFAULT),
Integer.valueOf(Constant.METRIC_RANGE_UNIT_DEFAULT));
// String[] range = {String.valueOf(rangeArray.get(0)),String.valueOf(rangeArray.get(1))};
portletConfig.put(new PropertySimple(Constant.METRIC_RANGE,
(String.valueOf(rangeArray.get(0)) + "," + String.valueOf(rangeArray.get(1)))));
}
}
}
protected boolean hasControlPermission() {
if (null == this.hasControlPermission) {
Set<Permission> globalPerm = this.getPortletWindow().getGlobalPermissions();
ResourcePermission resPerm = this.getPortletWindow().getResourcePermissions();
this.hasControlPermission = (globalPerm.contains(Permission.MANAGE_INVENTORY) || (null != resPerm && resPerm
.isControl()));
}
return this.hasControlPermission;
}
@Override
public void refreshTableInfo() {
super.refreshTableInfo();
if (getTableInfo() != null) {
int count = getListGrid().getSelectedRecords().length;
getTableInfo().setContents(
MSG.view_table_matchingRows(String.valueOf(getListGrid().getTotalRows()), String.valueOf(count)));
}
}
public void startRefreshCycle() {
refreshTimer = AutoRefreshUtil.startRefreshCycleWithPageRefreshInterval(this, this, refreshTimer);
}
public boolean isRefreshing() {
return false;
}
@Override
public void refresh() {
if (!isRefreshing()) {
super.refresh();
}
}
@Override
protected void onDestroy() {
AutoRefreshUtil.onDestroy(refreshTimer);
super.onDestroy();
}
static public class OperationHistoryPortletDataSource extends OperationHistoryDataSource {
private Configuration configuration;
public OperationHistoryPortletDataSource(EntityContext entityContext) {
this(entityContext, null);
}
public OperationHistoryPortletDataSource(EntityContext entityContext, Configuration configuration) {
super(entityContext);
this.configuration = configuration;
}
public Configuration getConfiguration() {
return configuration;
}
public void setConfiguration(Configuration configuration) {
this.configuration = configuration;
}
/* (non-Javadoc)
* This override allows us to set the total rows to the number of recent op history configured for
* the portlet. This sets the counter appropriately and stops further queries to the server.
*
* @see org.rhq.coregui.client.operation.OperationHistoryDataSource#getTotalRows(org.rhq.core.domain.util.PageList, com.smartgwt.client.data.DSResponse, com.smartgwt.client.data.DSRequest)
*/
@Override
protected int getTotalRows(final PageList<ResourceOperationHistory> result, final DSResponse response,
final DSRequest request) {
return result.size();
}
@Override
protected void setPagingInfo(DSResponse response, PageList<?> pageList) {
response.setTotalRows(pageList.size());
}
@Override
protected ResourceOperationHistoryCriteria getFetchCriteria(DSRequest request) {
ResourceOperationHistoryCriteria criteria = new ResourceOperationHistoryCriteria();
// result count
String currentSetting = this.configuration.getSimpleValue(Constant.RESULT_COUNT,
Constant.RESULT_COUNT_DEFAULT);
// We have to set a PageControl override here, or RPCDataSource will apply default paging based on the
// request. But, once setting a paging override the CriteriaQueryGenerator will use it for
// paging *and* sorting, so we need to also ensure our desired sorting is included in the override. So,
// to get the most recent op histories, apply a descending ordering on create time.
int pageNumber = 0;
int pageSize = Integer.valueOf(currentSetting);
OrderingField orderingField = new OrderingField(OperationHistoryDataSource.Field.CREATED_TIME,
PageOrdering.DESC);
criteria.setPageControl(new PageControl(pageNumber, pageSize, orderingField));
// status
currentSetting = this.configuration.getSimpleValue(Constant.OPERATION_STATUS,
Constant.OPERATION_STATUS_DEFAULT);
String[] parsedValues = currentSetting.trim().split(",");
if (!(currentSetting.trim().isEmpty() || parsedValues.length == OperationRequestStatus.values().length)) {
OperationRequestStatus[] operationStatuses = new OperationRequestStatus[parsedValues.length];
int indx = 0;
for (String priority : parsedValues) {
OperationRequestStatus s = OperationRequestStatus.valueOf(priority);
operationStatuses[indx++] = s;
}
criteria.addFilterStatuses(operationStatuses);
}
//result timeframe if enabled
PropertySimple property = configuration.getSimple(Constant.METRIC_RANGE_ENABLE);
if (null != property && Boolean.valueOf(property.getBooleanValue())) {//then proceed setting
boolean isAdvanced = Boolean.valueOf(configuration.getSimpleValue(Constant.METRIC_RANGE_BEGIN_END_FLAG,
Constant.METRIC_RANGE_BEGIN_END_FLAG_DEFAULT));
if (isAdvanced) {
//Advanced time settings
currentSetting = configuration.getSimpleValue(Constant.METRIC_RANGE, Constant.METRIC_RANGE_DEFAULT);
String[] range = currentSetting.split(",");
if (range.length == 2) {
criteria.addFilterStartTime(Long.valueOf(range[0]));
criteria.addFilterEndTime(Long.valueOf(range[1]));
}
} else {
//Simple time settings
property = configuration.getSimple(Constant.METRIC_RANGE_LASTN);
if (property != null) {
Integer lastN = Integer.valueOf(configuration.getSimpleValue(Constant.METRIC_RANGE_LASTN,
Constant.METRIC_RANGE_LASTN_DEFAULT));
Integer units = Integer.valueOf(configuration.getSimpleValue(Constant.METRIC_RANGE_UNIT,
Constant.METRIC_RANGE_UNIT_DEFAULT));
ArrayList<Long> beginEnd = MeasurementUtility.calculateTimeFrame(lastN, units);
criteria.addFilterStartTime(Long.valueOf(beginEnd.get(0)));
criteria.addFilterEndTime(Long.valueOf(beginEnd.get(1)));
}
}
}
// add any context related filters
switch (getEntityContext().type) {
case Resource:
criteria.addFilterResourceIds(getEntityContext().getResourceId());
break;
case ResourceGroup:
criteria.addFilterGroupOperationHistoryId(getEntityContext().getGroupId());
}
return criteria;
}
}
}