diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java index 11960330b..9fab32a51 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java @@ -139,6 +139,7 @@ import com.mongodb.util.JSONParseException; * @author Christoph Strobl * @author Doménique Tilleuil * @author Niko Schmuck + * @author Mark Paluch */ @SuppressWarnings("deprecation") public class MongoTemplate implements MongoOperations, ApplicationContextAware { @@ -2249,7 +2250,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware { * @author Thomas Darimont */ - static interface DbObjectCallback { + interface DbObjectCallback { T doWith(DBObject object); } @@ -2347,23 +2348,33 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware { DBCursor cursorToUse = cursor.copy(); try { + if (query.getSkip() > 0) { cursorToUse = cursorToUse.skip(query.getSkip()); } + if (query.getLimit() > 0) { cursorToUse = cursorToUse.limit(query.getLimit()); } + if (query.getSortObject() != null) { DBObject sortDbo = type != null ? getMappedSortObject(query, type) : query.getSortObject(); cursorToUse = cursorToUse.sort(sortDbo); } + if (StringUtils.hasText(query.getHint())) { cursorToUse = cursorToUse.hint(query.getHint()); } + if (query.getMeta().hasValues()) { + for (Entry entry : query.getMeta().values()) { cursorToUse = cursorToUse.addSpecial(entry.getKey(), entry.getValue()); } + + if (query.getMeta().isNoCursorTimeout() != null && query.getMeta().isNoCursorTimeout().booleanValue()) { + cursorToUse = cursorToUse.addOption(Bytes.QUERYOPTION_NOTIMEOUT); + } } } catch (RuntimeException e) { diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Meta.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Meta.java index 4b364bc59..c18481642 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Meta.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Meta.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ import org.springframework.util.StringUtils; * * @author Christoph Strobl * @author Oliver Gierke + * @author Mark Paluch * @since 1.6 */ public class Meta { @@ -39,12 +40,13 @@ public class Meta { private String key; - private MetaKey(String key) { + MetaKey(String key) { this.key = key; } } private final Map values = new LinkedHashMap(2); + private Boolean noCursorTimeout; /** * @return {@literal null} if not set. @@ -120,11 +122,29 @@ public class Meta { return getValue(MetaKey.SNAPSHOT.key, false); } + /** + * @return {@literal null} if not set. + * @since 1.10 + */ + public Boolean isNoCursorTimeout() { + return this.noCursorTimeout; + } + + /** + * Instructs the server to avoid closing a cursor automatically after a period of inactivity. + * + * @param noCursorTimeout + * @since 1.10 + */ + public void setNoCursorTimeout(boolean noCursorTimeout) { + this.noCursorTimeout = noCursorTimeout; + } + /** * @return */ public boolean hasValues() { - return !this.values.isEmpty(); + return !this.values.isEmpty() || this.noCursorTimeout != null; } /** diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java index b8bb5957b..02b2ef024 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 the original author or authors. + * Copyright 2010-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,6 +41,7 @@ import com.mongodb.DBObject; * @author Oliver Gierke * @author Thomas Darimont * @author Christoph Strobl + * @author Mark Paluch */ public class Query { @@ -336,6 +337,17 @@ public class Query { return this; } + /** + * @return + * @see Meta#setNoCursorTimeout(boolean) + * @since 1.10 + */ + public Query noCursorTimeout() { + + meta.setNoCursorTimeout(true); + return this; + } + /** * @return never {@literal null}. * @since 1.6 diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Meta.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Meta.java index 61890370b..c41b50942 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Meta.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Meta.java @@ -75,4 +75,12 @@ public @interface Meta { */ boolean snapshot() default false; + /** + * Instructs the server to avoid closing a cursor automatically after a period of inactivity. + * + * @return + * @since 1.10 + */ + boolean noCursorTimeout() default false; + } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryMethod.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryMethod.java index afbecf83d..1f1c743f2 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryMethod.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryMethod.java @@ -248,6 +248,10 @@ public class MongoQueryMethod extends QueryMethod { metaAttributes.setSnapshot(meta.snapshot()); } + if (meta.noCursorTimeout()) { + metaAttributes.setNoCursorTimeout(meta.noCursorTimeout()); + } + return metaAttributes; } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/QueryCursorPreparerUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/QueryCursorPreparerUnitTests.java index 333cfd7a7..21ca3f8c0 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/QueryCursorPreparerUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/QueryCursorPreparerUnitTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2014 the original author or authors. + * Copyright 2011-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,6 +32,7 @@ import org.springframework.data.mongodb.core.MongoTemplate.QueryCursorPreparer; import org.springframework.data.mongodb.core.query.Meta; import org.springframework.data.mongodb.core.query.Query; +import com.mongodb.Bytes; import com.mongodb.DBCursor; /** @@ -39,6 +40,7 @@ import com.mongodb.DBCursor; * * @author Oliver Gierke * @author Christoph Strobl + * @author Mark Paluch */ @RunWith(MockitoJUnitRunner.class) public class QueryCursorPreparerUnitTests { @@ -61,7 +63,7 @@ public class QueryCursorPreparerUnitTests { Query query = query(where("foo").is("bar")).withHint("hint"); - pepare(query); + prepare(query); verify(cursorToUse).hint("hint"); } @@ -75,7 +77,7 @@ public class QueryCursorPreparerUnitTests { Query query = query(where("foo").is("bar")); query.setMeta(new Meta()); - pepare(query); + prepare(query); verify(cursor, never()).copy(); verify(cursorToUse, never()).addSpecial(any(String.class), anyObject()); @@ -89,7 +91,7 @@ public class QueryCursorPreparerUnitTests { Query query = query(where("foo").is("bar")).maxScan(100); - pepare(query); + prepare(query); verify(cursorToUse).addSpecial(eq("$maxScan"), eq(100L)); } @@ -102,7 +104,7 @@ public class QueryCursorPreparerUnitTests { Query query = query(where("foo").is("bar")).maxTime(1, TimeUnit.SECONDS); - pepare(query); + prepare(query); verify(cursorToUse).addSpecial(eq("$maxTimeMS"), eq(1000L)); } @@ -115,7 +117,7 @@ public class QueryCursorPreparerUnitTests { Query query = query(where("foo").is("bar")).comment("spring data"); - pepare(query); + prepare(query); verify(cursorToUse).addSpecial(eq("$comment"), eq("spring data")); } @@ -128,12 +130,25 @@ public class QueryCursorPreparerUnitTests { Query query = query(where("foo").is("bar")).useSnapshot(); - pepare(query); + prepare(query); verify(cursorToUse).addSpecial(eq("$snapshot"), eq(true)); } - private DBCursor pepare(Query query) { + /** + * @see DATAMONGO-1480 + */ + @Test + public void appliesNoCursorTimeoutCorrectly() { + + Query query = query(where("foo").is("bar")).noCursorTimeout(); + + prepare(query); + + verify(cursorToUse).addOption(Bytes.QUERYOPTION_NOTIMEOUT); + } + + private DBCursor prepare(Query query) { CursorPreparer preparer = new MongoTemplate(factory).new QueryCursorPreparer(query, null); return preparer.prepare(cursor); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/AbstractMongoQueryUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/AbstractMongoQueryUnitTests.java index 981428dfb..0c6860a46 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/AbstractMongoQueryUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/AbstractMongoQueryUnitTests.java @@ -347,7 +347,7 @@ public class AbstractMongoQueryUnitTests { List findByFirstname(String firstname); - @Meta(comment = "comment") + @Meta(comment = "comment", noCursorTimeout = true) Page findByFirstname(String firstnanme, Pageable pageable); @Meta(comment = "comment") diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryMethodUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryMethodUnitTests.java index efea28a23..6b739144c 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryMethodUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryMethodUnitTests.java @@ -201,6 +201,18 @@ public class MongoQueryMethodUnitTests { assertThat(method.getQueryMetaAttributes().getSnapshot(), is(true)); } + /** + * @see DATAMONGO-1480 + */ + @Test + public void createsMongoQueryMethodWithNoCursorTimeoutCorrectly() throws Exception { + + MongoQueryMethod method = queryMethod(PersonRepository.class, "metaWithNoCursorTimeout"); + + assertThat(method.hasQueryMetaAttributes(), is(true)); + assertThat(method.getQueryMetaAttributes().isNoCursorTimeout(), is(true)); + } + /** * @see DATAMONGO-1266 */ @@ -250,6 +262,9 @@ public class MongoQueryMethodUnitTests { @Meta(snapshot = true) List metaWithSnapshotUsage(); + @Meta(noCursorTimeout = true) + List metaWithNoCursorTimeout(); + /** * @see DATAMONGO-1266 */