/** * Copyright (C) 2013 Arman Gal * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.clevermore.monitor.client.alerts; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.Set; import org.clevermore.monitor.client.AlertsService; import org.clevermore.monitor.client.AlertsServiceAsync; import org.clevermore.monitor.client.widgets.AbstractMonitoringWidget; import org.clevermore.monitor.client.widgets.IMonitoringWidget; import org.clevermore.monitor.shared.alert.Alert; import org.clevermore.monitor.shared.alert.AlertType; import org.clevermore.monitor.shared.alert.IAlertType; import org.clevermore.monitor.shared.alert.RefreshAlertsRequest; import org.clevermore.monitor.shared.alert.RefreshAlertsResponse; import com.allen_sauer.gwt.log.client.Log; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.FlexTable; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.ListBox; import com.google.gwt.user.client.ui.ScrollPanel; /** * Alert Widget is responsible to show the most up to date alerts coming from server. The widget takes care * for refreshing the list of last alerts. Only last 1000 are shown to user. <br> * Two features are present on the widget:<br> * - Filtering on client side by alert type <br> * - Exporting all alerts to excel file * * @author Arman Gal */ public class AlertsWidget extends AbstractMonitoringWidget<RefreshAlertsRequest, RefreshAlertsResponse, AlertsServiceAsync> implements IMonitoringWidget { /** * actual html table that holds last 1000 alerts */ private FlexTable alertsTable = new FlexTable(); /** * listbox with available alert types for filtering */ private ListBox typesListBox; /** * last alert id received by the widget. it's important to keep this one up-to-date caz it's used in * refresh request */ private int lastAlertId = -1; /** * locally stored last 1000 alerts, we need it in order to filter the alerts locally faster */ private LinkedList<Alert> alerts = new LinkedList<Alert>(); /** * Constructs alert widget with default alert type available for filtering */ public AlertsWidget() { this(new IAlertType[] {}); } /** * Constructs alert widget with default and additionally provided alert type available for filtering.<br> * Usually should be used by projects that have extended the Alerts * * @param types - additional alert types */ public AlertsWidget(IAlertType[]... types) { super("Alerts:", 20000, (AlertsServiceAsync) GWT.create(AlertsService.class)); Set<IAlertType> alertTypesSet = new HashSet<IAlertType>(); // default alert types alertTypesSet.addAll(new HashSet<IAlertType>(Arrays.asList(AlertType.values()))); // all the custom alert types for (IAlertType[] arr : types) { alertTypesSet.addAll(new HashSet<IAlertType>(Arrays.asList(arr))); } addStyleName("alertsWidget"); ScrollPanel sp = new ScrollPanel(); sp.setStyleName("alertsWidgetData"); getDataPanel().add(sp); sp.add(alertsTable); // creating title HorizontalPanel title = new HorizontalPanel(); title.setStyleName("serversHeader"); title.add(new HTML("Alerts: ")); title.add(new HTML("Filter:")); typesListBox = getTypesListBox(alertTypesSet); title.add(typesListBox); title.add(getExportButton()); title.add(getRefProg()); setTitleWidget(title); initAlertTable(); } /** * creates the filter listbox from available aret types * * @param alertTypesSet * @return */ private ListBox getTypesListBox(Set<IAlertType> alertTypesSet) { ListBox listBox = new ListBox(); listBox.addItem("All", "-1"); for (IAlertType at : alertTypesSet) { listBox.addItem(at.getName(), "" + at.getId()); } listBox.getElement().getStyle().setFontSize(10, Unit.PX); listBox.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { redrawTable(); } }); return listBox; } /** * creates the export to excel file button * * @return */ private Button getExportButton() { Button export = new Button("Exp.CSV"); export.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { Log.debug("Exporting alerts:" + (GWT.getHostPageBaseURL() + "exp_alerts")); Window.open(GWT.getHostPageBaseURL() + "exp_alerts", "Alerts", ""); } }); export.getElement().getStyle().setPadding(0d, Unit.PX); export.setTitle("Export all alerts to CSV file."); return export; } /** * Initializes the html table what will hold last alert messages */ private void initAlertTable() { alertsTable.removeAllRows(); alertsTable.getElement().setId("infoTable"); int i = 0; alertsTable.setText(0, i++, "Msg.Id:"); alertsTable.setText(0, i++, "Message"); alertsTable.setText(0, i++, "Server"); alertsTable.setText(0, i++, "Time"); alertsTable.getRowFormatter().getElement(0).setId("th"); } /** * recreates the content of HTML table that holds last alert messages, here the selected filter is * considered and messages are filtered */ private void redrawTable() { Iterator<Alert> it = alerts.iterator(); initAlertTable(); int i = 1; while (it.hasNext()) { Alert a = it.next(); if (a.getId() > lastAlertId) { lastAlertId = a.getId(); } int selInd = typesListBox.getSelectedIndex(); int val = Integer.valueOf(typesListBox.getValue(selInd)); if (val == -1 || val == a.getAlertType().getId()) { alertsTable.setText(i, 0, "" + a.getId()); HTML msg = new HTML(a.getMessage() + " [" + a.getServerName() + "]"); msg.setTitle(a.toString()); alertsTable.setWidget(i, 1, msg); alertsTable.setText(i, 2, "" + a.getServerCode()); alertsTable.setText(i, 3, a.getAlertTimeStr()); alertsTable.getRowFormatter().getElement(i).setAttribute("id", "" + a.getId()); i++; } } } @Override public void clear() { lastAlertId = -1; initAlertTable(); } @Override public RefreshAlertsRequest createRefreshRequest() { return new RefreshAlertsRequest(lastAlertId); } @Override public void refreshFailed(Throwable t) { Log.error("Failed to refresh alerts: " + t.getMessage(), t); } @Override public void refresh(RefreshAlertsResponse refershResponse) { getRefProg().progress(); try { for (Alert a : refershResponse.getAlerts()) { // take only alerts with higher ID number than already received if (a.getId() > lastAlertId) { alerts.add(a); } } // sort in descending order Collections.sort(alerts, new Comparator<Alert>() { @Override public int compare(Alert o1, Alert o2) { return o2.getId() - o1.getId(); } }); // shrink the local list to 1000 elements while (alerts.size() > 1000) { Alert remove = alerts.remove(); Log.debug("Alert widget, removing alert from memory:" + remove); } redrawTable(); } catch (Exception e) { getRefProg().progress(); Log.error(e.getMessage(), e); } } }