package org.zaproxy.zap.view; import java.awt.Color; import java.lang.ref.SoftReference; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Observable; import java.util.Observer; import org.zaproxy.zap.extension.search.SearchMatch; /* * Handles Highlights * Keeps them in a ordered list. Allows access via get/set. * Can inform interested partys when the list of Highlights changes. */ public class HighlighterManager extends Observable { static HighlighterManager hilighterManager = null; public static HighlighterManager getInstance() { if ( hilighterManager == null) { hilighterManager = new HighlighterManager(); } return hilighterManager; } private LinkedList<HighlightSearchEntry> highlights; private List<SoftObserver> observers; public HighlighterManager() { highlights = new LinkedList<>(); observers = new ArrayList<>(); } @SuppressWarnings("unchecked") public void reinitHighlights(LinkedList<HighlightSearchEntry> list) { this.highlights = (LinkedList<HighlightSearchEntry>) list.clone(); setChanged(); notifyObservers(null); } public void addHighlightEntry(String token, SearchMatch.Location type, boolean isActive) { HighlightSearchEntry entry = new HighlightSearchEntry(token, type, Color.red, isActive); addHighlightEntry(entry); } public void addHighlightEntry(HighlightSearchEntry entry) { highlights.add(entry); setChanged(); notifyObservers(entry); } public void removeHighlightEntry(int id) { highlights.remove(id); // null means the observers call getHighlights() to rebuild all highlights setChanged(); notifyObservers(null); } // TODO: sux @SuppressWarnings("unchecked") public LinkedList<HighlightSearchEntry> getHighlights() { return (LinkedList<HighlightSearchEntry>) highlights.clone(); } @Override public synchronized void addObserver(Observer obs) { if (obs == null) { throw new NullPointerException(); } boolean observerContained = false; for (Iterator<SoftObserver> it = observers.iterator(); it.hasNext();) { Observer other = it.next().get(); if (other == null) { it.remove(); } else if (obs.equals(other)) { observerContained = true; break; } } if (!observerContained) { observers.add(new SoftObserver(obs)); } } @Override public synchronized void deleteObserver(Observer obs) { for (Iterator<SoftObserver> it = observers.iterator(); it.hasNext();) { Observer other = it.next().get(); if (other == null) { it.remove(); } else if (obs.equals(other)) { it.remove(); break; } } } private synchronized void deleteSoftObserver(SoftObserver obs) { observers.remove(obs); } @Override public void notifyObservers(Object arg) { Observer[] arrLocal; synchronized (this) { if (!hasChanged()) { return; } arrLocal = new Observer[observers.size()]; arrLocal = observers.toArray(arrLocal); clearChanged(); } for (int i = arrLocal.length - 1; i >= 0; i--) { arrLocal[i].update(this, arg); } } @Override public synchronized void deleteObservers() { observers.clear(); } @Override public synchronized int countObservers() { return observers.size(); } private class SoftObserver extends SoftReference<Observer> implements Observer { public SoftObserver(Observer referent) { super(referent); } @Override public void update(Observable o, Object arg) { Observer observer = get(); if (observer != null) { observer.update(o, arg); } else { deleteSoftObserver(this); } } } }