/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
*
* 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 net.java.sip.communicator.impl.history;
import static
net.java.sip.communicator.service.history.HistoryService.DATE_FORMAT;
import java.text.*;
import java.util.*;
import net.java.sip.communicator.service.history.*;
import net.java.sip.communicator.service.history.event.*;
import net.java.sip.communicator.service.history.records.*;
import org.w3c.dom.*;
/**
* The <tt>InteractiveHistoryReaderImpl</tt> is an implementation of the
* <tt>InteractiveHistoryReader</tt> interface. It allows to search in the
* history in an interactive way, i.e. be able to cancel the search at any time
* and track the results through a <tt>HistoryQueryListener</tt>.
*
* @author Yana Stamcheva
*/
public class InteractiveHistoryReaderImpl
implements InteractiveHistoryReader
{
/**
* The <tt>HistoryImpl</tt> where this reader is registered.
*/
private final HistoryImpl history;
/**
* Creates an instance of <tt>InteractiveHistoryReaderImpl</tt> by
* specifying the corresponding <tt>history</tt> implementation.
* @param history the corresponding <tt>HistoryImpl</tt> to read from
*/
public InteractiveHistoryReaderImpl(HistoryImpl history)
{
this.history = history;
}
/**
* Searches the history for all records containing the <tt>keyword</tt>.
*
* @param keyword the keyword to search for
* @param field the field where to look for the keyword
* @param recordCount limits the result to this record count
* @return the found records
* @throws RuntimeException
* Thrown if an exception occurs during the execution of the
* query, such as internal IO error.
*/
public HistoryQuery findByKeyword( String keyword,
String field,
int recordCount)
{
return findByKeywords(new String[]{keyword}, field, recordCount);
}
/**
* Searches the history for all records containing all <tt>keywords</tt>.
*
* @param keywords array of keywords we search for
* @param field the field where to look for the keyword
* @param recordCount limits the result to this record count
* @return the found records
* @throws RuntimeException
* Thrown if an exception occurs during the execution of the
* query, such as internal IO error.
*/
public HistoryQuery findByKeywords( String[] keywords,
String field,
int recordCount)
{
return find(null, null, keywords, field, false, recordCount);
}
/**
* Finds the history results corresponding to the given criteria.
* @param startDate the start date
* @param endDate the end date
* @param keywords an array of keywords to search for
* @param field the field, where to search the keywords
* @param caseSensitive indicates if the search should be case sensitive
* @param resultCount the desired number of results
* @return the <tt>HistoryQuery</tt> that could be used to track the results
* or to cancel the search
*/
private HistoryQuery find( final Date startDate,
final Date endDate,
final String[] keywords,
final String field,
final boolean caseSensitive,
final int resultCount)
{
StringBuilder queryString = new StringBuilder();
for (String s : keywords)
{
queryString.append(' ');
queryString.append(s);
}
final HistoryQueryImpl query
= new HistoryQueryImpl(queryString.toString());
new Thread()
{
@Override
public void run()
{
find(startDate, endDate, keywords, field, caseSensitive,
resultCount, query);
}
}.start();
return query;
}
/**
* Finds the history results corresponding to the given criteria.
* @param startDate the start date
* @param endDate the end date
* @param keywords an array of keywords to search for
* @param field the field, where to search the keywords
* @param caseSensitive indicates if the search should be case sensitive
* @param resultCount the desired number of results
* @param query the query tracking the results
*/
private void find( Date startDate,
Date endDate,
String[] keywords,
String field,
boolean caseSensitive,
int resultCount,
HistoryQueryImpl query)
{
Vector<String> filelist
= HistoryReaderImpl.filterFilesByDate( history.getFileList(),
startDate, endDate, true);
Iterator<String> fileIterator = filelist.iterator();
SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
while (fileIterator.hasNext() && resultCount > 0 && !query.isCanceled())
{
String filename = fileIterator.next();
Document doc = history.getDocumentForFile(filename);
if(doc == null)
continue;
NodeList nodes = doc.getElementsByTagName("record");
for ( int i = nodes.getLength() - 1;
i >= 0 && !query.isCanceled();
i--)
{
Node node = nodes.item(i);
Date timestamp;
String ts = node.getAttributes().getNamedItem("timestamp")
.getNodeValue();
try
{
timestamp = sdf.parse(ts);
}
catch (ParseException e)
{
timestamp = new Date(Long.parseLong(ts));
}
if(HistoryReaderImpl.isInPeriod(timestamp, startDate, endDate))
{
NodeList propertyNodes = node.getChildNodes();
HistoryRecord record =
HistoryReaderImpl
.filterByKeyword(propertyNodes, timestamp,
keywords, field, caseSensitive);
if(record != null)
{
query.addHistoryRecord(record);
resultCount--;
}
}
}
}
if (query.isCanceled())
query.setStatus(HistoryQueryStatusEvent.QUERY_CANCELED);
else
query.setStatus(HistoryQueryStatusEvent.QUERY_COMPLETED);
}
}