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,