/*
* SearchModel.java
*
* Created on 19 June 2005, 01:41
*/
package org.owasp.webscarab.plugin.search;
import EDU.oswego.cs.dl.util.concurrent.Sync;
import org.owasp.webscarab.model.*;
import org.owasp.webscarab.plugin.*;
import java.util.Map;
import java.util.TreeMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.logging.Logger;
/**
*
* @author rogan
*/
public class SearchModel extends AbstractPluginModel {
public final static String PROPERTY_FILTER = "Filter";
public final static String PROPERTY_SEARCHES = "Searches";
private FrameworkModel _model;
private SearchConversationModel _conversationModel;
private Map<String, String> _searches = new TreeMap<String, String>();
private String _description = null;
private Logger _logger = Logger.getLogger(getClass().getName());
/** Creates a new instance of SearchModel */
public SearchModel(FrameworkModel model) {
_model = model;
_conversationModel = new SearchConversationModel(_model);
}
public ConversationModel getConversationModel() {
return _conversationModel;
}
public Sync readLock() {
return _rwl.readLock();
}
public void addSearch(String description, String expression) {
_logger.info("Adding search " + description);
_searches.put(description, expression);
_changeSupport.firePropertyChange(PROPERTY_SEARCHES, null, null);
}
public String[] getSearches() {
return (String[]) _searches.keySet().toArray(new String[_searches.size()]);
}
public String getSearchExpression(String description) {
return (String) _searches.get(description);
}
public void removeSearch(String description) {
_searches.remove(description);
_changeSupport.firePropertyChange(PROPERTY_SEARCHES, null, null);
}
public void setFilter(String description) {
if (_description == null && description == null) {
// do nothing
} else if (_description == null || description == null) {
changeFilter(description);
} else if (!_description.equals(description)) {
changeFilter(description);
} else {
// do nothing
}
}
private void changeFilter(String description) {
try {
_rwl.writeLock().acquire();
Object old = _description;
_description = description;
_conversationModel.refilter();
_rwl.readLock().acquire();
_rwl.writeLock().release();
_changeSupport.firePropertyChange(PROPERTY_FILTER, old, description);
_conversationModel.fireConversationsChanged();
_rwl.readLock().release();
} catch (Exception e) {
e.printStackTrace();
}
}
public void setSearchMatch(ConversationID id, String description, boolean matches) {
if (matches) {
_model.addConversationProperty(id, "SEARCH", description);
} else {
String[] searches = _model.getConversationProperties(id, "SEARCH");
if (searches != null) {
// FIXME this causes all the SEARCH results to be set to
// null, with the consequence that conversations are removed
// and immediately readded as we put the property back
// Need to implement a
// FrameworkModel.removeConversationProperty(id, name, value)
// method somehow
_model.setConversationProperty(id, "SEARCH", null);
for (int i=0; i<searches.length; i++) {
if (!searches[i].equals(description)) {
_model.addConversationProperty(id, "SEARCH", searches[i]);
}
}
}
}
}
public boolean hasSearchMatch(ConversationID id, String description) {
if (description == null) return false;
String[] searches = _model.getConversationProperties(id, "SEARCH");
if (searches == null) return false;
for (int i=0; i<searches.length; i++) {
if (searches[i].equals(description)) return true;
}
return false;
}
private class SearchConversationModel extends AbstractConversationModel {
private List<ConversationID> _conversations = new ArrayList<ConversationID>();
public SearchConversationModel(FrameworkModel model) {
super(model);
model.getConversationModel().addConversationListener(new Listener());
}
public void refilter() {
_conversations.clear();
if (_description != null) {
ConversationModel cmodel = _model.getConversationModel();
int count = cmodel.getConversationCount();
for (int i=0; i< count; i++) {
ConversationID id = cmodel.getConversationAt(i);
if (hasSearchMatch(id, _description)) {
_conversations.add(id);
}
}
}
}
public ConversationID getConversationAt(int index) {
return _conversations.get(index);
}
public int getConversationCount() {
return _conversations.size();
}
public int getIndexOfConversation(ConversationID id) {
return _conversations.indexOf(id);
}
public Sync readLock() {
return _rwl.readLock();
}
public void fireConversationsChanged() {
super.fireConversationsChanged();
}
private class Listener implements ConversationListener {
public void conversationAdded(ConversationEvent evt) {
}
public void conversationChanged(ConversationEvent evt) {
ConversationID id = evt.getConversationID();
int index = Collections.binarySearch(_conversations, id);
if (hasSearchMatch(id, _description)) {
if (index < 0) {
index = -index -1;
try {
_rwl.writeLock().acquire();
_conversations.add(index, id);
_rwl.readLock().acquire();
_rwl.writeLock().release();
SearchConversationModel.this.fireConversationAdded(id, index);
_rwl.readLock().release();
} catch (Exception e) {
e.printStackTrace();
}
}
} else {
if (index >= 0) {
try {
_rwl.writeLock().acquire();
_conversations.remove(index);
_rwl.readLock().acquire();
_rwl.writeLock().release();
SearchConversationModel.this.fireConversationRemoved(id, index);
_rwl.readLock().release();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public void conversationRemoved(ConversationEvent evt) {
ConversationID id = evt.getConversationID();
int index = Collections.binarySearch(_conversations, id);
if (index > -1) {
try {
_rwl.writeLock().acquire();
_conversations.remove(index);
_rwl.readLock().acquire();
_rwl.writeLock().release();
SearchConversationModel.this.fireConversationRemoved(id, index);
_rwl.readLock().release();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void conversationsChanged() {
setFilter(null);
}
}
}
}