/******************************************************************************* * Copyright (c) 2011 Subgraph. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Subgraph - initial API and implementation ******************************************************************************/ package com.subgraph.vega.ui.scanner.dashboard; import java.util.Timer; import java.util.TimerTask; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.forms.widgets.FormText; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.ScrolledForm; import org.eclipse.ui.forms.widgets.ScrolledFormText; import com.subgraph.vega.api.events.IEvent; import com.subgraph.vega.api.events.IEventHandler; import com.subgraph.vega.api.model.alerts.IScanAlert; import com.subgraph.vega.api.model.alerts.IScanAlertRepository; import com.subgraph.vega.api.model.alerts.IScanInstance; import com.subgraph.vega.api.model.alerts.NewScanAlertEvent; import com.subgraph.vega.api.model.alerts.ScanStatusChangeEvent; import com.subgraph.vega.ui.scanner.Activator; import com.subgraph.vega.ui.util.ImageCache; public class DashboardPane extends Composite implements IEventHandler { private static final RGB GREY_TEXT_COLOR = new RGB(200, 200, 200); private final static String VEGA_LOGO = "icons/vega_small.png"; private static final int UPDATE_INTERVAL = 100; private final Display display; private final Timer renderTimer = new Timer(); private TimerTask renderTask; private CrawlerPane crawlerPane; private AlertPane alertPane; private IScanInstance scanInstance; private volatile boolean outputRenderNeeded; private volatile boolean crawlerRenderNeeded; private volatile boolean disableRenderTaskStart; private volatile boolean isProgressPaneVisible; private FormToolkit toolkit; private ScrolledForm scrolledForm; private ScrolledFormText scrolledFormText; private int lastStatus; private int lastCompletedCount; private int lastTotalCount; private boolean isProxyInstance; private final ImageCache imageCache = new ImageCache(Activator.PLUGIN_ID); public DashboardPane(Composite parent) { super(parent, SWT.NONE); this.display = parent.getDisplay(); setLayout(new FillLayout()); toolkit = new FormToolkit(display); toolkit.getColors().createColor("grey", GREY_TEXT_COLOR); createDashboardForm(); renderOutput(); } public void displayScanInstance(IScanInstance scanInstance) { if(this.scanInstance == scanInstance) { return; } cancelRenderTask(); disableRenderTaskStart = true; if(this.scanInstance != null) { this.scanInstance.removeScanEventListener(this); } this.scanInstance = scanInstance; alertPane.reset(); isProxyInstance = (scanInstance == null) ? (false) : (scanInstance.getScanId() == IScanAlertRepository.PROXY_ALERT_ORIGIN_SCAN_ID); if(scanInstance != null) { this.scanInstance.addScanEventListenerAndPopulate(this); lastStatus = 0; lastCompletedCount = 0; lastTotalCount = 0; maybeUpdateCrawler(scanInstance.getScanStatus(), scanInstance.getScanCompletedCount(), scanInstance.getScanTotalCount()); maybeUpdateStatus(scanInstance.getScanStatus()); } final boolean progressPaneVisible = (!isProxyInstance && (scanInstance != null && scanInstance.getScanStatus() == IScanInstance.SCAN_AUDITING)); setProgressPaneVisible(progressPaneVisible); renderOutput(); disableRenderTaskStart = false; } private void setProgressPaneVisible(final boolean flag) { if(isProgressPaneVisible == flag) { return; } display.asyncExec(new Runnable() { @Override public void run() { crawlerPane.setVisible(flag); isProgressPaneVisible = flag; layout(); crawlerPane.redraw(); } }); } private void createDashboardForm() { if(scrolledForm != null) scrolledForm.dispose(); scrolledForm = createForm(this, toolkit); scrolledFormText = createFormText(scrolledForm.getBody(), toolkit); FormText formText = scrolledFormText.getFormText(); formText.setColor("grey", toolkit.getColors().getColor("grey")); formText.setFont("big", JFaceResources.getBannerFont()); formText.setFont("header", JFaceResources.getHeaderFont()); formText.setImage("logo", imageCache.get(VEGA_LOGO)); crawlerPane = new CrawlerPane(formText); crawlerPane.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER); toolkit.adapt(crawlerPane); formText.setControl("crawler", crawlerPane); alertPane = new AlertPane(formText); alertPane.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER); toolkit.adapt(alertPane); formText.setControl("alerts", alertPane); toolkit.paintBordersFor(formText); toolkit.decorateFormHeading(scrolledForm.getForm()); this.layout(); } private static ScrolledForm createForm(Composite parent, FormToolkit toolkit) { final ScrolledForm form = toolkit.createScrolledForm(parent); form.getBody().setLayout(new FillLayout()); return form; } private static ScrolledFormText createFormText(Composite parent, FormToolkit toolkit) { final ScrolledFormText sftext = new ScrolledFormText(parent, SWT.WRAP | SWT.NO_FOCUS | SWT.V_SCROLL, false); final FormText text = toolkit.createFormText(sftext, false); sftext.setFormText(text); text.marginWidth = 1; text.marginHeight = 0; text.setHyperlinkSettings(toolkit.getHyperlinkGroup()); text.setMenu(parent.getMenu()); text.setWhitespaceNormalized(false); toolkit.adapt(sftext); return sftext; } private void renderOutput() { final StringBuilder buffer = new StringBuilder(); buffer.append("<form>"); addHeader(buffer); renderCrawlerSection(buffer); renderAlertSummary(buffer); addVSpaces(buffer, 2); buffer.append("</form>"); if(!display.isDisposed()) { display.asyncExec(new Runnable() { @Override public void run() { if(!scrolledFormText.isDisposed()) { scrolledFormText.setText(buffer.toString()); } outputRenderNeeded = false; } }); } } private void renderCrawlerOutput() { if(!display.isDisposed()) { display.asyncExec(new Runnable() { @Override public void run() { if(!crawlerPane.isDisposed()) { crawlerPane.renderChanges(); } crawlerRenderNeeded = false; } }); } } private void renderCrawlerSection(StringBuilder sb) { if(isProxyInstance) { return; } if(scanInstance == null || scanInstance.getScanStatus() != IScanInstance.SCAN_AUDITING) { if(isProgressPaneVisible) { setProgressPaneVisible(false); } return; } if(!isProgressPaneVisible) { setProgressPaneVisible(true); } addIndented(sb, 10, "<span font='header'>Scanner Progress</span>"); addVSpaces(sb, 2); crawlerPane.renderChanges(); addIndented(sb, 20, "<control width='400' height='80' href='crawler'/>"); } private void renderAlertSummary(StringBuilder sb) { addVSpaces(sb, 2); final String title = isProxyInstance ? "Proxy Alert Summary" : "Scan Alert Summary"; addIndented(sb, 10, "<span font='header'>" + title +"</span>"); addVSpaces(sb, 2); addIndented(sb, 20, "<control width='400' href='alerts'/>"); addVSpaces(sb, 2); } private void addIndented(StringBuilder sb, int indent, String text) { sb.append("<p>"); for(int i = 0; i < indent; i++) sb.append(" "); sb.append(text); sb.append("</p>"); } private void addHeader(StringBuilder sb) { addVSpaces(sb, 2); addIndented(sb, 10, "<img href='logo'/>"); addVSpaces(sb, 2); } private void addVSpaces(StringBuilder sb, int count) { sb.append("<p>"); for(int i = 0; i < count; i++) sb.append("\n"); sb.append("</p>"); } private void processAlert(IScanAlert alert) { alertPane.addAlert(alert); outputRenderNeeded = true; } private void handleScannerStatusChanged(ScanStatusChangeEvent event) { maybeUpdateCrawler(event.getStatus(), event.getCompletedCount(), event.getTotalCount()); maybeUpdateStatus(event.getStatus()); } private void maybeUpdateCrawler(int status, int completed, int total) { if(completed != lastCompletedCount || total != lastTotalCount || status != lastStatus) { lastCompletedCount = completed; lastTotalCount = total; crawlerPane.updateCrawlerProgress(status, total, completed); crawlerRenderNeeded = true; } } private void maybeUpdateStatus(int status) { if(status == lastStatus) { return; } lastStatus = status; outputRenderNeeded = true; } private TimerTask createTimerTask() { return new TimerTask() { @Override public void run() { if(outputRenderNeeded) { renderOutput(); } if(crawlerRenderNeeded) { renderCrawlerOutput(); } } }; } private void cancelRenderTask() { synchronized(renderTimer) { if(renderTask != null) { renderTask.cancel(); renderTask = null; } } } private void startRenderTask() { synchronized(renderTimer) { if(renderTask == null) { renderTask = createTimerTask(); renderTimer.scheduleAtFixedRate(renderTask, 0, UPDATE_INTERVAL); } } } @Override public void handleEvent(IEvent event) { synchronized(renderTimer) { if(!disableRenderTaskStart && renderTask == null) { startRenderTask(); } } if (event instanceof ScanStatusChangeEvent) { handleScannerStatusChanged((ScanStatusChangeEvent) event); } else if (event instanceof NewScanAlertEvent) { processAlert(((NewScanAlertEvent)event).getAlert()); } } }