diff --git a/querydsl-lucene/src/main/java/com/mysema/query/lucene/AbstractLuceneQuery.java b/querydsl-lucene/src/main/java/com/mysema/query/lucene/AbstractLuceneQuery.java new file mode 100644 index 000000000..e5e535c97 --- /dev/null +++ b/querydsl-lucene/src/main/java/com/mysema/query/lucene/AbstractLuceneQuery.java @@ -0,0 +1,211 @@ +package com.mysema.query.lucene; + +import java.io.IOException; +import java.util.List; + +import org.apache.commons.collections15.Transformer; +import org.apache.lucene.document.Document; +import org.apache.lucene.search.MatchAllDocsQuery; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreDoc; +import org.apache.lucene.search.Searcher; +import org.apache.lucene.search.Sort; + +import com.mysema.commons.lang.CloseableIterator; +import com.mysema.commons.lang.EmptyCloseableIterator; +import com.mysema.commons.lang.IteratorAdapter; +import com.mysema.query.QueryException; +import com.mysema.query.QueryMetadata; +import com.mysema.query.QueryModifiers; +import com.mysema.query.SearchResults; +import com.mysema.query.SimpleProjectable; +import com.mysema.query.SimpleQuery; +import com.mysema.query.support.QueryMixin; +import com.mysema.query.types.OrderSpecifier; +import com.mysema.query.types.ParamExpression; +import com.mysema.query.types.Predicate; + +public class AbstractLuceneQuery> implements SimpleQuery, +SimpleProjectable { + + private final QueryMixin queryMixin; + + private final Searcher searcher; + + private final LuceneSerializer serializer; + + private final Transformer transformer; + + @SuppressWarnings("unchecked") + public AbstractLuceneQuery(final LuceneSerializer serializer, final Searcher searcher, + final Transformer transformer) { + queryMixin = new QueryMixin((Q) this); + this.serializer = serializer; + this.searcher = searcher; + this.transformer = transformer; + } + + public AbstractLuceneQuery(final Searcher searcher, final Transformer transformer) { + this(LuceneSerializer.DEFAULT, searcher, transformer); + } + + private long innerCount(){ + try { + final int maxDoc = searcher.maxDoc(); + if (maxDoc == 0) { + return 0; + } + return searcher.search(createQuery(), maxDoc).totalHits; + } catch (final IOException e) { + throw new QueryException(e); + } + } + + @Override + public long count() { + return innerCount(); + } + + @Override + public long countDistinct() { + return innerCount(); + } + + private Query createQuery() { + if (queryMixin.getMetadata().getWhere() == null) { + return new MatchAllDocsQuery(); + } + return serializer.toQuery(queryMixin.getMetadata().getWhere(), + queryMixin.getMetadata()); + } + + @Override + public Q distinct(){ + return queryMixin.distinct(); + } + + @Override + public Q limit(final long limit) { + return queryMixin.limit(limit); + } + + @Override + public CloseableIterator iterate() { + final QueryMetadata metadata = queryMixin.getMetadata(); + final List> orderBys = metadata.getOrderBy(); + final Long queryLimit = metadata.getModifiers().getLimit(); + final Long queryOffset = metadata.getModifiers().getOffset(); + Sort sort = null; + int limit; + final int offset = queryOffset != null ? queryOffset.intValue() : 0; + try { + limit = searcher.maxDoc(); + } catch (final IOException e) { + throw new QueryException(e); + } + if (queryLimit != null && queryLimit.intValue() < limit) { + limit = queryLimit.intValue(); + } + if (!orderBys.isEmpty()) { + sort = serializer.toSort(orderBys); + } + + try { + ScoreDoc[] scoreDocs; + if (sort != null) { + scoreDocs = searcher.search(createQuery(), null, + limit + offset, sort).scoreDocs; + } else { + scoreDocs = searcher.search(createQuery(), limit + offset).scoreDocs; + } + if (offset < scoreDocs.length) { + return new ResultIterator(scoreDocs, offset, searcher, transformer); + } else { + return new EmptyCloseableIterator(); + } + } catch (final IOException e) { + throw new QueryException(e); + } + } + + @Override + public CloseableIterator iterateDistinct() { + return iterate(); + } + + private List innerList(){ + return new IteratorAdapter(iterate()).asList(); + } + + @Override + public List list() { + return innerList(); + } + + @Override + public List listDistinct() { + return list(); + } + + @Override + public SearchResults listDistinctResults() { + return listResults(); + } + + @Override + public SearchResults listResults() { + List documents = innerList(); + /* + * TODO Get rid of count(). It could be implemented by iterating the + * list results in list* from n to m. + */ + return new SearchResults(documents, queryMixin.getMetadata().getModifiers(), innerCount()); + } + + @Override + public Q offset(final long offset) { + return queryMixin.offset(offset); + } + + @Override + public Q orderBy(final OrderSpecifier... o) { + return queryMixin.orderBy(o); + } + + @Override + public Q restrict(final QueryModifiers modifiers) { + return queryMixin.restrict(modifiers); + } + + @Override + public

Q set(final ParamExpression

param, final P value) { + return queryMixin.set(param, value); + } + + @Override + public T uniqueResult() { + try { + int maxDoc = searcher.maxDoc(); + if (maxDoc == 0) { + return null; + } + final ScoreDoc[] scoreDocs = searcher.search(createQuery(), maxDoc).scoreDocs; + if (scoreDocs.length > 1) { + throw new QueryException("More than one result found!"); + } else if (scoreDocs.length == 1) { + return transformer.transform(searcher.doc(scoreDocs[0].doc)); + } else { + return null; + } + } catch (IOException e) { + throw new QueryException(e); + } + } + + @Override + public Q where(final Predicate... e) { + return queryMixin.where(e); + } + + +} diff --git a/querydsl-lucene/src/main/java/com/mysema/query/lucene/LuceneQuery.java b/querydsl-lucene/src/main/java/com/mysema/query/lucene/LuceneQuery.java index bbe1ea6f5..a13986490 100644 --- a/querydsl-lucene/src/main/java/com/mysema/query/lucene/LuceneQuery.java +++ b/querydsl-lucene/src/main/java/com/mysema/query/lucene/LuceneQuery.java @@ -5,211 +5,32 @@ */ package com.mysema.query.lucene; -import java.io.IOException; -import java.util.List; - +import org.apache.commons.collections15.Transformer; import org.apache.lucene.document.Document; -import org.apache.lucene.search.MatchAllDocsQuery; -import org.apache.lucene.search.Query; -import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.Searcher; -import org.apache.lucene.search.Sort; - -import com.mysema.commons.lang.CloseableIterator; -import com.mysema.commons.lang.EmptyCloseableIterator; -import com.mysema.commons.lang.IteratorAdapter; -import com.mysema.query.QueryException; -import com.mysema.query.QueryMetadata; -import com.mysema.query.QueryModifiers; -import com.mysema.query.SearchResults; -import com.mysema.query.SimpleProjectable; -import com.mysema.query.SimpleQuery; -import com.mysema.query.support.QueryMixin; -import com.mysema.query.types.OrderSpecifier; -import com.mysema.query.types.ParamExpression; -import com.mysema.query.types.Predicate; /** * LuceneQuery is a Querydsl query implementation for Lucene queries. * * @author vema */ -public class LuceneQuery implements SimpleQuery, - SimpleProjectable { - - private final QueryMixin queryMixin; - - private final Searcher searcher; - - private final LuceneSerializer serializer; - - public LuceneQuery(final LuceneSerializer serializer, - final Searcher searcher) { - queryMixin = new QueryMixin(this); - this.serializer = serializer; - this.searcher = searcher; - } - - public LuceneQuery(final Searcher searcher) { - this(LuceneSerializer.DEFAULT, searcher); - } - - private long innerCount(){ - try { - final int maxDoc = searcher.maxDoc(); - if (maxDoc == 0) { - return 0; - } - return searcher.search(createQuery(), maxDoc).totalHits; - } catch (final IOException e) { - throw new QueryException(e); - } - } - - @Override - public long count() { - return innerCount(); - } - - @Override - public long countDistinct() { - return innerCount(); - } - - private Query createQuery() { - if (queryMixin.getMetadata().getWhere() == null) { - return new MatchAllDocsQuery(); - } - return serializer.toQuery(queryMixin.getMetadata().getWhere(), - queryMixin.getMetadata()); - } - - @Override - public LuceneQuery distinct(){ - return queryMixin.distinct(); - } +public class LuceneQuery extends AbstractLuceneQuery{ - @Override - public LuceneQuery limit(final long limit) { - return queryMixin.limit(limit); - } + private static final Transformer TRANSFORMER = new Transformer() { - @Override - public CloseableIterator iterate() { - final QueryMetadata metadata = queryMixin.getMetadata(); - final List> orderBys = metadata.getOrderBy(); - final Long queryLimit = metadata.getModifiers().getLimit(); - final Long queryOffset = metadata.getModifiers().getOffset(); - Sort sort = null; - int limit; - final int offset = queryOffset != null ? queryOffset.intValue() : 0; - try { - limit = searcher.maxDoc(); - } catch (final IOException e) { - throw new QueryException(e); - } - if (queryLimit != null && queryLimit.intValue() < limit) { - limit = queryLimit.intValue(); - } - if (!orderBys.isEmpty()) { - sort = serializer.toSort(orderBys); - } - - try { - ScoreDoc[] scoreDocs; - if (sort != null) { - scoreDocs = searcher.search(createQuery(), null, - limit + offset, sort).scoreDocs; - } else { - scoreDocs = searcher.search(createQuery(), limit + offset).scoreDocs; - } - if (offset < scoreDocs.length) { - return new DocumentIterator(scoreDocs, offset, searcher); - } else { - return new EmptyCloseableIterator(); - } - } catch (final IOException e) { - throw new QueryException(e); + @Override + public Document transform(Document input) { + return input; } + + }; + + public LuceneQuery(Searcher searcher) { + super(searcher, TRANSFORMER); } - @Override - public CloseableIterator iterateDistinct() { - return iterate(); - } - - private List innerList(){ - return new IteratorAdapter(iterate()).asList(); - } - - @Override - public List list() { - return innerList(); - } - - @Override - public List listDistinct() { - return list(); - } - - @Override - public SearchResults listDistinctResults() { - return listResults(); - } - - @Override - public SearchResults listResults() { - List documents = innerList(); - /* - * TODO Get rid of count(). It could be implemented by iterating the - * list results in list* from n to m. - */ - return new SearchResults(documents, queryMixin.getMetadata().getModifiers(), innerCount()); - } - - @Override - public LuceneQuery offset(final long offset) { - return queryMixin.offset(offset); - } - - @Override - public LuceneQuery orderBy(final OrderSpecifier... o) { - return queryMixin.orderBy(o); - } - - @Override - public LuceneQuery restrict(final QueryModifiers modifiers) { - return queryMixin.restrict(modifiers); - } - - @Override - public LuceneQuery set(final ParamExpression param, final T value) { - return queryMixin.set(param, value); - } - - @Override - public Document uniqueResult() { - try { - int maxDoc = searcher.maxDoc(); - if (maxDoc == 0) { - return null; - } - final ScoreDoc[] scoreDocs = searcher.search(createQuery(), maxDoc).scoreDocs; - if (scoreDocs.length > 1) { - throw new QueryException("More than one result found!"); - } else if (scoreDocs.length == 1) { - return searcher.doc(scoreDocs[0].doc); - } else { - return null; - } - } catch (IOException e) { - throw new QueryException(e); - } - } - - @Override - public LuceneQuery where(final Predicate... e) { - return queryMixin.where(e); + public LuceneQuery(LuceneSerializer luceneSerializer, Searcher searcher) { + super(luceneSerializer, searcher, TRANSFORMER); } } diff --git a/querydsl-lucene/src/main/java/com/mysema/query/lucene/DocumentIterator.java b/querydsl-lucene/src/main/java/com/mysema/query/lucene/ResultIterator.java similarity index 66% rename from querydsl-lucene/src/main/java/com/mysema/query/lucene/DocumentIterator.java rename to querydsl-lucene/src/main/java/com/mysema/query/lucene/ResultIterator.java index 339f47379..efc5efe96 100644 --- a/querydsl-lucene/src/main/java/com/mysema/query/lucene/DocumentIterator.java +++ b/querydsl-lucene/src/main/java/com/mysema/query/lucene/ResultIterator.java @@ -5,6 +5,7 @@ package com.mysema.query.lucene; import java.io.IOException; +import org.apache.commons.collections15.Transformer; import org.apache.lucene.document.Document; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.Searcher; @@ -12,18 +13,21 @@ import org.apache.lucene.search.Searcher; import com.mysema.commons.lang.CloseableIterator; import com.mysema.query.QueryException; -public final class DocumentIterator implements CloseableIterator { +public final class ResultIterator implements CloseableIterator { private final ScoreDoc[] scoreDocs; private int cursor; private final Searcher searcher; + + private final Transformer transformer; - public DocumentIterator(ScoreDoc[] scoreDocs, int offset, Searcher searcher) { + public ResultIterator(ScoreDoc[] scoreDocs, int offset, Searcher searcher, Transformer transformer) { this.scoreDocs = scoreDocs; cursor = offset; this.searcher = searcher; + this.transformer = transformer; } @Override @@ -32,9 +36,9 @@ public final class DocumentIterator implements CloseableIterator { } @Override - public Document next() { + public T next() { try { - return searcher.doc(scoreDocs[cursor++].doc); + return transformer.transform(searcher.doc(scoreDocs[cursor++].doc)); } catch (IOException e) { throw new QueryException(e); } diff --git a/querydsl-lucene/src/main/java/com/mysema/query/lucene/ResultTransformer.java b/querydsl-lucene/src/main/java/com/mysema/query/lucene/ResultTransformer.java new file mode 100644 index 000000000..71d5dfb4b --- /dev/null +++ b/querydsl-lucene/src/main/java/com/mysema/query/lucene/ResultTransformer.java @@ -0,0 +1,15 @@ +package com.mysema.query.lucene; + +import org.apache.lucene.document.Document; +import org.apache.lucene.search.ScoreDoc; +import org.apache.lucene.search.Searcher; + +import com.mysema.commons.lang.CloseableIterator; + +public interface ResultTransformer { + + CloseableIterator getIterator(ScoreDoc[] scoreDocs, int offset, Searcher searcher); + + T transform(Document doc); + +} diff --git a/querydsl-lucene/src/main/java/com/mysema/query/lucene/TypedQuery.java b/querydsl-lucene/src/main/java/com/mysema/query/lucene/TypedQuery.java new file mode 100644 index 000000000..62fefd3d0 --- /dev/null +++ b/querydsl-lucene/src/main/java/com/mysema/query/lucene/TypedQuery.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2010 Mysema Ltd. + * All rights reserved. + * + */ +package com.mysema.query.lucene; + +import org.apache.commons.collections15.Transformer; +import org.apache.lucene.document.Document; +import org.apache.lucene.search.Searcher; + +/** + * LuceneQuery is a typed query implementation for Lucene queries. + * + * @author vema + */ +public class TypedQuery extends AbstractLuceneQuery> { + + public TypedQuery(Searcher searcher, Transformer transformer) { + super(searcher, transformer); + } + + public TypedQuery(LuceneSerializer serializer, Searcher searcher, Transformer transformer) { + super(serializer, searcher, transformer); + } + +} diff --git a/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/LuceneSession.java b/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/LuceneSession.java index e601b3ca8..387762a3e 100644 --- a/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/LuceneSession.java +++ b/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/LuceneSession.java @@ -1,6 +1,7 @@ package com.mysema.query.lucene.session; import com.mysema.query.lucene.LuceneQuery; +import com.mysema.query.lucene.TypedQuery; public interface LuceneSession { @@ -12,6 +13,16 @@ public interface LuceneSession { */ LuceneQuery createQuery(); + /** + * Creates a new typed query. + * + * @param The result type + * @param clazz The result class + * @return A new typed query instance + * @throws SessionClosedException if session is closed + */ + TypedQuery createQuery(Class clazz); + /** * Adds documents to index. Creates a new index if the index is not * available. diff --git a/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/LuceneWriter.java b/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/LuceneWriter.java index 9c8dea496..45bc24be2 100644 --- a/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/LuceneWriter.java +++ b/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/LuceneWriter.java @@ -12,6 +12,8 @@ public interface LuceneWriter { LuceneWriter addDocument(Document doc); + LuceneWriter addObject(Object object); + LuceneWriter deleteDocuments(Term term); } diff --git a/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/FileLockingWriter.java b/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/FileLockingWriter.java index 8da4901de..30d5b6188 100644 --- a/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/FileLockingWriter.java +++ b/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/FileLockingWriter.java @@ -24,7 +24,10 @@ public class FileLockingWriter implements LuceneWriter, Leasable { protected IndexWriter writer; - public FileLockingWriter(Directory directory, boolean createNew, long defaultLockTimeout) { + protected final LuceneSessionFactoryImpl sessionFactory; + + public FileLockingWriter(Directory directory, boolean createNew, long defaultLockTimeout, + LuceneSessionFactoryImpl sessionFactory) { IndexWriter.setDefaultWriteLockTimeout(defaultLockTimeout); boolean create = createNew; try { @@ -55,6 +58,7 @@ public class FileLockingWriter implements LuceneWriter, Leasable { if (logger.isDebugEnabled()) { logger.debug("Created writer " + writer); } + this.sessionFactory = sessionFactory; } @Override @@ -67,6 +71,11 @@ public class FileLockingWriter implements LuceneWriter, Leasable { } } + @Override + public LuceneWriter addObject(Object object) { + return addDocument(sessionFactory.transformToDocument(object)); + } + @Override public LuceneWriter deleteDocuments(Term term) { try { diff --git a/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/LuceneSessionFactoryImpl.java b/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/LuceneSessionFactoryImpl.java index ee5c8b7e2..b04ef217a 100644 --- a/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/LuceneSessionFactoryImpl.java +++ b/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/LuceneSessionFactoryImpl.java @@ -6,6 +6,8 @@ import java.util.concurrent.atomic.AtomicBoolean; import javax.annotation.Nullable; +import org.apache.commons.collections15.Transformer; +import org.apache.lucene.document.Document; import org.apache.lucene.store.Directory; import org.apache.lucene.store.SimpleFSDirectory; import org.slf4j.Logger; @@ -72,7 +74,8 @@ public class LuceneSessionFactoryImpl implements LuceneSessionFactory { } public FileLockingWriter leaseWriter(boolean createNew) { - FileLockingWriter writer = new FileLockingWriter(directory, createNew, defaultLockTimeout); + FileLockingWriter writer = + new FileLockingWriter(directory, createNew, defaultLockTimeout, this); lease(writer); return writer; } @@ -145,4 +148,17 @@ public class LuceneSessionFactoryImpl implements LuceneSessionFactory { this.defaultLockTimeout = defaultLockTimeout; } + public Transformer getDocumentToObjectTransformer(Class clazz) { + //Luodaan transformer laiskasti, säilytetään tallessa + //Tsek morphia + + //Convertterit rdfbeanistä, uusi moduuli? + return null; + } + + public Document transformToDocument(Object object) { + // TODO Auto-generated method stub + return null; + } + } diff --git a/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/LuceneSessionImpl.java b/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/LuceneSessionImpl.java index dded407b6..735723c8f 100644 --- a/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/LuceneSessionImpl.java +++ b/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/LuceneSessionImpl.java @@ -5,6 +5,7 @@ import javax.annotation.Nullable; import com.mysema.query.QueryException; import com.mysema.query.lucene.LuceneQuery; import com.mysema.query.lucene.LuceneSerializer; +import com.mysema.query.lucene.TypedQuery; import com.mysema.query.lucene.session.LuceneSession; import com.mysema.query.lucene.session.LuceneWriter; import com.mysema.query.lucene.session.SessionClosedException; @@ -37,11 +38,11 @@ public class LuceneSessionImpl implements LuceneSession { return new LuceneQuery(serializer, getSearcher().getIndexSearcer()); } - private LuceneSearcher getSearcher() { - if (searcher == null) { - searcher = sessionFactory.leaseSearcher(); - } - return searcher; + @Override + public TypedQuery createQuery(Class clazz) { + checkClosed(); + return new TypedQuery(serializer, getSearcher().getIndexSearcer(), + sessionFactory.getDocumentToObjectTransformer(clazz)); } @Override @@ -56,18 +57,6 @@ public class LuceneSessionImpl implements LuceneSession { return getWriter(true); } - private LuceneWriter getWriter(boolean createNew) { - if (readOnly) { - throw new SessionReadOnlyException("Read only session, cannot create writer"); - } - - if (writer == null) { - writer = sessionFactory.leaseWriter(createNew); - } - - return writer; - } - @Override public void close() { checkClosed(); @@ -110,6 +99,25 @@ public class LuceneSessionImpl implements LuceneSession { } + private LuceneSearcher getSearcher() { + if (searcher == null) { + searcher = sessionFactory.leaseSearcher(); + } + return searcher; + } + + private LuceneWriter getWriter(boolean createNew) { + if (readOnly) { + throw new SessionReadOnlyException("Read only session, cannot create writer"); + } + + if (writer == null) { + writer = sessionFactory.leaseWriter(createNew); + } + + return writer; + } + private void checkClosed() { if (closed) { throw new SessionClosedException("Session is closed"); diff --git a/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/ObjectToDocumentTransformer.java b/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/ObjectToDocumentTransformer.java new file mode 100644 index 000000000..9ad632856 --- /dev/null +++ b/querydsl-lucene/src/main/java/com/mysema/query/lucene/session/impl/ObjectToDocumentTransformer.java @@ -0,0 +1,14 @@ +package com.mysema.query.lucene.session.impl; + +import org.apache.commons.collections15.Transformer; +import org.apache.lucene.document.Document; + +public class ObjectToDocumentTransformer implements Transformer{ + + @Override + public Document transform(Object input) { + // TODO Auto-generated method stub + return null; + } + +}