/*******************************************************************************
* Copyright (c) 2010, 2011 LogSaw project and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* LogSaw project committers - initial API and implementation
*******************************************************************************/
package net.sf.logsaw.index.internal;
import java.io.IOException;
import java.io.StringReader;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
import net.sf.logsaw.core.dialect.ILogDialect;
import net.sf.logsaw.core.dialect.ILogEntryCollector;
import net.sf.logsaw.core.dialect.support.ALogEntryCollector;
import net.sf.logsaw.core.field.ALogEntryField;
import net.sf.logsaw.core.field.ILogEntryFieldVisitor;
import net.sf.logsaw.core.field.Level;
import net.sf.logsaw.core.field.LogEntry;
import net.sf.logsaw.core.field.LogEntryFieldVisitorAdapter;
import net.sf.logsaw.core.field.model.DateLogEntryField;
import net.sf.logsaw.core.field.model.LevelLogEntryField;
import net.sf.logsaw.core.field.model.StringLogEntryField;
import net.sf.logsaw.core.logresource.IHasTimestampPattern;
import net.sf.logsaw.core.logresource.ILogResource;
import net.sf.logsaw.core.query.IRestrictionVisitor;
import net.sf.logsaw.core.query.Operators;
import net.sf.logsaw.core.query.model.DateRestriction;
import net.sf.logsaw.core.query.model.LevelRestriction;
import net.sf.logsaw.core.query.model.StringRestriction;
import net.sf.logsaw.core.query.support.ARestriction;
import net.sf.logsaw.core.util.DateFormatUtils;
import net.sf.logsaw.index.IIndexService;
import net.sf.logsaw.index.IQueryContext;
import net.sf.logsaw.index.IndexPlugin;
import net.sf.logsaw.index.ResultPage;
import net.sf.logsaw.index.SynchronizationResult;
import org.apache.commons.io.FileUtils;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.miscellaneous.LimitTokenCountAnalyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.IntField;
import org.apache.lucene.document.LongField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.PhraseQuery;
import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.TopFieldCollector;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.osgi.util.NLS;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A Lucene-based implementation of <code>IIndexService</code>.
*
* @author Philipp Nanz
*/
public class LuceneIndexServiceImpl implements IIndexService {
private static transient Logger logger = LoggerFactory.getLogger(LuceneIndexServiceImpl.class);
/* (non-Javadoc)
* @see net.sf.logsaw.index.IIndexService#synchronize(net.sf.logsaw.core.ILogResource, org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
public SynchronizationResult synchronize(ILogResource log, IProgressMonitor monitor) throws CoreException {
Assert.isNotNull(log, "log"); //$NON-NLS-1$
if (monitor == null) {
monitor = new NullProgressMonitor();
}
Date latestEntryDate = null;
if (log.getDialect().getFieldProvider().getTimestampField() != null) {
latestEntryDate = getLatestEntryDate(log); // the barrier timestamp
}
return updateIndex(log, latestEntryDate, monitor);
}
/* (non-Javadoc)
* @see net.sf.logsaw.index.IIndexService#unlock(net.sf.logsaw.core.ILogResource)
*/
@Override
public boolean unlock(ILogResource log) throws CoreException {
Assert.isNotNull(log, "log"); //$NON-NLS-1$
try {
Directory dir = FSDirectory.open(IndexPlugin.getDefault().getIndexFile(log));
if (IndexWriter.isLocked(dir)) {
IndexWriter.unlock(dir);
return true;
}
return false;
} catch (IOException e) {
// Unexpected exception; wrap with CoreException
throw new CoreException(new Status(IStatus.ERROR, IndexPlugin.PLUGIN_ID,
NLS.bind(Messages.LuceneIndexService_error_failedToUnlockIndex,
new Object[] {log.getName(), e.getLocalizedMessage()}), e));
}
}
/* (non-Javadoc)
* @see net.sf.logsaw.index.IIndexService#count(net.sf.logsaw.core.ILogResource)
*/
@Override
public int count(ILogResource log) throws CoreException {
Assert.isNotNull(log, "log"); //$NON-NLS-1$
ARunWithIndexReader<Integer> runnable = new ARunWithIndexReader<Integer>() {
/* (non-Javadoc)
* @see net.sf.logsaw.index.impl.ARunWithIndexReader#doRunWithIndexReader(org.apache.lucene.index.IndexReader, net.sf.logsaw.core.framework.ILogResource)
*/
@Override
protected Integer doRunWithIndexReader(IndexReader reader, ILogResource log) throws CoreException {
if (reader != null) {
return Integer.valueOf(reader.numDocs());
}
// Index does not exist yet
return Integer.valueOf(0);
}
};
return runnable.runWithIndexReader(log);
}
/* (non-Javadoc)
* @see net.sf.logsaw.index.IIndexService#size(net.sf.logsaw.core.framework.ILogResource)
*/
@Override
public String size(ILogResource log) {
Assert.isNotNull(log, "log"); //$NON-NLS-1$
long size = FileUtils.sizeOfDirectory(IndexPlugin.getDefault().getIndexFile(log));
return FileUtils.byteCountToDisplaySize(size);
}
/* (non-Javadoc)
* @see net.sf.logsaw.index.IIndexService#truncate(net.sf.logsaw.core.framework.ILogResource)
*/
@Override
public void truncate(ILogResource log) throws CoreException {
Assert.isNotNull(log, "log"); //$NON-NLS-1$
ARunWithIndexWriter<Boolean> runnable = new ARunWithIndexWriter<Boolean>() {
/* (non-Javadoc)
* @see net.sf.logsaw.index.impl.ARunWithIndexWriter#doRunWithIndexWriter(org.apache.lucene.index.IndexWriter, net.sf.logsaw.core.framework.ILogResource)
*/
@Override
protected Boolean doRunWithIndexWriter(IndexWriter writer, ILogResource log) throws CoreException {
truncate(log, writer);
return Boolean.TRUE;
}
};
runnable.runWithIndexWriter(log, getAnalyzer(), getMatchVersion());
}
/* (non-Javadoc)
* @see net.sf.logsaw.index.IIndexService#createIndex(net.sf.logsaw.core.logresource.ILogResource)
*/
@Override
public void createIndex(ILogResource log) throws CoreException {
Assert.isNotNull(log, "log"); //$NON-NLS-1$
Assert.isTrue(log.getPK() == null, "PK must be null"); //$NON-NLS-1$
log.setPK(UUID.randomUUID().toString());
}
/* (non-Javadoc)
* @see net.sf.logsaw.index.IIndexService#deleteIndex(net.sf.logsaw.core.logresource.ILogResource)
*/
@Override
public void deleteIndex(ILogResource log) throws CoreException {
Assert.isNotNull(log, "log"); //$NON-NLS-1$
try {
FileUtils.deleteDirectory(IndexPlugin.getDefault().getIndexFile(log));
} catch (IOException e) {
// Throw warning
throw new CoreException(new Status(IStatus.WARNING, IndexPlugin.PLUGIN_ID,
NLS.bind(Messages.LuceneIndexService_error_failedToDeleteIndex, log.getName())));
}
}
/* (non-Javadoc)
* @see net.sf.logsaw.index.IIndexService#createQueryContext(net.sf.logsaw.core.ILogResource)
*/
@Override
public IQueryContext createQueryContext(ILogResource log) {
Assert.isNotNull(log, "log"); //$NON-NLS-1$
return new LuceneQueryContextImpl(log);
}
/* (non-Javadoc)
* @see net.sf.logsaw.index.IIndexService#query(net.sf.logsaw.index.IQueryContext, java.util.List, int, int)
*/
@Override
public ResultPage query(IQueryContext context, final List<ARestriction<?>> restrictions,
final int offset, final int limit) throws CoreException {
Assert.isNotNull(context, "context"); //$NON-NLS-1$
Assert.isTrue(context instanceof LuceneQueryContextImpl,
"Query context must be of type net.sf.logsaw.index.impl.LuceneQueryContextImpl"); //$NON-NLS-1$
Assert.isTrue(context.isOpen(), "Query context must be open"); //$NON-NLS-1$
Assert.isNotNull(restrictions, "restrictions"); //$NON-NLS-1$
ARunWithIndexReader<ResultPage> runnable = new ARunWithIndexReader<ResultPage>() {
/* (non-Javadoc)
* @see net.sf.logsaw.index.impl.ARunWithIndexReader#doRunWithIndexReader(org.apache.lucene.index.IndexReader, net.sf.logsaw.core.framework.ILogResource)
*/
@Override
protected ResultPage doRunWithIndexReader(IndexReader reader, ILogResource log) throws CoreException {
if (reader == null) {
// Index does not exist yet
return new ResultPage();
}
try {
IndexSearcher searcher = new IndexSearcher(reader);
Sort sort = new Sort(new SortField[] {SortField.FIELD_DOC});
TopFieldCollector collector = TopFieldCollector.create(
sort, offset + limit, false, false, false, true);
// TODO Investigate use of searchAfter
searcher.search(convertToQuery(restrictions), collector);
List<LogEntry> result = new LinkedList<LogEntry>();
collectHits(searcher, collector.topDocs(offset), log.getDialect(), result);
return new ResultPage(result, offset, collector.getTotalHits());
} catch (IOException e) {
// Unexpected exception; wrap with CoreException
throw new CoreException(new Status(IStatus.ERROR, IndexPlugin.PLUGIN_ID,
NLS.bind(Messages.LuceneIndexService_error_failedToReadIndex,
new Object[] {log.getName(), e.getLocalizedMessage()}), e));
}
}
};
runnable.setQueryContext((LuceneQueryContextImpl) context);
return runnable.runWithIndexReader(context.getLogResource());
}
/**
* Returns the Lucene analyzer to use for indexing text fields.
* <p>
* Defaults to a <code>StandardAnalyzer</code> with Lucene 4.1 semantics.
*
* @return the Lucene analyzer to use
*/
protected Analyzer getAnalyzer() {
return new LimitTokenCountAnalyzer(new StandardAnalyzer(getMatchVersion()), 10000);
}
/**
* Returns the Lucene match version.
* <p>
* Defaults to Lucene 4.1 semantics.
*
* @return the Lucene match version to use
*/
protected Version getMatchVersion() {
return Version.LUCENE_41;
}
/*
* PRIVATE METHODS
*/
private Date getLatestEntryDate(ILogResource log) throws CoreException {
if (!hasDateComponent(log)) {
return null;
}
ARunWithIndexReader<Date> runnable = new ARunWithIndexReader<Date>() {
/* (non-Javadoc)
* @see net.sf.logsaw.index.impl.ARunWithIndexReader#doRunWithIndexReader(org.apache.lucene.index.IndexReader, net.sf.logsaw.core.framework.ILogResource)
*/
@Override
protected Date doRunWithIndexReader(IndexReader reader, ILogResource log) throws CoreException {
if (reader == null) {
// Index does not exist yet
return null;
}
int i = reader.maxDoc();
if (i > 0) {
try {
Document doc = reader.document(i - 1);
String val = doc.get(log.getDialect().getFieldProvider().getTimestampField().getKey());
return log.getDialect().getFieldProvider().getTimestampField().fromIndexedValue(val);
} catch (IOException e) {
// Unexpected exception; wrap with CoreException
throw new CoreException(new Status(IStatus.ERROR, IndexPlugin.PLUGIN_ID,
NLS.bind(Messages.LuceneIndexService_error_failedToReadIndex,
new Object[] {log.getName(), e.getLocalizedMessage()}), e));
}
}
return null;
}
};
return runnable.runWithIndexReader(log);
}
private boolean hasDateComponent(ILogResource log) {
IHasTimestampPattern hasPattern =
(IHasTimestampPattern) log.getDialect().getAdapter(IHasTimestampPattern.class);
if ((hasPattern != null) && (hasPattern.getTimestampPattern() != null)) {
return DateFormatUtils.hasDateComponent(hasPattern.getTimestampPattern());
}
return true;
}
private SynchronizationResult updateIndex(ILogResource log, final Date latestEntryDate,
final IProgressMonitor monitor) throws CoreException {
// Measure runtime
final long startTime = System.currentTimeMillis();
ARunWithIndexWriter<SynchronizationResult> runnable = new ARunWithIndexWriter<SynchronizationResult>() {
/* (non-Javadoc)
* @see net.sf.logsaw.index.impl.ARunWithIndexWriter#doRunWithIndexWriter(org.apache.lucene.index.IndexWriter, net.sf.logsaw.core.framework.ILogResource)
*/
@Override
protected SynchronizationResult doRunWithIndexWriter(final IndexWriter writer,
final ILogResource log) throws CoreException {
ILogEntryCollector collector = new ALogEntryCollector(monitor) {
/* (non-Javadoc)
* @see net.sf.logsaw.core.framework.support.ALogEntryCollector#doCollect(net.sf.logsaw.core.model.LogEntry)
*/
@Override
protected boolean doCollect(final LogEntry entry)
throws IOException {
final Document doc = new Document();
if (latestEntryDate != null) {
Date d = entry.get(log.getDialect().getFieldProvider().getTimestampField());
if (!d.after(latestEntryDate)) {
// Skip entry because it was already indexed
return false;
}
}
// Setup visitor
ILogEntryFieldVisitor visitor = new ILogEntryFieldVisitor() {
/* (non-Javadoc)
* @see net.sf.logsaw.core.model.ILogEntryFieldVisitor#visit(net.sf.logsaw.core.model.StringLogEntryField)
*/
@Override
public void visit(StringLogEntryField fld) {
// Decide whether to analyze the field
if (fld.isAnalyzed()) {
doc.add(new TextField(fld.getKey(),
fld.toIndexedValue(entry.get(fld)),
Field.Store.YES));
} else {
doc.add(new StringField(fld.getKey(),
fld.toIndexedValue(entry.get(fld)),
Field.Store.YES));
}
}
/* (non-Javadoc)
* @see net.sf.logsaw.core.model.ILogEntryFieldVisitor#visit(net.sf.logsaw.core.model.LevelLogEntryField)
*/
@Override
public void visit(LevelLogEntryField fld) {
Level lvl = entry.get(fld);
Assert.isTrue(lvl.getValue() > 0, "Level value must be a positive integer"); //$NON-NLS-1$
doc.add(new IntField(
fld.getKey(), fld.toIndexedValue(lvl), Field.Store.YES));
}
/* (non-Javadoc)
* @see net.sf.logsaw.core.model.ILogEntryFieldVisitor#visit(net.sf.logsaw.core.model.DateLogEntryField)
*/
@Override
public void visit(DateLogEntryField fld) {
doc.add(new LongField(
fld.getKey(), fld.toIndexedValue(entry.get(fld)), Field.Store.YES));
}
};
for (ALogEntryField<?, ?> fld : log.getDialect().getFieldProvider().getAllFields()) {
if (entry.contains(fld)) {
fld.visit(visitor);
}
}
writer.addDocument(doc);
return true;
}
};
if (log.getDialect().getFieldProvider().getTimestampField() == null) {
// We have no barrier timestamp, so perform truncate to avoid duplicates
truncate(log, writer);
collector.addMessage(new Status(IStatus.INFO, IndexPlugin.PLUGIN_ID,
Messages.LuceneIndexService_info_autoTruncate_noTimestampField));
} else if (!hasDateComponent(log)) {
// The date format only contains time components, so perform truncate to avoid duplicates
truncate(log, writer);
collector.addMessage(new Status(IStatus.INFO, IndexPlugin.PLUGIN_ID,
Messages.LuceneIndexService_info_autoTruncate_noDateComponent));
}
// Perform synchronize
log.synchronize(collector, monitor);
return new SynchronizationResult(monitor.isCanceled(), collector.getTotalCollected(),
System.currentTimeMillis() - startTime, collector.getMessages());
}
};
return runnable.runWithIndexWriter(log, getAnalyzer(), getMatchVersion());
}
private void truncate(ILogResource log, IndexWriter writer) throws CoreException {
try {
writer.deleteAll();
writer.commit();
} catch (Exception e) {
// Unexpected exception; wrap with CoreException
throw new CoreException(new Status(IStatus.ERROR, IndexPlugin.PLUGIN_ID,
NLS.bind(Messages.LuceneIndexService_error_failedToTruncateIndex,
new Object[] {log.getName(), e.getLocalizedMessage()}), e));
}
}
private Query convertToQuery(final List<ARestriction<?>> restrictions) {
if (restrictions.isEmpty()) {
// Unrestricted
return new MatchAllDocsQuery();
}
final BooleanQuery query = new BooleanQuery();
// Setup visitor
IRestrictionVisitor visitor = new IRestrictionVisitor() {
/* (non-Javadoc)
* @see net.sf.logsaw.core.query.IRestrictionVisitor#visit(net.sf.logsaw.core.query.DateRestriction)
*/
@Override
public void visit(final DateRestriction restriction) {
ILogEntryFieldVisitor visitor = new LogEntryFieldVisitorAdapter() {
/* (non-Javadoc)
* @see net.sf.logsaw.core.model.LogEntryFieldVisitorAdapter#visit(net.sf.logsaw.core.model.DateLogEntryField)
*/
@Override
public void visit(DateLogEntryField fld) {
if (restriction.getOperator().equals(Operators.OPERATOR_BEFORE)) {
query.add(NumericRangeQuery.newLongRange(
fld.getKey(), null,
fld.toIndexedValue(restriction.getValue()),
false, false), Occur.MUST);
} else if (restriction.getOperator().equals(Operators.OPERATOR_AFTER)) {
query.add(NumericRangeQuery.newLongRange(
fld.getKey(),
fld.toIndexedValue(restriction.getValue()), null,
false, false), Occur.MUST);
}
}
};
restriction.getField().visit(visitor);
}
/* (non-Javadoc)
* @see net.sf.logsaw.core.query.IRestrictionVisitor#visit(net.sf.logsaw.core.query.LevelRestriction)
*/
@Override
public void visit(final LevelRestriction restriction) {
ILogEntryFieldVisitor visitor = new LogEntryFieldVisitorAdapter() {
/* (non-Javadoc)
* @see net.sf.logsaw.core.model.LogEntryFieldVisitorAdapter#visit(net.sf.logsaw.core.model.LevelLogEntryField)
*/
@Override
public void visit(LevelLogEntryField fld) {
if (restriction.getOperator().equals(Operators.OPERATOR_GREATER_THAN)) {
query.add(NumericRangeQuery.newIntRange(
fld.getKey(),
restriction.getValue().getValue(), null,
false, false), Occur.MUST);
} else if (restriction.getOperator().equals(Operators.OPERATOR_LESS_THAN)) {
query.add(NumericRangeQuery.newIntRange(
fld.getKey(), null,
fld.toIndexedValue(restriction.getValue()),
false, false), Occur.MUST);
} else if (restriction.getOperator().equals(Operators.OPERATOR_EQUALS)) {
query.add(NumericRangeQuery.newIntRange(
fld.getKey(), fld.toIndexedValue(restriction.getValue()),
fld.toIndexedValue(restriction.getValue()),
true, true), Occur.MUST);
} else if (restriction.getOperator().equals(Operators.OPERATOR_NOT_EQUALS)) {
query.add(NumericRangeQuery.newIntRange(
fld.getKey(), fld.toIndexedValue(restriction.getValue()),
fld.toIndexedValue(restriction.getValue()),
true, true), Occur.MUST_NOT);
if (isAllNegative(restrictions) && restrictions.get(0).equals(restriction)) {
// By design Lucene does not process negative-only queries
query.add(new MatchAllDocsQuery(), Occur.SHOULD);
}
}
}
};
restriction.getField().visit(visitor);
}
/* (non-Javadoc)
* @see net.sf.logsaw.core.query.IRestrictionVisitor#visit(net.sf.logsaw.core.query.StringRestriction)
*/
@Override
public void visit(final StringRestriction restriction) {
if (restriction.getOperator().equals(Operators.OPERATOR_CONTAINS)) {
try {
// Setup phrase query with tokenized query string
PhraseQuery phrase = new PhraseQuery();
fillPhraseQuery(phrase, getAnalyzer(),
restriction.getField().getKey(), restriction.getValue());
query.add(phrase, Occur.MUST);
} catch (IOException e) {
logger.error(e.getLocalizedMessage(), e);
}
} else if (restriction.getOperator().equals(Operators.OPERATOR_NOT_CONTAINS)) {
try {
// Setup phrase query with tokenized query string
PhraseQuery phrase = new PhraseQuery();
fillPhraseQuery(phrase, getAnalyzer(),
restriction.getField().getKey(), restriction.getValue());
query.add(phrase, Occur.MUST_NOT);
if (isAllNegative(restrictions) && restrictions.get(0).equals(restriction)) {
// By design Lucene does not process negative-only queries
query.add(new MatchAllDocsQuery(), Occur.SHOULD);
}
} catch (IOException e) {
logger.error(e.getLocalizedMessage(), e);
}
} else if (restriction.getOperator().equals(Operators.OPERATOR_EQUALS)) {
query.add(new TermQuery(new Term(restriction.getField().getKey(),
restriction.getValue())), Occur.MUST);
} else if (restriction.getOperator().equals(Operators.OPERATOR_NOT_EQUALS)) {
query.add(new TermQuery(new Term(restriction.getField().getKey(),
restriction.getValue())), Occur.MUST_NOT);
if (isAllNegative(restrictions) && restrictions.get(0).equals(restriction)) {
// By design Lucene does not process negative-only queries
query.add(new MatchAllDocsQuery(), Occur.SHOULD);
}
} else if (restriction.getOperator().equals(Operators.OPERATOR_BEGINS_WITH)) {
query.add(new PrefixQuery(new Term(restriction.getField().getKey(),
restriction.getValue())), Occur.MUST);
} else if (restriction.getOperator().equals(Operators.OPERATOR_NOT_BEGINS_WITH)) {
query.add(new PrefixQuery(new Term(restriction.getField().getKey(),
restriction.getValue())), Occur.MUST_NOT);
if (isAllNegative(restrictions) && restrictions.get(0).equals(restriction)) {
// By design Lucene does not process negative-only queries
query.add(new MatchAllDocsQuery(), Occur.SHOULD);
}
}
}
};
for (ARestriction<?> restriction : restrictions) {
restriction.visit(visitor);
}
return query;
}
private void fillPhraseQuery(PhraseQuery phrase, Analyzer analyzer, String fld, String val) throws IOException {
TokenStream ts = analyzer.tokenStream(fld, new StringReader(val));
try {
ts.reset();
// Iterate over tokens and treat each token as term
int pos = 0;
while (ts.incrementToken()) {
CharTermAttribute t = ts.getAttribute(CharTermAttribute.class);
PositionIncrementAttribute p = ts.getAttribute(PositionIncrementAttribute.class);
pos += p.getPositionIncrement();
phrase.add(new Term(fld, t.toString()), pos - 1);
}
// End-of-stream clean-up
ts.end();
} finally {
ts.close();
}
}
private boolean isAllNegative(List<ARestriction<?>> restrictions) {
for (ARestriction<?> restriction : restrictions) {
if (!restriction.getOperator().isNegative()) {
return false;
}
}
return true;
}
private void collectHits(IndexSearcher searcher, TopDocs hits,
ILogDialect dialect, List<LogEntry> result) throws IOException {
for (int i = 0; i < hits.scoreDocs.length; i++) {
final Document doc = searcher.doc(hits.scoreDocs[i].doc);
final LogEntry entry = new LogEntry();
// Setup visitor
ILogEntryFieldVisitor visitor = new ILogEntryFieldVisitor() {
/* (non-Javadoc)
* @see net.sf.logsaw.core.model.ILogEntryFieldVisitor#visit(net.sf.logsaw.core.model.StringLogEntryField)
*/
@Override
public void visit(StringLogEntryField fld) {
String value = doc.get(fld.getKey());
if (value != null) {
entry.put(fld, fld.fromIndexedValue(value));
}
}
/* (non-Javadoc)
* @see net.sf.logsaw.core.model.ILogEntryFieldVisitor#visit(net.sf.logsaw.core.model.LevelLogEntryField)
*/
@Override
public void visit(LevelLogEntryField fld) {
String value = doc.get(fld.getKey());
if (value != null) {
entry.put(fld, fld.fromIndexedValue(value));
}
}
/* (non-Javadoc)
* @see net.sf.logsaw.core.model.ILogEntryFieldVisitor#visit(net.sf.logsaw.core.model.DateLogEntryField)
*/
@Override
public void visit(DateLogEntryField fld) {
String value = doc.get(fld.getKey());
if (value != null) {
entry.put(fld, fld.fromIndexedValue(value));
}
}
};
for (ALogEntryField<?, ?> field : dialect.getFieldProvider().getAllFields()) {
field.visit(visitor);
}
result.add(entry);
}
}
}