/* * Zed Attack Proxy (ZAP) and its related class files. * * ZAP is an HTTP/HTTPS proxy for assessing web application security. * * Copyright 2011 The ZAP Development team * * 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.zaproxy.zap.extension.alert; import java.awt.EventQueue; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.SortedSet; import java.util.TreeSet; import java.util.Vector; import javax.swing.JTree; import javax.swing.tree.TreePath; import org.apache.log4j.Logger; import org.parosproxy.paros.Constant; import org.parosproxy.paros.control.Control; import org.parosproxy.paros.control.Control.Mode; import org.parosproxy.paros.core.scanner.Alert; import org.parosproxy.paros.db.DatabaseException; import org.parosproxy.paros.db.RecordAlert; import org.parosproxy.paros.db.RecordScan; import org.parosproxy.paros.db.TableAlert; import org.parosproxy.paros.extension.ExtensionAdaptor; import org.parosproxy.paros.extension.ExtensionHook; import org.parosproxy.paros.extension.OptionsChangedListener; import org.parosproxy.paros.extension.SessionChangedListener; import org.parosproxy.paros.extension.ViewDelegate; import org.parosproxy.paros.extension.history.ExtensionHistory; import org.parosproxy.paros.model.HistoryReference; import org.parosproxy.paros.model.Model; import org.parosproxy.paros.model.OptionsParam; import org.parosproxy.paros.model.Session; import org.parosproxy.paros.model.SiteMap; import org.parosproxy.paros.model.SiteNode; import org.parosproxy.paros.network.HttpMalformedHeaderException; import org.parosproxy.paros.network.HttpMessage; import org.parosproxy.paros.view.MainFooterPanel; import org.parosproxy.paros.view.View; import org.zaproxy.zap.ZAP; import org.zaproxy.zap.eventBus.Event; import org.zaproxy.zap.extension.XmlReporterExtension; import org.zaproxy.zap.extension.help.ExtensionHelp; import org.zaproxy.zap.model.SessionStructure; import org.zaproxy.zap.model.Target; public class ExtensionAlert extends ExtensionAdaptor implements SessionChangedListener, XmlReporterExtension, OptionsChangedListener { public static final String NAME = "ExtensionAlert"; private Map<Integer, HistoryReference> hrefs = new HashMap<>(); private AlertTreeModel treeModel = null; private AlertTreeModel filteredTreeModel = null; private AlertPanel alertPanel = null; private RecordScan recordScan = null; private PopupMenuAlertEdit popupMenuAlertEdit = null; private PopupMenuAlertDelete popupMenuAlertDelete = null; private PopupMenuAlertsRefresh popupMenuAlertsRefresh = null; private PopupMenuShowAlerts popupMenuShowAlerts = null; private Logger logger = Logger.getLogger(ExtensionAlert.class); private AlertParam alertParam = null; private OptionsAlertPanel optionsPanel = null; private Properties alertOverrides = new Properties(); public ExtensionAlert() { super(NAME); this.setOrder(27); } @Override public void hook(ExtensionHook extensionHook) { super.hook(extensionHook); extensionHook.addOptionsParamSet(getAlertParam()); if (getView() != null) { extensionHook.getHookView().addOptionPanel(getOptionsPanel()); extensionHook.getHookMenu().addPopupMenuItem(getPopupMenuAlertEdit()); extensionHook.getHookMenu().addPopupMenuItem(getPopupMenuAlertDelete()); extensionHook.getHookMenu().addPopupMenuItem(getPopupMenuAlertsRefresh()); extensionHook.getHookMenu().addPopupMenuItem(getPopupMenuShowAlerts()); extensionHook.getHookView().addStatusPanel(getAlertPanel()); ExtensionHelp.enableHelpKey(getAlertPanel(), "ui.tabs.alerts"); } extensionHook.addSessionListener(this); extensionHook.addOptionsChangedListener(this); } @Override public void optionsLoaded() { reloadOverridesFile(); } @Override public void optionsChanged(OptionsParam optionsParam) { reloadOverridesFile(); } private void reloadOverridesFile() { this.alertOverrides.clear(); String filename = this.getAlertParam().getOverridesFilename(); if (filename != null && filename.length() > 0) { File file = new File(filename); if (! file.isFile() || ! file.canRead()) { logger.error("Cannot read alert overrides file " + file.getAbsolutePath()); } else { try (BufferedReader br = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8)) { this.alertOverrides.load(br); logger.info("Read " + this.alertOverrides.size() + " overrides from " + file.getAbsolutePath()); } catch (IOException e) { logger.error("Failed to read alert overrides file " + file.getAbsolutePath(), e); } } } } private OptionsAlertPanel getOptionsPanel() { if (optionsPanel == null) { optionsPanel = new OptionsAlertPanel(); } return optionsPanel; } private AlertParam getAlertParam() { if (alertParam == null) { alertParam = new AlertParam(); } return alertParam; } public void alertFound(Alert alert, HistoryReference ref) { try { logger.debug("alertFound " + alert.getName() + " " + alert.getUri()); if (ref == null) { ref = alert.getHistoryRef(); } if (ref == null) { ref = new HistoryReference(getModel().getSession(), HistoryReference.TYPE_SCANNER, alert.getMessage()); alert.setHistoryRef(ref); } if (alert.getSource() == Alert.Source.UNKNOWN) { alert.setSource(Alert.Source.TOOL); } alert.setSourceHistoryId(ref.getHistoryId()); hrefs.put(Integer.valueOf(ref.getHistoryId()), ref); this.applyOverrides(alert); writeAlertToDB(alert, ref); try { if (getView() == null || EventQueue.isDispatchThread()) { SessionStructure.addPath(Model.getSingleton().getSession(), ref, alert.getMessage()); } else { final HistoryReference fRef = ref; final HttpMessage fMsg = alert.getMessage(); EventQueue.invokeAndWait(new Runnable() { @Override public void run() { SessionStructure.addPath(Model.getSingleton().getSession(), fRef, fMsg); } }); } ref.addAlert(alert); } catch (Exception e) { logger.error(e.getMessage(), e); } addAlertToTree(alert); // Clear the message so that it can be GC'ed alert.setMessage(null); publishAlertEvent(alert, AlertEventPublisher.ALERT_ADDED_EVENT); } catch (Exception e) { logger.error(e.getMessage(), e); } } /* * This method is intended for internal use only, and should only * be called by other classes for unit testing. */ protected void applyOverrides(Alert alert) { if (this.alertOverrides.isEmpty()) { // Nothing to do return; } String changedName = this.alertOverrides.getProperty(alert.getPluginId() + ".name"); if (changedName != null) { alert.setName(applyOverride(alert.getName(), changedName)); } String changedDesc = this.alertOverrides.getProperty(alert.getPluginId() + ".description"); if (changedDesc != null) { alert.setDescription(applyOverride(alert.getDescription(), changedDesc)); } String changedSolution = this.alertOverrides.getProperty(alert.getPluginId() + ".solution"); if (changedSolution != null) { alert.setSolution(applyOverride(alert.getSolution(), changedSolution)); } String changedOther = this.alertOverrides.getProperty(alert.getPluginId() + ".otherInfo"); if (changedOther != null) { alert.setOtherInfo(applyOverride(alert.getOtherInfo(), changedOther)); } String changedReference = this.alertOverrides.getProperty(alert.getPluginId() + ".reference"); if (changedReference != null) { alert.setReference(applyOverride(alert.getReference(), changedReference)); } } /* * This method should only be used for testing */ protected void setAlertOverrideProperty(String key, String value) { this.alertOverrides.put(key, value); } private String applyOverride(String original, String override) { if (override.startsWith("+")) { return original + override.substring(1); } else if (override.startsWith("-")) { return override.substring(1) + original; } else { return override; } } private void publishAlertEvent(Alert alert, String event) { HistoryReference historyReference = hrefs.get(alert.getSourceHistoryId()); if (historyReference == null) { historyReference = Control.getSingleton() .getExtensionLoader() .getExtension(ExtensionHistory.class) .getHistoryReference(alert.getSourceHistoryId()); } Map<String, String> map = new HashMap<>(); map.put(AlertEventPublisher.ALERT_ID, Integer.toString(alert.getAlertId())); map.put(AlertEventPublisher.HISTORY_REFERENCE_ID, Integer.toString(alert.getSourceHistoryId())); ZAP.getEventBus().publishSyncEvent( AlertEventPublisher.getPublisher(), new Event(AlertEventPublisher.getPublisher(), event, new Target(historyReference.getSiteNode()), map)); } private void addAlertToTree(final Alert alert) { if (Constant.isLowMemoryOptionSet()) { return; } if (!View.isInitialised() || EventQueue.isDispatchThread()) { addAlertToTreeEventHandler(alert); } else { try { // Changed from invokeAndWait due to the number of interrupt exceptions // And its likely to always to run from a background thread anyway //EventQueue.invokeAndWait(new Runnable() { EventQueue.invokeLater(new Runnable() { @Override public void run() { addAlertToTreeEventHandler(alert); } }); } catch (Exception e) { logger.error(e.getMessage(), e); } } } private boolean isInFilter(Alert alert) { // Just support scope for now return this.getModel().getSession().isInScope(alert.getHistoryRef()); } private void addAlertToTreeEventHandler(Alert alert) { synchronized (this.getTreeModel()) { this.getTreeModel().addPath(alert); if (isInFilter(alert)) { this.getFilteredTreeModel().addPath(alert); } if (getView() != null) { getAlertPanel().expandRoot(); this.recalcAlerts(); } } } /** * This method initializes alertPanel * * @return org.parosproxy.paros.extension.scanner.AlertPanel */ AlertPanel getAlertPanel() { if (alertPanel == null) { alertPanel = new AlertPanel(this); alertPanel.setView(getView()); alertPanel.setSize(345, 122); setMainTreeModel(); } return alertPanel; } @Override public void initView(ViewDelegate view) { super.initView(view); getAlertPanel().setView(view); } AlertTreeModel getTreeModel() { if (treeModel == null) { treeModel = new AlertTreeModel(); } return treeModel; } private AlertTreeModel getFilteredTreeModel() { if (filteredTreeModel == null) { filteredTreeModel = new AlertTreeModel(); } return filteredTreeModel; } private void writeAlertToDB(Alert alert, HistoryReference ref) throws HttpMalformedHeaderException, DatabaseException { TableAlert tableAlert = getModel().getDb().getTableAlert(); int scanId = 0; if (recordScan != null) { scanId = recordScan.getScanId(); } RecordAlert recordAlert = tableAlert.write( scanId, alert.getPluginId(), alert.getName(), alert.getRisk(), alert.getConfidence(), alert.getDescription(), alert.getUri(), alert.getParam(), alert.getAttack(), alert.getOtherInfo(), alert.getSolution(), alert.getReference(), alert.getEvidence(), alert.getCweId(), alert.getWascId(), ref.getHistoryId(), alert.getSourceHistoryId(), alert.getSource().getId()); alert.setAlertId(recordAlert.getAlertId()); } public void updateAlert(Alert alert) throws HttpMalformedHeaderException, DatabaseException { logger.debug("updateAlert " + alert.getName() + " " + alert.getUri()); HistoryReference hRef = hrefs.get(alert.getSourceHistoryId()); if (hRef != null) { updateAlertInDB(alert); hRef.updateAlert(alert); publishAlertEvent(alert, AlertEventPublisher.ALERT_CHANGED_EVENT); updateAlertInTree(alert, alert); } } private void updateAlertInDB(Alert alert) throws HttpMalformedHeaderException, DatabaseException { TableAlert tableAlert = getModel().getDb().getTableAlert(); tableAlert.update(alert.getAlertId(), alert.getName(), alert.getRisk(), alert.getConfidence(), alert.getDescription(), alert.getUri(), alert.getParam(), alert.getAttack(), alert.getOtherInfo(), alert.getSolution(), alert.getReference(), alert.getEvidence(), alert.getCweId(), alert.getWascId(), alert.getSourceHistoryId()); } public void displayAlert(Alert alert) { logger.debug("displayAlert " + alert.getName() + " " + alert.getUri()); this.alertPanel.getAlertViewPanel().displayAlert(alert); } public void updateAlertInTree(Alert originalAlert, Alert alert) { if (Constant.isLowMemoryOptionSet()) { return; } this.getTreeModel().updatePath(originalAlert, alert); if (isInFilter(alert)) { this.getFilteredTreeModel().updatePath(originalAlert, alert); } this.recalcAlerts(); if (View.isInitialised()) { JTree alertTree = this.getAlertPanel().getTreeAlert(); TreePath alertPath = new TreePath(getTreeModel().getAlertNode(alert).getPath()); alertTree.setSelectionPath(alertPath); alertTree.scrollPathToVisible(alertPath); } } @Override public void sessionChanged(final Session session) { if (EventQueue.isDispatchThread()) { sessionChangedEventHandler(session); } else { try { EventQueue.invokeAndWait(new Runnable() { @Override public void run() { sessionChangedEventHandler(session); } }); } catch (Exception e) { logger.error(e.getMessage(), e); } } } private void sessionChangedEventHandler(Session session) { setTreeModel(new AlertTreeModel()); treeModel = null; filteredTreeModel = null; hrefs = new HashMap<>(); if (session == null) { // Null session indicated we're sutting down return; } try { refreshAlert(session); } catch (DatabaseException e) { logger.error(e.getMessage(), e); } setTreeModel(getTreeModel()); } private void refreshAlert(Session session) throws DatabaseException { if (Constant.isLowMemoryOptionSet()) { return; } SiteMap siteTree = this.getModel().getSession().getSiteTree(); TableAlert tableAlert = getModel().getDb().getTableAlert(); // TODO this doesnt work, but should be used when its fixed :/ //Vector<Integer> v = tableAlert.getAlertListBySession(Model.getSingleton().getSession().getSessionId()); Vector<Integer> v = tableAlert.getAlertList(); final ExtensionHistory extensionHistory = (ExtensionHistory) Control.getSingleton() .getExtensionLoader() .getExtension(ExtensionHistory.NAME); for (int i = 0; i < v.size(); i++) { int alertId = v.get(i).intValue(); RecordAlert recAlert = tableAlert.read(alertId); int historyId = recAlert.getHistoryId(); HistoryReference historyReference = null; if (extensionHistory != null) { historyReference = extensionHistory.getHistoryReference(historyId); } if (historyReference == null) { historyReference = this.hrefs.get(Integer.valueOf(historyId)); } Alert alert; if (historyReference != null) { alert = new Alert(recAlert, historyReference); } else { alert = new Alert(recAlert); } historyReference = alert.getHistoryRef(); if (historyReference != null) { // The ref can be null if hrefs are purged addAlertToTree(alert); Integer key = Integer.valueOf(historyId); if (!hrefs.containsKey(key)) { this.hrefs.put(key, alert.getHistoryRef()); } } } siteTree.nodeStructureChanged((SiteNode) siteTree.getRoot()); } private PopupMenuAlertEdit getPopupMenuAlertEdit() { if (popupMenuAlertEdit == null) { popupMenuAlertEdit = new PopupMenuAlertEdit(); } return popupMenuAlertEdit; } private PopupMenuAlertDelete getPopupMenuAlertDelete() { if (popupMenuAlertDelete == null) { popupMenuAlertDelete = new PopupMenuAlertDelete(); } return popupMenuAlertDelete; } private PopupMenuAlertsRefresh getPopupMenuAlertsRefresh() { if (popupMenuAlertsRefresh == null) { popupMenuAlertsRefresh = new PopupMenuAlertsRefresh(); } return popupMenuAlertsRefresh; } private PopupMenuShowAlerts getPopupMenuShowAlerts() { if (popupMenuShowAlerts == null) { popupMenuShowAlerts = new PopupMenuShowAlerts(Constant.messages.getString("alerts.view.popup")); } return popupMenuShowAlerts; } public void deleteAlert(Alert alert) { logger.debug("deleteAlert " + alert.getName() + " " + alert.getUri()); try { getModel().getDb().getTableAlert().deleteAlert(alert.getAlertId()); } catch (DatabaseException e) { logger.error(e.getMessage(), e); } deleteAlertFromDisplay(alert); publishAlertEvent(alert, AlertEventPublisher.ALERT_REMOVED_EVENT); } public void deleteAllAlerts() { try { getModel().getDb().getTableAlert().deleteAllAlerts(); } catch (DatabaseException e) { logger.error(e.getMessage(), e); } SiteMap siteTree = this.getModel().getSession().getSiteTree(); ((SiteNode) siteTree.getRoot()).deleteAllAlerts(); for (HistoryReference href : hrefs.values()) { href.deleteAllAlerts(); } ZAP.getEventBus().publishSyncEvent(AlertEventPublisher.getPublisher(), new Event(AlertEventPublisher.getPublisher(), AlertEventPublisher.ALL_ALERTS_REMOVED_EVENT, null)); hrefs = new HashMap<>(); treeModel = null; filteredTreeModel = null; setTreeModel(getTreeModel()); } private void deleteAlertFromDisplay(final Alert alert) { if (getView() == null || Constant.isLowMemoryOptionSet()) { // Running as a daemon return; } if (EventQueue.isDispatchThread()) { deleteAlertFromDisplayEventHandler(alert); } else { try { EventQueue.invokeAndWait(new Runnable() { @Override public void run() { deleteAlertFromDisplayEventHandler(alert); } }); } catch (Exception e) { logger.error(e.getMessage(), e); } } } private void deleteAlertFromDisplayEventHandler(Alert alert) { synchronized (this.getTreeModel()) { this.getTreeModel().deletePath(alert); this.getFilteredTreeModel().deletePath(alert); List<HistoryReference> toDelete = new ArrayList<>(); for (HistoryReference href : hrefs.values()) { if (href.hasAlert(alert)) { href.deleteAlert(alert); if (!href.hasAlerts()) { toDelete.add(href); } } } for (HistoryReference href : toDelete) { hrefs.remove(Integer.valueOf(href.getHistoryId())); } } this.recalcAlerts(); } public void deleteHistoryReferenceAlerts(HistoryReference hRef) { List<Alert> alerts = hRef.getAlerts(); SiteMap siteTree = this.getModel().getSession().getSiteTree(); synchronized (this.getTreeModel()) { for (int i = 0; i < alerts.size(); i++) { Alert alert = alerts.get(i); this.getTreeModel().deletePath(alert); this.getFilteredTreeModel().deletePath(alert); try { getModel().getDb().getTableAlert().deleteAlert(alert.getAlertId()); } catch (DatabaseException e) { logger.error("Failed to delete alert with ID: " + alert.getAlertId(), e); } } SiteNode node = hRef.getSiteNode(); if (node == null) { node = siteTree.findNode(hRef.getURI(), hRef.getMethod(), hRef.getRequestBody()); } if (node != null) { node.deleteAlerts(alerts); } alerts.clear(); this.recalcAlerts(); } hrefs.remove(Integer.valueOf(hRef.getHistoryId())); } /** * Recalculates the total number of alerts by alert's risk contained in the "Alerts" tree and updates the alert's risks * footer status labels with the new values. * <p> * The method has no effect if the view is not initialised. * </p> * * @see AlertPanel#getTreeAlert() * @see MainFooterPanel#setAlertHigh(int) * @see MainFooterPanel#setAlertInfo(int) * @see MainFooterPanel#setAlertLow(int) * @see MainFooterPanel#setAlertMedium(int) * @see View#isInitialised() */ void recalcAlerts() { if (!View.isInitialised()) { return; } // Must only be called when View is initialised int totalInfo = 0; int totalLow = 0; int totalMedium = 0; int totalHigh = 0; AlertNode parent = (AlertNode) getAlertPanel().getTreeAlert().getModel().getRoot(); if (parent != null) { for (int i=0; i<parent.getChildCount(); i++) { AlertNode child = parent.getChildAt(i); switch (child.getRisk()) { case Alert.RISK_INFO: totalInfo++; break; case Alert.RISK_LOW: totalLow++; break; case Alert.RISK_MEDIUM: totalMedium++; break; case Alert.RISK_HIGH: totalHigh++; break; } } } MainFooterPanel footer = View.getSingleton().getMainFrame().getMainFooterPanel(); footer.setAlertInfo(totalInfo); footer.setAlertLow(totalLow); footer.setAlertMedium(totalMedium); footer.setAlertHigh(totalHigh); } public List<Alert> getAllAlerts() { List<Alert> allAlerts = new ArrayList<>(); TableAlert tableAlert = getModel().getDb().getTableAlert(); Vector<Integer> v; try { // TODO this doesnt work, but should be used when its fixed :/ //v = tableAlert.getAlertListBySession(Model.getSingleton().getSession().getSessionId()); v = tableAlert.getAlertList(); for (int i = 0; i < v.size(); i++) { int alertId = v.get(i).intValue(); RecordAlert recAlert = tableAlert.read(alertId); Alert alert = new Alert(recAlert); if (alert.getHistoryRef() != null) { // Only use the alert if it has a history reference. if (!allAlerts.contains(alert)) { allAlerts.add(alert); } } } } catch (DatabaseException e) { logger.error(e.getMessage(), e); } return allAlerts; } @Override public String getXml(SiteNode site) { StringBuilder xml = new StringBuilder(); xml.append("<alerts>"); List<Alert> alerts = site.getAlerts(); SortedSet<String> handledAlerts = new TreeSet<String>(); for (int i=0; i < alerts.size(); i++) { Alert alert = alerts.get(i); if (alert.getConfidence() != Alert.CONFIDENCE_FALSE_POSITIVE) { if (this.getAlertParam().isMergeRelatedIssues()) { String fingerprint = alertFingerprint(alert); if (handledAlerts.add(fingerprint)) { // Its a new one // Build up the full set of details StringBuilder sb = new StringBuilder(); sb.append(" <instances>\n"); int count = 0; for (int j=i; j < alerts.size(); j++) { // Deliberately include i! Alert alert2 = alerts.get(j); if (fingerprint.equals(alertFingerprint(alert2))) { if (this.getAlertParam().getMaximumInstances() == 0 || count < this.getAlertParam().getMaximumInstances()) { sb.append(" <instance>\n"); sb.append(alert2.getUrlParamXML()); sb.append(" </instance>\n"); } count ++; } } sb.append(" </instances>\n"); sb.append(" <count>"); sb.append(count); sb.append("</count>\n"); xml.append(alert.toPluginXML(sb.toString())); } } else { String urlParamXML = alert.getUrlParamXML(); xml.append(alert.toPluginXML(urlParamXML)); } } } xml.append("</alerts>"); return xml.toString(); } private String alertFingerprint(Alert alert) { return alert.getPluginId() + "/" + alert.getName() + "/" + alert.getRisk() + "/" + alert.getConfidence(); } @Override public void sessionAboutToChange(Session session) { } @Override public String getAuthor() { return Constant.ZAP_TEAM; } @Override public String getDescription() { return Constant.messages.getString("alerts.desc"); } @Override public URL getURL() { try { return new URL(Constant.ZAP_HOMEPAGE); } catch (MalformedURLException e) { return null; } } @Override public void sessionScopeChanged(Session session) { // Have to recheck all alerts to see if they are in scope synchronized (this.getTreeModel()) { ((AlertNode)this.getFilteredTreeModel().getRoot()).removeAllChildren(); AlertNode root = (AlertNode)this.getTreeModel().getRoot(); filterTree(root); this.getFilteredTreeModel().nodeStructureChanged(root); } this.recalcAlerts(); } private void filterTree(AlertNode node) { if (node.getUserObject() != null) { Alert alert = node.getUserObject(); if (this.isInFilter(alert)) { this.getFilteredTreeModel().addPath(alert); } } for (int i=0; i < node.getChildCount(); i++) { this.filterTree(node.getChildAt(i)); } } @Override public void sessionModeChanged(Mode mode) { // Ignore } public void setAlertTabFocus() { this.getAlertPanel().setTabFocus(); } /** * Sets whether the "Alerts" tree is filtered, or not based on current session scope. * <p> * If {@code inScope} is {@code true} only the alerts that are in the current session scope will be shown. * </p> * <p> * Calling this method removes the filter "Link with Sites selection", if enabled, as they are mutually exclusive. * </p> * * @param inScope {@code true} if the "Alerts" tree should be filtered based on current session scope, {@code false} * otherwise. * @see #setLinkWithSitesTreeSelection(boolean) * @see Session */ public void setShowJustInScope(boolean inScope) { if (inScope) { setLinkWithSitesTreeSelection(false); setTreeModel(this.getFilteredTreeModel()); } else { setMainTreeModel(); } } /** * Sets the main tree model to the "Alerts" tree, by calling the method {@code setTreeModel(AlertTreeModel)} with the model * returned by the method {@code getTreeModel()} as parameter. * * @see #getTreeModel() * @see #setTreeModel(AlertTreeModel) */ void setMainTreeModel() { setTreeModel(getTreeModel()); } /** * Sets the given {@code alertTreeModel} to the "Alerts" tree and recalculates the number of alerts by calling the method * {@code recalcAlerts()}. * * @param alertTreeModel the model that will be set to the tree. * @see #recalcAlerts() * @see AlertPanel#getTreeAlert() */ private void setTreeModel(AlertTreeModel alertTreeModel) { if (getView() == null) { return; } getAlertPanel().getTreeAlert().setModel(alertTreeModel); recalcAlerts(); } /** * Sets whether the "Alerts" tree is filtered, or not based on a selected "Sites" tree node. * <p> * If {@code enabled} is {@code true} only the alerts of the selected "Sites" tree node will be shown. * </p> * <p> * Calling this method removes the filter "Just in Scope", if enabled, as they are mutually exclusive. * </p> * * @param enabled {@code true} if the "Alerts" tree should be filtered based on a selected "Sites" tree node, {@code false} * otherwise. * @see #setShowJustInScope(boolean) * @see View#getSiteTreePanel() */ public void setLinkWithSitesTreeSelection(boolean enabled) { getAlertPanel().setLinkWithSitesTreeSelection(enabled); } /** * Part of the core set of features that should be supported by all db types */ @Override public boolean supportsDb(String type) { return true; } @Override public boolean supportsLowMemory() { return true; } }