diff --git a/lib/oscar.client.run.properties b/lib/oscar.client.run.properties
index 6c86b9bc9..83614e0c2 100644
--- a/lib/oscar.client.run.properties
+++ b/lib/oscar.client.run.properties
@@ -20,9 +20,6 @@ org.osgi.framework.system.packages= org.osgi.framework; \
org.w3c.dom; \
org.xml.sax; \
javax.xml.parsers;\
- org.jaxen; \
- org.jaxen.dom; \
- org.jaxen.saxpath; \
org.apache.xml.serializer; \
javax.xml.transform; \
javax.xml.transform.dom; \
@@ -34,7 +31,7 @@ org.osgi.framework.system.packages= org.osgi.framework; \
edu.stanford.ejalbert; \
edu.stanford.ejalbert.exception; \
edu.stanford.ejalbert.exceptionhandler;
-
+
oscar.auto.start.1= \
file:lib/bundle/shell.jar \
file:lib/bundle/bundlerepository.jar \
diff --git a/lib/oscar.unit.test.properties b/lib/oscar.unit.test.properties
index 5a7fff35c..2e45cef6f 100644
--- a/lib/oscar.unit.test.properties
+++ b/lib/oscar.unit.test.properties
@@ -10,9 +10,6 @@ org.osgi.framework.system.packages= org.osgi.framework; \
org.w3c.dom; \
org.xml.sax; \
javax.xml.parsers;\
- org.jaxen; \
- org.jaxen.dom; \
- org.jaxen.saxpath; \
org.apache.xml.serializer;\
javax.xml.transform;\
javax.xml.transform.dom;\
diff --git a/resources/install/linux/run.sh b/resources/install/linux/run.sh
index 0f7bd3dca..ff63ed9a3 100755
--- a/resources/install/linux/run.sh
+++ b/resources/install/linux/run.sh
@@ -1,2 +1,2 @@
export JAVA_HOME=jre
-${JAVA_HOME}/bin/java -classpath "lib/JainSipApi1.1.jar:lib/Stun4J.jar:lib/architectureviewer1.1.jar:lib/bcprov-jdk14-130.jar:lib/jaxen-1.1-beta-8.jar:lib/joscar-0.9.4-cvs-bin.jar:lib/moduleloader.jar:lib/nist-sdp-1.0.jar:lib/nist-sip-1.2.jar:lib/oscar-aim.jar:lib/oscar.jar:lib/osgi.jar:lib/retroweaver-rt.jar:lib/retroweaver.jar:lib/servicebinder.jar" -Dicq.custom.message.charset=windows-1251 -Doscar.config.properties=file:./lib/oscar.client.run.properties -Djava.util.logging.config.file=lib/logging.properties org.ungoverned.oscar.Main
+${JAVA_HOME}/bin/java -classpath "lib/JainSipApi1.1.jar:lib/Stun4J.jar:lib/architectureviewer1.1.jar:lib/bcprov-jdk14-130.jar:lib/joscar-0.9.4-cvs-bin.jar:lib/moduleloader.jar:lib/nist-sdp-1.0.jar:lib/nist-sip-1.2.jar:lib/oscar-aim.jar:lib/oscar.jar:lib/osgi.jar:lib/retroweaver-rt.jar:lib/retroweaver.jar:lib/servicebinder.jar" -Dicq.custom.message.charset=windows-1251 -Doscar.config.properties=file:./lib/oscar.client.run.properties -Djava.util.logging.config.file=lib/logging.properties org.ungoverned.oscar.Main
diff --git a/resources/install/windows/run.bat b/resources/install/windows/run.bat
index ea053934d..0bbaf0f4c 100755
--- a/resources/install/windows/run.bat
+++ b/resources/install/windows/run.bat
@@ -1 +1 @@
-start javaw -classpath "lib/JainSipApi1.1.jar;lib/Stun4J.jar;lib/architectureviewer1.1.jar;lib/bcprov-jdk14-130.jar;lib/jaxen-1.1-beta-8.jar;lib/joscar-0.9.4-cvs-bin.jar;lib/moduleloader.jar;lib/nist-sdp-1.0.jar;lib/nist-sip-1.2.jar;lib/oscar-aim.jar;lib/oscar.jar;lib/osgi.jar;lib/retroweaver-rt.jar;lib/retroweaver.jar;lib/servicebinder.jar" -Dicq.custom.message.charset=windows-1251 -Doscar.config.properties=file:./lib/oscar.client.run.properties -Djava.util.logging.config.file=lib/logging.properties org.ungoverned.oscar.Main
+start javaw -classpath "lib/JainSipApi1.1.jar;lib/Stun4J.jar;lib/architectureviewer1.1.jar;lib/bcprov-jdk14-130.jar;lib/joscar-0.9.4-cvs-bin.jar;lib/moduleloader.jar;lib/nist-sdp-1.0.jar;lib/nist-sip-1.2.jar;lib/oscar-aim.jar;lib/oscar.jar;lib/osgi.jar;lib/retroweaver-rt.jar;lib/retroweaver.jar;lib/servicebinder.jar" -Dicq.custom.message.charset=windows-1251 -Doscar.config.properties=file:./lib/oscar.client.run.properties -Djava.util.logging.config.file=lib/logging.properties org.ungoverned.oscar.Main
diff --git a/src/net/java/sip/communicator/impl/history/HistoryReaderImpl.java b/src/net/java/sip/communicator/impl/history/HistoryReaderImpl.java
index e256e38f7..dfed54dbc 100644
--- a/src/net/java/sip/communicator/impl/history/HistoryReaderImpl.java
+++ b/src/net/java/sip/communicator/impl/history/HistoryReaderImpl.java
@@ -8,9 +8,6 @@
import java.util.*;
-import org.jaxen.*;
-import org.jaxen.dom.*;
-import org.jaxen.saxpath.*;
import org.w3c.dom.*;
import net.java.sip.communicator.service.history.*;
import net.java.sip.communicator.service.history.records.*;
@@ -21,96 +18,286 @@
* @author Alexander Pelov
* @author Damian Minkov
*/
-public class HistoryReaderImpl implements HistoryReader {
+public class HistoryReaderImpl
+ implements HistoryReader
+{
private static Logger logger = Logger.getLogger(HistoryReaderImpl.class);
private HistoryImpl historyImpl;
private Vector progressListeners = new Vector();
+ // regexp used for index of case(in)sensitive impl
+ private static String REGEXP_END = ".*$";
+ private static String REGEXP_SENSITIVE_START = "^.*";
+ private static String REGEXP_INSENSITIVE_START = "^(?i).*";
+
protected HistoryReaderImpl(HistoryImpl historyImpl)
{
this.historyImpl = historyImpl;
}
+ /**
+ * Searches the history for all records with timestamp after
+ * startDate.
+ *
+ * @param startDate the date after all records will be returned
+ * @return the found records
+ * @throws RuntimeException
+ * Thrown if an exception occurs during the execution of the
+ * query, such as internal IO error.
+ */
public QueryResultSet findByStartDate(Date startDate)
- throws RuntimeException {
- String expr = "/history/record[@timestamp>" + startDate.getTime() + "]";
-
- return this.findByXpath(expr, startDate, null, new ProgressEvent(this, startDate, null));
+ throws RuntimeException
+ {
+ return find(startDate, null, null, null, false);
}
+ /**
+ * Searches the history for all records with timestamp before
+ * endDate.
+ *
+ * @param endDate the date before which all records will be returned
+ * @return the found records
+ * @throws RuntimeException
+ * Thrown if an exception occurs during the execution of the
+ * query, such as internal IO error.
+ */
public QueryResultSet findByEndDate(Date endDate)
throws RuntimeException
{
- String expr = "/history/record[@timestamp<" + endDate.getTime() + "]";
-
- return this.findByXpath(expr, null, endDate,
- new ProgressEvent(this, null, endDate, null, null));
+ return find(null, endDate, null, null, false);
}
+ /**
+ * Searches the history for all records with timestamp between
+ * startDate and endDate.
+ *
+ * @param startDate start of the interval in which we search
+ * @param endDate end of the interval in which we search
+ * @return the found records
+ * @throws RuntimeException
+ * Thrown if an exception occurs during the execution of the
+ * query, such as internal IO error.
+ */
public QueryResultSet findByPeriod(Date startDate, Date endDate)
- throws RuntimeException {
- String expr = "/history/record[@timestamp>" + startDate.getTime() + "]"
- + "[@timestamp<" + endDate.getTime() + "]";
-
- return this.findByXpath(expr, startDate, endDate,
- new ProgressEvent(this, startDate, endDate, null, null));
+ throws RuntimeException
+ {
+ return find(startDate, endDate, null, null, false);
}
+ /**
+ * Searches the history for all records containing the keyword.
+ *
+ * @param keyword the keyword to search for
+ * @param field the field where to look for the keyword
+ * @return the found records
+ * @throws RuntimeException
+ * Thrown if an exception occurs during the execution of the
+ * query, such as internal IO error.
+ */
public QueryResultSet findByKeyword(String keyword, String field)
throws RuntimeException
{
return findByKeywords(new String[] { keyword }, field);
}
+ /**
+ * Searches the history for all records containing all keywords.
+ *
+ * @param keywords array of keywords we search for
+ * @param field the field where to look for the keyword
+ * @return the found records
+ * @throws RuntimeException
+ * Thrown if an exception occurs during the execution of the
+ * query, such as internal IO error.
+ */
public QueryResultSet findByKeywords(String[] keywords, String field)
- throws RuntimeException {
-
- String expr = "/history/record";
- for (int i = 0; i < keywords.length; i++)
- {
- expr += "[contains(" + field + "/text(),'" + keywords[i] + "')]";
- }
-
- return this.findByXpath(expr, null, null, new ProgressEvent(this, null, null, null, keywords));
+ throws RuntimeException
+ {
+ return find(null, null, keywords, field, false);
}
+ /**
+ * Searches for all history records containing all keywords,
+ * with timestamp between startDate and endDate.
+ *
+ * @param startDate start of the interval in which we search
+ * @param endDate end of the interval in which we search
+ * @param keywords array of keywords we search for
+ * @param field the field where to look for the keyword
+ * @return the found records
+ * @throws UnsupportedOperationException
+ * Thrown if an exception occurs during the execution of the
+ * query, such as internal IO error.
+ */
public QueryResultSet findByPeriod(Date startDate, Date endDate,
String[] keywords, String field) throws UnsupportedOperationException
{
- String expr = "/history/record[@timestamp>" + startDate.getTime() + "]"
- + "[@timestamp<" + endDate.getTime() + "]";
- for (int i = 0; i < keywords.length; i++)
+ return find(startDate, endDate, keywords, field, false);
+ }
+
+ /**
+ * Returns the last count messages.
+ * No progress firing as this method is supposed to be used
+ * in message windows and is supposed to be as quick as it can.
+ *
+ * @param count int
+ * @return QueryResultSet
+ * @throws RuntimeException
+ */
+ public QueryResultSet findLast(int count) throws RuntimeException
+ {
+ // the files are supposed to be ordered from oldest to newest
+ Vector filelist =
+ filterFilesByDate(this.historyImpl.getFileList(), null, null);
+
+ TreeSet result = new TreeSet(new HistoryRecordComparator());
+ int leftCount = count;
+ int currentFile = filelist.size() - 1;
+
+ while(leftCount > 0 && currentFile >= 0)
{
- expr += "[contains(" + field + "/text(),'" + keywords[i] + "')]";
+ Document doc = this.historyImpl.
+ getDocumentForFile( (String) filelist.get(currentFile));
+
+ // will get nodes and construct a List of nodes
+ // so we can easyly get sublist of it
+ List nodes = new ArrayList();
+ NodeList nodesList = doc.getElementsByTagName("record");
+ for (int i = 0; i < nodesList.getLength(); i++)
+ {
+ nodes.add(nodesList.item(i));
+ }
+
+ List lNodes = null;
+
+ if (nodes.size() > leftCount)
+ {
+ lNodes = nodes.subList(nodes.size() - leftCount , nodes.size());
+ leftCount = 0;
+ }
+ else
+ {
+ lNodes = nodes;
+ leftCount -= nodes.size();
+ }
+
+ Iterator i = lNodes.iterator();
+ while (i.hasNext())
+ {
+ Node node = (Node) i.next();
+
+ NodeList propertyNodes = node.getChildNodes();
+
+ String ts = node.getAttributes().getNamedItem("timestamp")
+ .getNodeValue();
+ Date timestamp = new Date(Long.parseLong(ts));
+
+ ArrayList nameVals = new ArrayList();
+
+ int len = propertyNodes.getLength();
+ for (int j = 0; j < len; j++)
+ {
+ Node propertyNode = propertyNodes.item(j);
+ if (propertyNode.getNodeType() == Node.ELEMENT_NODE)
+ {
+ nameVals.add(propertyNode.getNodeName());
+ // Get nested TEXT node's value
+ nameVals.add(propertyNode.getFirstChild()
+ .getNodeValue());
+ }
+ }
+
+ String[] propertyNames = new String[nameVals.size() / 2];
+ String[] propertyValues = new String[propertyNames.length];
+ for (int j = 0; j < propertyNames.length; j++)
+ {
+ propertyNames[j] = (String) nameVals.get(j * 2);
+ propertyValues[j] = (String) nameVals.get(j * 2 + 1);
+ }
+
+ HistoryRecord record = new HistoryRecord(propertyNames,
+ propertyValues, timestamp);
+
+ result.add(record);
+ }
+
+ currentFile--;
}
- return this.findByXpath(expr, startDate, endDate,
- new ProgressEvent(this, startDate, endDate, null, keywords));
+ return new OrderedQueryResultSet(result);
}
- public BidirectionalIterator bidirectionalIterator()
+ /**
+ * Searches the history for all records containing the keyword.
+ *
+ * @param keyword the keyword to search for
+ * @param field the field where to look for the keyword
+ * @param caseSensitive is keywords search case sensitive
+ * @return the found records
+ * @throws RuntimeException
+ * Thrown if an exception occurs during the execution of the
+ * query, such as internal IO error.
+ */
+ public QueryResultSet findByKeyword(String keyword, String field,
+ boolean caseSensitive)
+ throws RuntimeException
{
- String expr = "/history/record";
-
- return this.findByXpath(expr, null, null, new ProgressEvent(this, null, null, null, null));
+ return findByKeywords(new String[] { keyword }, field, caseSensitive);
}
- public Iterator iterator()
+ /**
+ * Searches the history for all records containing all keywords.
+ *
+ * @param keywords array of keywords we search for
+ * @param field the field where to look for the keyword
+ * @param caseSensitive is keywords search case sensitive
+ * @return the found records
+ * @throws RuntimeException
+ * Thrown if an exception occurs during the execution of the
+ * query, such as internal IO error.
+ */
+ public QueryResultSet findByKeywords(String[] keywords, String field,
+ boolean caseSensitive)
+ throws RuntimeException
{
- return this.bidirectionalIterator();
+ return find(null, null, keywords, field, caseSensitive);
}
+ /**
+ * Searches for all history records containing all keywords,
+ * with timestamp between startDate and endDate.
+ *
+ * @param startDate start of the interval in which we search
+ * @param endDate end of the interval in which we search
+ * @param keywords array of keywords we search for
+ * @param field the field where to look for the keyword
+ * @param caseSensitive is keywords search case sensitive
+ * @return the found records
+ * @throws UnsupportedOperationException
+ * Thrown if an exception occurs during the execution of the
+ * query, such as internal IO error.
+ */
+ public QueryResultSet findByPeriod(Date startDate, Date endDate,
+ String[] keywords, String field,
+ boolean caseSensitive)
+ throws UnsupportedOperationException
+ {
+ return find(startDate, endDate, keywords, field, caseSensitive);
+ }
- private QueryResultSet findByXpath(String xpathExpression,
- Date startDate, Date endDate,
- ProgressEvent progressEvent)
+ private QueryResultSet find(
+ Date startDate, Date endDate,
+ String[] keywords, String field, boolean caseSensitive)
{
TreeSet result = new TreeSet(new HistoryRecordComparator());
Vector filelist =
filterFilesByDate(this.historyImpl.getFileList(), startDate, endDate);
+ ProgressEvent progressEvent =
+ new ProgressEvent(this, startDate, endDate, keywords);
+
int currentProgress = HistorySearchProgressListener.PROGRESS_MINIMUM_VALUE;
int fileProgressStep = HistorySearchProgressListener.PROGRESS_MAXIMUM_VALUE;
@@ -121,17 +308,6 @@ private QueryResultSet findByXpath(String xpathExpression,
// start progress - minimum value
fireProgressStateChanged(progressEvent, HistorySearchProgressListener.PROGRESS_MINIMUM_VALUE);
- Navigator navigator = DocumentNavigator.getInstance();
- XPath xpath;
-
- try
- {
- xpath = navigator.parseXPath(xpathExpression);
- } catch (SAXPathException e)
- {
- throw new RuntimeException(e);
- }
-
Iterator fileIterator = filelist.iterator();
while (fileIterator.hasNext())
{
@@ -139,70 +315,165 @@ private QueryResultSet findByXpath(String xpathExpression,
Document doc = this.historyImpl.getDocumentForFile(filename);
- List nodes;
- try {
- nodes = xpath.selectNodes(doc);
- }
- catch (JaxenException e)
- {
- throw new RuntimeException(e);
- }
+ NodeList nodes = doc.getElementsByTagName("record");
int nodesProgressStep = fileProgressStep;
- if(nodes.size() != 0)
- nodesProgressStep = fileProgressStep / nodes.size();
+ if(nodes.getLength() != 0)
+ nodesProgressStep = fileProgressStep / nodes.getLength();
- Iterator i = nodes.iterator();
- while (i.hasNext())
+ Node node;
+ for (int i = 0; i < nodes.getLength(); i++)
{
- Node node = (Node) i.next();
-
- NodeList propertyNodes = node.getChildNodes();
+ node = nodes.item(i);
String ts = node.getAttributes().getNamedItem("timestamp")
.getNodeValue();
- Date timestamp = new Date(Long.parseLong(ts));
- ArrayList nameVals = new ArrayList();
+ Date timestamp = new Date(Long.parseLong(ts));
- int len = propertyNodes.getLength();
- for (int j = 0; j < len; j++)
+ if(isInPeriod(timestamp, startDate, endDate))
{
- Node propertyNode = propertyNodes.item(j);
- if (propertyNode.getNodeType() == Node.ELEMENT_NODE)
+ NodeList propertyNodes = node.getChildNodes();
+
+ HistoryRecord record =
+ filterByKeyword(propertyNodes, timestamp,
+ keywords, field, caseSensitive);
+
+ if(record != null)
{
- nameVals.add(propertyNode.getNodeName());
- // Get nested TEXT node's value
- nameVals.add(propertyNode.getFirstChild()
- .getNodeValue());
+ result.add(record);
}
}
- String[] propertyNames = new String[nameVals.size() / 2];
- String[] propertyValues = new String[propertyNames.length];
- for (int j = 0; j < propertyNames.length; j++)
- {
- propertyNames[j] = (String) nameVals.get(j * 2);
- propertyValues[j] = (String) nameVals.get(j * 2 + 1);
- }
-
- HistoryRecord record = new HistoryRecord(propertyNames,
- propertyValues, timestamp);
-
- result.add(record);
-
currentProgress += nodesProgressStep;
fireProgressStateChanged(progressEvent, currentProgress);
}
}
// end progress - maximum value
- fireProgressStateChanged(progressEvent, HistorySearchProgressListener.PROGRESS_MAXIMUM_VALUE);
+ fireProgressStateChanged(progressEvent,
+ HistorySearchProgressListener.PROGRESS_MAXIMUM_VALUE);
return new OrderedQueryResultSet(result);
}
+ /**
+ * Evaluetes does timestamp is in the given time period.
+ *
+ * @param timestamp Date
+ * @param startDate Date the start of the period
+ * @param endDate Date the end of the period
+ * @return boolean
+ */
+ private boolean isInPeriod(Date timestamp, Date startDate, Date endDate)
+ {
+ if(startDate == null)
+ {
+ if(endDate == null)
+ return true;
+ else
+ return timestamp.before(endDate);
+ }
+ else
+ {
+ if(endDate == null)
+ return timestamp.after(startDate);
+ else
+ return timestamp.after(startDate) && timestamp.before(endDate);
+ }
+ }
+
+ /**
+ * If there is keyword restriction and doesn't match the conditions
+ * return null. Otherwise return the HistoryRecord corresponding the
+ * given nodes.
+ *
+ * @param propertyNodes NodeList
+ * @param timestamp Date
+ * @param keywords String[]
+ * @param field String
+ * @param caseSensitive boolean
+ * @return HistoryRecord
+ */
+ private HistoryRecord filterByKeyword(NodeList propertyNodes,
+ Date timestamp,
+ String[] keywords,
+ String field,
+ boolean caseSensitive)
+ {
+ ArrayList nameVals = new ArrayList();
+ int len = propertyNodes.getLength();
+ for (int j = 0; j < len; j++)
+ {
+ Node propertyNode = propertyNodes.item(j);
+ if (propertyNode.getNodeType() == Node.ELEMENT_NODE)
+ {
+ String nodeName = propertyNode.getNodeName();
+ // Get nested TEXT node's value
+ String nodeValue =
+ propertyNode.getFirstChild().getNodeValue();
+
+ if(field != null && field.equals(nodeName)
+ && !matchKeyword(nodeValue, keywords, caseSensitive))
+ {
+ return null; // doesn't match the given keyword(s)
+ // so return nothing
+ }
+
+ nameVals.add(nodeName);
+ // Get nested TEXT node's value
+ nameVals.add(propertyNode.getFirstChild().getNodeValue());
+
+ }
+ }
+
+ String[] propertyNames = new String[nameVals.size() / 2];
+ String[] propertyValues = new String[propertyNames.length];
+ for (int j = 0; j < propertyNames.length; j++)
+ {
+ propertyNames[j] = (String) nameVals.get(j * 2);
+ propertyValues[j] = (String) nameVals.get(j * 2 + 1);
+ }
+
+ return new HistoryRecord(propertyNames, propertyValues, timestamp);
+ }
+
+ /**
+ * Check if a value is in the given keyword(s)
+ * If no keyword(s) given must return true
+ *
+ * @param value String
+ * @param keywords String[]
+ * @param caseSensitive boolean
+ * @return boolean
+ */
+ private boolean matchKeyword(String value, String[] keywords,
+ boolean caseSensitive)
+ {
+ if(keywords != null)
+ {
+ String regexpStart = null;
+ if(caseSensitive)
+ regexpStart = REGEXP_SENSITIVE_START;
+ else
+ regexpStart = REGEXP_INSENSITIVE_START;
+
+ for (int i = 0; i < keywords.length; i++)
+ {
+ if(!value.matches(regexpStart + keywords[i] + REGEXP_END))
+ return false;
+ }
+
+ // all keywords match return true
+ return true;
+ }
+
+ // if no keyword or keywords given
+ // we must not filter this record so will return true
+ return true;
+ }
+
/**
* Used to limit the files if any starting or ending date exist
* So only few files to be searched.
@@ -304,12 +575,22 @@ private void fireProgressStateChanged(ProgressEvent event, int progress)
}
}
+ /**
+ * Adding progress listener for monitoring progress of search process
+ *
+ * @param listener HistorySearchProgressListener
+ */
public void addSearchProgressListener(HistorySearchProgressListener
listener)
{
progressListeners.add(listener);
}
+ /**
+ * Removing progress listener
+ *
+ * @param listener HistorySearchProgressListener
+ */
public void removeSearchProgressListener(HistorySearchProgressListener
listener)
{
diff --git a/src/net/java/sip/communicator/impl/history/history.manifest.mf b/src/net/java/sip/communicator/impl/history/history.manifest.mf
index 7f5338830..a4939b37d 100644
--- a/src/net/java/sip/communicator/impl/history/history.manifest.mf
+++ b/src/net/java/sip/communicator/impl/history/history.manifest.mf
@@ -18,9 +18,6 @@ Import-Package: org.ungoverned.gravity.servicebinder,
javax.xml.transform.stream,
net.java.sip.communicator.util,
net.java.sip.communicator.util.xml,
- org.jaxen,
- org.jaxen.dom,
- org.jaxen.saxpath,
Export-Package: net.java.sip.communicator.service.history,
net.java.sip.communicator.impl.history,
net.java.sip.communicator.service.history.records,