diff --git a/.gitignore b/.gitignore index c9dca952c..8176c7bb4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .DS_Store *.iml *.ipr +*.iws target .springBeans .ant-targets-build.xml diff --git a/.project b/.project deleted file mode 100644 index 201c3b08a..000000000 --- a/.project +++ /dev/null @@ -1,17 +0,0 @@ - - - spring-data-document-dist - - - - - - org.maven.ide.eclipse.maven2Builder - - - - - - org.maven.ide.eclipse.maven2Nature - - diff --git a/.settings/org.maven.ide.eclipse.prefs b/.settings/org.maven.ide.eclipse.prefs deleted file mode 100644 index 39fb50b70..000000000 --- a/.settings/org.maven.ide.eclipse.prefs +++ /dev/null @@ -1,9 +0,0 @@ -#Fri Oct 08 14:31:54 EDT 2010 -activeProfiles= -eclipse.preferences.version=1 -fullBuildGoals=process-test-resources -includeModules=false -resolveWorkspaceProjects=true -resourceFilterGoals=process-resources resources\:testResources -skipCompilerPlugin=true -version=1 diff --git a/pom.xml b/pom.xml index 10907b79f..2926dbed7 100644 --- a/pom.xml +++ b/pom.xml @@ -1,257 +1,257 @@ - 4.0.0 - org.springframework.data - spring-data-document-dist - Spring Data Document Distribution - 1.0.0.BUILD-SNAPSHOT - pom - - spring-data-document-parent - spring-data-document-core - spring-data-mongodb - spring-data-mongodb-cross-store - spring-data-couchdb - + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + 4.0.0 + org.springframework.data + spring-data-document-dist + Spring Data Document Distribution + 1.0.0.BUILD-SNAPSHOT + pom + + spring-data-document-parent + spring-data-document-core + spring-data-mongodb + spring-data-mongodb-cross-store + spring-data-couchdb + - - - trisberg - Thomas Risberg - trisberg at vmware.com - SpringSource - http://www.SpringSource.com - - Project Admin - Developer - - -5 - - - mpollack - Mark Pollack - mpollack at vmware.com - SpringSource - http://www.SpringSource.com - - Project Admin - Developer - - -5 - - - ogierke - Oliver Gierke - ogierke at vmware.com - SpringSource - http://www.springsource.com - - Developer - - +1 - - + + + trisberg + Thomas Risberg + trisberg at vmware.com + SpringSource + http://www.SpringSource.com + + Project Admin + Developer + + -5 + + + mpollack + Mark Pollack + mpollack at vmware.com + SpringSource + http://www.SpringSource.com + + Project Admin + Developer + + -5 + + + ogierke + Oliver Gierke + ogierke at vmware.com + SpringSource + http://www.springsource.com + + Developer + + +1 + + - - - Apache License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0 - - Copyright 2010 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. - 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. - - - + + + Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0 + + Copyright 2010 the original author or authors. - - UTF-8 - - spring-data-document - Spring Data - DATADOC - ${project.version} - snapshot - ${dist.id}-${dist.version} - ${dist.finalName}.zip - target/${dist.fileName} - dist.springframework.org - - + 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 - - - - org.springframework.build.aws - org.springframework.build.aws.maven - 3.1.0.RELEASE - - + http://www.apache.org/licenses/LICENSE-2.0 - - - maven-compiler-plugin - - 1.6 - 1.6 - - + 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. + + + - - com.agilejava.docbkx - docbkx-maven-plugin - 2.0.7 - - - - generate-html - generate-pdf - - pre-site - - - - - org.docbook - docbook-xml - 4.4 - runtime - - - - index.xml - true - ${project.basedir}/src/docbkx/resources/xsl/fopdf.xsl - css/html.css - false - ${project.basedir}/src/docbkx/resources/xsl/html.xsl - 1 - 1 - + + UTF-8 + + spring-data-document + Spring Data + DATADOC + ${project.version} + snapshot + ${dist.id}-${dist.version} + ${dist.finalName}.zip + target/${dist.fileName} + dist.springframework.org + + + + + + + org.springframework.build.aws + org.springframework.build.aws.maven + 3.1.0.RELEASE + + + + + + maven-compiler-plugin + + 1.6 + 1.6 + + + + + com.agilejava.docbkx + docbkx-maven-plugin + 2.0.7 + + + + generate-html + generate-pdf + + pre-site + + + + + org.docbook + docbook-xml + 4.4 + runtime + + + + index.xml + true + ${project.basedir}/src/docbkx/resources/xsl/fopdf.xsl + css/html.css + false + ${project.basedir}/src/docbkx/resources/xsl/html.xsl + 1 + 1 + - - - version - ${pom.version} - - - - - - - - - - - - - - - - - - - - - - - maven-javadoc-plugin - 2.5 - - true - true -
Spring Data Graph
- 1.6 - true - ${project.basedir}/src/main/javadoc - ${project.basedir}/src/main/javadoc/overview.html - ${project.basedir}/src/main/javadoc/spring-javadoc.css - - true - - http://static.springframework.org/spring/docs/3.0.x/javadoc-api - http://java.sun.com/javase/6/docs/api - http://api.mongodb.org/java/2.3 - -
-
- + true + + http://static.springframework.org/spring/docs/3.0.x/javadoc-api + http://java.sun.com/javase/6/docs/api + http://api.mongodb.org/java/2.3 + +
+
+ - maven-assembly-plugin - 2.2-beta-5 - false - - - distribution - - single - - package - - - ${project.basedir}/src/assembly/distribution.xml - - false - - - - - - org.apache.maven.plugins - maven-antrun-plugin - 1.4 - - - upload-dist - deploy - - - - - - - - - run - - - - - - org.springframework.build - org.springframework.build.aws.ant - 3.0.5.RELEASE - - - net.java.dev.jets3t - jets3t - 0.7.2 - - - - - - ${dist.finalName} - + maven-assembly-plugin + 2.2-beta-5 + false + + + distribution + + single + + package + + + ${project.basedir}/src/assembly/distribution.xml + + false + + + + + + org.apache.maven.plugins + maven-antrun-plugin + 1.4 + + + upload-dist + deploy + + + + + + + + + run + + + + + + org.springframework.build + org.springframework.build.aws.ant + 3.0.5.RELEASE + + + net.java.dev.jets3t + jets3t + 0.7.2 + + + + + + ${dist.finalName} + diff --git a/spring-data-couchdb/.classpath b/spring-data-couchdb/.classpath deleted file mode 100644 index 2064dbb9b..000000000 --- a/spring-data-couchdb/.classpath +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/spring-data-couchdb/.project b/spring-data-couchdb/.project deleted file mode 100644 index b05e22d3a..000000000 --- a/spring-data-couchdb/.project +++ /dev/null @@ -1,23 +0,0 @@ - - - spring-data-couchdb - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.maven.ide.eclipse.maven2Builder - - - - - - org.eclipse.jdt.core.javanature - org.maven.ide.eclipse.maven2Nature - - diff --git a/spring-data-couchdb/.settings/org.eclipse.jdt.core.prefs b/spring-data-couchdb/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 449698a94..000000000 --- a/spring-data-couchdb/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,6 +0,0 @@ -#Wed Oct 06 14:49:48 EDT 2010 -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 -org.eclipse.jdt.core.compiler.compliance=1.5 -org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning -org.eclipse.jdt.core.compiler.source=1.5 diff --git a/spring-data-couchdb/.settings/org.maven.ide.eclipse.prefs b/spring-data-couchdb/.settings/org.maven.ide.eclipse.prefs deleted file mode 100644 index 5545b44b1..000000000 --- a/spring-data-couchdb/.settings/org.maven.ide.eclipse.prefs +++ /dev/null @@ -1,9 +0,0 @@ -#Wed Oct 06 14:49:46 EDT 2010 -activeProfiles= -eclipse.preferences.version=1 -fullBuildGoals=process-test-resources -includeModules=false -resolveWorkspaceProjects=true -resourceFilterGoals=process-resources resources\:testResources -skipCompilerPlugin=true -version=1 diff --git a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/CouchServerResourceUsageException.java b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/CouchServerResourceUsageException.java index ce8dee340..8221a5151 100644 --- a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/CouchServerResourceUsageException.java +++ b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/CouchServerResourceUsageException.java @@ -19,15 +19,16 @@ import org.springframework.dao.InvalidDataAccessResourceUsageException; import org.springframework.web.client.HttpServerErrorException; public class CouchServerResourceUsageException extends InvalidDataAccessResourceUsageException { - - /** - * Create a new CouchServerResourceUsageException, - * wrapping an arbitrary HttpServerErrorException. - * @param cause the HttpServerErrorException thrown - */ - public CouchServerResourceUsageException(HttpServerErrorException cause) { - super(cause != null ? cause.getMessage() : null, cause); - } + + /** + * Create a new CouchServerResourceUsageException, + * wrapping an arbitrary HttpServerErrorException. + * + * @param cause the HttpServerErrorException thrown + */ + public CouchServerResourceUsageException(HttpServerErrorException cause) { + super(cause != null ? cause.getMessage() : null, cause); + } } diff --git a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/CouchUsageException.java b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/CouchUsageException.java index 95f17ef92..16dd54432 100644 --- a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/CouchUsageException.java +++ b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/CouchUsageException.java @@ -17,19 +17,18 @@ package org.springframework.data.document.couchdb; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.client.HttpServerErrorException; -public class CouchUsageException extends InvalidDataAccessApiUsageException - { - - /** - * Create a new CouchUsageException, - * wrapping an arbitrary HttpServerErrorException. - * @param cause the HttpServerErrorException thrown - */ - public CouchUsageException(HttpClientErrorException cause) { - super(cause != null ? cause.getMessage() : null, cause); - } +public class CouchUsageException extends InvalidDataAccessApiUsageException { + + /** + * Create a new CouchUsageException, + * wrapping an arbitrary HttpServerErrorException. + * + * @param cause the HttpServerErrorException thrown + */ + public CouchUsageException(HttpClientErrorException cause) { + super(cause != null ? cause.getMessage() : null, cause); + } } diff --git a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/DocumentExistsException.java b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/DocumentExistsException.java index d564211a8..69ec7c871 100644 --- a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/DocumentExistsException.java +++ b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/DocumentExistsException.java @@ -18,17 +18,17 @@ package org.springframework.data.document.couchdb; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.web.client.HttpStatusCodeException; -public class DocumentExistsException extends DataIntegrityViolationException - { - - /** - * Create a new DocumentExistsException, - * wrapping an arbitrary HttpServerErrorException. - * @param cause the HttpServerErrorException thrown - */ - public DocumentExistsException(String documentId, HttpStatusCodeException cause) { - super(cause != null ? cause.getMessage() : null, cause); - } +public class DocumentExistsException extends DataIntegrityViolationException { + + /** + * Create a new DocumentExistsException, + * wrapping an arbitrary HttpServerErrorException. + * + * @param cause the HttpServerErrorException thrown + */ + public DocumentExistsException(String documentId, HttpStatusCodeException cause) { + super(cause != null ? cause.getMessage() : null, cause); + } } diff --git a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/DocumentRetrievalFailureException.java b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/DocumentRetrievalFailureException.java index c35a1ff6d..b9359e538 100644 --- a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/DocumentRetrievalFailureException.java +++ b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/DocumentRetrievalFailureException.java @@ -18,21 +18,18 @@ package org.springframework.data.document.couchdb; import org.springframework.dao.DataRetrievalFailureException; public class DocumentRetrievalFailureException extends - DataRetrievalFailureException { + DataRetrievalFailureException { - private String documentPath; - - public DocumentRetrievalFailureException(String documentPath) { - super("Could not find document at path = " + documentPath); - this.documentPath = documentPath; - } - - public String getDocumentPath() { - return documentPath; - } - + private String documentPath; + + public DocumentRetrievalFailureException(String documentPath) { + super("Could not find document at path = " + documentPath); + this.documentPath = documentPath; + } + + public String getDocumentPath() { + return documentPath; + } - - } diff --git a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/UncategorizedCouchDataAccessException.java b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/UncategorizedCouchDataAccessException.java index d951e5353..c4828c11b 100644 --- a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/UncategorizedCouchDataAccessException.java +++ b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/UncategorizedCouchDataAccessException.java @@ -20,14 +20,15 @@ import org.springframework.web.client.RestClientException; public class UncategorizedCouchDataAccessException extends UncategorizedDataAccessException { - /** - * Create a new HibernateSystemException, - * wrapping an arbitrary HibernateException. - * @param cause the HibernateException thrown - */ - public UncategorizedCouchDataAccessException(RestClientException cause) { - super(cause != null ? cause.getMessage() : null, cause); - } + /** + * Create a new HibernateSystemException, + * wrapping an arbitrary HibernateException. + * + * @param cause the HibernateException thrown + */ + public UncategorizedCouchDataAccessException(RestClientException cause) { + super(cause != null ? cause.getMessage() : null, cause); + } } diff --git a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/admin/CouchAdmin.java b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/admin/CouchAdmin.java index f9c0eb62d..0d1a3796b 100644 --- a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/admin/CouchAdmin.java +++ b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/admin/CouchAdmin.java @@ -26,39 +26,39 @@ import org.springframework.web.client.RestTemplate; public class CouchAdmin implements CouchAdminOperations { - private String databaseUrl; - private RestOperations restOperations = new RestTemplate(); - - public CouchAdmin(String databaseUrl) { - - if (!databaseUrl.trim().endsWith("/")) { - this.databaseUrl = databaseUrl.trim() + "/"; - } else { - this.databaseUrl = databaseUrl.trim(); - } - } - - public List listDatabases() { - String dbs = restOperations.getForObject(databaseUrl + "_all_dbs", String.class); - return Arrays.asList(StringUtils.commaDelimitedListToStringArray(dbs)); - } + private String databaseUrl; + private RestOperations restOperations = new RestTemplate(); - public void createDatabase(String dbName) { - org.springframework.util.Assert.hasText(dbName); - restOperations.put(databaseUrl + dbName, null); + public CouchAdmin(String databaseUrl) { - } + if (!databaseUrl.trim().endsWith("/")) { + this.databaseUrl = databaseUrl.trim() + "/"; + } else { + this.databaseUrl = databaseUrl.trim(); + } + } - public void deleteDatabase(String dbName) { - org.springframework.util.Assert.hasText(dbName); - restOperations.delete(CouchUtils.ensureTrailingSlash(databaseUrl + dbName)); + public List listDatabases() { + String dbs = restOperations.getForObject(databaseUrl + "_all_dbs", String.class); + return Arrays.asList(StringUtils.commaDelimitedListToStringArray(dbs)); + } - } + public void createDatabase(String dbName) { + org.springframework.util.Assert.hasText(dbName); + restOperations.put(databaseUrl + dbName, null); - public DbInfo getDatabaseInfo(String dbName) { - String url = CouchUtils.ensureTrailingSlash(databaseUrl + dbName); - Map dbInfoMap = (Map) restOperations.getForObject(url, Map.class); - return new DbInfo(dbInfoMap); - } + } + + public void deleteDatabase(String dbName) { + org.springframework.util.Assert.hasText(dbName); + restOperations.delete(CouchUtils.ensureTrailingSlash(databaseUrl + dbName)); + + } + + public DbInfo getDatabaseInfo(String dbName) { + String url = CouchUtils.ensureTrailingSlash(databaseUrl + dbName); + Map dbInfoMap = (Map) restOperations.getForObject(url, Map.class); + return new DbInfo(dbInfoMap); + } } \ No newline at end of file diff --git a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/admin/CouchAdminOperations.java b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/admin/CouchAdminOperations.java index 4c00dd68e..029e403ad 100644 --- a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/admin/CouchAdminOperations.java +++ b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/admin/CouchAdminOperations.java @@ -19,16 +19,16 @@ import java.util.List; public interface CouchAdminOperations { - - // functionality for /_special - replication, logs, UUIDs - - List listDatabases(); - - void createDatabase(String name); - - void deleteDatabase(String name); - - DbInfo getDatabaseInfo(String name); - - + + // functionality for /_special - replication, logs, UUIDs + + List listDatabases(); + + void createDatabase(String name); + + void deleteDatabase(String name); + + DbInfo getDatabaseInfo(String name); + + } diff --git a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/admin/DbInfo.java b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/admin/DbInfo.java index d8aa62b42..e65672f92 100644 --- a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/admin/DbInfo.java +++ b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/admin/DbInfo.java @@ -21,57 +21,52 @@ import java.util.Map; public class DbInfo { - private Map dbInfoMap; - - public DbInfo(Map dbInfoMap) { - super(); - this.dbInfoMap = dbInfoMap; - } + private Map dbInfoMap; - public boolean isCompactRunning() { - return (Boolean) this.dbInfoMap.get("compact_running"); - } + public DbInfo(Map dbInfoMap) { + super(); + this.dbInfoMap = dbInfoMap; + } - public String getDbName() { - return (String) this.dbInfoMap.get("db_name"); - } + public boolean isCompactRunning() { + return (Boolean) this.dbInfoMap.get("compact_running"); + } - public long getDiskFormatVersion() { - return (Long) this.dbInfoMap.get("disk_format_version"); - } + public String getDbName() { + return (String) this.dbInfoMap.get("db_name"); + } - public long getDiskSize() { - return (Long) this.dbInfoMap.get("disk_size"); - } + public long getDiskFormatVersion() { + return (Long) this.dbInfoMap.get("disk_format_version"); + } - public long getDocCount() { - return (Long) this.dbInfoMap.get("doc_count"); - } + public long getDiskSize() { + return (Long) this.dbInfoMap.get("disk_size"); + } - public long getDocDeleteCount() { - return (Long) this.dbInfoMap.get("doc_del_count"); - } + public long getDocCount() { + return (Long) this.dbInfoMap.get("doc_count"); + } - public long getInstanceStartTime() { - return (Long) this.dbInfoMap.get("instance_start_time"); - } + public long getDocDeleteCount() { + return (Long) this.dbInfoMap.get("doc_del_count"); + } - public long getPurgeSequence() { - return (Long) this.dbInfoMap.get("purge_seq"); - } + public long getInstanceStartTime() { + return (Long) this.dbInfoMap.get("instance_start_time"); + } - public long getUpdateSequence() { - return (Long) this.dbInfoMap.get("update_seq"); - } + public long getPurgeSequence() { + return (Long) this.dbInfoMap.get("purge_seq"); + } - public Map getDbInfoMap() { - return Collections.unmodifiableMap(dbInfoMap); - } + public long getUpdateSequence() { + return (Long) this.dbInfoMap.get("update_seq"); + } + + public Map getDbInfoMap() { + return Collections.unmodifiableMap(dbInfoMap); + } - - - - - } diff --git a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/config/CouchJmxParser.java b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/config/CouchJmxParser.java index 4521dc838..539084541 100644 --- a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/config/CouchJmxParser.java +++ b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/config/CouchJmxParser.java @@ -27,44 +27,44 @@ import org.w3c.dom.Element; public class CouchJmxParser implements BeanDefinitionParser { - public BeanDefinition parse(Element element, ParserContext parserContext) { - String databaseUrl = element.getAttribute("database-url"); - if (!StringUtils.hasText(databaseUrl)) { - databaseUrl = "http://localhost:5984"; - } - registerJmxComponents(databaseUrl, element, parserContext); - return null; - } + public BeanDefinition parse(Element element, ParserContext parserContext) { + String databaseUrl = element.getAttribute("database-url"); + if (!StringUtils.hasText(databaseUrl)) { + databaseUrl = "http://localhost:5984"; + } + registerJmxComponents(databaseUrl, element, parserContext); + return null; + } - protected void registerJmxComponents(String databaseUrl, Element element, ParserContext parserContext) { - Object eleSource = parserContext.extractSource(element); + protected void registerJmxComponents(String databaseUrl, Element element, ParserContext parserContext) { + Object eleSource = parserContext.extractSource(element); - CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource); - - /* - createBeanDefEntry(AssertMetrics.class, compositeDef, mongoRefName, eleSource, parserContext); - createBeanDefEntry(BackgroundFlushingMetrics.class, compositeDef, mongoRefName, eleSource, parserContext); - createBeanDefEntry(BtreeIndexCounters.class, compositeDef, mongoRefName, eleSource, parserContext); - createBeanDefEntry(ConnectionMetrics.class, compositeDef, mongoRefName, eleSource, parserContext); - createBeanDefEntry(GlobalLockMetrics.class, compositeDef, mongoRefName, eleSource, parserContext); - createBeanDefEntry(MemoryMetrics.class, compositeDef, mongoRefName, eleSource, parserContext); - createBeanDefEntry(OperationCounters.class, compositeDef, mongoRefName, eleSource, parserContext); - */ - createBeanDefEntry(ServerInfo.class, compositeDef, databaseUrl, eleSource, parserContext); - //createBeanDefEntry(MongoAdmin.class, compositeDef, mongoRefName, eleSource, parserContext); - - - parserContext.registerComponent(compositeDef); - - } + CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource); + + /* + createBeanDefEntry(AssertMetrics.class, compositeDef, mongoRefName, eleSource, parserContext); + createBeanDefEntry(BackgroundFlushingMetrics.class, compositeDef, mongoRefName, eleSource, parserContext); + createBeanDefEntry(BtreeIndexCounters.class, compositeDef, mongoRefName, eleSource, parserContext); + createBeanDefEntry(ConnectionMetrics.class, compositeDef, mongoRefName, eleSource, parserContext); + createBeanDefEntry(GlobalLockMetrics.class, compositeDef, mongoRefName, eleSource, parserContext); + createBeanDefEntry(MemoryMetrics.class, compositeDef, mongoRefName, eleSource, parserContext); + createBeanDefEntry(OperationCounters.class, compositeDef, mongoRefName, eleSource, parserContext); + */ + createBeanDefEntry(ServerInfo.class, compositeDef, databaseUrl, eleSource, parserContext); + //createBeanDefEntry(MongoAdmin.class, compositeDef, mongoRefName, eleSource, parserContext); + + + parserContext.registerComponent(compositeDef); + + } + + protected void createBeanDefEntry(Class clazz, CompositeComponentDefinition compositeDef, String databaseUrl, Object eleSource, ParserContext parserContext) { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz); + builder.getRawBeanDefinition().setSource(eleSource); + builder.addConstructorArg(databaseUrl); + BeanDefinition assertDef = builder.getBeanDefinition(); + String assertName = parserContext.getReaderContext().registerWithGeneratedName(assertDef); + compositeDef.addNestedComponent(new BeanComponentDefinition(assertDef, assertName)); + } - protected void createBeanDefEntry(Class clazz, CompositeComponentDefinition compositeDef, String databaseUrl, Object eleSource, ParserContext parserContext) { - BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz); - builder.getRawBeanDefinition().setSource(eleSource); - builder.addConstructorArg(databaseUrl); - BeanDefinition assertDef = builder.getBeanDefinition(); - String assertName = parserContext.getReaderContext().registerWithGeneratedName(assertDef); - compositeDef.addNestedComponent(new BeanComponentDefinition(assertDef, assertName)); - } - } diff --git a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/config/CouchNamespaceHandler.java b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/config/CouchNamespaceHandler.java index d47e1c76b..7c7ed6d02 100644 --- a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/config/CouchNamespaceHandler.java +++ b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/config/CouchNamespaceHandler.java @@ -21,23 +21,23 @@ import org.springframework.beans.factory.xml.NamespaceHandlerSupport; /** * {@link org.springframework.beans.factory.xml.NamespaceHandler} for Couch DB * based repositories. - * + * * @author Oliver Gierke */ public class CouchNamespaceHandler extends NamespaceHandlerSupport { - /* - * (non-Javadoc) - * - * @see org.springframework.beans.factory.xml.NamespaceHandler#init() - */ - public void init() { + /* + * (non-Javadoc) + * + * @see org.springframework.beans.factory.xml.NamespaceHandler#init() + */ + public void init() { - /* - registerBeanDefinitionParser("repositories", - new MongoRepositoryConfigDefinitionParser()); - */ - - registerBeanDefinitionParser("jmx", new CouchJmxParser()); - } + /* + registerBeanDefinitionParser("repositories", + new MongoRepositoryConfigDefinitionParser()); + */ + + registerBeanDefinitionParser("jmx", new CouchJmxParser()); + } } diff --git a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/core/CouchOperations.java b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/core/CouchOperations.java index b1573dc00..db46366d0 100644 --- a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/core/CouchOperations.java +++ b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/core/CouchOperations.java @@ -20,44 +20,44 @@ import java.net.URI; public interface CouchOperations { - /** - * Reads a document from the database and maps it a Java object. - *

- * This method is intended to work when a default database - * is set on the CouchDbDocumentOperations instance. - * - * @param id the id of the CouchDB document to read - * @param targetClass the target type to map to - * @return the mapped object - */ - T findOne(String id, Class targetClass); - - /** - * Reads a document from the database and maps it a Java object. - * - * @param uri the full URI of the document to read - * @param targetClass the target type to map to - * @return the mapped object - */ - T findOne(URI uri, Class targetClass); - - - /** - * Maps a Java object to JSON and writes it to the database - *

- * This method is intended to work when a default database - * is set on the CouchDbDocumentOperations instance. - * - * @param id the id of the document to write - * @param document the object to write - */ - void save(String id, Object document); - - /** - * Maps a Java object to JSON and writes it to the database - * - * @param uri the full URI of the document to write - * @param document the object to write - */ - void save(URI uri, Object document); + /** + * Reads a document from the database and maps it a Java object. + *

+ * This method is intended to work when a default database + * is set on the CouchDbDocumentOperations instance. + * + * @param id the id of the CouchDB document to read + * @param targetClass the target type to map to + * @return the mapped object + */ + T findOne(String id, Class targetClass); + + /** + * Reads a document from the database and maps it a Java object. + * + * @param uri the full URI of the document to read + * @param targetClass the target type to map to + * @return the mapped object + */ + T findOne(URI uri, Class targetClass); + + + /** + * Maps a Java object to JSON and writes it to the database + *

+ * This method is intended to work when a default database + * is set on the CouchDbDocumentOperations instance. + * + * @param id the id of the document to write + * @param document the object to write + */ + void save(String id, Object document); + + /** + * Maps a Java object to JSON and writes it to the database + * + * @param uri the full URI of the document to write + * @param document the object to write + */ + void save(URI uri, Object document); } diff --git a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/core/CouchTemplate.java b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/core/CouchTemplate.java index 8cb7014ec..a02e5b35f 100644 --- a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/core/CouchTemplate.java +++ b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/core/CouchTemplate.java @@ -26,128 +26,118 @@ import org.springframework.data.document.couchdb.CouchUsageException; import org.springframework.data.document.couchdb.DocumentRetrievalFailureException; import org.springframework.data.document.couchdb.UncategorizedCouchDataAccessException; import org.springframework.data.document.couchdb.support.CouchUtils; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; +import org.springframework.http.*; import org.springframework.util.Assert; -import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.client.HttpServerErrorException; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestOperations; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.client.*; public class CouchTemplate implements CouchOperations { - protected final Log logger = LogFactory.getLog(this.getClass()); + protected final Log logger = LogFactory.getLog(this.getClass()); - private String defaultDocumentUrl; - - private RestOperations restOperations = new RestTemplate(); - - /** - * Constructs an instance of CouchDbDocumentTemplate with a default database - * @param defaultDatabaseUrl the default database to connect to - */ - public CouchTemplate(String defaultDatabaseUrl) { - Assert.hasText(defaultDatabaseUrl, "defaultDatabaseUrl must not be empty"); - defaultDocumentUrl = CouchUtils.addId(defaultDatabaseUrl); + private String defaultDocumentUrl; + + private RestOperations restOperations = new RestTemplate(); + + /** + * Constructs an instance of CouchDbDocumentTemplate with a default database + * + * @param defaultDatabaseUrl the default database to connect to + */ + public CouchTemplate(String defaultDatabaseUrl) { + Assert.hasText(defaultDatabaseUrl, "defaultDatabaseUrl must not be empty"); + defaultDocumentUrl = CouchUtils.addId(defaultDatabaseUrl); + } + + /** + * Constructs an instance of CouchDbDocumentTemplate with a default database + * + * @param defaultDatabaseUrl the default database to connect to + */ + public CouchTemplate(String defaultDatabaseUrl, RestOperations restOperations) { + this(defaultDatabaseUrl); + Assert.notNull(restOperations, "restOperations must not be null"); + this.restOperations = restOperations; + } + + + public T findOne(String id, Class targetClass) { + Assert.state(defaultDocumentUrl != null, "defaultDatabaseUrl must be set to use this method"); + try { + return restOperations.getForObject(defaultDocumentUrl, targetClass, id); + //TODO check this exception translation and centralize. + } catch (HttpClientErrorException clientError) { + if (clientError.getStatusCode() == HttpStatus.NOT_FOUND) { + throw new DocumentRetrievalFailureException(defaultDocumentUrl + "/" + id); + } + throw new CouchUsageException(clientError); + } catch (HttpServerErrorException serverError) { + throw new CouchServerResourceUsageException(serverError); + } catch (RestClientException otherError) { + throw new UncategorizedCouchDataAccessException(otherError); } - - /** - * Constructs an instance of CouchDbDocumentTemplate with a default database - * @param defaultDatabaseUrl the default database to connect to - */ - public CouchTemplate(String defaultDatabaseUrl, RestOperations restOperations) { - this(defaultDatabaseUrl); - Assert.notNull(restOperations, "restOperations must not be null"); - this.restOperations = restOperations; + } + + public T findOne(URI uri, Class targetClass) { + Assert.state(uri != null, "uri must be set to use this method"); + try { + return restOperations.getForObject(uri, targetClass); + //TODO check this exception translation and centralize. + } catch (HttpClientErrorException clientError) { + if (clientError.getStatusCode() == HttpStatus.NOT_FOUND) { + throw new DocumentRetrievalFailureException(uri.getPath()); + } + throw new CouchUsageException(clientError); + } catch (HttpServerErrorException serverError) { + throw new CouchServerResourceUsageException(serverError); + } catch (RestClientException otherError) { + throw new UncategorizedCouchDataAccessException(otherError); } - - - - - - public T findOne(String id, Class targetClass) { - Assert.state(defaultDocumentUrl != null, "defaultDatabaseUrl must be set to use this method"); - try { - return restOperations.getForObject(defaultDocumentUrl, targetClass, id); - //TODO check this exception translation and centralize. - } catch (HttpClientErrorException clientError) { - if (clientError.getStatusCode() == HttpStatus.NOT_FOUND) { - throw new DocumentRetrievalFailureException(defaultDocumentUrl + "/" + id); - } - throw new CouchUsageException(clientError); - } catch (HttpServerErrorException serverError) { - throw new CouchServerResourceUsageException(serverError); - } catch (RestClientException otherError) { - throw new UncategorizedCouchDataAccessException(otherError); - } - } + } - public T findOne(URI uri, Class targetClass) { - Assert.state(uri != null, "uri must be set to use this method"); - try { - return restOperations.getForObject(uri, targetClass); - //TODO check this exception translation and centralize. - } catch (HttpClientErrorException clientError) { - if (clientError.getStatusCode() == HttpStatus.NOT_FOUND) { - throw new DocumentRetrievalFailureException(uri.getPath()); - } - throw new CouchUsageException(clientError); - } catch (HttpServerErrorException serverError) { - throw new CouchServerResourceUsageException(serverError); - } catch (RestClientException otherError) { - throw new UncategorizedCouchDataAccessException(otherError); - } - } - - public void save(String id, Object document) { - Assert.notNull(document, "document must not be null for save"); - HttpEntity httpEntity = createHttpEntity(document); - try { - ResponseEntity response = restOperations.exchange(defaultDocumentUrl, HttpMethod.PUT, httpEntity, Map.class, id); - //TODO update the document revision id on the object from the returned value - //TODO better exception translation - } catch (RestClientException e) { - throw new UncategorizedCouchDataAccessException(e); - } - - } - - public void save(URI uri, Object document) { - Assert.notNull(document, "document must not be null for save"); - Assert.notNull(uri, "URI must not be null for save"); - HttpEntity httpEntity = createHttpEntity(document); - try { - ResponseEntity response = restOperations.exchange(uri, HttpMethod.PUT, httpEntity, Map.class); - //TODO update the document revision id on the object from the returned value - //TODO better exception translation - } catch (RestClientException e) { - throw new UncategorizedCouchDataAccessException(e); - } - - - } - - private HttpEntity createHttpEntity(Object document) { - - if (document instanceof HttpEntity) { - HttpEntity httpEntity = (HttpEntity) document; - Assert.isTrue(httpEntity.getHeaders().getContentType().equals(MediaType.APPLICATION_JSON), - "HttpEntity payload with non application/json content type found."); - return httpEntity; - } - - HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.setContentType(MediaType.APPLICATION_JSON); - HttpEntity httpEntity = new HttpEntity(document, httpHeaders); - - return httpEntity; + public void save(String id, Object document) { + Assert.notNull(document, "document must not be null for save"); + HttpEntity httpEntity = createHttpEntity(document); + try { + ResponseEntity response = restOperations.exchange(defaultDocumentUrl, HttpMethod.PUT, httpEntity, Map.class, id); + //TODO update the document revision id on the object from the returned value + //TODO better exception translation + } catch (RestClientException e) { + throw new UncategorizedCouchDataAccessException(e); } - - + + } + + public void save(URI uri, Object document) { + Assert.notNull(document, "document must not be null for save"); + Assert.notNull(uri, "URI must not be null for save"); + HttpEntity httpEntity = createHttpEntity(document); + try { + ResponseEntity response = restOperations.exchange(uri, HttpMethod.PUT, httpEntity, Map.class); + //TODO update the document revision id on the object from the returned value + //TODO better exception translation + } catch (RestClientException e) { + throw new UncategorizedCouchDataAccessException(e); + } + + + } + + private HttpEntity createHttpEntity(Object document) { + + if (document instanceof HttpEntity) { + HttpEntity httpEntity = (HttpEntity) document; + Assert.isTrue(httpEntity.getHeaders().getContentType().equals(MediaType.APPLICATION_JSON), + "HttpEntity payload with non application/json content type found."); + return httpEntity; + } + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.APPLICATION_JSON); + HttpEntity httpEntity = new HttpEntity(document, httpHeaders); + + return httpEntity; + } + + } diff --git a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/core/support/CouchDbMappingJacksonHttpMessageConverter.java b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/core/support/CouchDbMappingJacksonHttpMessageConverter.java index b49bfa09e..8d7f6b9f3 100644 --- a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/core/support/CouchDbMappingJacksonHttpMessageConverter.java +++ b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/core/support/CouchDbMappingJacksonHttpMessageConverter.java @@ -17,20 +17,9 @@ package org.springframework.data.document.couchdb.core.support; import java.io.IOException; import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; -import org.codehaus.jackson.JsonEncoding; -import org.codehaus.jackson.JsonGenerationException; -import org.codehaus.jackson.JsonGenerator; -import org.codehaus.jackson.JsonNode; -import org.codehaus.jackson.JsonParseException; -import org.codehaus.jackson.JsonParser; -import org.codehaus.jackson.JsonProcessingException; -import org.codehaus.jackson.JsonToken; +import org.codehaus.jackson.*; import org.codehaus.jackson.map.JsonMappingException; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.type.TypeFactory; @@ -44,283 +33,283 @@ import org.springframework.http.converter.HttpMessageNotWritableException; import org.springframework.util.Assert; public class CouchDbMappingJacksonHttpMessageConverter extends - AbstractHttpMessageConverter { + AbstractHttpMessageConverter { - public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); + public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); - private static final String ROWS_FIELD_NAME = "rows"; - private static final String VALUE_FIELD_NAME = "value"; - private static final String INCLUDED_DOC_FIELD_NAME = "doc"; - private static final String TOTAL_ROWS_FIELD_NAME = "total_rows"; + private static final String ROWS_FIELD_NAME = "rows"; + private static final String VALUE_FIELD_NAME = "value"; + private static final String INCLUDED_DOC_FIELD_NAME = "doc"; + private static final String TOTAL_ROWS_FIELD_NAME = "total_rows"; - private ObjectMapper objectMapper = new ObjectMapper(); + private ObjectMapper objectMapper = new ObjectMapper(); - private boolean prefixJson = false; + private boolean prefixJson = false; - /** - * Construct a new {@code BindingJacksonHttpMessageConverter}. - */ - public CouchDbMappingJacksonHttpMessageConverter() { - super(new MediaType("application", "json", DEFAULT_CHARSET)); - } + /** + * Construct a new {@code BindingJacksonHttpMessageConverter}. + */ + public CouchDbMappingJacksonHttpMessageConverter() { + super(new MediaType("application", "json", DEFAULT_CHARSET)); + } - /** - * Sets the {@code ObjectMapper} for this view. If not set, a default - * {@link ObjectMapper#ObjectMapper() ObjectMapper} is used. - *

- * Setting a custom-configured {@code ObjectMapper} is one way to take - * further control of the JSON serialization process. For example, an - * extended {@link org.codehaus.jackson.map.SerializerFactory} can be - * configured that provides custom serializers for specific types. The other - * option for refining the serialization process is to use Jackson's - * provided annotations on the types to be serialized, in which case a - * custom-configured ObjectMapper is unnecessary. - */ - public void setObjectMapper(ObjectMapper objectMapper) { - Assert.notNull(objectMapper, "'objectMapper' must not be null"); - this.objectMapper = objectMapper; - } + /** + * Sets the {@code ObjectMapper} for this view. If not set, a default + * {@link ObjectMapper#ObjectMapper() ObjectMapper} is used. + *

+ * Setting a custom-configured {@code ObjectMapper} is one way to take + * further control of the JSON serialization process. For example, an + * extended {@link org.codehaus.jackson.map.SerializerFactory} can be + * configured that provides custom serializers for specific types. The other + * option for refining the serialization process is to use Jackson's + * provided annotations on the types to be serialized, in which case a + * custom-configured ObjectMapper is unnecessary. + */ + public void setObjectMapper(ObjectMapper objectMapper) { + Assert.notNull(objectMapper, "'objectMapper' must not be null"); + this.objectMapper = objectMapper; + } - /** - * Indicates whether the JSON output by this view should be prefixed with - * "{} &&". Default is false. - *

- * Prefixing the JSON string in this manner is used to help prevent JSON - * Hijacking. The prefix renders the string syntactically invalid as a - * script so that it cannot be hijacked. This prefix does not affect the - * evaluation of JSON, but if JSON validation is performed on the string, - * the prefix would need to be ignored. - */ - public void setPrefixJson(boolean prefixJson) { - this.prefixJson = prefixJson; - } + /** + * Indicates whether the JSON output by this view should be prefixed with + * "{} &&". Default is false. + *

+ * Prefixing the JSON string in this manner is used to help prevent JSON + * Hijacking. The prefix renders the string syntactically invalid as a + * script so that it cannot be hijacked. This prefix does not affect the + * evaluation of JSON, but if JSON validation is performed on the string, + * the prefix would need to be ignored. + */ + public void setPrefixJson(boolean prefixJson) { + this.prefixJson = prefixJson; + } - @Override - public boolean canRead(Class clazz, MediaType mediaType) { - JavaType javaType = getJavaType(clazz); - return this.objectMapper.canDeserialize(javaType) && canRead(mediaType); - } + @Override + public boolean canRead(Class clazz, MediaType mediaType) { + JavaType javaType = getJavaType(clazz); + return this.objectMapper.canDeserialize(javaType) && canRead(mediaType); + } - /** - * Returns the Jackson {@link JavaType} for the specific class. - * - *

- * Default implementation returns - * {@link TypeFactory#type(java.lang.reflect.Type)}, but this can be - * overridden in subclasses, to allow for custom generic collection - * handling. For instance: - * - *

-	 * protected JavaType getJavaType(Class<?> clazz) {
-	 * 	if (List.class.isAssignableFrom(clazz)) {
-	 * 		return TypeFactory.collectionType(ArrayList.class, MyBean.class);
-	 * 	} else {
-	 * 		return super.getJavaType(clazz);
-	 * 	}
-	 * }
-	 * 
- * - * @param clazz - * the class to return the java type for - * @return the java type - */ - protected JavaType getJavaType(Class clazz) { - return TypeFactory.type(clazz); - } + /** + * Returns the Jackson {@link JavaType} for the specific class. + *

+ *

+ * Default implementation returns + * {@link TypeFactory#type(java.lang.reflect.Type)}, but this can be + * overridden in subclasses, to allow for custom generic collection + * handling. For instance: + *

+ *

+   * protected JavaType getJavaType(Class<?> clazz) {
+   * if (List.class.isAssignableFrom(clazz)) {
+   * return TypeFactory.collectionType(ArrayList.class, MyBean.class);
+   * } else {
+   * return super.getJavaType(clazz);
+   * }
+   * }
+   * 
+ * + * @param clazz the class to return the java type for + * @return the java type + */ + protected JavaType getJavaType(Class clazz) { + return TypeFactory.type(clazz); + } - @Override - public boolean canWrite(Class clazz, MediaType mediaType) { - return this.objectMapper.canSerialize(clazz) && canWrite(mediaType); - } + @Override + public boolean canWrite(Class clazz, MediaType mediaType) { + return this.objectMapper.canSerialize(clazz) && canWrite(mediaType); + } - @Override - protected boolean supports(Class clazz) { - // should not be called, since we override canRead/Write instead - throw new UnsupportedOperationException(); - } + @Override + protected boolean supports(Class clazz) { + // should not be called, since we override canRead/Write instead + throw new UnsupportedOperationException(); + } - @Override - protected Object readInternal(Class clazz, HttpInputMessage inputMessage) - throws IOException, HttpMessageNotReadableException { - JavaType javaType = getJavaType(clazz); - try { - return success(clazz, inputMessage); + @Override + protected Object readInternal(Class clazz, HttpInputMessage inputMessage) + throws IOException, HttpMessageNotReadableException { + JavaType javaType = getJavaType(clazz); + try { + return success(clazz, inputMessage); - // return this.objectMapper.readValue(inputMessage.getBody(), - // javaType); - } catch (Exception ex) { - throw new HttpMessageNotReadableException("Could not read JSON: " - + ex.getMessage(), ex); - } - } + // return this.objectMapper.readValue(inputMessage.getBody(), + // javaType); + } catch (Exception ex) { + throw new HttpMessageNotReadableException("Could not read JSON: " + + ex.getMessage(), ex); + } + } - private Object success(Class clazz, HttpInputMessage inputMessage) - throws JsonParseException, IOException { - - //Note, parsing code used from ektorp project - JsonParser jp = objectMapper.getJsonFactory().createJsonParser( - inputMessage.getBody()); - if (jp.nextToken() != JsonToken.START_OBJECT) { - throw new RuntimeException("Expected data to start with an Object"); - } - Map fields = readHeaderFields(jp); + private Object success(Class clazz, HttpInputMessage inputMessage) + throws JsonParseException, IOException { - List result; - if (fields.containsKey(TOTAL_ROWS_FIELD_NAME)) { - int totalRows = fields.get(TOTAL_ROWS_FIELD_NAME); - if (totalRows == 0) { - return Collections.emptyList(); - } - result = new ArrayList(totalRows); - } else { - result = new ArrayList(); - } + //Note, parsing code used from ektorp project + JsonParser jp = objectMapper.getJsonFactory().createJsonParser( + inputMessage.getBody()); + if (jp.nextToken() != JsonToken.START_OBJECT) { + throw new RuntimeException("Expected data to start with an Object"); + } + Map fields = readHeaderFields(jp); - ParseState state = new ParseState(); + List result; + if (fields.containsKey(TOTAL_ROWS_FIELD_NAME)) { + int totalRows = fields.get(TOTAL_ROWS_FIELD_NAME); + if (totalRows == 0) { + return Collections.emptyList(); + } + result = new ArrayList(totalRows); + } else { + result = new ArrayList(); + } - Object first = parseFirstRow(jp, state, clazz); - if (first == null) { - return Collections.emptyList(); - } else { - result.add(first); - } + ParseState state = new ParseState(); - while (jp.getCurrentToken() != null) { - skipToField(jp, state.docFieldName, state); - if (atEndOfRows(jp)) { - return result; - } - result.add(jp.readValueAs(clazz)); - endRow(jp, state); - } - return result; - } + Object first = parseFirstRow(jp, state, clazz); + if (first == null) { + return Collections.emptyList(); + } else { + result.add(first); + } - private Object parseFirstRow(JsonParser jp, ParseState state, Class clazz) - throws JsonParseException, IOException, JsonProcessingException, - JsonMappingException { - skipToField(jp, VALUE_FIELD_NAME, state); - JsonNode value = null; - if (atObjectStart(jp)) { - value = jp.readValueAsTree(); - jp.nextToken(); - if (isEndOfRow(jp)) { - state.docFieldName = VALUE_FIELD_NAME; - Object doc = objectMapper.readValue(value, clazz); - endRow(jp, state); - return doc; - } - } - skipToField(jp, INCLUDED_DOC_FIELD_NAME, state); - if (atObjectStart(jp)) { - state.docFieldName = INCLUDED_DOC_FIELD_NAME; - Object doc = jp.readValueAs(clazz); - endRow(jp, state); - return doc; - } - return null; - } - + while (jp.getCurrentToken() != null) { + skipToField(jp, state.docFieldName, state); + if (atEndOfRows(jp)) { + return result; + } + result.add(jp.readValueAs(clazz)); + endRow(jp, state); + } + return result; + } - private boolean isEndOfRow(JsonParser jp) { - return jp.getCurrentToken() == JsonToken.END_OBJECT; - } - - private void endRow(JsonParser jp, ParseState state) throws IOException, JsonParseException { - state.inRow = false; - jp.nextToken(); - } - - private boolean atObjectStart(JsonParser jp) { - return jp.getCurrentToken() == JsonToken.START_OBJECT; - } - - private boolean atEndOfRows(JsonParser jp) { - return jp.getCurrentToken() != JsonToken.START_OBJECT; - } - private void skipToField(JsonParser jp, String fieldName, ParseState state) throws JsonParseException, IOException { - String lastFieldName = null; - while (jp.getCurrentToken() != null) { - switch (jp.getCurrentToken()) { - case FIELD_NAME: - lastFieldName = jp.getCurrentName(); - jp.nextToken(); - break; - case START_OBJECT: - if (!state.inRow) { - state.inRow = true; - jp.nextToken(); - } else { - if (isInField(fieldName, lastFieldName)) { - return; - } else { - jp.skipChildren(); - } - } - break; - default: - if (isInField(fieldName, lastFieldName)) { - jp.nextToken(); - return; - } - jp.nextToken(); - break; - } - } - } - - private boolean isInField(String fieldName, String lastFieldName) { - return lastFieldName != null && lastFieldName.equals(fieldName); - } + private Object parseFirstRow(JsonParser jp, ParseState state, Class clazz) + throws JsonParseException, IOException, JsonProcessingException, + JsonMappingException { + skipToField(jp, VALUE_FIELD_NAME, state); + JsonNode value = null; + if (atObjectStart(jp)) { + value = jp.readValueAsTree(); + jp.nextToken(); + if (isEndOfRow(jp)) { + state.docFieldName = VALUE_FIELD_NAME; + Object doc = objectMapper.readValue(value, clazz); + endRow(jp, state); + return doc; + } + } + skipToField(jp, INCLUDED_DOC_FIELD_NAME, state); + if (atObjectStart(jp)) { + state.docFieldName = INCLUDED_DOC_FIELD_NAME; + Object doc = jp.readValueAs(clazz); + endRow(jp, state); + return doc; + } + return null; + } - private Map readHeaderFields(JsonParser jp) - throws JsonParseException, IOException { - Map map = new HashMap(); - jp.nextToken(); - String nextFieldName = jp.getCurrentName(); - while (!nextFieldName.equals(ROWS_FIELD_NAME)) { - jp.nextToken(); - map.put(nextFieldName, Integer.valueOf(jp.getIntValue())); - jp.nextToken(); - nextFieldName = jp.getCurrentName(); - } - return map; - } + private boolean isEndOfRow(JsonParser jp) { + return jp.getCurrentToken() == JsonToken.END_OBJECT; + } - @Override - protected void writeInternal(Object o, HttpOutputMessage outputMessage) - throws IOException, HttpMessageNotWritableException { + private void endRow(JsonParser jp, ParseState state) throws IOException, JsonParseException { + state.inRow = false; + jp.nextToken(); + } - JsonEncoding encoding = getEncoding(outputMessage.getHeaders() - .getContentType()); - JsonGenerator jsonGenerator = this.objectMapper.getJsonFactory() - .createJsonGenerator(outputMessage.getBody(), encoding); - try { - if (this.prefixJson) { - jsonGenerator.writeRaw("{} && "); - } - this.objectMapper.writeValue(jsonGenerator, o); - } catch (JsonGenerationException ex) { - throw new HttpMessageNotWritableException("Could not write JSON: " - + ex.getMessage(), ex); - } - } + private boolean atObjectStart(JsonParser jp) { + return jp.getCurrentToken() == JsonToken.START_OBJECT; + } - private JsonEncoding getEncoding(MediaType contentType) { - if (contentType != null && contentType.getCharSet() != null) { - Charset charset = contentType.getCharSet(); - for (JsonEncoding encoding : JsonEncoding.values()) { - if (charset.name().equals(encoding.getJavaName())) { - return encoding; - } - } - } - return JsonEncoding.UTF8; - } + private boolean atEndOfRows(JsonParser jp) { + return jp.getCurrentToken() != JsonToken.START_OBJECT; + } - private static class ParseState { - boolean inRow; - String docFieldName = ""; - } + private void skipToField(JsonParser jp, String fieldName, ParseState state) throws JsonParseException, IOException { + String lastFieldName = null; + while (jp.getCurrentToken() != null) { + switch (jp.getCurrentToken()) { + case FIELD_NAME: + lastFieldName = jp.getCurrentName(); + jp.nextToken(); + break; + case START_OBJECT: + if (!state.inRow) { + state.inRow = true; + jp.nextToken(); + } else { + if (isInField(fieldName, lastFieldName)) { + return; + } else { + jp.skipChildren(); + } + } + break; + default: + if (isInField(fieldName, lastFieldName)) { + jp.nextToken(); + return; + } + jp.nextToken(); + break; + } + } + } + + private boolean isInField(String fieldName, String lastFieldName) { + return lastFieldName != null && lastFieldName.equals(fieldName); + } + + + private Map readHeaderFields(JsonParser jp) + throws JsonParseException, IOException { + Map map = new HashMap(); + jp.nextToken(); + String nextFieldName = jp.getCurrentName(); + while (!nextFieldName.equals(ROWS_FIELD_NAME)) { + jp.nextToken(); + map.put(nextFieldName, Integer.valueOf(jp.getIntValue())); + jp.nextToken(); + nextFieldName = jp.getCurrentName(); + } + return map; + } + + @Override + protected void writeInternal(Object o, HttpOutputMessage outputMessage) + throws IOException, HttpMessageNotWritableException { + + JsonEncoding encoding = getEncoding(outputMessage.getHeaders() + .getContentType()); + JsonGenerator jsonGenerator = this.objectMapper.getJsonFactory() + .createJsonGenerator(outputMessage.getBody(), encoding); + try { + if (this.prefixJson) { + jsonGenerator.writeRaw("{} && "); + } + this.objectMapper.writeValue(jsonGenerator, o); + } catch (JsonGenerationException ex) { + throw new HttpMessageNotWritableException("Could not write JSON: " + + ex.getMessage(), ex); + } + } + + private JsonEncoding getEncoding(MediaType contentType) { + if (contentType != null && contentType.getCharSet() != null) { + Charset charset = contentType.getCharSet(); + for (JsonEncoding encoding : JsonEncoding.values()) { + if (charset.name().equals(encoding.getJavaName())) { + return encoding; + } + } + } + return JsonEncoding.UTF8; + } + + private static class ParseState { + boolean inRow; + String docFieldName = ""; + } } diff --git a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/monitor/AbstractMonitor.java b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/monitor/AbstractMonitor.java index fc9d66c90..67e03ae41 100644 --- a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/monitor/AbstractMonitor.java +++ b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/monitor/AbstractMonitor.java @@ -15,32 +15,27 @@ */ package org.springframework.data.document.couchdb.monitor; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.springframework.web.client.RestTemplate; /** * Base class to encapsulate common configuration settings when connecting to a CouchDB database - * - * @author Mark Pollack * + * @author Mark Pollack */ public abstract class AbstractMonitor { - - protected RestTemplate restTemplate; - protected String databaseUrl; - - /** - * Gets the databaseUrl used to connect to CouchDB - * @return - */ - public String getDatabaseUrl() { - return this.databaseUrl; - } - + protected RestTemplate restTemplate; + protected String databaseUrl; + + /** + * Gets the databaseUrl used to connect to CouchDB + * + * @return + */ + public String getDatabaseUrl() { + return this.databaseUrl; + } - } diff --git a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/monitor/ServerInfo.java b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/monitor/ServerInfo.java index 80159a669..d45546ab3 100644 --- a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/monitor/ServerInfo.java +++ b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/monitor/ServerInfo.java @@ -24,40 +24,39 @@ import org.springframework.jmx.export.annotation.ManagedResource; import org.springframework.web.client.RestTemplate; /** - * Expose basic server information via JMX - * - * @author Mark Pollack + * Expose basic server information via JMX * + * @author Mark Pollack */ -@ManagedResource(description="Server Information") +@ManagedResource(description = "Server Information") public class ServerInfo extends AbstractMonitor { - - - public ServerInfo(String databaseUrl) { - this.databaseUrl = databaseUrl; - this.restTemplate = new RestTemplate(); - } - - - @ManagedOperation(description="Server host name") - public String getHostName() throws UnknownHostException { - return InetAddress.getLocalHost().getHostName(); - } - @ManagedOperation(description="CouchDB Server Version") - public String getVersion() { - return (String) getRoot().get("version"); - } - - @ManagedOperation(description="Message of the day") - public String getMotd() { - return (String) getRoot().get("greeting"); - } - - public Map getRoot() { - Map map = restTemplate.getForObject(getDatabaseUrl(),Map.class); - return map; - } + public ServerInfo(String databaseUrl) { + this.databaseUrl = databaseUrl; + this.restTemplate = new RestTemplate(); + } + + + @ManagedOperation(description = "Server host name") + public String getHostName() throws UnknownHostException { + return InetAddress.getLocalHost().getHostName(); + } + + + @ManagedOperation(description = "CouchDB Server Version") + public String getVersion() { + return (String) getRoot().get("version"); + } + + @ManagedOperation(description = "Message of the day") + public String getMotd() { + return (String) getRoot().get("greeting"); + } + + public Map getRoot() { + Map map = restTemplate.getForObject(getDatabaseUrl(), Map.class); + return map; + } } diff --git a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/support/CouchUtils.java b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/support/CouchUtils.java index 823454ca9..fb42d6486 100644 --- a/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/support/CouchUtils.java +++ b/spring-data-couchdb/src/main/java/org/springframework/data/document/couchdb/support/CouchUtils.java @@ -17,11 +17,10 @@ package org.springframework.data.document.couchdb.support; import org.springframework.dao.DataAccessException; -import org.springframework.data.document.UncategorizedDocumentStoreException; /** * Helper class featuring helper methods for internal CouchDB classes. - * + *

*

Mainly intended for internal use within the framework. * * @author Thomas Risberg @@ -30,49 +29,53 @@ import org.springframework.data.document.UncategorizedDocumentStoreException; */ public abstract class CouchUtils { - /** - * Convert the given runtime exception to an appropriate exception from the - * org.springframework.dao hierarchy. - * Return null if no translation is appropriate: any other exception may - * have resulted from user code, and should not be translated. - * @param ex runtime exception that occurred - * @return the corresponding DataAccessException instance, - * or null if the exception should not be translated - */ - public static DataAccessException translateCouchExceptionIfPossible(RuntimeException ex) { + /** + * Convert the given runtime exception to an appropriate exception from the + * org.springframework.dao hierarchy. + * Return null if no translation is appropriate: any other exception may + * have resulted from user code, and should not be translated. + * + * @param ex runtime exception that occurred + * @return the corresponding DataAccessException instance, + * or null if the exception should not be translated + */ + public static DataAccessException translateCouchExceptionIfPossible(RuntimeException ex) { - return null; - } - - /** - * Adds an id variable to a URL - * @param url the URL to modify - * @return the modified URL - */ - public static String addId(String url) { - return ensureTrailingSlash(url) + "{id}"; - } - - - /** - * Adds a 'changes since' variable to a URL - * @param url - * @return - */ - public static String addChangesSince(String url) { - return ensureTrailingSlash(url) + "_changes?since={seq}"; - } - - /** - * Ensures that a URL ends with a slash. - * @param url the URL to modify - * @return the modified URL - */ - public static String ensureTrailingSlash(String url) { - if (!url.endsWith("/")) { - url += "/"; - } - return url; + return null; + } + + /** + * Adds an id variable to a URL + * + * @param url the URL to modify + * @return the modified URL + */ + public static String addId(String url) { + return ensureTrailingSlash(url) + "{id}"; + } + + + /** + * Adds a 'changes since' variable to a URL + * + * @param url + * @return + */ + public static String addChangesSince(String url) { + return ensureTrailingSlash(url) + "_changes?since={seq}"; + } + + /** + * Ensures that a URL ends with a slash. + * + * @param url the URL to modify + * @return the modified URL + */ + public static String ensureTrailingSlash(String url) { + if (!url.endsWith("/")) { + url += "/"; } + return url; + } } diff --git a/spring-data-couchdb/src/main/resources/org/springframework/data/document/couchdb/config/spring-couch-1.0.xsd b/spring-data-couchdb/src/main/resources/org/springframework/data/document/couchdb/config/spring-couch-1.0.xsd index d4e21345b..ccf257511 100644 --- a/spring-data-couchdb/src/main/resources/org/springframework/data/document/couchdb/config/spring-couch-1.0.xsd +++ b/spring-data-couchdb/src/main/resources/org/springframework/data/document/couchdb/config/spring-couch-1.0.xsd @@ -1,33 +1,33 @@ + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:tool="http://www.springframework.org/schema/tool" + xmlns:context="http://www.springframework.org/schema/context" + xmlns:repository="http://www.springframework.org/schema/data/repository" + targetNamespace="http://www.springframework.org/schema/data/couch" + elementFormDefault="qualified" attributeFormDefault="unqualified"> - - - + + + - - - + + - - - - - + + + + - - - - - + + + + + \ No newline at end of file diff --git a/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/DummyDocument.java b/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/DummyDocument.java index d43677696..43368f470 100644 --- a/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/DummyDocument.java +++ b/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/DummyDocument.java @@ -16,62 +16,62 @@ package org.springframework.data.document.couchdb; -import org.codehaus.jackson.annotate.JsonIgnoreProperties; - import java.util.Date; +import org.codehaus.jackson.annotate.JsonIgnoreProperties; + /** * @author Tareq Abedrabbo (tareq.abedrabbo@opencredo.com) * @since 13/01/2011 */ -@JsonIgnoreProperties(ignoreUnknown=true) +@JsonIgnoreProperties(ignoreUnknown = true) public class DummyDocument { - private String message; + private String message; - private String timestamp = new Date().toString(); + private String timestamp = new Date().toString(); - public DummyDocument() { - } + public DummyDocument() { + } - public DummyDocument(String message) { - this.message = message; - } + public DummyDocument(String message) { + this.message = message; + } - public String getMessage() { - return message; - } + public String getMessage() { + return message; + } - public void setMessage(String message) { - this.message = message; - } + public void setMessage(String message) { + this.message = message; + } - public String getTimestamp() { - return timestamp; - } + public String getTimestamp() { + return timestamp; + } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; - DummyDocument document = (DummyDocument) o; + DummyDocument document = (DummyDocument) o; - if (message != null ? !message.equals(document.message) : document.message != null) return false; + if (message != null ? !message.equals(document.message) : document.message != null) return false; - return true; - } + return true; + } - @Override - public int hashCode() { - return message != null ? message.hashCode() : 0; - } + @Override + public int hashCode() { + return message != null ? message.hashCode() : 0; + } - @Override - public String toString() { - return "DummyDocument{" + - "message='" + message + '\'' + - ", timestamp=" + timestamp + - '}'; - } + @Override + public String toString() { + return "DummyDocument{" + + "message='" + message + '\'' + + ", timestamp=" + timestamp + + '}'; + } } diff --git a/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/IsBodyEqual.java b/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/IsBodyEqual.java index 8f690bcc2..bb43591ab 100644 --- a/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/IsBodyEqual.java +++ b/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/IsBodyEqual.java @@ -24,28 +24,29 @@ import org.springframework.http.HttpEntity; /** * Matches the content of the body of an HttpEntity. + * * @author Tareq Abedrabbo * @since 31/01/2011 */ public class IsBodyEqual extends TypeSafeMatcher { - private Object object; + private Object object; - public IsBodyEqual(Object object) { - this.object = object; - } + public IsBodyEqual(Object object) { + this.object = object; + } - @Override - public boolean matchesSafely(HttpEntity httpEntity) { - return httpEntity.getBody().equals(object); - } + @Override + public boolean matchesSafely(HttpEntity httpEntity) { + return httpEntity.getBody().equals(object); + } - public void describeTo(Description description) { - description.appendText("body equals ").appendValue(object); - } + public void describeTo(Description description) { + description.appendText("body equals ").appendValue(object); + } - @Factory - public static Matcher bodyEqual(Object object) { - return new IsBodyEqual(object); - } + @Factory + public static Matcher bodyEqual(Object object) { + return new IsBodyEqual(object); + } } diff --git a/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/admin/CouchAdminIntegrationTests.java b/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/admin/CouchAdminIntegrationTests.java index 93c13de54..31d603083 100644 --- a/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/admin/CouchAdminIntegrationTests.java +++ b/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/admin/CouchAdminIntegrationTests.java @@ -18,22 +18,21 @@ package org.springframework.data.document.couchdb.admin; import java.util.List; import junit.framework.Assert; - import org.junit.Ignore; import org.junit.Test; import org.springframework.data.document.couchdb.core.CouchConstants; public class CouchAdminIntegrationTests { - @Test - @Ignore("until CI has couch server running") - public void dbLifecycle() { - - CouchAdmin admin = new CouchAdmin(CouchConstants.COUCHDB_URL); - admin.deleteDatabase("foo"); - List dbs = admin.listDatabases(); - admin.createDatabase("foo"); - List newDbs = admin.listDatabases(); - Assert.assertEquals(dbs.size()+1, newDbs.size()); - } + @Test + @Ignore("until CI has couch server running") + public void dbLifecycle() { + + CouchAdmin admin = new CouchAdmin(CouchConstants.COUCHDB_URL); + admin.deleteDatabase("foo"); + List dbs = admin.listDatabases(); + admin.createDatabase("foo"); + List newDbs = admin.listDatabases(); + Assert.assertEquals(dbs.size() + 1, newDbs.size()); + } } diff --git a/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/core/AbstractCouchTemplateIntegrationTests.java b/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/core/AbstractCouchTemplateIntegrationTests.java index 98fa48750..7d114e307 100644 --- a/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/core/AbstractCouchTemplateIntegrationTests.java +++ b/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/core/AbstractCouchTemplateIntegrationTests.java @@ -16,28 +16,22 @@ package org.springframework.data.document.couchdb.core; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.runner.RunWith; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.http.client.ClientHttpResponse; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.web.client.DefaultResponseErrorHandler; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; +import static org.junit.Assume.assumeNoException; +import static org.junit.Assume.assumeTrue; +import static org.springframework.http.HttpStatus.OK; import java.io.IOException; import java.util.UUID; -import static org.junit.Assume.assumeNoException; -import static org.junit.Assume.assumeTrue; -import static org.springframework.http.HttpStatus.OK; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Before; +import org.junit.BeforeClass; +import org.springframework.http.*; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.web.client.DefaultResponseErrorHandler; +import org.springframework.web.client.RestClientException; +import org.springframework.web.client.RestTemplate; /** * Base class for CouchDB integration tests. Checks whether CouchDB is available before running each test, @@ -50,75 +44,75 @@ import static org.springframework.http.HttpStatus.OK; public abstract class AbstractCouchTemplateIntegrationTests { - protected static final Log log = LogFactory.getLog(AbstractCouchTemplateIntegrationTests.class); + protected static final Log log = LogFactory.getLog(AbstractCouchTemplateIntegrationTests.class); - protected static final RestTemplate restTemplate = new RestTemplate(); + protected static final RestTemplate restTemplate = new RestTemplate(); - /** - * This methods ensures that the database is running. Otherwise, the test is ignored. - */ - @BeforeClass - public static void assumeDatabaseIsUpAndRunning() { - try { - ResponseEntity responseEntity = restTemplate.getForEntity(CouchConstants.COUCHDB_URL, String.class); - assumeTrue(responseEntity.getStatusCode().equals(OK)); - log.debug("CouchDB is running on " + CouchConstants.COUCHDB_URL + - " with status " + responseEntity.getStatusCode()); - } catch (RestClientException e) { - log.debug("CouchDB is not running on " + CouchConstants.COUCHDB_URL); - assumeNoException(e); - } + /** + * This methods ensures that the database is running. Otherwise, the test is ignored. + */ + @BeforeClass + public static void assumeDatabaseIsUpAndRunning() { + try { + ResponseEntity responseEntity = restTemplate.getForEntity(CouchConstants.COUCHDB_URL, String.class); + assumeTrue(responseEntity.getStatusCode().equals(OK)); + log.debug("CouchDB is running on " + CouchConstants.COUCHDB_URL + + " with status " + responseEntity.getStatusCode()); + } catch (RestClientException e) { + log.debug("CouchDB is not running on " + CouchConstants.COUCHDB_URL); + assumeNoException(e); } + } - @Before - public void setUpTestDatabase() throws Exception { - RestTemplate template = new RestTemplate(); - template.setErrorHandler(new DefaultResponseErrorHandler(){ - @Override - public void handleError(ClientHttpResponse response) throws IOException { - // do nothing, error status will be handled in the switch statement - } - }); - ResponseEntity response = template.getForEntity(CouchConstants.TEST_DATABASE_URL, String.class); - HttpStatus statusCode = response.getStatusCode(); - switch (statusCode) { - case NOT_FOUND: - createNewTestDatabase(); - break; - case OK: - deleteExisitingTestDatabase(); - createNewTestDatabase(); - break; - default: - throw new IllegalStateException("Unsupported http status [" + statusCode + "]"); - } + @Before + public void setUpTestDatabase() throws Exception { + RestTemplate template = new RestTemplate(); + template.setErrorHandler(new DefaultResponseErrorHandler() { + @Override + public void handleError(ClientHttpResponse response) throws IOException { + // do nothing, error status will be handled in the switch statement + } + }); + ResponseEntity response = template.getForEntity(CouchConstants.TEST_DATABASE_URL, String.class); + HttpStatus statusCode = response.getStatusCode(); + switch (statusCode) { + case NOT_FOUND: + createNewTestDatabase(); + break; + case OK: + deleteExisitingTestDatabase(); + createNewTestDatabase(); + break; + default: + throw new IllegalStateException("Unsupported http status [" + statusCode + "]"); } + } - private void deleteExisitingTestDatabase() { - restTemplate.delete(CouchConstants.TEST_DATABASE_URL); - } + private void deleteExisitingTestDatabase() { + restTemplate.delete(CouchConstants.TEST_DATABASE_URL); + } - private void createNewTestDatabase() { - restTemplate.put(CouchConstants.TEST_DATABASE_URL, null); - } + private void createNewTestDatabase() { + restTemplate.put(CouchConstants.TEST_DATABASE_URL, null); + } - /** - * Reads a CouchDB document and converts it to the expected type. - */ - protected T getDocument(String id, Class expectedType) { - String url = CouchConstants.TEST_DATABASE_URL + "{id}"; - return restTemplate.getForObject(url, expectedType, id); - } + /** + * Reads a CouchDB document and converts it to the expected type. + */ + protected T getDocument(String id, Class expectedType) { + String url = CouchConstants.TEST_DATABASE_URL + "{id}"; + return restTemplate.getForObject(url, expectedType, id); + } - /** - * Writes a CouchDB document - */ - protected String putDocument(Object document) { - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - HttpEntity request = new HttpEntity(document, headers); - String id = UUID.randomUUID().toString(); - restTemplate.put(CouchConstants.TEST_DATABASE_URL + "{id}", request, id); - return id; - } + /** + * Writes a CouchDB document + */ + protected String putDocument(Object document) { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity request = new HttpEntity(document, headers); + String id = UUID.randomUUID().toString(); + restTemplate.put(CouchConstants.TEST_DATABASE_URL + "{id}", request, id); + return id; + } } diff --git a/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/core/CouchConstants.java b/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/core/CouchConstants.java index 14412b947..1ae934684 100644 --- a/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/core/CouchConstants.java +++ b/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/core/CouchConstants.java @@ -17,11 +17,11 @@ package org.springframework.data.document.couchdb.core; public abstract class CouchConstants { - public static final String COUCHDB_URL = "http://127.0.0.1:5984/"; - public static final String TEST_DATABASE_URL = COUCHDB_URL + "si_couchdb_test/"; + public static final String COUCHDB_URL = "http://127.0.0.1:5984/"; + public static final String TEST_DATABASE_URL = COUCHDB_URL + "si_couchdb_test/"; - public CouchConstants() { - // TODO Auto-generated constructor stub - } + public CouchConstants() { + // TODO Auto-generated constructor stub + } } diff --git a/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/core/CouchTemplateIntegrationTests.java b/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/core/CouchTemplateIntegrationTests.java index 893f32471..31302ea25 100644 --- a/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/core/CouchTemplateIntegrationTests.java +++ b/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/core/CouchTemplateIntegrationTests.java @@ -19,22 +19,21 @@ package org.springframework.data.document.couchdb.core; import java.util.UUID; import junit.framework.Assert; - import org.junit.Ignore; import org.junit.Test; import org.springframework.data.document.couchdb.DummyDocument; public class CouchTemplateIntegrationTests extends AbstractCouchTemplateIntegrationTests { - - @Test - @Ignore("until CI has couch server running") - public void saveAndFindTest() { - CouchTemplate template = new CouchTemplate(CouchConstants.TEST_DATABASE_URL); - DummyDocument document = new DummyDocument("hello"); - String id = UUID.randomUUID().toString(); - template.save(id, document); - DummyDocument foundDocument = template.findOne(id, DummyDocument.class); - Assert.assertEquals(document.getMessage(), foundDocument.getMessage()); - } + + @Test + @Ignore("until CI has couch server running") + public void saveAndFindTest() { + CouchTemplate template = new CouchTemplate(CouchConstants.TEST_DATABASE_URL); + DummyDocument document = new DummyDocument("hello"); + String id = UUID.randomUUID().toString(); + template.save(id, document); + DummyDocument foundDocument = template.findOne(id, DummyDocument.class); + Assert.assertEquals(document.getMessage(), foundDocument.getMessage()); + } } diff --git a/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/core/CouchTemplateTests.java b/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/core/CouchTemplateTests.java index b0163aa43..da4afe30c 100644 --- a/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/core/CouchTemplateTests.java +++ b/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/core/CouchTemplateTests.java @@ -20,13 +20,11 @@ import org.junit.Test; /** * Unit tests for CouchTemplate with mocks - * - * */ public class CouchTemplateTests { - @Test - public void foo() { - - } + @Test + public void foo() { + + } } diff --git a/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/monitor/JmxServer.java b/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/monitor/JmxServer.java index 07cf47222..e846ea8d2 100644 --- a/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/monitor/JmxServer.java +++ b/spring-data-couchdb/src/test/java/org/springframework/data/document/couchdb/monitor/JmxServer.java @@ -20,17 +20,17 @@ import org.springframework.context.support.ClassPathXmlApplicationContext; /** * Server application to test JMX functionality. - * + * * @author Mark Pollack */ public class JmxServer { - public static void main(String[] args) { - new JmxServer().run(); - } + public static void main(String[] args) { + new JmxServer().run(); + } - public void run() { - new ClassPathXmlApplicationContext(new String[] {"server-jmx.xml"} ); - } + public void run() { + new ClassPathXmlApplicationContext(new String[]{"server-jmx.xml"}); + } } diff --git a/spring-data-couchdb/src/test/resources/server-jmx.xml b/spring-data-couchdb/src/test/resources/server-jmx.xml index 30c1933fe..d5c9028d5 100644 --- a/spring-data-couchdb/src/test/resources/server-jmx.xml +++ b/spring-data-couchdb/src/test/resources/server-jmx.xml @@ -1,25 +1,24 @@ - - + - + + + + + + - - - - - \ No newline at end of file diff --git a/spring-data-document-core/.classpath b/spring-data-document-core/.classpath deleted file mode 100644 index 6019b8317..000000000 --- a/spring-data-document-core/.classpath +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/spring-data-document-core/.project b/spring-data-document-core/.project deleted file mode 100644 index 903baba7a..000000000 --- a/spring-data-document-core/.project +++ /dev/null @@ -1,36 +0,0 @@ - - - spring-data-document-core - - - - - - org.eclipse.wst.common.project.facet.core.builder - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.maven.ide.eclipse.maven2Builder - - - - - org.eclipse.wst.validation.validationbuilder - - - - - - org.eclipse.jem.workbench.JavaEMFNature - org.eclipse.wst.common.modulecore.ModuleCoreNature - org.eclipse.jdt.core.javanature - org.maven.ide.eclipse.maven2Nature - org.eclipse.wst.common.project.facet.core.nature - - diff --git a/spring-data-document-core/.settings/org.eclipse.jdt.core.prefs b/spring-data-document-core/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index aa62685f0..000000000 --- a/spring-data-document-core/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,9 +0,0 @@ -#Wed Mar 09 13:51:17 EST 2011 -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 -org.eclipse.jdt.core.compiler.compliance=1.6 -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning -org.eclipse.jdt.core.compiler.source=1.6 diff --git a/spring-data-document-core/.settings/org.eclipse.wst.common.component b/spring-data-document-core/.settings/org.eclipse.wst.common.component deleted file mode 100644 index 8eb900276..000000000 --- a/spring-data-document-core/.settings/org.eclipse.wst.common.component +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/spring-data-document-core/.settings/org.eclipse.wst.common.project.facet.core.xml b/spring-data-document-core/.settings/org.eclipse.wst.common.project.facet.core.xml deleted file mode 100644 index 5c9bd7532..000000000 --- a/spring-data-document-core/.settings/org.eclipse.wst.common.project.facet.core.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/spring-data-document-core/.settings/org.maven.ide.eclipse.prefs b/spring-data-document-core/.settings/org.maven.ide.eclipse.prefs deleted file mode 100644 index 5545b44b1..000000000 --- a/spring-data-document-core/.settings/org.maven.ide.eclipse.prefs +++ /dev/null @@ -1,9 +0,0 @@ -#Wed Oct 06 14:49:46 EDT 2010 -activeProfiles= -eclipse.preferences.version=1 -fullBuildGoals=process-test-resources -includeModules=false -resolveWorkspaceProjects=true -resourceFilterGoals=process-resources resources\:testResources -skipCompilerPlugin=true -version=1 diff --git a/spring-data-document-core/src/main/java/org/springframework/data/document/AbstractDocumentStoreTemplate.java b/spring-data-document-core/src/main/java/org/springframework/data/document/AbstractDocumentStoreTemplate.java index 97439420b..dfea53c99 100644 --- a/spring-data-document-core/src/main/java/org/springframework/data/document/AbstractDocumentStoreTemplate.java +++ b/spring-data-document-core/src/main/java/org/springframework/data/document/AbstractDocumentStoreTemplate.java @@ -18,16 +18,15 @@ package org.springframework.data.document; public abstract class AbstractDocumentStoreTemplate { - - public abstract C getConnection(); - public T execute(DocumentStoreConnectionCallback action) { - try { - return action.doInConnection(getConnection()); - } - catch (Exception e) { - throw new UncategorizedDocumentStoreException("Failure executing using datastore connection", e); - } - } - + public abstract C getConnection(); + + public T execute(DocumentStoreConnectionCallback action) { + try { + return action.doInConnection(getConnection()); + } catch (Exception e) { + throw new UncategorizedDocumentStoreException("Failure executing using datastore connection", e); + } + } + } diff --git a/spring-data-document-core/src/main/java/org/springframework/data/document/DocumentMapper.java b/spring-data-document-core/src/main/java/org/springframework/data/document/DocumentMapper.java index 48cf9919b..dc50394a5 100644 --- a/spring-data-document-core/src/main/java/org/springframework/data/document/DocumentMapper.java +++ b/spring-data-document-core/src/main/java/org/springframework/data/document/DocumentMapper.java @@ -23,7 +23,7 @@ package org.springframework.data.document; * @since 1.0 */ public interface DocumentMapper { - - T mapDocument(D document); + + T mapDocument(D document); } diff --git a/spring-data-document-core/src/main/java/org/springframework/data/document/DocumentStoreConnectionCallback.java b/spring-data-document-core/src/main/java/org/springframework/data/document/DocumentStoreConnectionCallback.java index 5711adaa6..d6cb0e232 100644 --- a/spring-data-document-core/src/main/java/org/springframework/data/document/DocumentStoreConnectionCallback.java +++ b/spring-data-document-core/src/main/java/org/springframework/data/document/DocumentStoreConnectionCallback.java @@ -18,5 +18,5 @@ package org.springframework.data.document; public interface DocumentStoreConnectionCallback { - T doInConnection(C con) throws Exception; + T doInConnection(C con) throws Exception; } diff --git a/spring-data-document-core/src/main/java/org/springframework/data/document/InvalidDocumentStoreApiUsageException.java b/spring-data-document-core/src/main/java/org/springframework/data/document/InvalidDocumentStoreApiUsageException.java index 205d93ef4..19eacb1c7 100644 --- a/spring-data-document-core/src/main/java/org/springframework/data/document/InvalidDocumentStoreApiUsageException.java +++ b/spring-data-document-core/src/main/java/org/springframework/data/document/InvalidDocumentStoreApiUsageException.java @@ -20,12 +20,12 @@ import org.springframework.dao.InvalidDataAccessApiUsageException; public class InvalidDocumentStoreApiUsageException extends InvalidDataAccessApiUsageException { - public InvalidDocumentStoreApiUsageException(String msg) { - super(msg); - } + public InvalidDocumentStoreApiUsageException(String msg) { + super(msg); + } - public InvalidDocumentStoreApiUsageException(String msg, Throwable cause) { - super(msg, cause); - } + public InvalidDocumentStoreApiUsageException(String msg, Throwable cause) { + super(msg, cause); + } } diff --git a/spring-data-document-core/src/main/java/org/springframework/data/document/UncategorizedDocumentStoreException.java b/spring-data-document-core/src/main/java/org/springframework/data/document/UncategorizedDocumentStoreException.java index 44ee8b879..f7fe00595 100644 --- a/spring-data-document-core/src/main/java/org/springframework/data/document/UncategorizedDocumentStoreException.java +++ b/spring-data-document-core/src/main/java/org/springframework/data/document/UncategorizedDocumentStoreException.java @@ -20,8 +20,8 @@ import org.springframework.dao.UncategorizedDataAccessException; public class UncategorizedDocumentStoreException extends UncategorizedDataAccessException { - public UncategorizedDocumentStoreException(String msg, Throwable cause) { - super(msg, cause); - } + public UncategorizedDocumentStoreException(String msg, Throwable cause) { + super(msg, cause); + } } diff --git a/spring-data-document-core/src/main/java/org/springframework/data/document/analytics/ControllerCounter.java b/spring-data-document-core/src/main/java/org/springframework/data/document/analytics/ControllerCounter.java index 459feeaed..77c2696b8 100644 --- a/spring-data-document-core/src/main/java/org/springframework/data/document/analytics/ControllerCounter.java +++ b/spring-data-document-core/src/main/java/org/springframework/data/document/analytics/ControllerCounter.java @@ -1,45 +1,43 @@ package org.springframework.data.document.analytics; -import java.util.Date; import java.util.Map; public class ControllerCounter { - - public String getName() { - return name; - } - public void setName(String name) { - this.name = name; - } + public String getName() { + return name; + } - public double getCount() { - return count; - } + public void setName(String name) { + this.name = name; + } - public void setCount(double count) { - this.count = count; - } + public double getCount() { + return count; + } - public Map getMethods() { - return methods; - } - - + public void setCount(double count) { + this.count = count; + } - public void setMethods(Map methods) { - this.methods = methods; - } + public Map getMethods() { + return methods; + } - private String name; - - private double count; - - private Map methods; - - @Override - public String toString() { - return "ControllerCounter [name=" + name + ", count=" + count - + ", methods=" + methods + "]"; - } + + public void setMethods(Map methods) { + this.methods = methods; + } + + private String name; + + private double count; + + private Map methods; + + @Override + public String toString() { + return "ControllerCounter [name=" + name + ", count=" + count + + ", methods=" + methods + "]"; + } } diff --git a/spring-data-document-core/src/main/java/org/springframework/data/document/analytics/MvcEvent.java b/spring-data-document-core/src/main/java/org/springframework/data/document/analytics/MvcEvent.java index a63fe2ee6..fea3bc4e5 100644 --- a/spring-data-document-core/src/main/java/org/springframework/data/document/analytics/MvcEvent.java +++ b/spring-data-document-core/src/main/java/org/springframework/data/document/analytics/MvcEvent.java @@ -4,81 +4,80 @@ import java.util.Date; public class MvcEvent { - private String controller; - - private String action; - - private Parameters parameters; - - private Date date; - - private String requestUri; - - private String requestAddress; - - private String remoteUser; - - private String view; + private String controller; - public String getController() { - return controller; - } + private String action; - public void setController(String controller) { - this.controller = controller; - } + private Parameters parameters; - public String getAction() { - return action; - } + private Date date; - public void setAction(String action) { - this.action = action; - } + private String requestUri; - public Parameters getParameters() { - return parameters; - } + private String requestAddress; - public void setParameters(Parameters parameters) { - this.parameters = parameters; - } + private String remoteUser; - public Date getDate() { - return date; - } + private String view; - public void setDate(Date date) { - this.date = date; - } + public String getController() { + return controller; + } - public String getRequestUri() { - return requestUri; - } + public void setController(String controller) { + this.controller = controller; + } - public void setRequestUri(String requestUri) { - this.requestUri = requestUri; - } + public String getAction() { + return action; + } - public String getRequestAddress() { - return requestAddress; - } + public void setAction(String action) { + this.action = action; + } - public void setRequestAddress(String requestAddress) { - this.requestAddress = requestAddress; - } + public Parameters getParameters() { + return parameters; + } + + public void setParameters(Parameters parameters) { + this.parameters = parameters; + } + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + public String getRequestUri() { + return requestUri; + } + + public void setRequestUri(String requestUri) { + this.requestUri = requestUri; + } + + public String getRequestAddress() { + return requestAddress; + } + + public void setRequestAddress(String requestAddress) { + this.requestAddress = requestAddress; + } + + public String getRemoteUser() { + return remoteUser; + } + + public void setRemoteUser(String remoteUser) { + this.remoteUser = remoteUser; + } + + //TODO + //Map sessionAttributes - public String getRemoteUser() { - return remoteUser; - } - public void setRemoteUser(String remoteUser) { - this.remoteUser = remoteUser; - } - - //TODO - //Map sessionAttributes - - - } diff --git a/spring-data-document-core/src/main/java/org/springframework/data/document/analytics/Parameters.java b/spring-data-document-core/src/main/java/org/springframework/data/document/analytics/Parameters.java index a8c9eaef0..0fe1a4f71 100644 --- a/spring-data-document-core/src/main/java/org/springframework/data/document/analytics/Parameters.java +++ b/spring-data-document-core/src/main/java/org/springframework/data/document/analytics/Parameters.java @@ -2,34 +2,34 @@ package org.springframework.data.document.analytics; public class Parameters { - private String p1; - - private String p2; - - private String p3; + private String p1; - public String getP1() { - return p1; - } + private String p2; - public void setP1(String p1) { - this.p1 = p1; - } + private String p3; - public String getP2() { - return p2; - } + public String getP1() { + return p1; + } - public void setP2(String p2) { - this.p2 = p2; - } + public void setP1(String p1) { + this.p1 = p1; + } - public String getP3() { - return p3; - } + public String getP2() { + return p2; + } + + public void setP2(String p2) { + this.p2 = p2; + } + + public String getP3() { + return p3; + } + + public void setP3(String p3) { + this.p3 = p3; + } - public void setP3(String p3) { - this.p3 = p3; - } - } diff --git a/spring-data-document-core/src/main/java/org/springframework/data/document/web/bind/annotation/support/HandlerMethodInvoker.java b/spring-data-document-core/src/main/java/org/springframework/data/document/web/bind/annotation/support/HandlerMethodInvoker.java index a5d7c4416..0e6e4119a 100644 --- a/spring-data-document-core/src/main/java/org/springframework/data/document/web/bind/annotation/support/HandlerMethodInvoker.java +++ b/spring-data-document-core/src/main/java/org/springframework/data/document/web/bind/annotation/support/HandlerMethodInvoker.java @@ -18,67 +18,29 @@ package org.springframework.data.document.web.bind.annotation.support; import java.lang.annotation.Annotation; -import java.lang.reflect.Array; -import java.lang.reflect.GenericArrayType; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.lang.reflect.*; +import java.util.*; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Value; -import org.springframework.core.BridgeMethodResolver; -import org.springframework.core.Conventions; -import org.springframework.core.GenericTypeResolver; -import org.springframework.core.MethodParameter; -import org.springframework.core.ParameterNameDiscoverer; +import org.springframework.core.*; import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpInputMessage; -import org.springframework.http.HttpOutputMessage; -import org.springframework.http.MediaType; +import org.springframework.http.*; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.ui.ExtendedModelMap; import org.springframework.ui.Model; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.util.ReflectionUtils; +import org.springframework.util.*; import org.springframework.validation.BindException; import org.springframework.validation.BindingResult; import org.springframework.validation.Errors; import org.springframework.web.HttpMediaTypeNotSupportedException; import org.springframework.web.bind.WebDataBinder; -import org.springframework.web.bind.annotation.CookieValue; -import org.springframework.web.bind.annotation.InitBinder; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ValueConstants; +import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.support.HandlerMethodInvocationException; import org.springframework.web.bind.annotation.support.HandlerMethodResolver; -import org.springframework.web.bind.support.DefaultSessionAttributeStore; -import org.springframework.web.bind.support.SessionAttributeStore; -import org.springframework.web.bind.support.SessionStatus; -import org.springframework.web.bind.support.SimpleSessionStatus; -import org.springframework.web.bind.support.WebArgumentResolver; -import org.springframework.web.bind.support.WebBindingInitializer; -import org.springframework.web.bind.support.WebRequestDataBinder; +import org.springframework.web.bind.support.*; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.WebRequest; import org.springframework.web.multipart.MultipartFile; @@ -87,812 +49,773 @@ import org.springframework.web.multipart.MultipartRequest; /** * Support class for invoking an annotated handler method. Operates on the introspection results of a {@link * HandlerMethodResolver} for a specific handler type. - * + *

*

Used by {@link org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter} and {@link * org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter}. * * @author Juergen Hoeller * @author Arjen Poutsma - * @since 2.5.2 * @see #invokeHandlerMethod + * @since 2.5.2 */ public class HandlerMethodInvoker { - private static final String MODEL_KEY_PREFIX_STALE = SessionAttributeStore.class.getName() + ".STALE."; - - /** We'll create a lot of these objects, so we don't want a new logger every time. */ - private static final Log logger = LogFactory.getLog(HandlerMethodInvoker.class); - - private final HandlerMethodResolver methodResolver; - - private final WebBindingInitializer bindingInitializer; - - private final SessionAttributeStore sessionAttributeStore; - - private final ParameterNameDiscoverer parameterNameDiscoverer; - - private final WebArgumentResolver[] customArgumentResolvers; - - private final HttpMessageConverter[] messageConverters; - - private final SimpleSessionStatus sessionStatus = new SimpleSessionStatus(); - - - public HandlerMethodInvoker(HandlerMethodResolver methodResolver) { - this(methodResolver, null); - } - - public HandlerMethodInvoker(HandlerMethodResolver methodResolver, WebBindingInitializer bindingInitializer) { - this(methodResolver, bindingInitializer, new DefaultSessionAttributeStore(), null, null, null); - } - - public HandlerMethodInvoker(HandlerMethodResolver methodResolver, WebBindingInitializer bindingInitializer, - SessionAttributeStore sessionAttributeStore, ParameterNameDiscoverer parameterNameDiscoverer, - WebArgumentResolver[] customArgumentResolvers, HttpMessageConverter[] messageConverters) { - - this.methodResolver = methodResolver; - this.bindingInitializer = bindingInitializer; - this.sessionAttributeStore = sessionAttributeStore; - this.parameterNameDiscoverer = parameterNameDiscoverer; - this.customArgumentResolvers = customArgumentResolvers; - this.messageConverters = messageConverters; - } - - - public final Object invokeHandlerMethod(Method handlerMethod, Object handler, - NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception { - - Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod); - try { - boolean debug = logger.isDebugEnabled(); - for (String attrName : this.methodResolver.getActualSessionAttributeNames()) { - Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName); - if (attrValue != null) { - implicitModel.addAttribute(attrName, attrValue); - } - } - for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) { - Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod); - Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel); - if (debug) { - logger.debug("Invoking model attribute method: " + attributeMethodToInvoke); - } - String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value(); - if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) { - continue; - } - ReflectionUtils.makeAccessible(attributeMethodToInvoke); - Object attrValue = attributeMethodToInvoke.invoke(handler, args); - if ("".equals(attrName)) { - Class resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass()); - attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue); - } - if (!implicitModel.containsAttribute(attrName)) { - implicitModel.addAttribute(attrName, attrValue); - } - } - Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel); - if (debug) { - logger.debug("Invoking request handler method: " + handlerMethodToInvoke); - } - ReflectionUtils.makeAccessible(handlerMethodToInvoke); - return handlerMethodToInvoke.invoke(handler, args); - } - catch (IllegalStateException ex) { - // Internal assertion failed (e.g. invalid signature): - // throw exception with full handler method context... - throw new HandlerMethodInvocationException(handlerMethodToInvoke, ex); - } - catch (InvocationTargetException ex) { - // User-defined @ModelAttribute/@InitBinder/@RequestMapping method threw an exception... - ReflectionUtils.rethrowException(ex.getTargetException()); - return null; - } - } - - public final void updateModelAttributes(Object handler, Map mavModel, - ExtendedModelMap implicitModel, NativeWebRequest webRequest) throws Exception { - - if (this.methodResolver.hasSessionAttributes() && this.sessionStatus.isComplete()) { - for (String attrName : this.methodResolver.getActualSessionAttributeNames()) { - this.sessionAttributeStore.cleanupAttribute(webRequest, attrName); - } - } - - // Expose model attributes as session attributes, if required. - // Expose BindingResults for all attributes, making custom editors available. - Map model = (mavModel != null ? mavModel : implicitModel); - if (model != null) { - try { - String[] originalAttrNames = model.keySet().toArray(new String[model.size()]); - for (String attrName : originalAttrNames) { - Object attrValue = model.get(attrName); - boolean isSessionAttr = this.methodResolver.isSessionAttribute( - attrName, (attrValue != null ? attrValue.getClass() : null)); - if (isSessionAttr) { - if (this.sessionStatus.isComplete()) { - implicitModel.put(MODEL_KEY_PREFIX_STALE + attrName, Boolean.TRUE); - } - else if (!implicitModel.containsKey(MODEL_KEY_PREFIX_STALE + attrName)) { - this.sessionAttributeStore.storeAttribute(webRequest, attrName, attrValue); - } - } - if (!attrName.startsWith(BindingResult.MODEL_KEY_PREFIX) && - (isSessionAttr || isBindingCandidate(attrValue))) { - String bindingResultKey = BindingResult.MODEL_KEY_PREFIX + attrName; - if (mavModel != null && !model.containsKey(bindingResultKey)) { - WebDataBinder binder = createBinder(webRequest, attrValue, attrName); - initBinder(handler, attrName, binder, webRequest); - mavModel.put(bindingResultKey, binder.getBindingResult()); - } - } - } - } - catch (InvocationTargetException ex) { - // User-defined @InitBinder method threw an exception... - ReflectionUtils.rethrowException(ex.getTargetException()); - } - } - } - - - private Object[] resolveHandlerArguments(Method handlerMethod, Object handler, - NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception { - - Class[] paramTypes = handlerMethod.getParameterTypes(); - Object[] args = new Object[paramTypes.length]; - - for (int i = 0; i < args.length; i++) { - MethodParameter methodParam = new MethodParameter(handlerMethod, i); - methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer); - GenericTypeResolver.resolveParameterType(methodParam, handler.getClass()); - String paramName = null; - String headerName = null; - boolean requestBodyFound = false; - String cookieName = null; - String pathVarName = null; - String attrName = null; - boolean required = false; - String defaultValue = null; - boolean validate = false; - int annotationsFound = 0; - Annotation[] paramAnns = methodParam.getParameterAnnotations(); - - for (Annotation paramAnn : paramAnns) { - if (RequestParam.class.isInstance(paramAnn)) { - RequestParam requestParam = (RequestParam) paramAnn; - paramName = requestParam.value(); - required = requestParam.required(); - defaultValue = parseDefaultValueAttribute(requestParam.defaultValue()); - annotationsFound++; - } - else if (RequestHeader.class.isInstance(paramAnn)) { - RequestHeader requestHeader = (RequestHeader) paramAnn; - headerName = requestHeader.value(); - required = requestHeader.required(); - defaultValue = parseDefaultValueAttribute(requestHeader.defaultValue()); - annotationsFound++; - } - else if (RequestBody.class.isInstance(paramAnn)) { - requestBodyFound = true; - annotationsFound++; - } - else if (CookieValue.class.isInstance(paramAnn)) { - CookieValue cookieValue = (CookieValue) paramAnn; - cookieName = cookieValue.value(); - required = cookieValue.required(); - defaultValue = parseDefaultValueAttribute(cookieValue.defaultValue()); - annotationsFound++; - } - else if (PathVariable.class.isInstance(paramAnn)) { - PathVariable pathVar = (PathVariable) paramAnn; - pathVarName = pathVar.value(); - annotationsFound++; - } - else if (ModelAttribute.class.isInstance(paramAnn)) { - ModelAttribute attr = (ModelAttribute) paramAnn; - attrName = attr.value(); - annotationsFound++; - } - else if (Value.class.isInstance(paramAnn)) { - defaultValue = ((Value) paramAnn).value(); - } - else if ("Valid".equals(paramAnn.annotationType().getSimpleName())) { - validate = true; - } - } - - if (annotationsFound > 1) { - throw new IllegalStateException("Handler parameter annotations are exclusive choices - " + - "do not specify more than one such annotation on the same parameter: " + handlerMethod); - } - - if (annotationsFound == 0) { - Object argValue = resolveCommonArgument(methodParam, webRequest); - if (argValue != WebArgumentResolver.UNRESOLVED) { - args[i] = argValue; - } - else if (defaultValue != null) { - args[i] = resolveDefaultValue(defaultValue); - } - else { - Class paramType = methodParam.getParameterType(); - if (Model.class.isAssignableFrom(paramType) || Map.class.isAssignableFrom(paramType)) { - args[i] = implicitModel; - } - else if (SessionStatus.class.isAssignableFrom(paramType)) { - args[i] = this.sessionStatus; - } - else if (HttpEntity.class.isAssignableFrom(paramType)) { - args[i] = resolveHttpEntityRequest(methodParam, webRequest); - } - else if (Errors.class.isAssignableFrom(paramType)) { - throw new IllegalStateException("Errors/BindingResult argument declared " + - "without preceding model attribute. Check your handler method signature!"); - } - else if (BeanUtils.isSimpleProperty(paramType)) { - paramName = ""; - } - else { - attrName = ""; - } - } - } - - if (paramName != null) { - args[i] = resolveRequestParam(paramName, required, defaultValue, methodParam, webRequest, handler); - } - else if (headerName != null) { - args[i] = resolveRequestHeader(headerName, required, defaultValue, methodParam, webRequest, handler); - } - else if (requestBodyFound) { - args[i] = resolveRequestBody(methodParam, webRequest, handler); - } - else if (cookieName != null) { - args[i] = resolveCookieValue(cookieName, required, defaultValue, methodParam, webRequest, handler); - } - else if (pathVarName != null) { - args[i] = resolvePathVariable(pathVarName, methodParam, webRequest, handler); - } - else if (attrName != null) { - WebDataBinder binder = - resolveModelAttribute(attrName, methodParam, implicitModel, webRequest, handler); - boolean assignBindingResult = (args.length > i + 1 && Errors.class.isAssignableFrom(paramTypes[i + 1])); - if (binder.getTarget() != null) { - doBind(binder, webRequest, validate, !assignBindingResult); - } - args[i] = binder.getTarget(); - if (assignBindingResult) { - args[i + 1] = binder.getBindingResult(); - i++; - } - implicitModel.putAll(binder.getBindingResult().getModel()); - } - } - - return args; - } - - protected void initBinder(Object handler, String attrName, WebDataBinder binder, NativeWebRequest webRequest) - throws Exception { - - if (this.bindingInitializer != null) { - this.bindingInitializer.initBinder(binder, webRequest); - } - if (handler != null) { - Set initBinderMethods = this.methodResolver.getInitBinderMethods(); - if (!initBinderMethods.isEmpty()) { - boolean debug = logger.isDebugEnabled(); - for (Method initBinderMethod : initBinderMethods) { - Method methodToInvoke = BridgeMethodResolver.findBridgedMethod(initBinderMethod); - String[] targetNames = AnnotationUtils.findAnnotation(initBinderMethod, InitBinder.class).value(); - if (targetNames.length == 0 || Arrays.asList(targetNames).contains(attrName)) { - Object[] initBinderArgs = - resolveInitBinderArguments(handler, methodToInvoke, binder, webRequest); - if (debug) { - logger.debug("Invoking init-binder method: " + methodToInvoke); - } - ReflectionUtils.makeAccessible(methodToInvoke); - Object returnValue = methodToInvoke.invoke(handler, initBinderArgs); - if (returnValue != null) { - throw new IllegalStateException( - "InitBinder methods must not have a return value: " + methodToInvoke); - } - } - } - } - } - } - - private Object[] resolveInitBinderArguments(Object handler, Method initBinderMethod, - WebDataBinder binder, NativeWebRequest webRequest) throws Exception { - - Class[] initBinderParams = initBinderMethod.getParameterTypes(); - Object[] initBinderArgs = new Object[initBinderParams.length]; - - for (int i = 0; i < initBinderArgs.length; i++) { - MethodParameter methodParam = new MethodParameter(initBinderMethod, i); - methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer); - GenericTypeResolver.resolveParameterType(methodParam, handler.getClass()); - String paramName = null; - boolean paramRequired = false; - String paramDefaultValue = null; - String pathVarName = null; - Annotation[] paramAnns = methodParam.getParameterAnnotations(); - - for (Annotation paramAnn : paramAnns) { - if (RequestParam.class.isInstance(paramAnn)) { - RequestParam requestParam = (RequestParam) paramAnn; - paramName = requestParam.value(); - paramRequired = requestParam.required(); - paramDefaultValue = parseDefaultValueAttribute(requestParam.defaultValue()); - break; - } - else if (ModelAttribute.class.isInstance(paramAnn)) { - throw new IllegalStateException( - "@ModelAttribute is not supported on @InitBinder methods: " + initBinderMethod); - } - else if (PathVariable.class.isInstance(paramAnn)) { - PathVariable pathVar = (PathVariable) paramAnn; - pathVarName = pathVar.value(); - } - } - - if (paramName == null && pathVarName == null) { - Object argValue = resolveCommonArgument(methodParam, webRequest); - if (argValue != WebArgumentResolver.UNRESOLVED) { - initBinderArgs[i] = argValue; - } - else { - Class paramType = initBinderParams[i]; - if (paramType.isInstance(binder)) { - initBinderArgs[i] = binder; - } - else if (BeanUtils.isSimpleProperty(paramType)) { - paramName = ""; - } - else { - throw new IllegalStateException("Unsupported argument [" + paramType.getName() + - "] for @InitBinder method: " + initBinderMethod); - } - } - } - - if (paramName != null) { - initBinderArgs[i] = - resolveRequestParam(paramName, paramRequired, paramDefaultValue, methodParam, webRequest, null); - } - else if (pathVarName != null) { - initBinderArgs[i] = resolvePathVariable(pathVarName, methodParam, webRequest, null); - } - } - - return initBinderArgs; - } - - @SuppressWarnings("unchecked") - private Object resolveRequestParam(String paramName, boolean required, String defaultValue, - MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall) - throws Exception { - - Class paramType = methodParam.getParameterType(); - if (Map.class.isAssignableFrom(paramType) && paramName.length() == 0) { - return resolveRequestParamMap((Class) paramType, webRequest); - } - if (paramName.length() == 0) { - paramName = getRequiredParameterName(methodParam); - } - Object paramValue = null; - MultipartRequest multipartRequest = webRequest.getNativeRequest(MultipartRequest.class); - if (multipartRequest != null) { - List files = multipartRequest.getFiles(paramName); - if (!files.isEmpty()) { - if (files.size() == 1 && !paramType.isArray() && !Collection.class.isAssignableFrom(paramType)) { - paramValue = files.get(0); - } - else { - paramValue = files; - } - } - } - if (paramValue == null) { - String[] paramValues = webRequest.getParameterValues(paramName); - if (paramValues != null) { - if (paramValues.length == 1 && !paramType.isArray() && !Collection.class.isAssignableFrom(paramType)) { - paramValue = paramValues[0]; - } - else { - paramValue = paramValues; - } - } - } - if (paramValue == null) { - if (defaultValue != null) { - paramValue = resolveDefaultValue(defaultValue); - } - else if (required) { - raiseMissingParameterException(paramName, paramType); - } - paramValue = checkValue(paramName, paramValue, paramType); - } - WebDataBinder binder = createBinder(webRequest, null, paramName); - initBinder(handlerForInitBinderCall, paramName, binder, webRequest); - return binder.convertIfNecessary(paramValue, paramType, methodParam); - } - - private Map resolveRequestParamMap(Class mapType, NativeWebRequest webRequest) { - Map parameterMap = webRequest.getParameterMap(); - if (MultiValueMap.class.isAssignableFrom(mapType)) { - MultiValueMap result = new LinkedMultiValueMap(parameterMap.size()); - for (Map.Entry entry : parameterMap.entrySet()) { - for (String value : entry.getValue()) { - result.add(entry.getKey(), value); - } - } - return result; - } - else { - Map result = new LinkedHashMap(parameterMap.size()); - for (Map.Entry entry : parameterMap.entrySet()) { - if (entry.getValue().length > 0) { - result.put(entry.getKey(), entry.getValue()[0]); - } - } - return result; - } - } - - @SuppressWarnings("unchecked") - private Object resolveRequestHeader(String headerName, boolean required, String defaultValue, - MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall) - throws Exception { - - Class paramType = methodParam.getParameterType(); - if (Map.class.isAssignableFrom(paramType)) { - return resolveRequestHeaderMap((Class) paramType, webRequest); - } - if (headerName.length() == 0) { - headerName = getRequiredParameterName(methodParam); - } - Object headerValue = null; - String[] headerValues = webRequest.getHeaderValues(headerName); - if (headerValues != null) { - headerValue = (headerValues.length == 1 ? headerValues[0] : headerValues); - } - if (headerValue == null) { - if (defaultValue != null) { - headerValue = resolveDefaultValue(defaultValue); - } - else if (required) { - raiseMissingHeaderException(headerName, paramType); - } - headerValue = checkValue(headerName, headerValue, paramType); - } - WebDataBinder binder = createBinder(webRequest, null, headerName); - initBinder(handlerForInitBinderCall, headerName, binder, webRequest); - return binder.convertIfNecessary(headerValue, paramType, methodParam); - } - - private Map resolveRequestHeaderMap(Class mapType, NativeWebRequest webRequest) { - if (MultiValueMap.class.isAssignableFrom(mapType)) { - MultiValueMap result; - if (HttpHeaders.class.isAssignableFrom(mapType)) { - result = new HttpHeaders(); - } - else { - result = new LinkedMultiValueMap(); - } - for (Iterator iterator = webRequest.getHeaderNames(); iterator.hasNext();) { - String headerName = iterator.next(); - for (String headerValue : webRequest.getHeaderValues(headerName)) { - result.add(headerName, headerValue); - } - } - return result; - } - else { - Map result = new LinkedHashMap(); - for (Iterator iterator = webRequest.getHeaderNames(); iterator.hasNext();) { - String headerName = iterator.next(); - String headerValue = webRequest.getHeader(headerName); - result.put(headerName, headerValue); - } - return result; - } - } - - /** - * Resolves the given {@link RequestBody @RequestBody} annotation. - */ - protected Object resolveRequestBody(MethodParameter methodParam, NativeWebRequest webRequest, Object handler) - throws Exception { - - return readWithMessageConverters(methodParam, createHttpInputMessage(webRequest), methodParam.getParameterType()); - } - - private HttpEntity resolveHttpEntityRequest(MethodParameter methodParam, NativeWebRequest webRequest) - throws Exception { - - HttpInputMessage inputMessage = createHttpInputMessage(webRequest); - Class paramType = getHttpEntityType(methodParam); - Object body = readWithMessageConverters(methodParam, inputMessage, paramType); - return new HttpEntity(body, inputMessage.getHeaders()); - } - - private Object readWithMessageConverters(MethodParameter methodParam, HttpInputMessage inputMessage, Class paramType) - throws Exception { - - MediaType contentType = inputMessage.getHeaders().getContentType(); - if (contentType == null) { - StringBuilder builder = new StringBuilder(ClassUtils.getShortName(methodParam.getParameterType())); - String paramName = methodParam.getParameterName(); - if (paramName != null) { - builder.append(' '); - builder.append(paramName); - } - throw new HttpMediaTypeNotSupportedException( - "Cannot extract parameter (" + builder.toString() + "): no Content-Type found"); - } - - List allSupportedMediaTypes = new ArrayList(); - if (this.messageConverters != null) { - for (HttpMessageConverter messageConverter : this.messageConverters) { - allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes()); - if (messageConverter.canRead(paramType, contentType)) { - if (logger.isDebugEnabled()) { - logger.debug("Reading [" + paramType.getName() + "] as \"" + contentType - +"\" using [" + messageConverter + "]"); - } - return messageConverter.read(paramType, inputMessage); - } - } - } - throw new HttpMediaTypeNotSupportedException(contentType, allSupportedMediaTypes); - } - - private Class getHttpEntityType(MethodParameter methodParam) { - Assert.isAssignable(HttpEntity.class, methodParam.getParameterType()); - ParameterizedType type = (ParameterizedType) methodParam.getGenericParameterType(); - if (type.getActualTypeArguments().length == 1) { - Type typeArgument = type.getActualTypeArguments()[0]; - if (typeArgument instanceof Class) { - return (Class) typeArgument; - } - else if (typeArgument instanceof GenericArrayType) { - Type componentType = ((GenericArrayType) typeArgument).getGenericComponentType(); - if (componentType instanceof Class) { - // Surely, there should be a nicer way to do this - Object array = Array.newInstance((Class) componentType, 0); - return array.getClass(); - } - } - } - throw new IllegalArgumentException( - "HttpEntity parameter (" + methodParam.getParameterName() + ") is not parameterized"); - - } - - private Object resolveCookieValue(String cookieName, boolean required, String defaultValue, - MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall) - throws Exception { - - Class paramType = methodParam.getParameterType(); - if (cookieName.length() == 0) { - cookieName = getRequiredParameterName(methodParam); - } - Object cookieValue = resolveCookieValue(cookieName, paramType, webRequest); - if (cookieValue == null) { - if (defaultValue != null) { - cookieValue = resolveDefaultValue(defaultValue); - } - else if (required) { - raiseMissingCookieException(cookieName, paramType); - } - cookieValue = checkValue(cookieName, cookieValue, paramType); - } - WebDataBinder binder = createBinder(webRequest, null, cookieName); - initBinder(handlerForInitBinderCall, cookieName, binder, webRequest); - return binder.convertIfNecessary(cookieValue, paramType, methodParam); - } - - /** - * Resolves the given {@link CookieValue @CookieValue} annotation. - *

Throws an UnsupportedOperationException by default. - */ - protected Object resolveCookieValue(String cookieName, Class paramType, NativeWebRequest webRequest) - throws Exception { - - throw new UnsupportedOperationException("@CookieValue not supported"); - } - - private Object resolvePathVariable(String pathVarName, MethodParameter methodParam, - NativeWebRequest webRequest, Object handlerForInitBinderCall) throws Exception { - - Class paramType = methodParam.getParameterType(); - if (pathVarName.length() == 0) { - pathVarName = getRequiredParameterName(methodParam); - } - String pathVarValue = resolvePathVariable(pathVarName, paramType, webRequest); - WebDataBinder binder = createBinder(webRequest, null, pathVarName); - initBinder(handlerForInitBinderCall, pathVarName, binder, webRequest); - return binder.convertIfNecessary(pathVarValue, paramType, methodParam); - } - - /** - * Resolves the given {@link PathVariable @PathVariable} annotation. - *

Throws an UnsupportedOperationException by default. - */ - protected String resolvePathVariable(String pathVarName, Class paramType, NativeWebRequest webRequest) - throws Exception { - - throw new UnsupportedOperationException("@PathVariable not supported"); - } - - private String getRequiredParameterName(MethodParameter methodParam) { - String name = methodParam.getParameterName(); - if (name == null) { - throw new IllegalStateException( - "No parameter name specified for argument of type [" + methodParam.getParameterType().getName() + - "], and no parameter name information found in class file either."); - } - return name; - } - - private Object checkValue(String name, Object value, Class paramType) { - if (value == null) { - if (boolean.class.equals(paramType)) { - return Boolean.FALSE; - } - else if (paramType.isPrimitive()) { - throw new IllegalStateException("Optional " + paramType + " parameter '" + name + - "' is not present but cannot be translated into a null value due to being declared as a " + - "primitive type. Consider declaring it as object wrapper for the corresponding primitive type."); - } - } - return value; - } - - private WebDataBinder resolveModelAttribute(String attrName, MethodParameter methodParam, - ExtendedModelMap implicitModel, NativeWebRequest webRequest, Object handler) throws Exception { - - // Bind request parameter onto object... - String name = attrName; - if ("".equals(name)) { - name = Conventions.getVariableNameForParameter(methodParam); - } - Class paramType = methodParam.getParameterType(); - Object bindObject; - if (implicitModel.containsKey(name)) { - bindObject = implicitModel.get(name); - } - else if (this.methodResolver.isSessionAttribute(name, paramType)) { - bindObject = this.sessionAttributeStore.retrieveAttribute(webRequest, name); - if (bindObject == null) { - raiseSessionRequiredException("Session attribute '" + name + "' required - not found in session"); - } - } - else { - bindObject = BeanUtils.instantiateClass(paramType); - } - WebDataBinder binder = createBinder(webRequest, bindObject, name); - initBinder(handler, name, binder, webRequest); - return binder; - } - - - /** - * Determine whether the given value qualifies as a "binding candidate", i.e. might potentially be subject to - * bean-style data binding later on. - */ - protected boolean isBindingCandidate(Object value) { - return (value != null && !value.getClass().isArray() && !(value instanceof Collection) && - !(value instanceof Map) && !BeanUtils.isSimpleValueType(value.getClass())); - } - - protected void raiseMissingParameterException(String paramName, Class paramType) throws Exception { - throw new IllegalStateException("Missing parameter '" + paramName + "' of type [" + paramType.getName() + "]"); - } - - protected void raiseMissingHeaderException(String headerName, Class paramType) throws Exception { - throw new IllegalStateException("Missing header '" + headerName + "' of type [" + paramType.getName() + "]"); - } - - protected void raiseMissingCookieException(String cookieName, Class paramType) throws Exception { - throw new IllegalStateException( - "Missing cookie value '" + cookieName + "' of type [" + paramType.getName() + "]"); - } - - protected void raiseSessionRequiredException(String message) throws Exception { - throw new IllegalStateException(message); - } - - protected WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName) - throws Exception { - - return new WebRequestDataBinder(target, objectName); - } - - private void doBind(WebDataBinder binder, NativeWebRequest webRequest, boolean validate, boolean failOnErrors) - throws Exception { - - doBind(binder, webRequest); - if (validate) { - binder.validate(); - } - if (failOnErrors && binder.getBindingResult().hasErrors()) { - throw new BindException(binder.getBindingResult()); - } - } - - protected void doBind(WebDataBinder binder, NativeWebRequest webRequest) throws Exception { - ((WebRequestDataBinder) binder).bind(webRequest); - } - - /** - * Return a {@link HttpInputMessage} for the given {@link NativeWebRequest}. - *

Throws an UnsupportedOperation1Exception by default. - */ - protected HttpInputMessage createHttpInputMessage(NativeWebRequest webRequest) throws Exception { - throw new UnsupportedOperationException("@RequestBody not supported"); - } - - /** - * Return a {@link HttpOutputMessage} for the given {@link NativeWebRequest}. - *

Throws an UnsupportedOperationException by default. - */ - protected HttpOutputMessage createHttpOutputMessage(NativeWebRequest webRequest) throws Exception { - throw new UnsupportedOperationException("@ResponseBody not supported"); - } - - protected String parseDefaultValueAttribute(String value) { - return (ValueConstants.DEFAULT_NONE.equals(value) ? null : value); - } - - protected Object resolveDefaultValue(String value) { - return value; - } - - protected Object resolveCommonArgument(MethodParameter methodParameter, NativeWebRequest webRequest) - throws Exception { - - // Invoke custom argument resolvers if present... - if (this.customArgumentResolvers != null) { - for (WebArgumentResolver argumentResolver : this.customArgumentResolvers) { - Object value = argumentResolver.resolveArgument(methodParameter, webRequest); - if (value != WebArgumentResolver.UNRESOLVED) { - return value; - } - } - } - - // Resolution of standard parameter types... - Class paramType = methodParameter.getParameterType(); - Object value = resolveStandardArgument(paramType, webRequest); - if (value != WebArgumentResolver.UNRESOLVED && !ClassUtils.isAssignableValue(paramType, value)) { - throw new IllegalStateException("Standard argument type [" + paramType.getName() + - "] resolved to incompatible value of type [" + (value != null ? value.getClass() : null) + - "]. Consider declaring the argument type in a less specific fashion."); - } - return value; - } - - protected Object resolveStandardArgument(Class parameterType, NativeWebRequest webRequest) throws Exception { - if (WebRequest.class.isAssignableFrom(parameterType)) { - return webRequest; - } - return WebArgumentResolver.UNRESOLVED; - } - - protected final void addReturnValueAsModelAttribute(Method handlerMethod, Class handlerType, - Object returnValue, ExtendedModelMap implicitModel) { - - ModelAttribute attr = AnnotationUtils.findAnnotation(handlerMethod, ModelAttribute.class); - String attrName = (attr != null ? attr.value() : ""); - if ("".equals(attrName)) { - Class resolvedType = GenericTypeResolver.resolveReturnType(handlerMethod, handlerType); - attrName = Conventions.getVariableNameForReturnType(handlerMethod, resolvedType, returnValue); - } - implicitModel.addAttribute(attrName, returnValue); - } + private static final String MODEL_KEY_PREFIX_STALE = SessionAttributeStore.class.getName() + ".STALE."; + + /** + * We'll create a lot of these objects, so we don't want a new logger every time. + */ + private static final Log logger = LogFactory.getLog(HandlerMethodInvoker.class); + + private final HandlerMethodResolver methodResolver; + + private final WebBindingInitializer bindingInitializer; + + private final SessionAttributeStore sessionAttributeStore; + + private final ParameterNameDiscoverer parameterNameDiscoverer; + + private final WebArgumentResolver[] customArgumentResolvers; + + private final HttpMessageConverter[] messageConverters; + + private final SimpleSessionStatus sessionStatus = new SimpleSessionStatus(); + + + public HandlerMethodInvoker(HandlerMethodResolver methodResolver) { + this(methodResolver, null); + } + + public HandlerMethodInvoker(HandlerMethodResolver methodResolver, WebBindingInitializer bindingInitializer) { + this(methodResolver, bindingInitializer, new DefaultSessionAttributeStore(), null, null, null); + } + + public HandlerMethodInvoker(HandlerMethodResolver methodResolver, WebBindingInitializer bindingInitializer, + SessionAttributeStore sessionAttributeStore, ParameterNameDiscoverer parameterNameDiscoverer, + WebArgumentResolver[] customArgumentResolvers, HttpMessageConverter[] messageConverters) { + + this.methodResolver = methodResolver; + this.bindingInitializer = bindingInitializer; + this.sessionAttributeStore = sessionAttributeStore; + this.parameterNameDiscoverer = parameterNameDiscoverer; + this.customArgumentResolvers = customArgumentResolvers; + this.messageConverters = messageConverters; + } + + + public final Object invokeHandlerMethod(Method handlerMethod, Object handler, + NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception { + + Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod); + try { + boolean debug = logger.isDebugEnabled(); + for (String attrName : this.methodResolver.getActualSessionAttributeNames()) { + Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName); + if (attrValue != null) { + implicitModel.addAttribute(attrName, attrValue); + } + } + for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) { + Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod); + Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel); + if (debug) { + logger.debug("Invoking model attribute method: " + attributeMethodToInvoke); + } + String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value(); + if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) { + continue; + } + ReflectionUtils.makeAccessible(attributeMethodToInvoke); + Object attrValue = attributeMethodToInvoke.invoke(handler, args); + if ("".equals(attrName)) { + Class resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass()); + attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue); + } + if (!implicitModel.containsAttribute(attrName)) { + implicitModel.addAttribute(attrName, attrValue); + } + } + Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel); + if (debug) { + logger.debug("Invoking request handler method: " + handlerMethodToInvoke); + } + ReflectionUtils.makeAccessible(handlerMethodToInvoke); + return handlerMethodToInvoke.invoke(handler, args); + } catch (IllegalStateException ex) { + // Internal assertion failed (e.g. invalid signature): + // throw exception with full handler method context... + throw new HandlerMethodInvocationException(handlerMethodToInvoke, ex); + } catch (InvocationTargetException ex) { + // User-defined @ModelAttribute/@InitBinder/@RequestMapping method threw an exception... + ReflectionUtils.rethrowException(ex.getTargetException()); + return null; + } + } + + public final void updateModelAttributes(Object handler, Map mavModel, + ExtendedModelMap implicitModel, NativeWebRequest webRequest) throws Exception { + + if (this.methodResolver.hasSessionAttributes() && this.sessionStatus.isComplete()) { + for (String attrName : this.methodResolver.getActualSessionAttributeNames()) { + this.sessionAttributeStore.cleanupAttribute(webRequest, attrName); + } + } + + // Expose model attributes as session attributes, if required. + // Expose BindingResults for all attributes, making custom editors available. + Map model = (mavModel != null ? mavModel : implicitModel); + if (model != null) { + try { + String[] originalAttrNames = model.keySet().toArray(new String[model.size()]); + for (String attrName : originalAttrNames) { + Object attrValue = model.get(attrName); + boolean isSessionAttr = this.methodResolver.isSessionAttribute( + attrName, (attrValue != null ? attrValue.getClass() : null)); + if (isSessionAttr) { + if (this.sessionStatus.isComplete()) { + implicitModel.put(MODEL_KEY_PREFIX_STALE + attrName, Boolean.TRUE); + } else if (!implicitModel.containsKey(MODEL_KEY_PREFIX_STALE + attrName)) { + this.sessionAttributeStore.storeAttribute(webRequest, attrName, attrValue); + } + } + if (!attrName.startsWith(BindingResult.MODEL_KEY_PREFIX) && + (isSessionAttr || isBindingCandidate(attrValue))) { + String bindingResultKey = BindingResult.MODEL_KEY_PREFIX + attrName; + if (mavModel != null && !model.containsKey(bindingResultKey)) { + WebDataBinder binder = createBinder(webRequest, attrValue, attrName); + initBinder(handler, attrName, binder, webRequest); + mavModel.put(bindingResultKey, binder.getBindingResult()); + } + } + } + } catch (InvocationTargetException ex) { + // User-defined @InitBinder method threw an exception... + ReflectionUtils.rethrowException(ex.getTargetException()); + } + } + } + + + private Object[] resolveHandlerArguments(Method handlerMethod, Object handler, + NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception { + + Class[] paramTypes = handlerMethod.getParameterTypes(); + Object[] args = new Object[paramTypes.length]; + + for (int i = 0; i < args.length; i++) { + MethodParameter methodParam = new MethodParameter(handlerMethod, i); + methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer); + GenericTypeResolver.resolveParameterType(methodParam, handler.getClass()); + String paramName = null; + String headerName = null; + boolean requestBodyFound = false; + String cookieName = null; + String pathVarName = null; + String attrName = null; + boolean required = false; + String defaultValue = null; + boolean validate = false; + int annotationsFound = 0; + Annotation[] paramAnns = methodParam.getParameterAnnotations(); + + for (Annotation paramAnn : paramAnns) { + if (RequestParam.class.isInstance(paramAnn)) { + RequestParam requestParam = (RequestParam) paramAnn; + paramName = requestParam.value(); + required = requestParam.required(); + defaultValue = parseDefaultValueAttribute(requestParam.defaultValue()); + annotationsFound++; + } else if (RequestHeader.class.isInstance(paramAnn)) { + RequestHeader requestHeader = (RequestHeader) paramAnn; + headerName = requestHeader.value(); + required = requestHeader.required(); + defaultValue = parseDefaultValueAttribute(requestHeader.defaultValue()); + annotationsFound++; + } else if (RequestBody.class.isInstance(paramAnn)) { + requestBodyFound = true; + annotationsFound++; + } else if (CookieValue.class.isInstance(paramAnn)) { + CookieValue cookieValue = (CookieValue) paramAnn; + cookieName = cookieValue.value(); + required = cookieValue.required(); + defaultValue = parseDefaultValueAttribute(cookieValue.defaultValue()); + annotationsFound++; + } else if (PathVariable.class.isInstance(paramAnn)) { + PathVariable pathVar = (PathVariable) paramAnn; + pathVarName = pathVar.value(); + annotationsFound++; + } else if (ModelAttribute.class.isInstance(paramAnn)) { + ModelAttribute attr = (ModelAttribute) paramAnn; + attrName = attr.value(); + annotationsFound++; + } else if (Value.class.isInstance(paramAnn)) { + defaultValue = ((Value) paramAnn).value(); + } else if ("Valid".equals(paramAnn.annotationType().getSimpleName())) { + validate = true; + } + } + + if (annotationsFound > 1) { + throw new IllegalStateException("Handler parameter annotations are exclusive choices - " + + "do not specify more than one such annotation on the same parameter: " + handlerMethod); + } + + if (annotationsFound == 0) { + Object argValue = resolveCommonArgument(methodParam, webRequest); + if (argValue != WebArgumentResolver.UNRESOLVED) { + args[i] = argValue; + } else if (defaultValue != null) { + args[i] = resolveDefaultValue(defaultValue); + } else { + Class paramType = methodParam.getParameterType(); + if (Model.class.isAssignableFrom(paramType) || Map.class.isAssignableFrom(paramType)) { + args[i] = implicitModel; + } else if (SessionStatus.class.isAssignableFrom(paramType)) { + args[i] = this.sessionStatus; + } else if (HttpEntity.class.isAssignableFrom(paramType)) { + args[i] = resolveHttpEntityRequest(methodParam, webRequest); + } else if (Errors.class.isAssignableFrom(paramType)) { + throw new IllegalStateException("Errors/BindingResult argument declared " + + "without preceding model attribute. Check your handler method signature!"); + } else if (BeanUtils.isSimpleProperty(paramType)) { + paramName = ""; + } else { + attrName = ""; + } + } + } + + if (paramName != null) { + args[i] = resolveRequestParam(paramName, required, defaultValue, methodParam, webRequest, handler); + } else if (headerName != null) { + args[i] = resolveRequestHeader(headerName, required, defaultValue, methodParam, webRequest, handler); + } else if (requestBodyFound) { + args[i] = resolveRequestBody(methodParam, webRequest, handler); + } else if (cookieName != null) { + args[i] = resolveCookieValue(cookieName, required, defaultValue, methodParam, webRequest, handler); + } else if (pathVarName != null) { + args[i] = resolvePathVariable(pathVarName, methodParam, webRequest, handler); + } else if (attrName != null) { + WebDataBinder binder = + resolveModelAttribute(attrName, methodParam, implicitModel, webRequest, handler); + boolean assignBindingResult = (args.length > i + 1 && Errors.class.isAssignableFrom(paramTypes[i + 1])); + if (binder.getTarget() != null) { + doBind(binder, webRequest, validate, !assignBindingResult); + } + args[i] = binder.getTarget(); + if (assignBindingResult) { + args[i + 1] = binder.getBindingResult(); + i++; + } + implicitModel.putAll(binder.getBindingResult().getModel()); + } + } + + return args; + } + + protected void initBinder(Object handler, String attrName, WebDataBinder binder, NativeWebRequest webRequest) + throws Exception { + + if (this.bindingInitializer != null) { + this.bindingInitializer.initBinder(binder, webRequest); + } + if (handler != null) { + Set initBinderMethods = this.methodResolver.getInitBinderMethods(); + if (!initBinderMethods.isEmpty()) { + boolean debug = logger.isDebugEnabled(); + for (Method initBinderMethod : initBinderMethods) { + Method methodToInvoke = BridgeMethodResolver.findBridgedMethod(initBinderMethod); + String[] targetNames = AnnotationUtils.findAnnotation(initBinderMethod, InitBinder.class).value(); + if (targetNames.length == 0 || Arrays.asList(targetNames).contains(attrName)) { + Object[] initBinderArgs = + resolveInitBinderArguments(handler, methodToInvoke, binder, webRequest); + if (debug) { + logger.debug("Invoking init-binder method: " + methodToInvoke); + } + ReflectionUtils.makeAccessible(methodToInvoke); + Object returnValue = methodToInvoke.invoke(handler, initBinderArgs); + if (returnValue != null) { + throw new IllegalStateException( + "InitBinder methods must not have a return value: " + methodToInvoke); + } + } + } + } + } + } + + private Object[] resolveInitBinderArguments(Object handler, Method initBinderMethod, + WebDataBinder binder, NativeWebRequest webRequest) throws Exception { + + Class[] initBinderParams = initBinderMethod.getParameterTypes(); + Object[] initBinderArgs = new Object[initBinderParams.length]; + + for (int i = 0; i < initBinderArgs.length; i++) { + MethodParameter methodParam = new MethodParameter(initBinderMethod, i); + methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer); + GenericTypeResolver.resolveParameterType(methodParam, handler.getClass()); + String paramName = null; + boolean paramRequired = false; + String paramDefaultValue = null; + String pathVarName = null; + Annotation[] paramAnns = methodParam.getParameterAnnotations(); + + for (Annotation paramAnn : paramAnns) { + if (RequestParam.class.isInstance(paramAnn)) { + RequestParam requestParam = (RequestParam) paramAnn; + paramName = requestParam.value(); + paramRequired = requestParam.required(); + paramDefaultValue = parseDefaultValueAttribute(requestParam.defaultValue()); + break; + } else if (ModelAttribute.class.isInstance(paramAnn)) { + throw new IllegalStateException( + "@ModelAttribute is not supported on @InitBinder methods: " + initBinderMethod); + } else if (PathVariable.class.isInstance(paramAnn)) { + PathVariable pathVar = (PathVariable) paramAnn; + pathVarName = pathVar.value(); + } + } + + if (paramName == null && pathVarName == null) { + Object argValue = resolveCommonArgument(methodParam, webRequest); + if (argValue != WebArgumentResolver.UNRESOLVED) { + initBinderArgs[i] = argValue; + } else { + Class paramType = initBinderParams[i]; + if (paramType.isInstance(binder)) { + initBinderArgs[i] = binder; + } else if (BeanUtils.isSimpleProperty(paramType)) { + paramName = ""; + } else { + throw new IllegalStateException("Unsupported argument [" + paramType.getName() + + "] for @InitBinder method: " + initBinderMethod); + } + } + } + + if (paramName != null) { + initBinderArgs[i] = + resolveRequestParam(paramName, paramRequired, paramDefaultValue, methodParam, webRequest, null); + } else if (pathVarName != null) { + initBinderArgs[i] = resolvePathVariable(pathVarName, methodParam, webRequest, null); + } + } + + return initBinderArgs; + } + + @SuppressWarnings("unchecked") + private Object resolveRequestParam(String paramName, boolean required, String defaultValue, + MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall) + throws Exception { + + Class paramType = methodParam.getParameterType(); + if (Map.class.isAssignableFrom(paramType) && paramName.length() == 0) { + return resolveRequestParamMap((Class) paramType, webRequest); + } + if (paramName.length() == 0) { + paramName = getRequiredParameterName(methodParam); + } + Object paramValue = null; + MultipartRequest multipartRequest = webRequest.getNativeRequest(MultipartRequest.class); + if (multipartRequest != null) { + List files = multipartRequest.getFiles(paramName); + if (!files.isEmpty()) { + if (files.size() == 1 && !paramType.isArray() && !Collection.class.isAssignableFrom(paramType)) { + paramValue = files.get(0); + } else { + paramValue = files; + } + } + } + if (paramValue == null) { + String[] paramValues = webRequest.getParameterValues(paramName); + if (paramValues != null) { + if (paramValues.length == 1 && !paramType.isArray() && !Collection.class.isAssignableFrom(paramType)) { + paramValue = paramValues[0]; + } else { + paramValue = paramValues; + } + } + } + if (paramValue == null) { + if (defaultValue != null) { + paramValue = resolveDefaultValue(defaultValue); + } else if (required) { + raiseMissingParameterException(paramName, paramType); + } + paramValue = checkValue(paramName, paramValue, paramType); + } + WebDataBinder binder = createBinder(webRequest, null, paramName); + initBinder(handlerForInitBinderCall, paramName, binder, webRequest); + return binder.convertIfNecessary(paramValue, paramType, methodParam); + } + + private Map resolveRequestParamMap(Class mapType, NativeWebRequest webRequest) { + Map parameterMap = webRequest.getParameterMap(); + if (MultiValueMap.class.isAssignableFrom(mapType)) { + MultiValueMap result = new LinkedMultiValueMap(parameterMap.size()); + for (Map.Entry entry : parameterMap.entrySet()) { + for (String value : entry.getValue()) { + result.add(entry.getKey(), value); + } + } + return result; + } else { + Map result = new LinkedHashMap(parameterMap.size()); + for (Map.Entry entry : parameterMap.entrySet()) { + if (entry.getValue().length > 0) { + result.put(entry.getKey(), entry.getValue()[0]); + } + } + return result; + } + } + + @SuppressWarnings("unchecked") + private Object resolveRequestHeader(String headerName, boolean required, String defaultValue, + MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall) + throws Exception { + + Class paramType = methodParam.getParameterType(); + if (Map.class.isAssignableFrom(paramType)) { + return resolveRequestHeaderMap((Class) paramType, webRequest); + } + if (headerName.length() == 0) { + headerName = getRequiredParameterName(methodParam); + } + Object headerValue = null; + String[] headerValues = webRequest.getHeaderValues(headerName); + if (headerValues != null) { + headerValue = (headerValues.length == 1 ? headerValues[0] : headerValues); + } + if (headerValue == null) { + if (defaultValue != null) { + headerValue = resolveDefaultValue(defaultValue); + } else if (required) { + raiseMissingHeaderException(headerName, paramType); + } + headerValue = checkValue(headerName, headerValue, paramType); + } + WebDataBinder binder = createBinder(webRequest, null, headerName); + initBinder(handlerForInitBinderCall, headerName, binder, webRequest); + return binder.convertIfNecessary(headerValue, paramType, methodParam); + } + + private Map resolveRequestHeaderMap(Class mapType, NativeWebRequest webRequest) { + if (MultiValueMap.class.isAssignableFrom(mapType)) { + MultiValueMap result; + if (HttpHeaders.class.isAssignableFrom(mapType)) { + result = new HttpHeaders(); + } else { + result = new LinkedMultiValueMap(); + } + for (Iterator iterator = webRequest.getHeaderNames(); iterator.hasNext();) { + String headerName = iterator.next(); + for (String headerValue : webRequest.getHeaderValues(headerName)) { + result.add(headerName, headerValue); + } + } + return result; + } else { + Map result = new LinkedHashMap(); + for (Iterator iterator = webRequest.getHeaderNames(); iterator.hasNext();) { + String headerName = iterator.next(); + String headerValue = webRequest.getHeader(headerName); + result.put(headerName, headerValue); + } + return result; + } + } + + /** + * Resolves the given {@link RequestBody @RequestBody} annotation. + */ + protected Object resolveRequestBody(MethodParameter methodParam, NativeWebRequest webRequest, Object handler) + throws Exception { + + return readWithMessageConverters(methodParam, createHttpInputMessage(webRequest), methodParam.getParameterType()); + } + + private HttpEntity resolveHttpEntityRequest(MethodParameter methodParam, NativeWebRequest webRequest) + throws Exception { + + HttpInputMessage inputMessage = createHttpInputMessage(webRequest); + Class paramType = getHttpEntityType(methodParam); + Object body = readWithMessageConverters(methodParam, inputMessage, paramType); + return new HttpEntity(body, inputMessage.getHeaders()); + } + + private Object readWithMessageConverters(MethodParameter methodParam, HttpInputMessage inputMessage, Class paramType) + throws Exception { + + MediaType contentType = inputMessage.getHeaders().getContentType(); + if (contentType == null) { + StringBuilder builder = new StringBuilder(ClassUtils.getShortName(methodParam.getParameterType())); + String paramName = methodParam.getParameterName(); + if (paramName != null) { + builder.append(' '); + builder.append(paramName); + } + throw new HttpMediaTypeNotSupportedException( + "Cannot extract parameter (" + builder.toString() + "): no Content-Type found"); + } + + List allSupportedMediaTypes = new ArrayList(); + if (this.messageConverters != null) { + for (HttpMessageConverter messageConverter : this.messageConverters) { + allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes()); + if (messageConverter.canRead(paramType, contentType)) { + if (logger.isDebugEnabled()) { + logger.debug("Reading [" + paramType.getName() + "] as \"" + contentType + + "\" using [" + messageConverter + "]"); + } + return messageConverter.read(paramType, inputMessage); + } + } + } + throw new HttpMediaTypeNotSupportedException(contentType, allSupportedMediaTypes); + } + + private Class getHttpEntityType(MethodParameter methodParam) { + Assert.isAssignable(HttpEntity.class, methodParam.getParameterType()); + ParameterizedType type = (ParameterizedType) methodParam.getGenericParameterType(); + if (type.getActualTypeArguments().length == 1) { + Type typeArgument = type.getActualTypeArguments()[0]; + if (typeArgument instanceof Class) { + return (Class) typeArgument; + } else if (typeArgument instanceof GenericArrayType) { + Type componentType = ((GenericArrayType) typeArgument).getGenericComponentType(); + if (componentType instanceof Class) { + // Surely, there should be a nicer way to do this + Object array = Array.newInstance((Class) componentType, 0); + return array.getClass(); + } + } + } + throw new IllegalArgumentException( + "HttpEntity parameter (" + methodParam.getParameterName() + ") is not parameterized"); + + } + + private Object resolveCookieValue(String cookieName, boolean required, String defaultValue, + MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall) + throws Exception { + + Class paramType = methodParam.getParameterType(); + if (cookieName.length() == 0) { + cookieName = getRequiredParameterName(methodParam); + } + Object cookieValue = resolveCookieValue(cookieName, paramType, webRequest); + if (cookieValue == null) { + if (defaultValue != null) { + cookieValue = resolveDefaultValue(defaultValue); + } else if (required) { + raiseMissingCookieException(cookieName, paramType); + } + cookieValue = checkValue(cookieName, cookieValue, paramType); + } + WebDataBinder binder = createBinder(webRequest, null, cookieName); + initBinder(handlerForInitBinderCall, cookieName, binder, webRequest); + return binder.convertIfNecessary(cookieValue, paramType, methodParam); + } + + /** + * Resolves the given {@link CookieValue @CookieValue} annotation. + *

Throws an UnsupportedOperationException by default. + */ + protected Object resolveCookieValue(String cookieName, Class paramType, NativeWebRequest webRequest) + throws Exception { + + throw new UnsupportedOperationException("@CookieValue not supported"); + } + + private Object resolvePathVariable(String pathVarName, MethodParameter methodParam, + NativeWebRequest webRequest, Object handlerForInitBinderCall) throws Exception { + + Class paramType = methodParam.getParameterType(); + if (pathVarName.length() == 0) { + pathVarName = getRequiredParameterName(methodParam); + } + String pathVarValue = resolvePathVariable(pathVarName, paramType, webRequest); + WebDataBinder binder = createBinder(webRequest, null, pathVarName); + initBinder(handlerForInitBinderCall, pathVarName, binder, webRequest); + return binder.convertIfNecessary(pathVarValue, paramType, methodParam); + } + + /** + * Resolves the given {@link PathVariable @PathVariable} annotation. + *

Throws an UnsupportedOperationException by default. + */ + protected String resolvePathVariable(String pathVarName, Class paramType, NativeWebRequest webRequest) + throws Exception { + + throw new UnsupportedOperationException("@PathVariable not supported"); + } + + private String getRequiredParameterName(MethodParameter methodParam) { + String name = methodParam.getParameterName(); + if (name == null) { + throw new IllegalStateException( + "No parameter name specified for argument of type [" + methodParam.getParameterType().getName() + + "], and no parameter name information found in class file either."); + } + return name; + } + + private Object checkValue(String name, Object value, Class paramType) { + if (value == null) { + if (boolean.class.equals(paramType)) { + return Boolean.FALSE; + } else if (paramType.isPrimitive()) { + throw new IllegalStateException("Optional " + paramType + " parameter '" + name + + "' is not present but cannot be translated into a null value due to being declared as a " + + "primitive type. Consider declaring it as object wrapper for the corresponding primitive type."); + } + } + return value; + } + + private WebDataBinder resolveModelAttribute(String attrName, MethodParameter methodParam, + ExtendedModelMap implicitModel, NativeWebRequest webRequest, Object handler) throws Exception { + + // Bind request parameter onto object... + String name = attrName; + if ("".equals(name)) { + name = Conventions.getVariableNameForParameter(methodParam); + } + Class paramType = methodParam.getParameterType(); + Object bindObject; + if (implicitModel.containsKey(name)) { + bindObject = implicitModel.get(name); + } else if (this.methodResolver.isSessionAttribute(name, paramType)) { + bindObject = this.sessionAttributeStore.retrieveAttribute(webRequest, name); + if (bindObject == null) { + raiseSessionRequiredException("Session attribute '" + name + "' required - not found in session"); + } + } else { + bindObject = BeanUtils.instantiateClass(paramType); + } + WebDataBinder binder = createBinder(webRequest, bindObject, name); + initBinder(handler, name, binder, webRequest); + return binder; + } + + + /** + * Determine whether the given value qualifies as a "binding candidate", i.e. might potentially be subject to + * bean-style data binding later on. + */ + protected boolean isBindingCandidate(Object value) { + return (value != null && !value.getClass().isArray() && !(value instanceof Collection) && + !(value instanceof Map) && !BeanUtils.isSimpleValueType(value.getClass())); + } + + protected void raiseMissingParameterException(String paramName, Class paramType) throws Exception { + throw new IllegalStateException("Missing parameter '" + paramName + "' of type [" + paramType.getName() + "]"); + } + + protected void raiseMissingHeaderException(String headerName, Class paramType) throws Exception { + throw new IllegalStateException("Missing header '" + headerName + "' of type [" + paramType.getName() + "]"); + } + + protected void raiseMissingCookieException(String cookieName, Class paramType) throws Exception { + throw new IllegalStateException( + "Missing cookie value '" + cookieName + "' of type [" + paramType.getName() + "]"); + } + + protected void raiseSessionRequiredException(String message) throws Exception { + throw new IllegalStateException(message); + } + + protected WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName) + throws Exception { + + return new WebRequestDataBinder(target, objectName); + } + + private void doBind(WebDataBinder binder, NativeWebRequest webRequest, boolean validate, boolean failOnErrors) + throws Exception { + + doBind(binder, webRequest); + if (validate) { + binder.validate(); + } + if (failOnErrors && binder.getBindingResult().hasErrors()) { + throw new BindException(binder.getBindingResult()); + } + } + + protected void doBind(WebDataBinder binder, NativeWebRequest webRequest) throws Exception { + ((WebRequestDataBinder) binder).bind(webRequest); + } + + /** + * Return a {@link HttpInputMessage} for the given {@link NativeWebRequest}. + *

Throws an UnsupportedOperation1Exception by default. + */ + protected HttpInputMessage createHttpInputMessage(NativeWebRequest webRequest) throws Exception { + throw new UnsupportedOperationException("@RequestBody not supported"); + } + + /** + * Return a {@link HttpOutputMessage} for the given {@link NativeWebRequest}. + *

Throws an UnsupportedOperationException by default. + */ + protected HttpOutputMessage createHttpOutputMessage(NativeWebRequest webRequest) throws Exception { + throw new UnsupportedOperationException("@ResponseBody not supported"); + } + + protected String parseDefaultValueAttribute(String value) { + return (ValueConstants.DEFAULT_NONE.equals(value) ? null : value); + } + + protected Object resolveDefaultValue(String value) { + return value; + } + + protected Object resolveCommonArgument(MethodParameter methodParameter, NativeWebRequest webRequest) + throws Exception { + + // Invoke custom argument resolvers if present... + if (this.customArgumentResolvers != null) { + for (WebArgumentResolver argumentResolver : this.customArgumentResolvers) { + Object value = argumentResolver.resolveArgument(methodParameter, webRequest); + if (value != WebArgumentResolver.UNRESOLVED) { + return value; + } + } + } + + // Resolution of standard parameter types... + Class paramType = methodParameter.getParameterType(); + Object value = resolveStandardArgument(paramType, webRequest); + if (value != WebArgumentResolver.UNRESOLVED && !ClassUtils.isAssignableValue(paramType, value)) { + throw new IllegalStateException("Standard argument type [" + paramType.getName() + + "] resolved to incompatible value of type [" + (value != null ? value.getClass() : null) + + "]. Consider declaring the argument type in a less specific fashion."); + } + return value; + } + + protected Object resolveStandardArgument(Class parameterType, NativeWebRequest webRequest) throws Exception { + if (WebRequest.class.isAssignableFrom(parameterType)) { + return webRequest; + } + return WebArgumentResolver.UNRESOLVED; + } + + protected final void addReturnValueAsModelAttribute(Method handlerMethod, Class handlerType, + Object returnValue, ExtendedModelMap implicitModel) { + + ModelAttribute attr = AnnotationUtils.findAnnotation(handlerMethod, ModelAttribute.class); + String attrName = (attr != null ? attr.value() : ""); + if ("".equals(attrName)) { + Class resolvedType = GenericTypeResolver.resolveReturnType(handlerMethod, handlerType); + attrName = Conventions.getVariableNameForReturnType(handlerMethod, resolvedType, returnValue); + } + implicitModel.addAttribute(attrName, returnValue); + } } diff --git a/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/ActionExecutedContext.java b/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/ActionExecutedContext.java index 33726acd2..97123fdbe 100644 --- a/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/ActionExecutedContext.java +++ b/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/ActionExecutedContext.java @@ -22,40 +22,37 @@ import org.springframework.web.servlet.ModelAndView; public class ActionExecutedContext extends ActionExecutingContext { - private ModelAndView modelAndView; - - private Exception exception; - - public ActionExecutedContext(ActionExecutingContext actionExecutingContext, ModelAndView modelAndView, Exception exception) { - super(actionExecutingContext.getServletWebRequest(), actionExecutingContext.getHandler(), - actionExecutingContext.getHandlerMethod(), actionExecutingContext.getHandlerParameters(), - actionExecutingContext.getImplicitModel()); - this.modelAndView = modelAndView; - this.exception = exception; - } + private ModelAndView modelAndView; - @Override - public String toString() { - return "ActionExecutedContext [handler=" + getHandler() - + ", servletWebRequest=" + getServletWebRequest() - + ", implicitModel=" + getImplicitModel() + ", handlerMethod=" - + getHandlerMethod() + ", handlerParameters=" - + Arrays.toString(getHandlerParameters()) + ",modelAndView=" + modelAndView - + ", exception=" + exception + "]"; - } - + private Exception exception; + + public ActionExecutedContext(ActionExecutingContext actionExecutingContext, ModelAndView modelAndView, Exception exception) { + super(actionExecutingContext.getServletWebRequest(), actionExecutingContext.getHandler(), + actionExecutingContext.getHandlerMethod(), actionExecutingContext.getHandlerParameters(), + actionExecutingContext.getImplicitModel()); + this.modelAndView = modelAndView; + this.exception = exception; + } + + @Override + public String toString() { + return "ActionExecutedContext [handler=" + getHandler() + + ", servletWebRequest=" + getServletWebRequest() + + ", implicitModel=" + getImplicitModel() + ", handlerMethod=" + + getHandlerMethod() + ", handlerParameters=" + + Arrays.toString(getHandlerParameters()) + ",modelAndView=" + modelAndView + + ", exception=" + exception + "]"; + } - public ModelAndView getModelAndView() { - return modelAndView; - } + public ModelAndView getModelAndView() { + return modelAndView; + } - public Exception getException() { - return exception; - } + public Exception getException() { + return exception; + } - - } diff --git a/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/ActionExecutingContext.java b/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/ActionExecutingContext.java index 45c839c6a..f87c63884 100644 --- a/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/ActionExecutingContext.java +++ b/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/ActionExecutingContext.java @@ -17,7 +17,6 @@ package org.springframework.data.document.web.servlet; import java.lang.reflect.Method; import java.util.Arrays; - import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -26,67 +25,65 @@ import org.springframework.web.context.request.ServletWebRequest; public class ActionExecutingContext { - - private Object handler; - - private ServletWebRequest servletWebRequest; - - private ExtendedModelMap implicitModel; - - private Method handlerMethod; - - private Object[] handlerParameters; - - public ActionExecutingContext(ServletWebRequest servletWebRequest, - Object handler, Method handlerMethod, Object[] handlerParameters, - ExtendedModelMap implicitModel) { - super(); - this.servletWebRequest = servletWebRequest; - this.handler = handler; - this.handlerMethod = handlerMethod; - this.handlerParameters = handlerParameters; - this.implicitModel = implicitModel; - } + private Object handler; - public HttpServletRequest getHttpServletRequest() { - return servletWebRequest.getRequest(); - } + private ServletWebRequest servletWebRequest; - public HttpServletResponse getHttpServletResponse() { - return servletWebRequest.getResponse(); - } + private ExtendedModelMap implicitModel; - public Object getHandler() { - return handler; - } + private Method handlerMethod; - public ServletWebRequest getServletWebRequest() { - return servletWebRequest; - } + private Object[] handlerParameters; - public ExtendedModelMap getImplicitModel() { - return implicitModel; - } - public Method getHandlerMethod() { - return handlerMethod; - } + public ActionExecutingContext(ServletWebRequest servletWebRequest, + Object handler, Method handlerMethod, Object[] handlerParameters, + ExtendedModelMap implicitModel) { + super(); + this.servletWebRequest = servletWebRequest; + this.handler = handler; + this.handlerMethod = handlerMethod; + this.handlerParameters = handlerParameters; + this.implicitModel = implicitModel; + } + + public HttpServletRequest getHttpServletRequest() { + return servletWebRequest.getRequest(); + } + + public HttpServletResponse getHttpServletResponse() { + return servletWebRequest.getResponse(); + } + + public Object getHandler() { + return handler; + } + + public ServletWebRequest getServletWebRequest() { + return servletWebRequest; + } + + public ExtendedModelMap getImplicitModel() { + return implicitModel; + } + + public Method getHandlerMethod() { + return handlerMethod; + } + + public Object[] getHandlerParameters() { + return handlerParameters; + } + + @Override + public String toString() { + return "ActionExecutingContext [handler=" + handler + + ", servletWebRequest=" + servletWebRequest + + ", implicitModel=" + implicitModel + ", handlerMethod=" + + handlerMethod + ", handlerParameters=" + + Arrays.toString(handlerParameters) + "]"; + } - public Object[] getHandlerParameters() { - return handlerParameters; - } - - @Override - public String toString() { - return "ActionExecutingContext [handler=" + handler - + ", servletWebRequest=" + servletWebRequest - + ", implicitModel=" + implicitModel + ", handlerMethod=" - + handlerMethod + ", handlerParameters=" - + Arrays.toString(handlerParameters) + "]"; - } - - - } diff --git a/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/ActionInterceptor.java b/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/ActionInterceptor.java index 30f440540..6327c2605 100644 --- a/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/ActionInterceptor.java +++ b/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/ActionInterceptor.java @@ -17,9 +17,9 @@ package org.springframework.data.document.web.servlet; public interface ActionInterceptor { - boolean preHandle(ActionExecutingContext actionExecutingContext); - - void postHandle(ActionExecutedContext actionExecutedContext); - - void afterCompletion(ActionExecutedContext actionExecutedContext); + boolean preHandle(ActionExecutingContext actionExecutingContext); + + void postHandle(ActionExecutedContext actionExecutedContext); + + void afterCompletion(ActionExecutedContext actionExecutedContext); } diff --git a/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java b/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java index 5038ed1cd..8761e5101 100644 --- a/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java +++ b/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java @@ -16,26 +16,11 @@ package org.springframework.data.document.web.servlet.mvc.annotation; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.Reader; -import java.io.Writer; +import java.io.*; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.security.Principal; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import javax.servlet.ServletException; import javax.servlet.ServletRequest; @@ -47,32 +32,19 @@ import javax.servlet.http.HttpSession; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.config.BeanExpressionContext; import org.springframework.beans.factory.config.BeanExpressionResolver; import org.springframework.beans.factory.config.ConfigurableBeanFactory; -import org.springframework.core.BridgeMethodResolver; -import org.springframework.core.Conventions; -import org.springframework.core.GenericTypeResolver; -import org.springframework.core.LocalVariableTableParameterNameDiscoverer; -import org.springframework.core.Ordered; -import org.springframework.core.ParameterNameDiscoverer; +import org.springframework.core.*; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.data.document.web.servlet.ActionExecutedContext; import org.springframework.data.document.web.servlet.ActionExecutingContext; import org.springframework.data.document.web.servlet.ActionInterceptor; import org.springframework.data.document.web.servlet.mvc.annotation.support.InterceptingHandlerMethodInvoker; -import org.springframework.format.support.FormattingConversionService; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpInputMessage; -import org.springframework.http.HttpOutputMessage; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; +import org.springframework.http.*; import org.springframework.http.converter.ByteArrayHttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; @@ -84,13 +56,7 @@ import org.springframework.http.server.ServletServerHttpRequest; import org.springframework.http.server.ServletServerHttpResponse; import org.springframework.ui.ExtendedModelMap; import org.springframework.ui.Model; -import org.springframework.util.AntPathMatcher; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; -import org.springframework.util.ObjectUtils; -import org.springframework.util.PathMatcher; -import org.springframework.util.ReflectionUtils; -import org.springframework.util.StringUtils; +import org.springframework.util.*; import org.springframework.validation.support.BindingAwareModelMap; import org.springframework.web.HttpMediaTypeNotAcceptableException; import org.springframework.web.HttpRequestMethodNotSupportedException; @@ -98,14 +64,7 @@ import org.springframework.web.HttpSessionRequiredException; import org.springframework.web.bind.MissingServletRequestParameterException; import org.springframework.web.bind.ServletRequestDataBinder; import org.springframework.web.bind.WebDataBinder; -import org.springframework.web.bind.annotation.InitBinder; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.bind.annotation.SessionAttributes; +import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.support.HandlerMethodInvocationException; import org.springframework.web.bind.annotation.support.HandlerMethodInvoker; import org.springframework.web.bind.annotation.support.HandlerMethodResolver; @@ -134,1178 +93,1153 @@ import org.springframework.web.util.WebUtils; * Implementation of the {@link org.springframework.web.servlet.HandlerAdapter} interface * that maps handler methods based on HTTP paths, HTTP methods and request parameters * expressed through the {@link RequestMapping} annotation. - * + *

*

Supports request parameter binding through the {@link RequestParam} annotation. * Also supports the {@link ModelAttribute} annotation for exposing model attribute * values to the view, as well as {@link InitBinder} for binder initialization methods * and {@link SessionAttributes} for automatic session management of specific attributes. - * + *

*

This adapter can be customized through various bean properties. * A common use case is to apply shared binder initialization logic through * a custom {@link #setWebBindingInitializer WebBindingInitializer}. * * @author Juergen Hoeller * @author Arjen Poutsma - * @since 2.5 * @see #setPathMatcher * @see #setMethodNameResolver * @see #setWebBindingInitializer * @see #setSessionAttributeStore + * @since 2.5 */ public class AnnotationMethodHandlerAdapter extends WebContentGenerator - implements HandlerAdapter, Ordered, BeanFactoryAware { + implements HandlerAdapter, Ordered, BeanFactoryAware { - - private ActionInterceptor[] actionInterceptors; - - /** - * Log category to use when no mapped handler is found for a request. - * @see #pageNotFoundLogger - */ - public static final String PAGE_NOT_FOUND_LOG_CATEGORY = "org.springframework.web.servlet.PageNotFound"; - /** - * Additional logger to use when no mapped handler is found for a request. - * @see #PAGE_NOT_FOUND_LOG_CATEGORY - */ - protected static final Log pageNotFoundLogger = LogFactory.getLog(PAGE_NOT_FOUND_LOG_CATEGORY); - - - private UrlPathHelper urlPathHelper = new UrlPathHelper(); - - private PathMatcher pathMatcher = new AntPathMatcher(); - - private MethodNameResolver methodNameResolver = new InternalPathMethodNameResolver(); - - private WebBindingInitializer webBindingInitializer; - - private SessionAttributeStore amhaSessionAttributeStore = new DefaultSessionAttributeStore(); - - private int cacheSecondsForSessionAttributeHandlers = 0; - - private boolean synchronizeOnSession = false; - - private ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer(); - - private WebArgumentResolver[] customArgumentResolvers; - - private ModelAndViewResolver[] customModelAndViewResolvers; - - private HttpMessageConverter[] messageConverters; - - private int order = Ordered.LOWEST_PRECEDENCE; - - private ConfigurableBeanFactory beanFactory; - - private BeanExpressionContext expressionContext; - - private final Map, ServletHandlerMethodResolver> methodResolverCache = - new ConcurrentHashMap, ServletHandlerMethodResolver>(); - - - public AnnotationMethodHandlerAdapter() { - // no restriction of HTTP methods by default - // MLP - super(false); - - // See SPR-7316 - StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(); - stringHttpMessageConverter.setWriteAcceptCharset(false); - messageConverters = new HttpMessageConverter[]{new ByteArrayHttpMessageConverter(), stringHttpMessageConverter, - new SourceHttpMessageConverter(), new XmlAwareFormHttpMessageConverter()}; - } - - - /** - * Set if URL lookup should always use the full path within the current servlet - * context. Else, the path within the current servlet mapping is used if applicable - * (that is, in the case of a ".../*" servlet mapping in web.xml). - *

Default is "false". - * @see org.springframework.web.util.UrlPathHelper#setAlwaysUseFullPath - */ - public void setAlwaysUseFullPath(boolean alwaysUseFullPath) { - this.urlPathHelper.setAlwaysUseFullPath(alwaysUseFullPath); - } - - /** - * Set if context path and request URI should be URL-decoded. Both are returned - * undecoded by the Servlet API, in contrast to the servlet path. - *

Uses either the request encoding or the default encoding according - * to the Servlet spec (ISO-8859-1). - * @see org.springframework.web.util.UrlPathHelper#setUrlDecode - */ - public void setUrlDecode(boolean urlDecode) { - this.urlPathHelper.setUrlDecode(urlDecode); - } - - /** - * Set the UrlPathHelper to use for resolution of lookup paths. - *

Use this to override the default UrlPathHelper with a custom subclass, - * or to share common UrlPathHelper settings across multiple HandlerMappings and HandlerAdapters. - */ - public void setUrlPathHelper(UrlPathHelper urlPathHelper) { - Assert.notNull(urlPathHelper, "UrlPathHelper must not be null"); - this.urlPathHelper = urlPathHelper; - } - - /** - * Set the PathMatcher implementation to use for matching URL paths against registered URL patterns. - *

Default is {@link org.springframework.util.AntPathMatcher}. - */ - public void setPathMatcher(PathMatcher pathMatcher) { - Assert.notNull(pathMatcher, "PathMatcher must not be null"); - this.pathMatcher = pathMatcher; - } - - /** - * Set the MethodNameResolver to use for resolving default handler methods - * (carrying an empty @RequestMapping annotation). - *

Will only kick in when the handler method cannot be resolved uniquely - * through the annotation metadata already. - */ - public void setMethodNameResolver(MethodNameResolver methodNameResolver) { - this.methodNameResolver = methodNameResolver; - } - - /** - * Specify a WebBindingInitializer which will apply pre-configured - * configuration to every DataBinder that this controller uses. - */ - public void setWebBindingInitializer(WebBindingInitializer webBindingInitializer) { - this.webBindingInitializer = webBindingInitializer; - } - - /** - * Specify the strategy to store session attributes with. - *

Default is {@link org.springframework.web.bind.support.DefaultSessionAttributeStore}, - * storing session attributes in the HttpSession, using the same attribute name as in the model. - */ - public void setSessionAttributeStore(SessionAttributeStore sessionAttributeStore) { - Assert.notNull(sessionAttributeStore, "SessionAttributeStore must not be null"); - this.amhaSessionAttributeStore = sessionAttributeStore; - } - - /** - * Cache content produced by @SessionAttributes annotated handlers - * for the given number of seconds. Default is 0, preventing caching completely. - *

In contrast to the "cacheSeconds" property which will apply to all general handlers - * (but not to @SessionAttributes annotated handlers), this setting will - * apply to @SessionAttributes annotated handlers only. - * @see #setCacheSeconds - * @see org.springframework.web.bind.annotation.SessionAttributes - */ - public void setCacheSecondsForSessionAttributeHandlers(int cacheSecondsForSessionAttributeHandlers) { - this.cacheSecondsForSessionAttributeHandlers = cacheSecondsForSessionAttributeHandlers; - } - - /** - * Set if controller execution should be synchronized on the session, - * to serialize parallel invocations from the same client. - *

More specifically, the execution of the handleRequestInternal - * method will get synchronized if this flag is "true". The best available - * session mutex will be used for the synchronization; ideally, this will - * be a mutex exposed by HttpSessionMutexListener. - *

The session mutex is guaranteed to be the same object during - * the entire lifetime of the session, available under the key defined - * by the SESSION_MUTEX_ATTRIBUTE constant. It serves as a - * safe reference to synchronize on for locking on the current session. - *

In many cases, the HttpSession reference itself is a safe mutex - * as well, since it will always be the same object reference for the - * same active logical session. However, this is not guaranteed across - * different servlet containers; the only 100% safe way is a session mutex. - * @see org.springframework.web.util.HttpSessionMutexListener - * @see org.springframework.web.util.WebUtils#getSessionMutex(javax.servlet.http.HttpSession) - */ - public void setSynchronizeOnSession(boolean synchronizeOnSession) { - this.synchronizeOnSession = synchronizeOnSession; - } - - /** - * Set the ParameterNameDiscoverer to use for resolving method parameter names if needed - * (e.g. for default attribute names). - *

Default is a {@link org.springframework.core.LocalVariableTableParameterNameDiscoverer}. - */ - public void setParameterNameDiscoverer(ParameterNameDiscoverer parameterNameDiscoverer) { - this.parameterNameDiscoverer = parameterNameDiscoverer; - } - - /** - * Set a custom WebArgumentResolvers to use for special method parameter types. - *

Such a custom WebArgumentResolver will kick in first, having a chance to resolve - * an argument value before the standard argument handling kicks in. - */ - public void setCustomArgumentResolver(WebArgumentResolver argumentResolver) { - this.customArgumentResolvers = new WebArgumentResolver[] {argumentResolver}; - } - - /** - * Set one or more custom WebArgumentResolvers to use for special method parameter types. - *

Any such custom WebArgumentResolver will kick in first, having a chance to resolve - * an argument value before the standard argument handling kicks in. - */ - public void setCustomArgumentResolvers(WebArgumentResolver[] argumentResolvers) { - this.customArgumentResolvers = argumentResolvers; - } - - /** - * Set a custom ModelAndViewResolvers to use for special method return types. - *

Such a custom ModelAndViewResolver will kick in first, having a chance to resolve - * a return value before the standard ModelAndView handling kicks in. - */ - public void setCustomModelAndViewResolver(ModelAndViewResolver customModelAndViewResolver) { - this.customModelAndViewResolvers = new ModelAndViewResolver[] {customModelAndViewResolver}; - } - - /** - * Set one or more custom ModelAndViewResolvers to use for special method return types. - *

Any such custom ModelAndViewResolver will kick in first, having a chance to resolve - * a return value before the standard ModelAndView handling kicks in. - */ - public void setCustomModelAndViewResolvers(ModelAndViewResolver[] customModelAndViewResolvers) { - this.customModelAndViewResolvers = customModelAndViewResolvers; - } - - /** - * Set the message body converters to use. - *

These converters are used to convert from and to HTTP requests and responses. - */ - public void setMessageConverters(HttpMessageConverter[] messageConverters) { - this.messageConverters = messageConverters; - } - - /** - * Return the message body converters that this adapter has been configured with. - */ - public HttpMessageConverter[] getMessageConverters() { - return messageConverters; - } - - public void setActionInterceptors(ActionInterceptor[] actionInterceptors) { - this.actionInterceptors = actionInterceptors; - } - - /** - * Specify the order value for this HandlerAdapter bean. - *

Default value is Integer.MAX_VALUE, meaning that it's non-ordered. - * @see org.springframework.core.Ordered#getOrder() - */ - public void setOrder(int order) { - this.order = order; - } - - public int getOrder() { - return this.order; - } - - public void setBeanFactory(BeanFactory beanFactory) { - if (beanFactory instanceof ConfigurableBeanFactory) { - this.beanFactory = (ConfigurableBeanFactory) beanFactory; - this.expressionContext = new BeanExpressionContext(this.beanFactory, new RequestScope()); - } - } - - - public boolean supports(Object handler) { - return getMethodResolver(handler).hasHandlerMethods(); - } - - public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) - throws Exception { - - if (AnnotationUtils.findAnnotation(handler.getClass(), SessionAttributes.class) != null) { - // Always prevent caching in case of session attribute management. - checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true); - // Prepare cached set of session attributes names. - } - else { - // Uses configured default cacheSeconds setting. - checkAndPrepare(request, response, true); - } - - // Execute invokeHandlerMethod in synchronized block if required. - if (this.synchronizeOnSession) { - HttpSession session = request.getSession(false); - if (session != null) { - Object mutex = WebUtils.getSessionMutex(session); - synchronized (mutex) { - return invokeHandlerMethod(request, response, handler); - } - } - } - - return invokeHandlerMethod(request, response, handler); - } - - protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler) - throws Exception { - - ServletHandlerMethodResolver methodResolver = getMethodResolver(handler); - Method handlerMethod = methodResolver.resolveHandlerMethod(request); - ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver, actionInterceptors); - ServletWebRequest webRequest = new ServletWebRequest(request, response); - ExtendedModelMap implicitModel = new BindingAwareModelMap(); - - - return methodInvoker.interceptingInvokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel); - //Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel); - //ModelAndView mav = - // methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest); - // methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest); - // return mav; - } - - public long getLastModified(HttpServletRequest request, Object handler) { - return -1; - } - - /** - * Build a HandlerMethodResolver for the given handler type. - */ - private ServletHandlerMethodResolver getMethodResolver(Object handler) { - Class handlerClass = ClassUtils.getUserClass(handler); - ServletHandlerMethodResolver resolver = this.methodResolverCache.get(handlerClass); - if (resolver == null) { - resolver = new ServletHandlerMethodResolver(handlerClass); - this.methodResolverCache.put(handlerClass, resolver); - } - return resolver; - } - - - /** - * Template method for creating a new ServletRequestDataBinder instance. - *

The default implementation creates a standard ServletRequestDataBinder. - * This can be overridden for custom ServletRequestDataBinder subclasses. - * @param request current HTTP request - * @param target the target object to bind onto (or null - * if the binder is just used to convert a plain parameter value) - * @param objectName the objectName of the target object - * @return the ServletRequestDataBinder instance to use - * @throws Exception in case of invalid state or arguments - * @see ServletRequestDataBinder#bind(javax.servlet.ServletRequest) - * @see ServletRequestDataBinder#convertIfNecessary(Object, Class, org.springframework.core.MethodParameter) - */ - protected ServletRequestDataBinder createBinder(HttpServletRequest request, Object target, String objectName) - throws Exception { - return new ServletRequestDataBinder(target, objectName); - } - - /** - * Template method for creating a new HttpInputMessage instance. - *

The default implementation creates a standard {@link ServletServerHttpRequest}. - * This can be overridden for custom {@code HttpInputMessage} implementations - * @param servletRequest current HTTP request - * @return the HttpInputMessage instance to use - * @throws Exception in case of errors - */ - protected HttpInputMessage createHttpInputMessage(HttpServletRequest servletRequest) throws Exception { - return new ServletServerHttpRequest(servletRequest); - } - - /** - * Template method for creating a new HttpOuputMessage instance. - *

The default implementation creates a standard {@link ServletServerHttpResponse}. - * This can be overridden for custom {@code HttpOutputMessage} implementations - * @param servletResponse current HTTP response - * @return the HttpInputMessage instance to use - * @throws Exception in case of errors - */ - protected HttpOutputMessage createHttpOutputMessage(HttpServletResponse servletResponse) throws Exception { - return new ServletServerHttpResponse(servletResponse); - } - - - /** - * Servlet-specific subclass of {@link HandlerMethodResolver}. - */ - private class ServletHandlerMethodResolver extends HandlerMethodResolver { - - private final Map mappings = new HashMap(); - - private ServletHandlerMethodResolver(Class handlerType) { - init(handlerType); - } - - @Override - protected boolean isHandlerMethod(Method method) { - if (this.mappings.containsKey(method)) { - return true; - } - RequestMapping mapping = AnnotationUtils.findAnnotation(method, RequestMapping.class); - if (mapping != null) { - RequestMappingInfo mappingInfo = new RequestMappingInfo(); - mappingInfo.patterns = mapping.value(); - if (!hasTypeLevelMapping() || !Arrays.equals(mapping.method(), getTypeLevelMapping().method())) { - mappingInfo.methods = mapping.method(); - } - if (!hasTypeLevelMapping() || !Arrays.equals(mapping.params(), getTypeLevelMapping().params())) { - mappingInfo.params = mapping.params(); - } - if (!hasTypeLevelMapping() || !Arrays.equals(mapping.headers(), getTypeLevelMapping().headers())) { - mappingInfo.headers = mapping.headers(); - } - this.mappings.put(method, mappingInfo); - return true; - } - return false; - } - - public Method resolveHandlerMethod(HttpServletRequest request) throws ServletException { - String lookupPath = urlPathHelper.getLookupPathForRequest(request); - Comparator pathComparator = pathMatcher.getPatternComparator(lookupPath); - Map targetHandlerMethods = new LinkedHashMap(); - Set allowedMethods = new LinkedHashSet(7); - String resolvedMethodName = null; - for (Method handlerMethod : getHandlerMethods()) { - RequestMappingInfo mappingInfo = this.mappings.get(handlerMethod); - boolean match = false; - if (mappingInfo.hasPatterns()) { - List matchingPatterns = new ArrayList(mappingInfo.patterns.length); - for (String pattern : mappingInfo.patterns) { - if (!hasTypeLevelMapping() && !pattern.startsWith("/")) { - pattern = "/" + pattern; - } - String combinedPattern = getCombinedPattern(pattern, lookupPath, request); - if (combinedPattern != null) { - if (mappingInfo.matches(request)) { - match = true; - matchingPatterns.add(combinedPattern); - } - else { - if (!mappingInfo.matchesRequestMethod(request)) { - allowedMethods.addAll(mappingInfo.methodNames()); - } - break; - } - } - } - Collections.sort(matchingPatterns, pathComparator); - mappingInfo.matchedPatterns = matchingPatterns; - } - else { - // No paths specified: parameter match sufficient. - match = mappingInfo.matches(request); - if (match && mappingInfo.methods.length == 0 && mappingInfo.params.length == 0 && - resolvedMethodName != null && !resolvedMethodName.equals(handlerMethod.getName())) { - match = false; - } - else { - if (!mappingInfo.matchesRequestMethod(request)) { - allowedMethods.addAll(mappingInfo.methodNames()); - } - } - } - if (match) { - Method oldMappedMethod = targetHandlerMethods.put(mappingInfo, handlerMethod); - if (oldMappedMethod != null && oldMappedMethod != handlerMethod) { - if (methodNameResolver != null && mappingInfo.patterns.length == 0) { - if (!oldMappedMethod.getName().equals(handlerMethod.getName())) { - if (resolvedMethodName == null) { - resolvedMethodName = methodNameResolver.getHandlerMethodName(request); - } - if (!resolvedMethodName.equals(oldMappedMethod.getName())) { - oldMappedMethod = null; - } - if (!resolvedMethodName.equals(handlerMethod.getName())) { - if (oldMappedMethod != null) { - targetHandlerMethods.put(mappingInfo, oldMappedMethod); - oldMappedMethod = null; - } - else { - targetHandlerMethods.remove(mappingInfo); - } - } - } - } - if (oldMappedMethod != null) { - throw new IllegalStateException( - "Ambiguous handler methods mapped for HTTP path '" + lookupPath + "': {" + - oldMappedMethod + ", " + handlerMethod + - "}. If you intend to handle the same path in multiple methods, then factor " + - "them out into a dedicated handler class with that path mapped at the type level!"); - } - } - } - } - if (!targetHandlerMethods.isEmpty()) { - List matches = new ArrayList(targetHandlerMethods.keySet()); - RequestMappingInfoComparator requestMappingInfoComparator = - new RequestMappingInfoComparator(pathComparator, request); - Collections.sort(matches, requestMappingInfoComparator); - RequestMappingInfo bestMappingMatch = matches.get(0); - String bestMatchedPath = bestMappingMatch.bestMatchedPattern(); - if (bestMatchedPath != null) { - extractHandlerMethodUriTemplates(bestMatchedPath, lookupPath, request); - } - return targetHandlerMethods.get(bestMappingMatch); - } - else { - if (!allowedMethods.isEmpty()) { - throw new HttpRequestMethodNotSupportedException(request.getMethod(), - StringUtils.toStringArray(allowedMethods)); - } - throw new NoSuchRequestHandlingMethodException(lookupPath, request.getMethod(), - request.getParameterMap()); - } - } - - /** - * Determines the combined pattern for the given methodLevelPattern and path. - *

Uses the following algorithm:

    - *
  1. If there is a type-level mapping with path information, it is {@linkplain - * PathMatcher#combine(String, String) combined} with the method-level pattern.
  2. - *
  3. If there is a {@linkplain HandlerMapping#BEST_MATCHING_PATTERN_ATTRIBUTE best matching pattern} in the - * request, it is combined with the method-level pattern.
  4. - *
  5. Otherwise, the method-level pattern is returned.
  6. - *
- */ - private String getCombinedPattern(String methodLevelPattern, String lookupPath, HttpServletRequest request) { - if (hasTypeLevelMapping() && (!ObjectUtils.isEmpty(getTypeLevelMapping().value()))) { - String[] typeLevelPatterns = getTypeLevelMapping().value(); - for (String typeLevelPattern : typeLevelPatterns) { - if (!typeLevelPattern.startsWith("/")) { - typeLevelPattern = "/" + typeLevelPattern; - } - String combinedPattern = pathMatcher.combine(typeLevelPattern, methodLevelPattern); - if (isPathMatchInternal(combinedPattern, lookupPath)) { - return combinedPattern; - } - } - return null; - } - String bestMatchingPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE); - if (StringUtils.hasText(bestMatchingPattern) && bestMatchingPattern.endsWith("*")) { - String combinedPattern = pathMatcher.combine(bestMatchingPattern, methodLevelPattern); - if (!combinedPattern.equals(bestMatchingPattern) && - (isPathMatchInternal(combinedPattern, lookupPath))) { - return combinedPattern; - } - } - if (isPathMatchInternal(methodLevelPattern, lookupPath)) { - return methodLevelPattern; - } - return null; - } - - private boolean isPathMatchInternal(String pattern, String lookupPath) { - if (pattern.equals(lookupPath) || pathMatcher.match(pattern, lookupPath)) { - return true; - } - boolean hasSuffix = pattern.indexOf('.') != -1; - if (!hasSuffix && pathMatcher.match(pattern + ".*", lookupPath)) { - return true; - } - boolean endsWithSlash = pattern.endsWith("/"); - if (!endsWithSlash && pathMatcher.match(pattern + "/", lookupPath)) { - return true; - } - return false; - } - - @SuppressWarnings("unchecked") - private void extractHandlerMethodUriTemplates(String mappedPattern, - String lookupPath, - HttpServletRequest request) { - - Map variables = - (Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE); - - int patternVariableCount = StringUtils.countOccurrencesOf(mappedPattern, "{"); - - if ( (variables == null || patternVariableCount != variables.size()) - && pathMatcher.match(mappedPattern, lookupPath)) { - variables = pathMatcher.extractUriTemplateVariables(mappedPattern, lookupPath); - request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, variables); - } - } - } - - - /** - * Servlet-specific subclass of {@link HandlerMethodInvoker}. - */ - private class ServletHandlerMethodInvoker extends InterceptingHandlerMethodInvoker { - - private boolean responseArgumentUsed = false; - - private ServletHandlerMethodInvoker(HandlerMethodResolver resolver, ActionInterceptor[] actionInterceptors) { - super(resolver, webBindingInitializer, amhaSessionAttributeStore, parameterNameDiscoverer, - customArgumentResolvers, messageConverters, actionInterceptors); - } - - public ModelAndView interceptingInvokeHandlerMethod(Method handlerMethod, Object handler, - NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception { - - int interceptorIndex = -1; - ModelAndView mav = null; - ActionExecutingContext executingContext = null; - Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod); - try { - boolean debug = logger.isDebugEnabled(); - for (String attrName : this.methodResolver.getActualSessionAttributeNames()) { - Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName); - if (attrValue != null) { - implicitModel.addAttribute(attrName, attrValue); - } - } - for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) { - Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod); - Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel); - if (debug) { - logger.debug("Invoking model attribute method: " + attributeMethodToInvoke); - } - String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value(); - if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) { - continue; - } - ReflectionUtils.makeAccessible(attributeMethodToInvoke); - Object attrValue = attributeMethodToInvoke.invoke(handler, args); - if ("".equals(attrName)) { - Class resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass()); - attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue); - } - if (!implicitModel.containsAttribute(attrName)) { - implicitModel.addAttribute(attrName, attrValue); - } - } - Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel); - if (debug) { - logger.debug("Invoking request handler method: " + handlerMethodToInvoke); - } - ReflectionUtils.makeAccessible(handlerMethodToInvoke); - - executingContext = new ActionExecutingContext((ServletWebRequest)webRequest, handler, handlerMethodToInvoke, args, implicitModel); - - // Apply preHandle methods of registered interceptors. - ActionInterceptor[] interceptors = getActionInterceptors(); - if (interceptors != null) { - for (int i = 0; i < interceptors.length; i++) { - ActionInterceptor interceptor = interceptors[i]; - if (!interceptor.preHandle(executingContext)) { - triggerAfterCompletion(executingContext, interceptorIndex, null, null); - return null; //TODO verify null is ok - } - interceptorIndex = i; - } - } - - // Actually invoke the handler - Object result = handlerMethodToInvoke.invoke(handler, args); - - - mav = getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, (ServletWebRequest)webRequest); - updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest); - - // Trigger after-completion for successful outcome - triggerAfterCompletion(executingContext, interceptorIndex, mav, null); - - return mav; - } - catch (IllegalStateException ex) { - // Internal assertion failed (e.g. invalid signature): - // throw exception with full handler method context... - triggerAfterCompletion(executingContext, interceptorIndex, mav, ex); - throw new HandlerMethodInvocationException(handlerMethodToInvoke, ex); - } - catch (InvocationTargetException ex) { - // User-defined @ModelAttribute/@InitBinder/@RequestMapping method threw an exception... - triggerAfterCompletion(executingContext, interceptorIndex, mav, ex); - ReflectionUtils.rethrowException(ex.getTargetException()); - return null; - } - } - - private void triggerAfterCompletion(ActionExecutingContext executingContext, - int interceptorIndex, - ModelAndView modelAndView, - Exception ex) throws Exception { - - // Apply afterCompletion methods of registered interceptors. - if (executingContext.getHandler() != null) { - //TODO should be passed in; - ActionInterceptor[] interceptors = getActionInterceptors(); - if (interceptors != null) { - for (int i = interceptorIndex; i >= 0; i--) { - ActionInterceptor interceptor = interceptors[i]; - ActionExecutedContext actionExecutedContext = new ActionExecutedContext(executingContext, modelAndView, ex); - try { - interceptor.afterCompletion(actionExecutedContext); - } - catch (Throwable ex2) { - logger.error("ActionInterceptor threw exception", ex2); - } - } - } - } - } - - - @Override - protected void raiseMissingParameterException(String paramName, Class paramType) throws Exception { - throw new MissingServletRequestParameterException(paramName, paramType.getSimpleName()); - } - - @Override - protected void raiseSessionRequiredException(String message) throws Exception { - throw new HttpSessionRequiredException(message); - } - - @Override - protected WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName) - throws Exception { - - return AnnotationMethodHandlerAdapter.this.createBinder( - webRequest.getNativeRequest(HttpServletRequest.class), target, objectName); - } - - @Override - protected void doBind(WebDataBinder binder, NativeWebRequest webRequest) throws Exception { - ServletRequestDataBinder servletBinder = (ServletRequestDataBinder) binder; - servletBinder.bind(webRequest.getNativeRequest(ServletRequest.class)); - } - - @Override - protected HttpInputMessage createHttpInputMessage(NativeWebRequest webRequest) throws Exception { - HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); - return AnnotationMethodHandlerAdapter.this.createHttpInputMessage(servletRequest); - } - - @Override - protected HttpOutputMessage createHttpOutputMessage(NativeWebRequest webRequest) throws Exception { - HttpServletResponse servletResponse = (HttpServletResponse) webRequest.getNativeResponse(); - return AnnotationMethodHandlerAdapter.this.createHttpOutputMessage(servletResponse); - } - - @Override - protected Object resolveDefaultValue(String value) { - if (beanFactory == null) { - return value; - } - String placeholdersResolved = beanFactory.resolveEmbeddedValue(value); - BeanExpressionResolver exprResolver = beanFactory.getBeanExpressionResolver(); - if (exprResolver == null) { - return value; - } - return exprResolver.evaluate(placeholdersResolved, expressionContext); - } - - @Override - protected Object resolveCookieValue(String cookieName, Class paramType, NativeWebRequest webRequest) - throws Exception { - - HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); - Cookie cookieValue = WebUtils.getCookie(servletRequest, cookieName); - if (Cookie.class.isAssignableFrom(paramType)) { - return cookieValue; - } - else if (cookieValue != null) { - return urlPathHelper.decodeRequestString(servletRequest, cookieValue.getValue()); - } - else { - return null; - } - } - - @Override - @SuppressWarnings({"unchecked"}) - protected String resolvePathVariable(String pathVarName, Class paramType, NativeWebRequest webRequest) - throws Exception { - - HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); - Map uriTemplateVariables = - (Map) servletRequest.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE); - if (uriTemplateVariables == null || !uriTemplateVariables.containsKey(pathVarName)) { - throw new IllegalStateException( - "Could not find @PathVariable [" + pathVarName + "] in @RequestMapping"); - } - return uriTemplateVariables.get(pathVarName); - } - - @Override - protected Object resolveStandardArgument(Class parameterType, NativeWebRequest webRequest) throws Exception { - HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); - HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class); - - if (ServletRequest.class.isAssignableFrom(parameterType) || - MultipartRequest.class.isAssignableFrom(parameterType)) { - Object nativeRequest = webRequest.getNativeRequest(parameterType); - if (nativeRequest == null) { - throw new IllegalStateException( - "Current request is not of type [" + parameterType.getName() + "]: " + request); - } - return nativeRequest; - } - else if (ServletResponse.class.isAssignableFrom(parameterType)) { - this.responseArgumentUsed = true; - Object nativeResponse = webRequest.getNativeResponse(parameterType); - if (nativeResponse == null) { - throw new IllegalStateException( - "Current response is not of type [" + parameterType.getName() + "]: " + response); - } - return nativeResponse; - } - else if (HttpSession.class.isAssignableFrom(parameterType)) { - return request.getSession(); - } - else if (Principal.class.isAssignableFrom(parameterType)) { - return request.getUserPrincipal(); - } - else if (Locale.class.equals(parameterType)) { - return RequestContextUtils.getLocale(request); - } - else if (InputStream.class.isAssignableFrom(parameterType)) { - return request.getInputStream(); - } - else if (Reader.class.isAssignableFrom(parameterType)) { - return request.getReader(); - } - else if (OutputStream.class.isAssignableFrom(parameterType)) { - this.responseArgumentUsed = true; - return response.getOutputStream(); - } - else if (Writer.class.isAssignableFrom(parameterType)) { - this.responseArgumentUsed = true; - return response.getWriter(); - } - return super.resolveStandardArgument(parameterType, webRequest); - } - - @SuppressWarnings("unchecked") - public ModelAndView getModelAndView(Method handlerMethod, Class handlerType, Object returnValue, - ExtendedModelMap implicitModel, ServletWebRequest webRequest) throws Exception { - - ResponseStatus responseStatusAnn = AnnotationUtils.findAnnotation(handlerMethod, ResponseStatus.class); - if (responseStatusAnn != null) { - HttpStatus responseStatus = responseStatusAnn.value(); - String reason = responseStatusAnn.reason(); - if (!StringUtils.hasText(reason)) { - webRequest.getResponse().setStatus(responseStatus.value()); - } - else { - webRequest.getResponse().sendError(responseStatus.value(), reason); - } - - // to be picked up by the RedirectView - webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, responseStatus); - - responseArgumentUsed = true; - } - - // Invoke custom resolvers if present... - if (customModelAndViewResolvers != null) { - for (ModelAndViewResolver mavResolver : customModelAndViewResolvers) { - ModelAndView mav = mavResolver.resolveModelAndView( - handlerMethod, handlerType, returnValue, implicitModel, webRequest); - if (mav != ModelAndViewResolver.UNRESOLVED) { - return mav; - } - } - } - - if (returnValue instanceof HttpEntity) { - handleHttpEntityResponse((HttpEntity) returnValue, webRequest); - return null; - } - else if (AnnotationUtils.findAnnotation(handlerMethod, ResponseBody.class) != null) { - handleResponseBody(returnValue, webRequest); - return null; - } - else if (returnValue instanceof ModelAndView) { - ModelAndView mav = (ModelAndView) returnValue; - mav.getModelMap().mergeAttributes(implicitModel); - return mav; - } - else if (returnValue instanceof Model) { - return new ModelAndView().addAllObjects(implicitModel).addAllObjects(((Model) returnValue).asMap()); - } - else if (returnValue instanceof View) { - return new ModelAndView((View) returnValue).addAllObjects(implicitModel); - } - else if (AnnotationUtils.findAnnotation(handlerMethod, ModelAttribute.class) != null) { - addReturnValueAsModelAttribute(handlerMethod, handlerType, returnValue, implicitModel); - return new ModelAndView().addAllObjects(implicitModel); - } - else if (returnValue instanceof Map) { - return new ModelAndView().addAllObjects(implicitModel).addAllObjects((Map) returnValue); - } - else if (returnValue instanceof String) { - return new ModelAndView((String) returnValue).addAllObjects(implicitModel); - } - else if (returnValue == null) { - // Either returned null or was 'void' return. - if (this.responseArgumentUsed || webRequest.isNotModified()) { - return null; - } - else { - // Assuming view name translation... - return new ModelAndView().addAllObjects(implicitModel); - } - } - else if (!BeanUtils.isSimpleProperty(returnValue.getClass())) { - // Assume a single model attribute... - addReturnValueAsModelAttribute(handlerMethod, handlerType, returnValue, implicitModel); - return new ModelAndView().addAllObjects(implicitModel); - } - else { - throw new IllegalArgumentException("Invalid handler method return value: " + returnValue); - } - } - - private void handleResponseBody(Object returnValue, ServletWebRequest webRequest) - throws Exception { - if (returnValue == null) { - return; - } - HttpInputMessage inputMessage = createHttpInputMessage(webRequest); - HttpOutputMessage outputMessage = createHttpOutputMessage(webRequest); - writeWithMessageConverters(returnValue, inputMessage, outputMessage); - } - - private void handleHttpEntityResponse(HttpEntity responseEntity, ServletWebRequest webRequest) - throws Exception { - if (responseEntity == null) { - return; - } - HttpInputMessage inputMessage = createHttpInputMessage(webRequest); - HttpOutputMessage outputMessage = createHttpOutputMessage(webRequest); - if (responseEntity instanceof ResponseEntity && outputMessage instanceof ServerHttpResponse) { - ((ServerHttpResponse)outputMessage).setStatusCode(((ResponseEntity) responseEntity).getStatusCode()); - } - HttpHeaders entityHeaders = responseEntity.getHeaders(); - if (!entityHeaders.isEmpty()) { - outputMessage.getHeaders().putAll(entityHeaders); - } - Object body = responseEntity.getBody(); - if (body != null) { - writeWithMessageConverters(body, inputMessage, outputMessage); - } - else { - // flush headers - outputMessage.getBody(); - } - } - - @SuppressWarnings("unchecked") - private void writeWithMessageConverters(Object returnValue, - HttpInputMessage inputMessage, HttpOutputMessage outputMessage) - throws IOException, HttpMediaTypeNotAcceptableException { - List acceptedMediaTypes = inputMessage.getHeaders().getAccept(); - if (acceptedMediaTypes.isEmpty()) { - acceptedMediaTypes = Collections.singletonList(MediaType.ALL); - } - MediaType.sortByQualityValue(acceptedMediaTypes); - Class returnValueType = returnValue.getClass(); - List allSupportedMediaTypes = new ArrayList(); - if (getMessageConverters() != null) { - for (MediaType acceptedMediaType : acceptedMediaTypes) { - for (HttpMessageConverter messageConverter : getMessageConverters()) { - if (messageConverter.canWrite(returnValueType, acceptedMediaType)) { - messageConverter.write(returnValue, acceptedMediaType, outputMessage); - if (logger.isDebugEnabled()) { - MediaType contentType = outputMessage.getHeaders().getContentType(); - if (contentType == null) { - contentType = acceptedMediaType; - } - logger.debug("Written [" + returnValue + "] as \"" + contentType + - "\" using [" + messageConverter + "]"); - } - this.responseArgumentUsed = true; - return; - } - } - } - for (HttpMessageConverter messageConverter : messageConverters) { - allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes()); - } - } - throw new HttpMediaTypeNotAcceptableException(allSupportedMediaTypes); - } - - } - - - /** - * Holder for request mapping metadata. Allows for finding a best matching candidate. - */ - static class RequestMappingInfo { - - String[] patterns = new String[0]; - - List matchedPatterns = Collections.emptyList(); - - RequestMethod[] methods = new RequestMethod[0]; - - String[] params = new String[0]; - - String[] headers = new String[0]; - - public boolean hasPatterns() { - return patterns.length > 0; - } - - public String bestMatchedPattern() { - return (!this.matchedPatterns.isEmpty() ? this.matchedPatterns.get(0) : null); - } - - public boolean matches(HttpServletRequest request) { - return matchesRequestMethod(request) && matchesParameters(request) && matchesHeaders(request); - } - - public boolean matchesHeaders(HttpServletRequest request) { - return ServletAnnotationMappingUtils.checkHeaders(this.headers, request); - } - - public boolean matchesParameters(HttpServletRequest request) { - return ServletAnnotationMappingUtils.checkParameters(this.params, request); - } - - public boolean matchesRequestMethod(HttpServletRequest request) { - return ServletAnnotationMappingUtils.checkRequestMethod(this.methods, request); - } - - public Set methodNames() { - Set methodNames = new LinkedHashSet(methods.length); - for (RequestMethod method : methods) { - methodNames.add(method.name()); - } - return methodNames; - } - - @Override - public boolean equals(Object obj) { - RequestMappingInfo other = (RequestMappingInfo) obj; - return (Arrays.equals(this.patterns, other.patterns) && Arrays.equals(this.methods, other.methods) && - Arrays.equals(this.params, other.params) && Arrays.equals(this.headers, other.headers)); - } - - @Override - public int hashCode() { - return (Arrays.hashCode(this.patterns) * 23 + Arrays.hashCode(this.methods) * 29 + - Arrays.hashCode(this.params) * 31 + Arrays.hashCode(this.headers)); - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append(Arrays.asList(patterns)); - if (methods.length > 0) { - builder.append(','); - builder.append(Arrays.asList(methods)); - } - if (headers.length > 0) { - builder.append(','); - builder.append(Arrays.asList(headers)); - } - if (params.length > 0) { - builder.append(','); - builder.append(Arrays.asList(params)); - } - return builder.toString(); - } - } - - - /** - * Comparator capable of sorting {@link RequestMappingInfo}s (RHIs) so that sorting a list with this comparator will - * result in: - *
    - *
  • RHIs with {@linkplain RequestMappingInfo#matchedPatterns better matched paths} take prescedence - * over those with a weaker match (as expressed by the {@linkplain PathMatcher#getPatternComparator(String) path - * pattern comparator}.) Typically, this means that patterns without wild cards and uri templates will be ordered - * before those without.
  • - *
  • RHIs with one single {@linkplain RequestMappingInfo#methods request method} will be - * ordered before those without a method, or with more than one method.
  • - *
  • RHIs with more {@linkplain RequestMappingInfo#params request parameters} will be ordered before those with - * less parameters
  • - * - */ - static class RequestMappingInfoComparator implements Comparator { - - private final Comparator pathComparator; - - private final ServerHttpRequest request; - - RequestMappingInfoComparator(Comparator pathComparator, HttpServletRequest request) { - this.pathComparator = pathComparator; - this.request = new ServletServerHttpRequest(request); - } - - public int compare(RequestMappingInfo info1, RequestMappingInfo info2) { - int pathComparison = pathComparator.compare(info1.bestMatchedPattern(), info2.bestMatchedPattern()); - if (pathComparison != 0) { - return pathComparison; - } - int info1ParamCount = info1.params.length; - int info2ParamCount = info2.params.length; - if (info1ParamCount != info2ParamCount) { - return info2ParamCount - info1ParamCount; - } - int info1HeaderCount = info1.headers.length; - int info2HeaderCount = info2.headers.length; - if (info1HeaderCount != info2HeaderCount) { - return info2HeaderCount - info1HeaderCount; - } - int acceptComparison = compareAcceptHeaders(info1, info2); - if (acceptComparison != 0) { - return acceptComparison; - } - int info1MethodCount = info1.methods.length; - int info2MethodCount = info2.methods.length; - if (info1MethodCount == 0 && info2MethodCount > 0) { - return 1; - } - else if (info2MethodCount == 0 && info1MethodCount > 0) { - return -1; - } - else if (info1MethodCount == 1 & info2MethodCount > 1) { - return -1; - } - else if (info2MethodCount == 1 & info1MethodCount > 1) { - return 1; - } - return 0; - } - - private int compareAcceptHeaders(RequestMappingInfo info1, RequestMappingInfo info2) { - List requestAccepts = request.getHeaders().getAccept(); - MediaType.sortByQualityValue(requestAccepts); - - List info1Accepts = getAcceptHeaderValue(info1); - List info2Accepts = getAcceptHeaderValue(info2); - - for (MediaType requestAccept : requestAccepts) { - int pos1 = indexOfIncluded(info1Accepts, requestAccept); - int pos2 = indexOfIncluded(info2Accepts, requestAccept); - if (pos1 != pos2) { - return pos2 - pos1; - } - } - return 0; - } - - private int indexOfIncluded(List infoAccepts, MediaType requestAccept) { - for (int i = 0; i < infoAccepts.size(); i++) { - MediaType info1Accept = infoAccepts.get(i); - if (requestAccept.includes(info1Accept)) { - return i; - } - } - return -1; - } - - private List getAcceptHeaderValue(RequestMappingInfo info) { - for (String header : info.headers) { - int separator = header.indexOf('='); - if (separator != -1) { - String key = header.substring(0, separator); - String value = header.substring(separator + 1); - if ("Accept".equalsIgnoreCase(key)) { - return MediaType.parseMediaTypes(value); - } - } - } - return Collections.emptyList(); - } - } + private ActionInterceptor[] actionInterceptors; + + /** + * Log category to use when no mapped handler is found for a request. + * + * @see #pageNotFoundLogger + */ + public static final String PAGE_NOT_FOUND_LOG_CATEGORY = "org.springframework.web.servlet.PageNotFound"; + + /** + * Additional logger to use when no mapped handler is found for a request. + * + * @see #PAGE_NOT_FOUND_LOG_CATEGORY + */ + protected static final Log pageNotFoundLogger = LogFactory.getLog(PAGE_NOT_FOUND_LOG_CATEGORY); + + + private UrlPathHelper urlPathHelper = new UrlPathHelper(); + + private PathMatcher pathMatcher = new AntPathMatcher(); + + private MethodNameResolver methodNameResolver = new InternalPathMethodNameResolver(); + + private WebBindingInitializer webBindingInitializer; + + private SessionAttributeStore amhaSessionAttributeStore = new DefaultSessionAttributeStore(); + + private int cacheSecondsForSessionAttributeHandlers = 0; + + private boolean synchronizeOnSession = false; + + private ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer(); + + private WebArgumentResolver[] customArgumentResolvers; + + private ModelAndViewResolver[] customModelAndViewResolvers; + + private HttpMessageConverter[] messageConverters; + + private int order = Ordered.LOWEST_PRECEDENCE; + + private ConfigurableBeanFactory beanFactory; + + private BeanExpressionContext expressionContext; + + private final Map, ServletHandlerMethodResolver> methodResolverCache = + new ConcurrentHashMap, ServletHandlerMethodResolver>(); + + + public AnnotationMethodHandlerAdapter() { + // no restriction of HTTP methods by default + // MLP + super(false); + + // See SPR-7316 + StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(); + stringHttpMessageConverter.setWriteAcceptCharset(false); + messageConverters = new HttpMessageConverter[]{new ByteArrayHttpMessageConverter(), stringHttpMessageConverter, + new SourceHttpMessageConverter(), new XmlAwareFormHttpMessageConverter()}; + } + + + /** + * Set if URL lookup should always use the full path within the current servlet + * context. Else, the path within the current servlet mapping is used if applicable + * (that is, in the case of a ".../*" servlet mapping in web.xml). + *

    Default is "false". + * + * @see org.springframework.web.util.UrlPathHelper#setAlwaysUseFullPath + */ + public void setAlwaysUseFullPath(boolean alwaysUseFullPath) { + this.urlPathHelper.setAlwaysUseFullPath(alwaysUseFullPath); + } + + /** + * Set if context path and request URI should be URL-decoded. Both are returned + * undecoded by the Servlet API, in contrast to the servlet path. + *

    Uses either the request encoding or the default encoding according + * to the Servlet spec (ISO-8859-1). + * + * @see org.springframework.web.util.UrlPathHelper#setUrlDecode + */ + public void setUrlDecode(boolean urlDecode) { + this.urlPathHelper.setUrlDecode(urlDecode); + } + + /** + * Set the UrlPathHelper to use for resolution of lookup paths. + *

    Use this to override the default UrlPathHelper with a custom subclass, + * or to share common UrlPathHelper settings across multiple HandlerMappings and HandlerAdapters. + */ + public void setUrlPathHelper(UrlPathHelper urlPathHelper) { + Assert.notNull(urlPathHelper, "UrlPathHelper must not be null"); + this.urlPathHelper = urlPathHelper; + } + + /** + * Set the PathMatcher implementation to use for matching URL paths against registered URL patterns. + *

    Default is {@link org.springframework.util.AntPathMatcher}. + */ + public void setPathMatcher(PathMatcher pathMatcher) { + Assert.notNull(pathMatcher, "PathMatcher must not be null"); + this.pathMatcher = pathMatcher; + } + + /** + * Set the MethodNameResolver to use for resolving default handler methods + * (carrying an empty @RequestMapping annotation). + *

    Will only kick in when the handler method cannot be resolved uniquely + * through the annotation metadata already. + */ + public void setMethodNameResolver(MethodNameResolver methodNameResolver) { + this.methodNameResolver = methodNameResolver; + } + + /** + * Specify a WebBindingInitializer which will apply pre-configured + * configuration to every DataBinder that this controller uses. + */ + public void setWebBindingInitializer(WebBindingInitializer webBindingInitializer) { + this.webBindingInitializer = webBindingInitializer; + } + + /** + * Specify the strategy to store session attributes with. + *

    Default is {@link org.springframework.web.bind.support.DefaultSessionAttributeStore}, + * storing session attributes in the HttpSession, using the same attribute name as in the model. + */ + public void setSessionAttributeStore(SessionAttributeStore sessionAttributeStore) { + Assert.notNull(sessionAttributeStore, "SessionAttributeStore must not be null"); + this.amhaSessionAttributeStore = sessionAttributeStore; + } + + /** + * Cache content produced by @SessionAttributes annotated handlers + * for the given number of seconds. Default is 0, preventing caching completely. + *

    In contrast to the "cacheSeconds" property which will apply to all general handlers + * (but not to @SessionAttributes annotated handlers), this setting will + * apply to @SessionAttributes annotated handlers only. + * + * @see #setCacheSeconds + * @see org.springframework.web.bind.annotation.SessionAttributes + */ + public void setCacheSecondsForSessionAttributeHandlers(int cacheSecondsForSessionAttributeHandlers) { + this.cacheSecondsForSessionAttributeHandlers = cacheSecondsForSessionAttributeHandlers; + } + + /** + * Set if controller execution should be synchronized on the session, + * to serialize parallel invocations from the same client. + *

    More specifically, the execution of the handleRequestInternal + * method will get synchronized if this flag is "true". The best available + * session mutex will be used for the synchronization; ideally, this will + * be a mutex exposed by HttpSessionMutexListener. + *

    The session mutex is guaranteed to be the same object during + * the entire lifetime of the session, available under the key defined + * by the SESSION_MUTEX_ATTRIBUTE constant. It serves as a + * safe reference to synchronize on for locking on the current session. + *

    In many cases, the HttpSession reference itself is a safe mutex + * as well, since it will always be the same object reference for the + * same active logical session. However, this is not guaranteed across + * different servlet containers; the only 100% safe way is a session mutex. + * + * @see org.springframework.web.util.HttpSessionMutexListener + * @see org.springframework.web.util.WebUtils#getSessionMutex(javax.servlet.http.HttpSession) + */ + public void setSynchronizeOnSession(boolean synchronizeOnSession) { + this.synchronizeOnSession = synchronizeOnSession; + } + + /** + * Set the ParameterNameDiscoverer to use for resolving method parameter names if needed + * (e.g. for default attribute names). + *

    Default is a {@link org.springframework.core.LocalVariableTableParameterNameDiscoverer}. + */ + public void setParameterNameDiscoverer(ParameterNameDiscoverer parameterNameDiscoverer) { + this.parameterNameDiscoverer = parameterNameDiscoverer; + } + + /** + * Set a custom WebArgumentResolvers to use for special method parameter types. + *

    Such a custom WebArgumentResolver will kick in first, having a chance to resolve + * an argument value before the standard argument handling kicks in. + */ + public void setCustomArgumentResolver(WebArgumentResolver argumentResolver) { + this.customArgumentResolvers = new WebArgumentResolver[]{argumentResolver}; + } + + /** + * Set one or more custom WebArgumentResolvers to use for special method parameter types. + *

    Any such custom WebArgumentResolver will kick in first, having a chance to resolve + * an argument value before the standard argument handling kicks in. + */ + public void setCustomArgumentResolvers(WebArgumentResolver[] argumentResolvers) { + this.customArgumentResolvers = argumentResolvers; + } + + /** + * Set a custom ModelAndViewResolvers to use for special method return types. + *

    Such a custom ModelAndViewResolver will kick in first, having a chance to resolve + * a return value before the standard ModelAndView handling kicks in. + */ + public void setCustomModelAndViewResolver(ModelAndViewResolver customModelAndViewResolver) { + this.customModelAndViewResolvers = new ModelAndViewResolver[]{customModelAndViewResolver}; + } + + /** + * Set one or more custom ModelAndViewResolvers to use for special method return types. + *

    Any such custom ModelAndViewResolver will kick in first, having a chance to resolve + * a return value before the standard ModelAndView handling kicks in. + */ + public void setCustomModelAndViewResolvers(ModelAndViewResolver[] customModelAndViewResolvers) { + this.customModelAndViewResolvers = customModelAndViewResolvers; + } + + /** + * Set the message body converters to use. + *

    These converters are used to convert from and to HTTP requests and responses. + */ + public void setMessageConverters(HttpMessageConverter[] messageConverters) { + this.messageConverters = messageConverters; + } + + /** + * Return the message body converters that this adapter has been configured with. + */ + public HttpMessageConverter[] getMessageConverters() { + return messageConverters; + } + + public void setActionInterceptors(ActionInterceptor[] actionInterceptors) { + this.actionInterceptors = actionInterceptors; + } + + /** + * Specify the order value for this HandlerAdapter bean. + *

    Default value is Integer.MAX_VALUE, meaning that it's non-ordered. + * + * @see org.springframework.core.Ordered#getOrder() + */ + public void setOrder(int order) { + this.order = order; + } + + public int getOrder() { + return this.order; + } + + public void setBeanFactory(BeanFactory beanFactory) { + if (beanFactory instanceof ConfigurableBeanFactory) { + this.beanFactory = (ConfigurableBeanFactory) beanFactory; + this.expressionContext = new BeanExpressionContext(this.beanFactory, new RequestScope()); + } + } + + + public boolean supports(Object handler) { + return getMethodResolver(handler).hasHandlerMethods(); + } + + public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) + throws Exception { + + if (AnnotationUtils.findAnnotation(handler.getClass(), SessionAttributes.class) != null) { + // Always prevent caching in case of session attribute management. + checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true); + // Prepare cached set of session attributes names. + } else { + // Uses configured default cacheSeconds setting. + checkAndPrepare(request, response, true); + } + + // Execute invokeHandlerMethod in synchronized block if required. + if (this.synchronizeOnSession) { + HttpSession session = request.getSession(false); + if (session != null) { + Object mutex = WebUtils.getSessionMutex(session); + synchronized (mutex) { + return invokeHandlerMethod(request, response, handler); + } + } + } + + return invokeHandlerMethod(request, response, handler); + } + + protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler) + throws Exception { + + ServletHandlerMethodResolver methodResolver = getMethodResolver(handler); + Method handlerMethod = methodResolver.resolveHandlerMethod(request); + ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver, actionInterceptors); + ServletWebRequest webRequest = new ServletWebRequest(request, response); + ExtendedModelMap implicitModel = new BindingAwareModelMap(); + + + return methodInvoker.interceptingInvokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel); + //Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel); + //ModelAndView mav = + // methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest); + // methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest); + // return mav; + } + + public long getLastModified(HttpServletRequest request, Object handler) { + return -1; + } + + /** + * Build a HandlerMethodResolver for the given handler type. + */ + private ServletHandlerMethodResolver getMethodResolver(Object handler) { + Class handlerClass = ClassUtils.getUserClass(handler); + ServletHandlerMethodResolver resolver = this.methodResolverCache.get(handlerClass); + if (resolver == null) { + resolver = new ServletHandlerMethodResolver(handlerClass); + this.methodResolverCache.put(handlerClass, resolver); + } + return resolver; + } + + + /** + * Template method for creating a new ServletRequestDataBinder instance. + *

    The default implementation creates a standard ServletRequestDataBinder. + * This can be overridden for custom ServletRequestDataBinder subclasses. + * + * @param request current HTTP request + * @param target the target object to bind onto (or null + * if the binder is just used to convert a plain parameter value) + * @param objectName the objectName of the target object + * @return the ServletRequestDataBinder instance to use + * @throws Exception in case of invalid state or arguments + * @see ServletRequestDataBinder#bind(javax.servlet.ServletRequest) + * @see ServletRequestDataBinder#convertIfNecessary(Object, Class, org.springframework.core.MethodParameter) + */ + protected ServletRequestDataBinder createBinder(HttpServletRequest request, Object target, String objectName) + throws Exception { + return new ServletRequestDataBinder(target, objectName); + } + + /** + * Template method for creating a new HttpInputMessage instance. + *

    The default implementation creates a standard {@link ServletServerHttpRequest}. + * This can be overridden for custom {@code HttpInputMessage} implementations + * + * @param servletRequest current HTTP request + * @return the HttpInputMessage instance to use + * @throws Exception in case of errors + */ + protected HttpInputMessage createHttpInputMessage(HttpServletRequest servletRequest) throws Exception { + return new ServletServerHttpRequest(servletRequest); + } + + /** + * Template method for creating a new HttpOuputMessage instance. + *

    The default implementation creates a standard {@link ServletServerHttpResponse}. + * This can be overridden for custom {@code HttpOutputMessage} implementations + * + * @param servletResponse current HTTP response + * @return the HttpInputMessage instance to use + * @throws Exception in case of errors + */ + protected HttpOutputMessage createHttpOutputMessage(HttpServletResponse servletResponse) throws Exception { + return new ServletServerHttpResponse(servletResponse); + } + + + /** + * Servlet-specific subclass of {@link HandlerMethodResolver}. + */ + private class ServletHandlerMethodResolver extends HandlerMethodResolver { + + private final Map mappings = new HashMap(); + + private ServletHandlerMethodResolver(Class handlerType) { + init(handlerType); + } + + @Override + protected boolean isHandlerMethod(Method method) { + if (this.mappings.containsKey(method)) { + return true; + } + RequestMapping mapping = AnnotationUtils.findAnnotation(method, RequestMapping.class); + if (mapping != null) { + RequestMappingInfo mappingInfo = new RequestMappingInfo(); + mappingInfo.patterns = mapping.value(); + if (!hasTypeLevelMapping() || !Arrays.equals(mapping.method(), getTypeLevelMapping().method())) { + mappingInfo.methods = mapping.method(); + } + if (!hasTypeLevelMapping() || !Arrays.equals(mapping.params(), getTypeLevelMapping().params())) { + mappingInfo.params = mapping.params(); + } + if (!hasTypeLevelMapping() || !Arrays.equals(mapping.headers(), getTypeLevelMapping().headers())) { + mappingInfo.headers = mapping.headers(); + } + this.mappings.put(method, mappingInfo); + return true; + } + return false; + } + + public Method resolveHandlerMethod(HttpServletRequest request) throws ServletException { + String lookupPath = urlPathHelper.getLookupPathForRequest(request); + Comparator pathComparator = pathMatcher.getPatternComparator(lookupPath); + Map targetHandlerMethods = new LinkedHashMap(); + Set allowedMethods = new LinkedHashSet(7); + String resolvedMethodName = null; + for (Method handlerMethod : getHandlerMethods()) { + RequestMappingInfo mappingInfo = this.mappings.get(handlerMethod); + boolean match = false; + if (mappingInfo.hasPatterns()) { + List matchingPatterns = new ArrayList(mappingInfo.patterns.length); + for (String pattern : mappingInfo.patterns) { + if (!hasTypeLevelMapping() && !pattern.startsWith("/")) { + pattern = "/" + pattern; + } + String combinedPattern = getCombinedPattern(pattern, lookupPath, request); + if (combinedPattern != null) { + if (mappingInfo.matches(request)) { + match = true; + matchingPatterns.add(combinedPattern); + } else { + if (!mappingInfo.matchesRequestMethod(request)) { + allowedMethods.addAll(mappingInfo.methodNames()); + } + break; + } + } + } + Collections.sort(matchingPatterns, pathComparator); + mappingInfo.matchedPatterns = matchingPatterns; + } else { + // No paths specified: parameter match sufficient. + match = mappingInfo.matches(request); + if (match && mappingInfo.methods.length == 0 && mappingInfo.params.length == 0 && + resolvedMethodName != null && !resolvedMethodName.equals(handlerMethod.getName())) { + match = false; + } else { + if (!mappingInfo.matchesRequestMethod(request)) { + allowedMethods.addAll(mappingInfo.methodNames()); + } + } + } + if (match) { + Method oldMappedMethod = targetHandlerMethods.put(mappingInfo, handlerMethod); + if (oldMappedMethod != null && oldMappedMethod != handlerMethod) { + if (methodNameResolver != null && mappingInfo.patterns.length == 0) { + if (!oldMappedMethod.getName().equals(handlerMethod.getName())) { + if (resolvedMethodName == null) { + resolvedMethodName = methodNameResolver.getHandlerMethodName(request); + } + if (!resolvedMethodName.equals(oldMappedMethod.getName())) { + oldMappedMethod = null; + } + if (!resolvedMethodName.equals(handlerMethod.getName())) { + if (oldMappedMethod != null) { + targetHandlerMethods.put(mappingInfo, oldMappedMethod); + oldMappedMethod = null; + } else { + targetHandlerMethods.remove(mappingInfo); + } + } + } + } + if (oldMappedMethod != null) { + throw new IllegalStateException( + "Ambiguous handler methods mapped for HTTP path '" + lookupPath + "': {" + + oldMappedMethod + ", " + handlerMethod + + "}. If you intend to handle the same path in multiple methods, then factor " + + "them out into a dedicated handler class with that path mapped at the type level!"); + } + } + } + } + if (!targetHandlerMethods.isEmpty()) { + List matches = new ArrayList(targetHandlerMethods.keySet()); + RequestMappingInfoComparator requestMappingInfoComparator = + new RequestMappingInfoComparator(pathComparator, request); + Collections.sort(matches, requestMappingInfoComparator); + RequestMappingInfo bestMappingMatch = matches.get(0); + String bestMatchedPath = bestMappingMatch.bestMatchedPattern(); + if (bestMatchedPath != null) { + extractHandlerMethodUriTemplates(bestMatchedPath, lookupPath, request); + } + return targetHandlerMethods.get(bestMappingMatch); + } else { + if (!allowedMethods.isEmpty()) { + throw new HttpRequestMethodNotSupportedException(request.getMethod(), + StringUtils.toStringArray(allowedMethods)); + } + throw new NoSuchRequestHandlingMethodException(lookupPath, request.getMethod(), + request.getParameterMap()); + } + } + + /** + * Determines the combined pattern for the given methodLevelPattern and path. + *

    Uses the following algorithm:

      + *
    1. If there is a type-level mapping with path information, it is {@linkplain + * PathMatcher#combine(String, String) combined} with the method-level pattern.
    2. + *
    3. If there is a {@linkplain HandlerMapping#BEST_MATCHING_PATTERN_ATTRIBUTE best matching pattern} in the + * request, it is combined with the method-level pattern.
    4. + *
    5. Otherwise, the method-level pattern is returned.
    6. + *
    + */ + private String getCombinedPattern(String methodLevelPattern, String lookupPath, HttpServletRequest request) { + if (hasTypeLevelMapping() && (!ObjectUtils.isEmpty(getTypeLevelMapping().value()))) { + String[] typeLevelPatterns = getTypeLevelMapping().value(); + for (String typeLevelPattern : typeLevelPatterns) { + if (!typeLevelPattern.startsWith("/")) { + typeLevelPattern = "/" + typeLevelPattern; + } + String combinedPattern = pathMatcher.combine(typeLevelPattern, methodLevelPattern); + if (isPathMatchInternal(combinedPattern, lookupPath)) { + return combinedPattern; + } + } + return null; + } + String bestMatchingPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE); + if (StringUtils.hasText(bestMatchingPattern) && bestMatchingPattern.endsWith("*")) { + String combinedPattern = pathMatcher.combine(bestMatchingPattern, methodLevelPattern); + if (!combinedPattern.equals(bestMatchingPattern) && + (isPathMatchInternal(combinedPattern, lookupPath))) { + return combinedPattern; + } + } + if (isPathMatchInternal(methodLevelPattern, lookupPath)) { + return methodLevelPattern; + } + return null; + } + + private boolean isPathMatchInternal(String pattern, String lookupPath) { + if (pattern.equals(lookupPath) || pathMatcher.match(pattern, lookupPath)) { + return true; + } + boolean hasSuffix = pattern.indexOf('.') != -1; + if (!hasSuffix && pathMatcher.match(pattern + ".*", lookupPath)) { + return true; + } + boolean endsWithSlash = pattern.endsWith("/"); + if (!endsWithSlash && pathMatcher.match(pattern + "/", lookupPath)) { + return true; + } + return false; + } + + @SuppressWarnings("unchecked") + private void extractHandlerMethodUriTemplates(String mappedPattern, + String lookupPath, + HttpServletRequest request) { + + Map variables = + (Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE); + + int patternVariableCount = StringUtils.countOccurrencesOf(mappedPattern, "{"); + + if ((variables == null || patternVariableCount != variables.size()) + && pathMatcher.match(mappedPattern, lookupPath)) { + variables = pathMatcher.extractUriTemplateVariables(mappedPattern, lookupPath); + request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, variables); + } + } + } + + + /** + * Servlet-specific subclass of {@link HandlerMethodInvoker}. + */ + private class ServletHandlerMethodInvoker extends InterceptingHandlerMethodInvoker { + + private boolean responseArgumentUsed = false; + + private ServletHandlerMethodInvoker(HandlerMethodResolver resolver, ActionInterceptor[] actionInterceptors) { + super(resolver, webBindingInitializer, amhaSessionAttributeStore, parameterNameDiscoverer, + customArgumentResolvers, messageConverters, actionInterceptors); + } + + public ModelAndView interceptingInvokeHandlerMethod(Method handlerMethod, Object handler, + NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception { + + int interceptorIndex = -1; + ModelAndView mav = null; + ActionExecutingContext executingContext = null; + Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod); + try { + boolean debug = logger.isDebugEnabled(); + for (String attrName : this.methodResolver.getActualSessionAttributeNames()) { + Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName); + if (attrValue != null) { + implicitModel.addAttribute(attrName, attrValue); + } + } + for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) { + Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod); + Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel); + if (debug) { + logger.debug("Invoking model attribute method: " + attributeMethodToInvoke); + } + String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value(); + if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) { + continue; + } + ReflectionUtils.makeAccessible(attributeMethodToInvoke); + Object attrValue = attributeMethodToInvoke.invoke(handler, args); + if ("".equals(attrName)) { + Class resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass()); + attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue); + } + if (!implicitModel.containsAttribute(attrName)) { + implicitModel.addAttribute(attrName, attrValue); + } + } + Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel); + if (debug) { + logger.debug("Invoking request handler method: " + handlerMethodToInvoke); + } + ReflectionUtils.makeAccessible(handlerMethodToInvoke); + + executingContext = new ActionExecutingContext((ServletWebRequest) webRequest, handler, handlerMethodToInvoke, args, implicitModel); + + // Apply preHandle methods of registered interceptors. + ActionInterceptor[] interceptors = getActionInterceptors(); + if (interceptors != null) { + for (int i = 0; i < interceptors.length; i++) { + ActionInterceptor interceptor = interceptors[i]; + if (!interceptor.preHandle(executingContext)) { + triggerAfterCompletion(executingContext, interceptorIndex, null, null); + return null; //TODO verify null is ok + } + interceptorIndex = i; + } + } + + // Actually invoke the handler + Object result = handlerMethodToInvoke.invoke(handler, args); + + + mav = getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, (ServletWebRequest) webRequest); + updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest); + + // Trigger after-completion for successful outcome + triggerAfterCompletion(executingContext, interceptorIndex, mav, null); + + return mav; + } catch (IllegalStateException ex) { + // Internal assertion failed (e.g. invalid signature): + // throw exception with full handler method context... + triggerAfterCompletion(executingContext, interceptorIndex, mav, ex); + throw new HandlerMethodInvocationException(handlerMethodToInvoke, ex); + } catch (InvocationTargetException ex) { + // User-defined @ModelAttribute/@InitBinder/@RequestMapping method threw an exception... + triggerAfterCompletion(executingContext, interceptorIndex, mav, ex); + ReflectionUtils.rethrowException(ex.getTargetException()); + return null; + } + } + + private void triggerAfterCompletion(ActionExecutingContext executingContext, + int interceptorIndex, + ModelAndView modelAndView, + Exception ex) throws Exception { + + // Apply afterCompletion methods of registered interceptors. + if (executingContext.getHandler() != null) { + //TODO should be passed in; + ActionInterceptor[] interceptors = getActionInterceptors(); + if (interceptors != null) { + for (int i = interceptorIndex; i >= 0; i--) { + ActionInterceptor interceptor = interceptors[i]; + ActionExecutedContext actionExecutedContext = new ActionExecutedContext(executingContext, modelAndView, ex); + try { + interceptor.afterCompletion(actionExecutedContext); + } catch (Throwable ex2) { + logger.error("ActionInterceptor threw exception", ex2); + } + } + } + } + } + + + @Override + protected void raiseMissingParameterException(String paramName, Class paramType) throws Exception { + throw new MissingServletRequestParameterException(paramName, paramType.getSimpleName()); + } + + @Override + protected void raiseSessionRequiredException(String message) throws Exception { + throw new HttpSessionRequiredException(message); + } + + @Override + protected WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName) + throws Exception { + + return AnnotationMethodHandlerAdapter.this.createBinder( + webRequest.getNativeRequest(HttpServletRequest.class), target, objectName); + } + + @Override + protected void doBind(WebDataBinder binder, NativeWebRequest webRequest) throws Exception { + ServletRequestDataBinder servletBinder = (ServletRequestDataBinder) binder; + servletBinder.bind(webRequest.getNativeRequest(ServletRequest.class)); + } + + @Override + protected HttpInputMessage createHttpInputMessage(NativeWebRequest webRequest) throws Exception { + HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); + return AnnotationMethodHandlerAdapter.this.createHttpInputMessage(servletRequest); + } + + @Override + protected HttpOutputMessage createHttpOutputMessage(NativeWebRequest webRequest) throws Exception { + HttpServletResponse servletResponse = (HttpServletResponse) webRequest.getNativeResponse(); + return AnnotationMethodHandlerAdapter.this.createHttpOutputMessage(servletResponse); + } + + @Override + protected Object resolveDefaultValue(String value) { + if (beanFactory == null) { + return value; + } + String placeholdersResolved = beanFactory.resolveEmbeddedValue(value); + BeanExpressionResolver exprResolver = beanFactory.getBeanExpressionResolver(); + if (exprResolver == null) { + return value; + } + return exprResolver.evaluate(placeholdersResolved, expressionContext); + } + + @Override + protected Object resolveCookieValue(String cookieName, Class paramType, NativeWebRequest webRequest) + throws Exception { + + HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); + Cookie cookieValue = WebUtils.getCookie(servletRequest, cookieName); + if (Cookie.class.isAssignableFrom(paramType)) { + return cookieValue; + } else if (cookieValue != null) { + return urlPathHelper.decodeRequestString(servletRequest, cookieValue.getValue()); + } else { + return null; + } + } + + @Override + @SuppressWarnings({"unchecked"}) + protected String resolvePathVariable(String pathVarName, Class paramType, NativeWebRequest webRequest) + throws Exception { + + HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); + Map uriTemplateVariables = + (Map) servletRequest.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE); + if (uriTemplateVariables == null || !uriTemplateVariables.containsKey(pathVarName)) { + throw new IllegalStateException( + "Could not find @PathVariable [" + pathVarName + "] in @RequestMapping"); + } + return uriTemplateVariables.get(pathVarName); + } + + @Override + protected Object resolveStandardArgument(Class parameterType, NativeWebRequest webRequest) throws Exception { + HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); + HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class); + + if (ServletRequest.class.isAssignableFrom(parameterType) || + MultipartRequest.class.isAssignableFrom(parameterType)) { + Object nativeRequest = webRequest.getNativeRequest(parameterType); + if (nativeRequest == null) { + throw new IllegalStateException( + "Current request is not of type [" + parameterType.getName() + "]: " + request); + } + return nativeRequest; + } else if (ServletResponse.class.isAssignableFrom(parameterType)) { + this.responseArgumentUsed = true; + Object nativeResponse = webRequest.getNativeResponse(parameterType); + if (nativeResponse == null) { + throw new IllegalStateException( + "Current response is not of type [" + parameterType.getName() + "]: " + response); + } + return nativeResponse; + } else if (HttpSession.class.isAssignableFrom(parameterType)) { + return request.getSession(); + } else if (Principal.class.isAssignableFrom(parameterType)) { + return request.getUserPrincipal(); + } else if (Locale.class.equals(parameterType)) { + return RequestContextUtils.getLocale(request); + } else if (InputStream.class.isAssignableFrom(parameterType)) { + return request.getInputStream(); + } else if (Reader.class.isAssignableFrom(parameterType)) { + return request.getReader(); + } else if (OutputStream.class.isAssignableFrom(parameterType)) { + this.responseArgumentUsed = true; + return response.getOutputStream(); + } else if (Writer.class.isAssignableFrom(parameterType)) { + this.responseArgumentUsed = true; + return response.getWriter(); + } + return super.resolveStandardArgument(parameterType, webRequest); + } + + @SuppressWarnings("unchecked") + public ModelAndView getModelAndView(Method handlerMethod, Class handlerType, Object returnValue, + ExtendedModelMap implicitModel, ServletWebRequest webRequest) throws Exception { + + ResponseStatus responseStatusAnn = AnnotationUtils.findAnnotation(handlerMethod, ResponseStatus.class); + if (responseStatusAnn != null) { + HttpStatus responseStatus = responseStatusAnn.value(); + String reason = responseStatusAnn.reason(); + if (!StringUtils.hasText(reason)) { + webRequest.getResponse().setStatus(responseStatus.value()); + } else { + webRequest.getResponse().sendError(responseStatus.value(), reason); + } + + // to be picked up by the RedirectView + webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, responseStatus); + + responseArgumentUsed = true; + } + + // Invoke custom resolvers if present... + if (customModelAndViewResolvers != null) { + for (ModelAndViewResolver mavResolver : customModelAndViewResolvers) { + ModelAndView mav = mavResolver.resolveModelAndView( + handlerMethod, handlerType, returnValue, implicitModel, webRequest); + if (mav != ModelAndViewResolver.UNRESOLVED) { + return mav; + } + } + } + + if (returnValue instanceof HttpEntity) { + handleHttpEntityResponse((HttpEntity) returnValue, webRequest); + return null; + } else if (AnnotationUtils.findAnnotation(handlerMethod, ResponseBody.class) != null) { + handleResponseBody(returnValue, webRequest); + return null; + } else if (returnValue instanceof ModelAndView) { + ModelAndView mav = (ModelAndView) returnValue; + mav.getModelMap().mergeAttributes(implicitModel); + return mav; + } else if (returnValue instanceof Model) { + return new ModelAndView().addAllObjects(implicitModel).addAllObjects(((Model) returnValue).asMap()); + } else if (returnValue instanceof View) { + return new ModelAndView((View) returnValue).addAllObjects(implicitModel); + } else if (AnnotationUtils.findAnnotation(handlerMethod, ModelAttribute.class) != null) { + addReturnValueAsModelAttribute(handlerMethod, handlerType, returnValue, implicitModel); + return new ModelAndView().addAllObjects(implicitModel); + } else if (returnValue instanceof Map) { + return new ModelAndView().addAllObjects(implicitModel).addAllObjects((Map) returnValue); + } else if (returnValue instanceof String) { + return new ModelAndView((String) returnValue).addAllObjects(implicitModel); + } else if (returnValue == null) { + // Either returned null or was 'void' return. + if (this.responseArgumentUsed || webRequest.isNotModified()) { + return null; + } else { + // Assuming view name translation... + return new ModelAndView().addAllObjects(implicitModel); + } + } else if (!BeanUtils.isSimpleProperty(returnValue.getClass())) { + // Assume a single model attribute... + addReturnValueAsModelAttribute(handlerMethod, handlerType, returnValue, implicitModel); + return new ModelAndView().addAllObjects(implicitModel); + } else { + throw new IllegalArgumentException("Invalid handler method return value: " + returnValue); + } + } + + private void handleResponseBody(Object returnValue, ServletWebRequest webRequest) + throws Exception { + if (returnValue == null) { + return; + } + HttpInputMessage inputMessage = createHttpInputMessage(webRequest); + HttpOutputMessage outputMessage = createHttpOutputMessage(webRequest); + writeWithMessageConverters(returnValue, inputMessage, outputMessage); + } + + private void handleHttpEntityResponse(HttpEntity responseEntity, ServletWebRequest webRequest) + throws Exception { + if (responseEntity == null) { + return; + } + HttpInputMessage inputMessage = createHttpInputMessage(webRequest); + HttpOutputMessage outputMessage = createHttpOutputMessage(webRequest); + if (responseEntity instanceof ResponseEntity && outputMessage instanceof ServerHttpResponse) { + ((ServerHttpResponse) outputMessage).setStatusCode(((ResponseEntity) responseEntity).getStatusCode()); + } + HttpHeaders entityHeaders = responseEntity.getHeaders(); + if (!entityHeaders.isEmpty()) { + outputMessage.getHeaders().putAll(entityHeaders); + } + Object body = responseEntity.getBody(); + if (body != null) { + writeWithMessageConverters(body, inputMessage, outputMessage); + } else { + // flush headers + outputMessage.getBody(); + } + } + + @SuppressWarnings("unchecked") + private void writeWithMessageConverters(Object returnValue, + HttpInputMessage inputMessage, HttpOutputMessage outputMessage) + throws IOException, HttpMediaTypeNotAcceptableException { + List acceptedMediaTypes = inputMessage.getHeaders().getAccept(); + if (acceptedMediaTypes.isEmpty()) { + acceptedMediaTypes = Collections.singletonList(MediaType.ALL); + } + MediaType.sortByQualityValue(acceptedMediaTypes); + Class returnValueType = returnValue.getClass(); + List allSupportedMediaTypes = new ArrayList(); + if (getMessageConverters() != null) { + for (MediaType acceptedMediaType : acceptedMediaTypes) { + for (HttpMessageConverter messageConverter : getMessageConverters()) { + if (messageConverter.canWrite(returnValueType, acceptedMediaType)) { + messageConverter.write(returnValue, acceptedMediaType, outputMessage); + if (logger.isDebugEnabled()) { + MediaType contentType = outputMessage.getHeaders().getContentType(); + if (contentType == null) { + contentType = acceptedMediaType; + } + logger.debug("Written [" + returnValue + "] as \"" + contentType + + "\" using [" + messageConverter + "]"); + } + this.responseArgumentUsed = true; + return; + } + } + } + for (HttpMessageConverter messageConverter : messageConverters) { + allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes()); + } + } + throw new HttpMediaTypeNotAcceptableException(allSupportedMediaTypes); + } + + } + + + /** + * Holder for request mapping metadata. Allows for finding a best matching candidate. + */ + static class RequestMappingInfo { + + String[] patterns = new String[0]; + + List matchedPatterns = Collections.emptyList(); + + RequestMethod[] methods = new RequestMethod[0]; + + String[] params = new String[0]; + + String[] headers = new String[0]; + + public boolean hasPatterns() { + return patterns.length > 0; + } + + public String bestMatchedPattern() { + return (!this.matchedPatterns.isEmpty() ? this.matchedPatterns.get(0) : null); + } + + public boolean matches(HttpServletRequest request) { + return matchesRequestMethod(request) && matchesParameters(request) && matchesHeaders(request); + } + + public boolean matchesHeaders(HttpServletRequest request) { + return ServletAnnotationMappingUtils.checkHeaders(this.headers, request); + } + + public boolean matchesParameters(HttpServletRequest request) { + return ServletAnnotationMappingUtils.checkParameters(this.params, request); + } + + public boolean matchesRequestMethod(HttpServletRequest request) { + return ServletAnnotationMappingUtils.checkRequestMethod(this.methods, request); + } + + public Set methodNames() { + Set methodNames = new LinkedHashSet(methods.length); + for (RequestMethod method : methods) { + methodNames.add(method.name()); + } + return methodNames; + } + + @Override + public boolean equals(Object obj) { + RequestMappingInfo other = (RequestMappingInfo) obj; + return (Arrays.equals(this.patterns, other.patterns) && Arrays.equals(this.methods, other.methods) && + Arrays.equals(this.params, other.params) && Arrays.equals(this.headers, other.headers)); + } + + @Override + public int hashCode() { + return (Arrays.hashCode(this.patterns) * 23 + Arrays.hashCode(this.methods) * 29 + + Arrays.hashCode(this.params) * 31 + Arrays.hashCode(this.headers)); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append(Arrays.asList(patterns)); + if (methods.length > 0) { + builder.append(','); + builder.append(Arrays.asList(methods)); + } + if (headers.length > 0) { + builder.append(','); + builder.append(Arrays.asList(headers)); + } + if (params.length > 0) { + builder.append(','); + builder.append(Arrays.asList(params)); + } + return builder.toString(); + } + } + + + /** + * Comparator capable of sorting {@link RequestMappingInfo}s (RHIs) so that sorting a list with this comparator will + * result in: + *
      + *
    • RHIs with {@linkplain RequestMappingInfo#matchedPatterns better matched paths} take prescedence + * over those with a weaker match (as expressed by the {@linkplain PathMatcher#getPatternComparator(String) path + * pattern comparator}.) Typically, this means that patterns without wild cards and uri templates will be ordered + * before those without.
    • + *
    • RHIs with one single {@linkplain RequestMappingInfo#methods request method} will be + * ordered before those without a method, or with more than one method.
    • + *
    • RHIs with more {@linkplain RequestMappingInfo#params request parameters} will be ordered before those with + * less parameters
    • + * + */ + static class RequestMappingInfoComparator implements Comparator { + + private final Comparator pathComparator; + + private final ServerHttpRequest request; + + RequestMappingInfoComparator(Comparator pathComparator, HttpServletRequest request) { + this.pathComparator = pathComparator; + this.request = new ServletServerHttpRequest(request); + } + + public int compare(RequestMappingInfo info1, RequestMappingInfo info2) { + int pathComparison = pathComparator.compare(info1.bestMatchedPattern(), info2.bestMatchedPattern()); + if (pathComparison != 0) { + return pathComparison; + } + int info1ParamCount = info1.params.length; + int info2ParamCount = info2.params.length; + if (info1ParamCount != info2ParamCount) { + return info2ParamCount - info1ParamCount; + } + int info1HeaderCount = info1.headers.length; + int info2HeaderCount = info2.headers.length; + if (info1HeaderCount != info2HeaderCount) { + return info2HeaderCount - info1HeaderCount; + } + int acceptComparison = compareAcceptHeaders(info1, info2); + if (acceptComparison != 0) { + return acceptComparison; + } + int info1MethodCount = info1.methods.length; + int info2MethodCount = info2.methods.length; + if (info1MethodCount == 0 && info2MethodCount > 0) { + return 1; + } else if (info2MethodCount == 0 && info1MethodCount > 0) { + return -1; + } else if (info1MethodCount == 1 & info2MethodCount > 1) { + return -1; + } else if (info2MethodCount == 1 & info1MethodCount > 1) { + return 1; + } + return 0; + } + + private int compareAcceptHeaders(RequestMappingInfo info1, RequestMappingInfo info2) { + List requestAccepts = request.getHeaders().getAccept(); + MediaType.sortByQualityValue(requestAccepts); + + List info1Accepts = getAcceptHeaderValue(info1); + List info2Accepts = getAcceptHeaderValue(info2); + + for (MediaType requestAccept : requestAccepts) { + int pos1 = indexOfIncluded(info1Accepts, requestAccept); + int pos2 = indexOfIncluded(info2Accepts, requestAccept); + if (pos1 != pos2) { + return pos2 - pos1; + } + } + return 0; + } + + private int indexOfIncluded(List infoAccepts, MediaType requestAccept) { + for (int i = 0; i < infoAccepts.size(); i++) { + MediaType info1Accept = infoAccepts.get(i); + if (requestAccept.includes(info1Accept)) { + return i; + } + } + return -1; + } + + private List getAcceptHeaderValue(RequestMappingInfo info) { + for (String header : info.headers) { + int separator = header.indexOf('='); + if (separator != -1) { + String key = header.substring(0, separator); + String value = header.substring(separator + 1); + if ("Accept".equalsIgnoreCase(key)) { + return MediaType.parseMediaTypes(value); + } + } + } + return Collections.emptyList(); + } + } } diff --git a/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/mvc/annotation/ServletAnnotationMappingUtils.java b/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/mvc/annotation/ServletAnnotationMappingUtils.java index 279c8904b..5d0bd7386 100644 --- a/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/mvc/annotation/ServletAnnotationMappingUtils.java +++ b/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/mvc/annotation/ServletAnnotationMappingUtils.java @@ -34,110 +34,108 @@ import org.springframework.web.util.WebUtils; */ abstract class ServletAnnotationMappingUtils { - /** - * Check whether the given request matches the specified request methods. - * @param methods the HTTP request methods to check against - * @param request the current HTTP request to check - */ - public static boolean checkRequestMethod(RequestMethod[] methods, HttpServletRequest request) { - if (ObjectUtils.isEmpty(methods)) { - return true; - } - for (RequestMethod method : methods) { - if (method.name().equals(request.getMethod())) { - return true; - } - } - return false; - } + /** + * Check whether the given request matches the specified request methods. + * + * @param methods the HTTP request methods to check against + * @param request the current HTTP request to check + */ + public static boolean checkRequestMethod(RequestMethod[] methods, HttpServletRequest request) { + if (ObjectUtils.isEmpty(methods)) { + return true; + } + for (RequestMethod method : methods) { + if (method.name().equals(request.getMethod())) { + return true; + } + } + return false; + } - /** - * Check whether the given request matches the specified parameter conditions. - * @param params the parameter conditions, following - * {@link org.springframework.web.bind.annotation.RequestMapping#params() RequestMapping.#params()} - * @param request the current HTTP request to check - */ - public static boolean checkParameters(String[] params, HttpServletRequest request) { - if (!ObjectUtils.isEmpty(params)) { - for (String param : params) { - int separator = param.indexOf('='); - if (separator == -1) { - if (param.startsWith("!")) { - if (WebUtils.hasSubmitParameter(request, param.substring(1))) { - return false; - } - } - else if (!WebUtils.hasSubmitParameter(request, param)) { - return false; - } - } - else { - boolean negated = separator > 0 && param.charAt(separator - 1) == '!'; - String key = !negated ? param.substring(0, separator) : param.substring(0, separator - 1); - String value = param.substring(separator + 1); - if (!value.equals(request.getParameter(key))) { - return negated; - } - } - } - } - return true; - } + /** + * Check whether the given request matches the specified parameter conditions. + * + * @param params the parameter conditions, following + * {@link org.springframework.web.bind.annotation.RequestMapping#params() RequestMapping.#params()} + * @param request the current HTTP request to check + */ + public static boolean checkParameters(String[] params, HttpServletRequest request) { + if (!ObjectUtils.isEmpty(params)) { + for (String param : params) { + int separator = param.indexOf('='); + if (separator == -1) { + if (param.startsWith("!")) { + if (WebUtils.hasSubmitParameter(request, param.substring(1))) { + return false; + } + } else if (!WebUtils.hasSubmitParameter(request, param)) { + return false; + } + } else { + boolean negated = separator > 0 && param.charAt(separator - 1) == '!'; + String key = !negated ? param.substring(0, separator) : param.substring(0, separator - 1); + String value = param.substring(separator + 1); + if (!value.equals(request.getParameter(key))) { + return negated; + } + } + } + } + return true; + } - /** - * Check whether the given request matches the specified header conditions. - * @param headers the header conditions, following - * {@link org.springframework.web.bind.annotation.RequestMapping#headers() RequestMapping.headers()} - * @param request the current HTTP request to check - */ - public static boolean checkHeaders(String[] headers, HttpServletRequest request) { - if (!ObjectUtils.isEmpty(headers)) { - for (String header : headers) { - int separator = header.indexOf('='); - if (separator == -1) { - if (header.startsWith("!")) { - if (request.getHeader(header.substring(1)) != null) { - return false; - } - } - else if (request.getHeader(header) == null) { - return false; - } - } - else { - boolean negated = separator > 0 && header.charAt(separator - 1) == '!'; - String key = !negated ? header.substring(0, separator) : header.substring(0, separator - 1); - String value = header.substring(separator + 1); - if (isMediaTypeHeader(key)) { - List requestMediaTypes = MediaType.parseMediaTypes(request.getHeader(key)); - List valueMediaTypes = MediaType.parseMediaTypes(value); - boolean found = false; - for (Iterator valIter = valueMediaTypes.iterator(); valIter.hasNext() && !found;) { - MediaType valueMediaType = valIter.next(); - for (Iterator reqIter = requestMediaTypes.iterator(); - reqIter.hasNext() && !found;) { - MediaType requestMediaType = reqIter.next(); - if (valueMediaType.includes(requestMediaType)) { - found = true; - } - } + /** + * Check whether the given request matches the specified header conditions. + * + * @param headers the header conditions, following + * {@link org.springframework.web.bind.annotation.RequestMapping#headers() RequestMapping.headers()} + * @param request the current HTTP request to check + */ + public static boolean checkHeaders(String[] headers, HttpServletRequest request) { + if (!ObjectUtils.isEmpty(headers)) { + for (String header : headers) { + int separator = header.indexOf('='); + if (separator == -1) { + if (header.startsWith("!")) { + if (request.getHeader(header.substring(1)) != null) { + return false; + } + } else if (request.getHeader(header) == null) { + return false; + } + } else { + boolean negated = separator > 0 && header.charAt(separator - 1) == '!'; + String key = !negated ? header.substring(0, separator) : header.substring(0, separator - 1); + String value = header.substring(separator + 1); + if (isMediaTypeHeader(key)) { + List requestMediaTypes = MediaType.parseMediaTypes(request.getHeader(key)); + List valueMediaTypes = MediaType.parseMediaTypes(value); + boolean found = false; + for (Iterator valIter = valueMediaTypes.iterator(); valIter.hasNext() && !found;) { + MediaType valueMediaType = valIter.next(); + for (Iterator reqIter = requestMediaTypes.iterator(); + reqIter.hasNext() && !found;) { + MediaType requestMediaType = reqIter.next(); + if (valueMediaType.includes(requestMediaType)) { + found = true; + } + } - } - if (!found) { - return negated; - } - } - else if (!value.equals(request.getHeader(key))) { - return negated; - } - } - } - } - return true; - } + } + if (!found) { + return negated; + } + } else if (!value.equals(request.getHeader(key))) { + return negated; + } + } + } + } + return true; + } - private static boolean isMediaTypeHeader(String headerName) { - return "Accept".equalsIgnoreCase(headerName) || "Content-Type".equalsIgnoreCase(headerName); - } + private static boolean isMediaTypeHeader(String headerName) { + return "Accept".equalsIgnoreCase(headerName) || "Content-Type".equalsIgnoreCase(headerName); + } } diff --git a/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/mvc/annotation/support/InterceptingHandlerMethodInvoker.java b/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/mvc/annotation/support/InterceptingHandlerMethodInvoker.java index 8918ace3b..76abcbc31 100644 --- a/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/mvc/annotation/support/InterceptingHandlerMethodInvoker.java +++ b/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/mvc/annotation/support/InterceptingHandlerMethodInvoker.java @@ -17,68 +17,30 @@ package org.springframework.data.document.web.servlet.mvc.annotation.support; import java.lang.annotation.Annotation; -import java.lang.reflect.Array; -import java.lang.reflect.GenericArrayType; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.lang.reflect.*; +import java.util.*; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Value; -import org.springframework.core.BridgeMethodResolver; -import org.springframework.core.Conventions; -import org.springframework.core.GenericTypeResolver; -import org.springframework.core.MethodParameter; -import org.springframework.core.ParameterNameDiscoverer; +import org.springframework.core.*; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.data.document.web.servlet.ActionInterceptor; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpInputMessage; -import org.springframework.http.HttpOutputMessage; -import org.springframework.http.MediaType; +import org.springframework.http.*; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.ui.ExtendedModelMap; import org.springframework.ui.Model; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.util.ReflectionUtils; +import org.springframework.util.*; import org.springframework.validation.BindException; import org.springframework.validation.BindingResult; import org.springframework.validation.Errors; import org.springframework.web.HttpMediaTypeNotSupportedException; import org.springframework.web.bind.WebDataBinder; -import org.springframework.web.bind.annotation.CookieValue; -import org.springframework.web.bind.annotation.InitBinder; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ValueConstants; +import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.support.HandlerMethodInvocationException; import org.springframework.web.bind.annotation.support.HandlerMethodResolver; -import org.springframework.web.bind.support.DefaultSessionAttributeStore; -import org.springframework.web.bind.support.SessionAttributeStore; -import org.springframework.web.bind.support.SessionStatus; -import org.springframework.web.bind.support.SimpleSessionStatus; -import org.springframework.web.bind.support.WebArgumentResolver; -import org.springframework.web.bind.support.WebBindingInitializer; -import org.springframework.web.bind.support.WebRequestDataBinder; +import org.springframework.web.bind.support.*; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.WebRequest; import org.springframework.web.multipart.MultipartFile; @@ -87,819 +49,780 @@ import org.springframework.web.multipart.MultipartRequest; /** * Support class for invoking an annotated handler method. Operates on the introspection results of a {@link * HandlerMethodResolver} for a specific handler type. - * + *

      *

      Used by {@link org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter} and {@link * org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter}. * * @author Juergen Hoeller * @author Arjen Poutsma - * @since 2.5.2 * @see #invokeHandlerMethod + * @since 2.5.2 */ public class InterceptingHandlerMethodInvoker { - private static final String MODEL_KEY_PREFIX_STALE = SessionAttributeStore.class.getName() + ".STALE."; - - /** We'll create a lot of these objects, so we don't want a new logger every time. */ - private static final Log logger = LogFactory.getLog(InterceptingHandlerMethodInvoker.class); - - protected final HandlerMethodResolver methodResolver; - - private final WebBindingInitializer bindingInitializer; - - protected final SessionAttributeStore sessionAttributeStore; - - private final ParameterNameDiscoverer parameterNameDiscoverer; - - private final WebArgumentResolver[] customArgumentResolvers; - - private final HttpMessageConverter[] messageConverters; - - private final ActionInterceptor[] actionInterceptors; - - private final SimpleSessionStatus sessionStatus = new SimpleSessionStatus(); - - - public InterceptingHandlerMethodInvoker(HandlerMethodResolver methodResolver) { - this(methodResolver, null); - } - - public InterceptingHandlerMethodInvoker(HandlerMethodResolver methodResolver, WebBindingInitializer bindingInitializer) { - this(methodResolver, bindingInitializer, new DefaultSessionAttributeStore(), null, null, null, null); - } - - public InterceptingHandlerMethodInvoker(HandlerMethodResolver methodResolver, WebBindingInitializer bindingInitializer, - SessionAttributeStore sessionAttributeStore, ParameterNameDiscoverer parameterNameDiscoverer, - WebArgumentResolver[] customArgumentResolvers, HttpMessageConverter[] messageConverters, ActionInterceptor[] actionInterceptors) { - - this.methodResolver = methodResolver; - this.bindingInitializer = bindingInitializer; - this.sessionAttributeStore = sessionAttributeStore; - this.parameterNameDiscoverer = parameterNameDiscoverer; - this.customArgumentResolvers = customArgumentResolvers; - this.messageConverters = messageConverters; - this.actionInterceptors = actionInterceptors; - } - - protected ActionInterceptor[] getActionInterceptors() { - return actionInterceptors; - } - - - public final Object invokeHandlerMethod(Method handlerMethod, Object handler, - NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception { - - Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod); - try { - boolean debug = logger.isDebugEnabled(); - for (String attrName : this.methodResolver.getActualSessionAttributeNames()) { - Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName); - if (attrValue != null) { - implicitModel.addAttribute(attrName, attrValue); - } - } - for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) { - Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod); - Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel); - if (debug) { - logger.debug("Invoking model attribute method: " + attributeMethodToInvoke); - } - String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value(); - if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) { - continue; - } - ReflectionUtils.makeAccessible(attributeMethodToInvoke); - Object attrValue = attributeMethodToInvoke.invoke(handler, args); - if ("".equals(attrName)) { - Class resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass()); - attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue); - } - if (!implicitModel.containsAttribute(attrName)) { - implicitModel.addAttribute(attrName, attrValue); - } - } - Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel); - if (debug) { - logger.debug("Invoking request handler method: " + handlerMethodToInvoke); - } - ReflectionUtils.makeAccessible(handlerMethodToInvoke); - return handlerMethodToInvoke.invoke(handler, args); - } - catch (IllegalStateException ex) { - // Internal assertion failed (e.g. invalid signature): - // throw exception with full handler method context... - throw new HandlerMethodInvocationException(handlerMethodToInvoke, ex); - } - catch (InvocationTargetException ex) { - // User-defined @ModelAttribute/@InitBinder/@RequestMapping method threw an exception... - ReflectionUtils.rethrowException(ex.getTargetException()); - return null; - } - } - - public final void updateModelAttributes(Object handler, Map mavModel, - ExtendedModelMap implicitModel, NativeWebRequest webRequest) throws Exception { - - if (this.methodResolver.hasSessionAttributes() && this.sessionStatus.isComplete()) { - for (String attrName : this.methodResolver.getActualSessionAttributeNames()) { - this.sessionAttributeStore.cleanupAttribute(webRequest, attrName); - } - } - - // Expose model attributes as session attributes, if required. - // Expose BindingResults for all attributes, making custom editors available. - Map model = (mavModel != null ? mavModel : implicitModel); - if (model != null) { - try { - String[] originalAttrNames = model.keySet().toArray(new String[model.size()]); - for (String attrName : originalAttrNames) { - Object attrValue = model.get(attrName); - boolean isSessionAttr = this.methodResolver.isSessionAttribute( - attrName, (attrValue != null ? attrValue.getClass() : null)); - if (isSessionAttr) { - if (this.sessionStatus.isComplete()) { - implicitModel.put(MODEL_KEY_PREFIX_STALE + attrName, Boolean.TRUE); - } - else if (!implicitModel.containsKey(MODEL_KEY_PREFIX_STALE + attrName)) { - this.sessionAttributeStore.storeAttribute(webRequest, attrName, attrValue); - } - } - if (!attrName.startsWith(BindingResult.MODEL_KEY_PREFIX) && - (isSessionAttr || isBindingCandidate(attrValue))) { - String bindingResultKey = BindingResult.MODEL_KEY_PREFIX + attrName; - if (mavModel != null && !model.containsKey(bindingResultKey)) { - WebDataBinder binder = createBinder(webRequest, attrValue, attrName); - initBinder(handler, attrName, binder, webRequest); - mavModel.put(bindingResultKey, binder.getBindingResult()); - } - } - } - } - catch (InvocationTargetException ex) { - // User-defined @InitBinder method threw an exception... - ReflectionUtils.rethrowException(ex.getTargetException()); - } - } - } - - - protected Object[] resolveHandlerArguments(Method handlerMethod, Object handler, - NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception { - - Class[] paramTypes = handlerMethod.getParameterTypes(); - Object[] args = new Object[paramTypes.length]; - - for (int i = 0; i < args.length; i++) { - MethodParameter methodParam = new MethodParameter(handlerMethod, i); - methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer); - GenericTypeResolver.resolveParameterType(methodParam, handler.getClass()); - String paramName = null; - String headerName = null; - boolean requestBodyFound = false; - String cookieName = null; - String pathVarName = null; - String attrName = null; - boolean required = false; - String defaultValue = null; - boolean validate = false; - int annotationsFound = 0; - Annotation[] paramAnns = methodParam.getParameterAnnotations(); - - for (Annotation paramAnn : paramAnns) { - if (RequestParam.class.isInstance(paramAnn)) { - RequestParam requestParam = (RequestParam) paramAnn; - paramName = requestParam.value(); - required = requestParam.required(); - defaultValue = parseDefaultValueAttribute(requestParam.defaultValue()); - annotationsFound++; - } - else if (RequestHeader.class.isInstance(paramAnn)) { - RequestHeader requestHeader = (RequestHeader) paramAnn; - headerName = requestHeader.value(); - required = requestHeader.required(); - defaultValue = parseDefaultValueAttribute(requestHeader.defaultValue()); - annotationsFound++; - } - else if (RequestBody.class.isInstance(paramAnn)) { - requestBodyFound = true; - annotationsFound++; - } - else if (CookieValue.class.isInstance(paramAnn)) { - CookieValue cookieValue = (CookieValue) paramAnn; - cookieName = cookieValue.value(); - required = cookieValue.required(); - defaultValue = parseDefaultValueAttribute(cookieValue.defaultValue()); - annotationsFound++; - } - else if (PathVariable.class.isInstance(paramAnn)) { - PathVariable pathVar = (PathVariable) paramAnn; - pathVarName = pathVar.value(); - annotationsFound++; - } - else if (ModelAttribute.class.isInstance(paramAnn)) { - ModelAttribute attr = (ModelAttribute) paramAnn; - attrName = attr.value(); - annotationsFound++; - } - else if (Value.class.isInstance(paramAnn)) { - defaultValue = ((Value) paramAnn).value(); - } - else if ("Valid".equals(paramAnn.annotationType().getSimpleName())) { - validate = true; - } - } - - if (annotationsFound > 1) { - throw new IllegalStateException("Handler parameter annotations are exclusive choices - " + - "do not specify more than one such annotation on the same parameter: " + handlerMethod); - } - - if (annotationsFound == 0) { - Object argValue = resolveCommonArgument(methodParam, webRequest); - if (argValue != WebArgumentResolver.UNRESOLVED) { - args[i] = argValue; - } - else if (defaultValue != null) { - args[i] = resolveDefaultValue(defaultValue); - } - else { - Class paramType = methodParam.getParameterType(); - if (Model.class.isAssignableFrom(paramType) || Map.class.isAssignableFrom(paramType)) { - args[i] = implicitModel; - } - else if (SessionStatus.class.isAssignableFrom(paramType)) { - args[i] = this.sessionStatus; - } - else if (HttpEntity.class.isAssignableFrom(paramType)) { - args[i] = resolveHttpEntityRequest(methodParam, webRequest); - } - else if (Errors.class.isAssignableFrom(paramType)) { - throw new IllegalStateException("Errors/BindingResult argument declared " + - "without preceding model attribute. Check your handler method signature!"); - } - else if (BeanUtils.isSimpleProperty(paramType)) { - paramName = ""; - } - else { - attrName = ""; - } - } - } - - if (paramName != null) { - args[i] = resolveRequestParam(paramName, required, defaultValue, methodParam, webRequest, handler); - } - else if (headerName != null) { - args[i] = resolveRequestHeader(headerName, required, defaultValue, methodParam, webRequest, handler); - } - else if (requestBodyFound) { - args[i] = resolveRequestBody(methodParam, webRequest, handler); - } - else if (cookieName != null) { - args[i] = resolveCookieValue(cookieName, required, defaultValue, methodParam, webRequest, handler); - } - else if (pathVarName != null) { - args[i] = resolvePathVariable(pathVarName, methodParam, webRequest, handler); - } - else if (attrName != null) { - WebDataBinder binder = - resolveModelAttribute(attrName, methodParam, implicitModel, webRequest, handler); - boolean assignBindingResult = (args.length > i + 1 && Errors.class.isAssignableFrom(paramTypes[i + 1])); - if (binder.getTarget() != null) { - doBind(binder, webRequest, validate, !assignBindingResult); - } - args[i] = binder.getTarget(); - if (assignBindingResult) { - args[i + 1] = binder.getBindingResult(); - i++; - } - implicitModel.putAll(binder.getBindingResult().getModel()); - } - } - - return args; - } - - protected void initBinder(Object handler, String attrName, WebDataBinder binder, NativeWebRequest webRequest) - throws Exception { - - if (this.bindingInitializer != null) { - this.bindingInitializer.initBinder(binder, webRequest); - } - if (handler != null) { - Set initBinderMethods = this.methodResolver.getInitBinderMethods(); - if (!initBinderMethods.isEmpty()) { - boolean debug = logger.isDebugEnabled(); - for (Method initBinderMethod : initBinderMethods) { - Method methodToInvoke = BridgeMethodResolver.findBridgedMethod(initBinderMethod); - String[] targetNames = AnnotationUtils.findAnnotation(initBinderMethod, InitBinder.class).value(); - if (targetNames.length == 0 || Arrays.asList(targetNames).contains(attrName)) { - Object[] initBinderArgs = - resolveInitBinderArguments(handler, methodToInvoke, binder, webRequest); - if (debug) { - logger.debug("Invoking init-binder method: " + methodToInvoke); - } - ReflectionUtils.makeAccessible(methodToInvoke); - Object returnValue = methodToInvoke.invoke(handler, initBinderArgs); - if (returnValue != null) { - throw new IllegalStateException( - "InitBinder methods must not have a return value: " + methodToInvoke); - } - } - } - } - } - } - - private Object[] resolveInitBinderArguments(Object handler, Method initBinderMethod, - WebDataBinder binder, NativeWebRequest webRequest) throws Exception { - - Class[] initBinderParams = initBinderMethod.getParameterTypes(); - Object[] initBinderArgs = new Object[initBinderParams.length]; - - for (int i = 0; i < initBinderArgs.length; i++) { - MethodParameter methodParam = new MethodParameter(initBinderMethod, i); - methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer); - GenericTypeResolver.resolveParameterType(methodParam, handler.getClass()); - String paramName = null; - boolean paramRequired = false; - String paramDefaultValue = null; - String pathVarName = null; - Annotation[] paramAnns = methodParam.getParameterAnnotations(); - - for (Annotation paramAnn : paramAnns) { - if (RequestParam.class.isInstance(paramAnn)) { - RequestParam requestParam = (RequestParam) paramAnn; - paramName = requestParam.value(); - paramRequired = requestParam.required(); - paramDefaultValue = parseDefaultValueAttribute(requestParam.defaultValue()); - break; - } - else if (ModelAttribute.class.isInstance(paramAnn)) { - throw new IllegalStateException( - "@ModelAttribute is not supported on @InitBinder methods: " + initBinderMethod); - } - else if (PathVariable.class.isInstance(paramAnn)) { - PathVariable pathVar = (PathVariable) paramAnn; - pathVarName = pathVar.value(); - } - } - - if (paramName == null && pathVarName == null) { - Object argValue = resolveCommonArgument(methodParam, webRequest); - if (argValue != WebArgumentResolver.UNRESOLVED) { - initBinderArgs[i] = argValue; - } - else { - Class paramType = initBinderParams[i]; - if (paramType.isInstance(binder)) { - initBinderArgs[i] = binder; - } - else if (BeanUtils.isSimpleProperty(paramType)) { - paramName = ""; - } - else { - throw new IllegalStateException("Unsupported argument [" + paramType.getName() + - "] for @InitBinder method: " + initBinderMethod); - } - } - } - - if (paramName != null) { - initBinderArgs[i] = - resolveRequestParam(paramName, paramRequired, paramDefaultValue, methodParam, webRequest, null); - } - else if (pathVarName != null) { - initBinderArgs[i] = resolvePathVariable(pathVarName, methodParam, webRequest, null); - } - } - - return initBinderArgs; - } - - @SuppressWarnings("unchecked") - private Object resolveRequestParam(String paramName, boolean required, String defaultValue, - MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall) - throws Exception { - - Class paramType = methodParam.getParameterType(); - if (Map.class.isAssignableFrom(paramType) && paramName.length() == 0) { - return resolveRequestParamMap((Class) paramType, webRequest); - } - if (paramName.length() == 0) { - paramName = getRequiredParameterName(methodParam); - } - Object paramValue = null; - MultipartRequest multipartRequest = webRequest.getNativeRequest(MultipartRequest.class); - if (multipartRequest != null) { - List files = multipartRequest.getFiles(paramName); - if (!files.isEmpty()) { - if (files.size() == 1 && !paramType.isArray() && !Collection.class.isAssignableFrom(paramType)) { - paramValue = files.get(0); - } - else { - paramValue = files; - } - } - } - if (paramValue == null) { - String[] paramValues = webRequest.getParameterValues(paramName); - if (paramValues != null) { - if (paramValues.length == 1 && !paramType.isArray() && !Collection.class.isAssignableFrom(paramType)) { - paramValue = paramValues[0]; - } - else { - paramValue = paramValues; - } - } - } - if (paramValue == null) { - if (defaultValue != null) { - paramValue = resolveDefaultValue(defaultValue); - } - else if (required) { - raiseMissingParameterException(paramName, paramType); - } - paramValue = checkValue(paramName, paramValue, paramType); - } - WebDataBinder binder = createBinder(webRequest, null, paramName); - initBinder(handlerForInitBinderCall, paramName, binder, webRequest); - return binder.convertIfNecessary(paramValue, paramType, methodParam); - } - - private Map resolveRequestParamMap(Class mapType, NativeWebRequest webRequest) { - Map parameterMap = webRequest.getParameterMap(); - if (MultiValueMap.class.isAssignableFrom(mapType)) { - MultiValueMap result = new LinkedMultiValueMap(parameterMap.size()); - for (Map.Entry entry : parameterMap.entrySet()) { - for (String value : entry.getValue()) { - result.add(entry.getKey(), value); - } - } - return result; - } - else { - Map result = new LinkedHashMap(parameterMap.size()); - for (Map.Entry entry : parameterMap.entrySet()) { - if (entry.getValue().length > 0) { - result.put(entry.getKey(), entry.getValue()[0]); - } - } - return result; - } - } - - @SuppressWarnings("unchecked") - private Object resolveRequestHeader(String headerName, boolean required, String defaultValue, - MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall) - throws Exception { - - Class paramType = methodParam.getParameterType(); - if (Map.class.isAssignableFrom(paramType)) { - return resolveRequestHeaderMap((Class) paramType, webRequest); - } - if (headerName.length() == 0) { - headerName = getRequiredParameterName(methodParam); - } - Object headerValue = null; - String[] headerValues = webRequest.getHeaderValues(headerName); - if (headerValues != null) { - headerValue = (headerValues.length == 1 ? headerValues[0] : headerValues); - } - if (headerValue == null) { - if (defaultValue != null) { - headerValue = resolveDefaultValue(defaultValue); - } - else if (required) { - raiseMissingHeaderException(headerName, paramType); - } - headerValue = checkValue(headerName, headerValue, paramType); - } - WebDataBinder binder = createBinder(webRequest, null, headerName); - initBinder(handlerForInitBinderCall, headerName, binder, webRequest); - return binder.convertIfNecessary(headerValue, paramType, methodParam); - } - - private Map resolveRequestHeaderMap(Class mapType, NativeWebRequest webRequest) { - if (MultiValueMap.class.isAssignableFrom(mapType)) { - MultiValueMap result; - if (HttpHeaders.class.isAssignableFrom(mapType)) { - result = new HttpHeaders(); - } - else { - result = new LinkedMultiValueMap(); - } - for (Iterator iterator = webRequest.getHeaderNames(); iterator.hasNext();) { - String headerName = iterator.next(); - for (String headerValue : webRequest.getHeaderValues(headerName)) { - result.add(headerName, headerValue); - } - } - return result; - } - else { - Map result = new LinkedHashMap(); - for (Iterator iterator = webRequest.getHeaderNames(); iterator.hasNext();) { - String headerName = iterator.next(); - String headerValue = webRequest.getHeader(headerName); - result.put(headerName, headerValue); - } - return result; - } - } - - /** - * Resolves the given {@link RequestBody @RequestBody} annotation. - */ - protected Object resolveRequestBody(MethodParameter methodParam, NativeWebRequest webRequest, Object handler) - throws Exception { - - return readWithMessageConverters(methodParam, createHttpInputMessage(webRequest), methodParam.getParameterType()); - } - - private HttpEntity resolveHttpEntityRequest(MethodParameter methodParam, NativeWebRequest webRequest) - throws Exception { - - HttpInputMessage inputMessage = createHttpInputMessage(webRequest); - Class paramType = getHttpEntityType(methodParam); - Object body = readWithMessageConverters(methodParam, inputMessage, paramType); - return new HttpEntity(body, inputMessage.getHeaders()); - } - - private Object readWithMessageConverters(MethodParameter methodParam, HttpInputMessage inputMessage, Class paramType) - throws Exception { - - MediaType contentType = inputMessage.getHeaders().getContentType(); - if (contentType == null) { - StringBuilder builder = new StringBuilder(ClassUtils.getShortName(methodParam.getParameterType())); - String paramName = methodParam.getParameterName(); - if (paramName != null) { - builder.append(' '); - builder.append(paramName); - } - throw new HttpMediaTypeNotSupportedException( - "Cannot extract parameter (" + builder.toString() + "): no Content-Type found"); - } - - List allSupportedMediaTypes = new ArrayList(); - if (this.messageConverters != null) { - for (HttpMessageConverter messageConverter : this.messageConverters) { - allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes()); - if (messageConverter.canRead(paramType, contentType)) { - if (logger.isDebugEnabled()) { - logger.debug("Reading [" + paramType.getName() + "] as \"" + contentType - +"\" using [" + messageConverter + "]"); - } - return messageConverter.read(paramType, inputMessage); - } - } - } - throw new HttpMediaTypeNotSupportedException(contentType, allSupportedMediaTypes); - } - - private Class getHttpEntityType(MethodParameter methodParam) { - Assert.isAssignable(HttpEntity.class, methodParam.getParameterType()); - ParameterizedType type = (ParameterizedType) methodParam.getGenericParameterType(); - if (type.getActualTypeArguments().length == 1) { - Type typeArgument = type.getActualTypeArguments()[0]; - if (typeArgument instanceof Class) { - return (Class) typeArgument; - } - else if (typeArgument instanceof GenericArrayType) { - Type componentType = ((GenericArrayType) typeArgument).getGenericComponentType(); - if (componentType instanceof Class) { - // Surely, there should be a nicer way to do this - Object array = Array.newInstance((Class) componentType, 0); - return array.getClass(); - } - } - } - throw new IllegalArgumentException( - "HttpEntity parameter (" + methodParam.getParameterName() + ") is not parameterized"); - - } - - private Object resolveCookieValue(String cookieName, boolean required, String defaultValue, - MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall) - throws Exception { - - Class paramType = methodParam.getParameterType(); - if (cookieName.length() == 0) { - cookieName = getRequiredParameterName(methodParam); - } - Object cookieValue = resolveCookieValue(cookieName, paramType, webRequest); - if (cookieValue == null) { - if (defaultValue != null) { - cookieValue = resolveDefaultValue(defaultValue); - } - else if (required) { - raiseMissingCookieException(cookieName, paramType); - } - cookieValue = checkValue(cookieName, cookieValue, paramType); - } - WebDataBinder binder = createBinder(webRequest, null, cookieName); - initBinder(handlerForInitBinderCall, cookieName, binder, webRequest); - return binder.convertIfNecessary(cookieValue, paramType, methodParam); - } - - /** - * Resolves the given {@link CookieValue @CookieValue} annotation. - *

      Throws an UnsupportedOperationException by default. - */ - protected Object resolveCookieValue(String cookieName, Class paramType, NativeWebRequest webRequest) - throws Exception { - - throw new UnsupportedOperationException("@CookieValue not supported"); - } - - private Object resolvePathVariable(String pathVarName, MethodParameter methodParam, - NativeWebRequest webRequest, Object handlerForInitBinderCall) throws Exception { - - Class paramType = methodParam.getParameterType(); - if (pathVarName.length() == 0) { - pathVarName = getRequiredParameterName(methodParam); - } - String pathVarValue = resolvePathVariable(pathVarName, paramType, webRequest); - WebDataBinder binder = createBinder(webRequest, null, pathVarName); - initBinder(handlerForInitBinderCall, pathVarName, binder, webRequest); - return binder.convertIfNecessary(pathVarValue, paramType, methodParam); - } - - /** - * Resolves the given {@link PathVariable @PathVariable} annotation. - *

      Throws an UnsupportedOperationException by default. - */ - protected String resolvePathVariable(String pathVarName, Class paramType, NativeWebRequest webRequest) - throws Exception { - - throw new UnsupportedOperationException("@PathVariable not supported"); - } - - private String getRequiredParameterName(MethodParameter methodParam) { - String name = methodParam.getParameterName(); - if (name == null) { - throw new IllegalStateException( - "No parameter name specified for argument of type [" + methodParam.getParameterType().getName() + - "], and no parameter name information found in class file either."); - } - return name; - } - - private Object checkValue(String name, Object value, Class paramType) { - if (value == null) { - if (boolean.class.equals(paramType)) { - return Boolean.FALSE; - } - else if (paramType.isPrimitive()) { - throw new IllegalStateException("Optional " + paramType + " parameter '" + name + - "' is not present but cannot be translated into a null value due to being declared as a " + - "primitive type. Consider declaring it as object wrapper for the corresponding primitive type."); - } - } - return value; - } - - private WebDataBinder resolveModelAttribute(String attrName, MethodParameter methodParam, - ExtendedModelMap implicitModel, NativeWebRequest webRequest, Object handler) throws Exception { - - // Bind request parameter onto object... - String name = attrName; - if ("".equals(name)) { - name = Conventions.getVariableNameForParameter(methodParam); - } - Class paramType = methodParam.getParameterType(); - Object bindObject; - if (implicitModel.containsKey(name)) { - bindObject = implicitModel.get(name); - } - else if (this.methodResolver.isSessionAttribute(name, paramType)) { - bindObject = this.sessionAttributeStore.retrieveAttribute(webRequest, name); - if (bindObject == null) { - raiseSessionRequiredException("Session attribute '" + name + "' required - not found in session"); - } - } - else { - bindObject = BeanUtils.instantiateClass(paramType); - } - WebDataBinder binder = createBinder(webRequest, bindObject, name); - initBinder(handler, name, binder, webRequest); - return binder; - } - - - /** - * Determine whether the given value qualifies as a "binding candidate", i.e. might potentially be subject to - * bean-style data binding later on. - */ - protected boolean isBindingCandidate(Object value) { - return (value != null && !value.getClass().isArray() && !(value instanceof Collection) && - !(value instanceof Map) && !BeanUtils.isSimpleValueType(value.getClass())); - } - - protected void raiseMissingParameterException(String paramName, Class paramType) throws Exception { - throw new IllegalStateException("Missing parameter '" + paramName + "' of type [" + paramType.getName() + "]"); - } - - protected void raiseMissingHeaderException(String headerName, Class paramType) throws Exception { - throw new IllegalStateException("Missing header '" + headerName + "' of type [" + paramType.getName() + "]"); - } - - protected void raiseMissingCookieException(String cookieName, Class paramType) throws Exception { - throw new IllegalStateException( - "Missing cookie value '" + cookieName + "' of type [" + paramType.getName() + "]"); - } - - protected void raiseSessionRequiredException(String message) throws Exception { - throw new IllegalStateException(message); - } - - protected WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName) - throws Exception { - - return new WebRequestDataBinder(target, objectName); - } - - private void doBind(WebDataBinder binder, NativeWebRequest webRequest, boolean validate, boolean failOnErrors) - throws Exception { - - doBind(binder, webRequest); - if (validate) { - binder.validate(); - } - if (failOnErrors && binder.getBindingResult().hasErrors()) { - throw new BindException(binder.getBindingResult()); - } - } - - protected void doBind(WebDataBinder binder, NativeWebRequest webRequest) throws Exception { - ((WebRequestDataBinder) binder).bind(webRequest); - } - - /** - * Return a {@link HttpInputMessage} for the given {@link NativeWebRequest}. - *

      Throws an UnsupportedOperation1Exception by default. - */ - protected HttpInputMessage createHttpInputMessage(NativeWebRequest webRequest) throws Exception { - throw new UnsupportedOperationException("@RequestBody not supported"); - } - - /** - * Return a {@link HttpOutputMessage} for the given {@link NativeWebRequest}. - *

      Throws an UnsupportedOperationException by default. - */ - protected HttpOutputMessage createHttpOutputMessage(NativeWebRequest webRequest) throws Exception { - throw new UnsupportedOperationException("@ResponseBody not supported"); - } - - protected String parseDefaultValueAttribute(String value) { - return (ValueConstants.DEFAULT_NONE.equals(value) ? null : value); - } - - protected Object resolveDefaultValue(String value) { - return value; - } - - protected Object resolveCommonArgument(MethodParameter methodParameter, NativeWebRequest webRequest) - throws Exception { - - // Invoke custom argument resolvers if present... - if (this.customArgumentResolvers != null) { - for (WebArgumentResolver argumentResolver : this.customArgumentResolvers) { - Object value = argumentResolver.resolveArgument(methodParameter, webRequest); - if (value != WebArgumentResolver.UNRESOLVED) { - return value; - } - } - } - - // Resolution of standard parameter types... - Class paramType = methodParameter.getParameterType(); - Object value = resolveStandardArgument(paramType, webRequest); - if (value != WebArgumentResolver.UNRESOLVED && !ClassUtils.isAssignableValue(paramType, value)) { - throw new IllegalStateException("Standard argument type [" + paramType.getName() + - "] resolved to incompatible value of type [" + (value != null ? value.getClass() : null) + - "]. Consider declaring the argument type in a less specific fashion."); - } - return value; - } - - protected Object resolveStandardArgument(Class parameterType, NativeWebRequest webRequest) throws Exception { - if (WebRequest.class.isAssignableFrom(parameterType)) { - return webRequest; - } - return WebArgumentResolver.UNRESOLVED; - } - - protected final void addReturnValueAsModelAttribute(Method handlerMethod, Class handlerType, - Object returnValue, ExtendedModelMap implicitModel) { - - ModelAttribute attr = AnnotationUtils.findAnnotation(handlerMethod, ModelAttribute.class); - String attrName = (attr != null ? attr.value() : ""); - if ("".equals(attrName)) { - Class resolvedType = GenericTypeResolver.resolveReturnType(handlerMethod, handlerType); - attrName = Conventions.getVariableNameForReturnType(handlerMethod, resolvedType, returnValue); - } - implicitModel.addAttribute(attrName, returnValue); - } + private static final String MODEL_KEY_PREFIX_STALE = SessionAttributeStore.class.getName() + ".STALE."; + + /** + * We'll create a lot of these objects, so we don't want a new logger every time. + */ + private static final Log logger = LogFactory.getLog(InterceptingHandlerMethodInvoker.class); + + protected final HandlerMethodResolver methodResolver; + + private final WebBindingInitializer bindingInitializer; + + protected final SessionAttributeStore sessionAttributeStore; + + private final ParameterNameDiscoverer parameterNameDiscoverer; + + private final WebArgumentResolver[] customArgumentResolvers; + + private final HttpMessageConverter[] messageConverters; + + private final ActionInterceptor[] actionInterceptors; + + private final SimpleSessionStatus sessionStatus = new SimpleSessionStatus(); + + + public InterceptingHandlerMethodInvoker(HandlerMethodResolver methodResolver) { + this(methodResolver, null); + } + + public InterceptingHandlerMethodInvoker(HandlerMethodResolver methodResolver, WebBindingInitializer bindingInitializer) { + this(methodResolver, bindingInitializer, new DefaultSessionAttributeStore(), null, null, null, null); + } + + public InterceptingHandlerMethodInvoker(HandlerMethodResolver methodResolver, WebBindingInitializer bindingInitializer, + SessionAttributeStore sessionAttributeStore, ParameterNameDiscoverer parameterNameDiscoverer, + WebArgumentResolver[] customArgumentResolvers, HttpMessageConverter[] messageConverters, ActionInterceptor[] actionInterceptors) { + + this.methodResolver = methodResolver; + this.bindingInitializer = bindingInitializer; + this.sessionAttributeStore = sessionAttributeStore; + this.parameterNameDiscoverer = parameterNameDiscoverer; + this.customArgumentResolvers = customArgumentResolvers; + this.messageConverters = messageConverters; + this.actionInterceptors = actionInterceptors; + } + + protected ActionInterceptor[] getActionInterceptors() { + return actionInterceptors; + } + + + public final Object invokeHandlerMethod(Method handlerMethod, Object handler, + NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception { + + Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod); + try { + boolean debug = logger.isDebugEnabled(); + for (String attrName : this.methodResolver.getActualSessionAttributeNames()) { + Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName); + if (attrValue != null) { + implicitModel.addAttribute(attrName, attrValue); + } + } + for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) { + Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod); + Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel); + if (debug) { + logger.debug("Invoking model attribute method: " + attributeMethodToInvoke); + } + String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value(); + if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) { + continue; + } + ReflectionUtils.makeAccessible(attributeMethodToInvoke); + Object attrValue = attributeMethodToInvoke.invoke(handler, args); + if ("".equals(attrName)) { + Class resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass()); + attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue); + } + if (!implicitModel.containsAttribute(attrName)) { + implicitModel.addAttribute(attrName, attrValue); + } + } + Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel); + if (debug) { + logger.debug("Invoking request handler method: " + handlerMethodToInvoke); + } + ReflectionUtils.makeAccessible(handlerMethodToInvoke); + return handlerMethodToInvoke.invoke(handler, args); + } catch (IllegalStateException ex) { + // Internal assertion failed (e.g. invalid signature): + // throw exception with full handler method context... + throw new HandlerMethodInvocationException(handlerMethodToInvoke, ex); + } catch (InvocationTargetException ex) { + // User-defined @ModelAttribute/@InitBinder/@RequestMapping method threw an exception... + ReflectionUtils.rethrowException(ex.getTargetException()); + return null; + } + } + + public final void updateModelAttributes(Object handler, Map mavModel, + ExtendedModelMap implicitModel, NativeWebRequest webRequest) throws Exception { + + if (this.methodResolver.hasSessionAttributes() && this.sessionStatus.isComplete()) { + for (String attrName : this.methodResolver.getActualSessionAttributeNames()) { + this.sessionAttributeStore.cleanupAttribute(webRequest, attrName); + } + } + + // Expose model attributes as session attributes, if required. + // Expose BindingResults for all attributes, making custom editors available. + Map model = (mavModel != null ? mavModel : implicitModel); + if (model != null) { + try { + String[] originalAttrNames = model.keySet().toArray(new String[model.size()]); + for (String attrName : originalAttrNames) { + Object attrValue = model.get(attrName); + boolean isSessionAttr = this.methodResolver.isSessionAttribute( + attrName, (attrValue != null ? attrValue.getClass() : null)); + if (isSessionAttr) { + if (this.sessionStatus.isComplete()) { + implicitModel.put(MODEL_KEY_PREFIX_STALE + attrName, Boolean.TRUE); + } else if (!implicitModel.containsKey(MODEL_KEY_PREFIX_STALE + attrName)) { + this.sessionAttributeStore.storeAttribute(webRequest, attrName, attrValue); + } + } + if (!attrName.startsWith(BindingResult.MODEL_KEY_PREFIX) && + (isSessionAttr || isBindingCandidate(attrValue))) { + String bindingResultKey = BindingResult.MODEL_KEY_PREFIX + attrName; + if (mavModel != null && !model.containsKey(bindingResultKey)) { + WebDataBinder binder = createBinder(webRequest, attrValue, attrName); + initBinder(handler, attrName, binder, webRequest); + mavModel.put(bindingResultKey, binder.getBindingResult()); + } + } + } + } catch (InvocationTargetException ex) { + // User-defined @InitBinder method threw an exception... + ReflectionUtils.rethrowException(ex.getTargetException()); + } + } + } + + + protected Object[] resolveHandlerArguments(Method handlerMethod, Object handler, + NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception { + + Class[] paramTypes = handlerMethod.getParameterTypes(); + Object[] args = new Object[paramTypes.length]; + + for (int i = 0; i < args.length; i++) { + MethodParameter methodParam = new MethodParameter(handlerMethod, i); + methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer); + GenericTypeResolver.resolveParameterType(methodParam, handler.getClass()); + String paramName = null; + String headerName = null; + boolean requestBodyFound = false; + String cookieName = null; + String pathVarName = null; + String attrName = null; + boolean required = false; + String defaultValue = null; + boolean validate = false; + int annotationsFound = 0; + Annotation[] paramAnns = methodParam.getParameterAnnotations(); + + for (Annotation paramAnn : paramAnns) { + if (RequestParam.class.isInstance(paramAnn)) { + RequestParam requestParam = (RequestParam) paramAnn; + paramName = requestParam.value(); + required = requestParam.required(); + defaultValue = parseDefaultValueAttribute(requestParam.defaultValue()); + annotationsFound++; + } else if (RequestHeader.class.isInstance(paramAnn)) { + RequestHeader requestHeader = (RequestHeader) paramAnn; + headerName = requestHeader.value(); + required = requestHeader.required(); + defaultValue = parseDefaultValueAttribute(requestHeader.defaultValue()); + annotationsFound++; + } else if (RequestBody.class.isInstance(paramAnn)) { + requestBodyFound = true; + annotationsFound++; + } else if (CookieValue.class.isInstance(paramAnn)) { + CookieValue cookieValue = (CookieValue) paramAnn; + cookieName = cookieValue.value(); + required = cookieValue.required(); + defaultValue = parseDefaultValueAttribute(cookieValue.defaultValue()); + annotationsFound++; + } else if (PathVariable.class.isInstance(paramAnn)) { + PathVariable pathVar = (PathVariable) paramAnn; + pathVarName = pathVar.value(); + annotationsFound++; + } else if (ModelAttribute.class.isInstance(paramAnn)) { + ModelAttribute attr = (ModelAttribute) paramAnn; + attrName = attr.value(); + annotationsFound++; + } else if (Value.class.isInstance(paramAnn)) { + defaultValue = ((Value) paramAnn).value(); + } else if ("Valid".equals(paramAnn.annotationType().getSimpleName())) { + validate = true; + } + } + + if (annotationsFound > 1) { + throw new IllegalStateException("Handler parameter annotations are exclusive choices - " + + "do not specify more than one such annotation on the same parameter: " + handlerMethod); + } + + if (annotationsFound == 0) { + Object argValue = resolveCommonArgument(methodParam, webRequest); + if (argValue != WebArgumentResolver.UNRESOLVED) { + args[i] = argValue; + } else if (defaultValue != null) { + args[i] = resolveDefaultValue(defaultValue); + } else { + Class paramType = methodParam.getParameterType(); + if (Model.class.isAssignableFrom(paramType) || Map.class.isAssignableFrom(paramType)) { + args[i] = implicitModel; + } else if (SessionStatus.class.isAssignableFrom(paramType)) { + args[i] = this.sessionStatus; + } else if (HttpEntity.class.isAssignableFrom(paramType)) { + args[i] = resolveHttpEntityRequest(methodParam, webRequest); + } else if (Errors.class.isAssignableFrom(paramType)) { + throw new IllegalStateException("Errors/BindingResult argument declared " + + "without preceding model attribute. Check your handler method signature!"); + } else if (BeanUtils.isSimpleProperty(paramType)) { + paramName = ""; + } else { + attrName = ""; + } + } + } + + if (paramName != null) { + args[i] = resolveRequestParam(paramName, required, defaultValue, methodParam, webRequest, handler); + } else if (headerName != null) { + args[i] = resolveRequestHeader(headerName, required, defaultValue, methodParam, webRequest, handler); + } else if (requestBodyFound) { + args[i] = resolveRequestBody(methodParam, webRequest, handler); + } else if (cookieName != null) { + args[i] = resolveCookieValue(cookieName, required, defaultValue, methodParam, webRequest, handler); + } else if (pathVarName != null) { + args[i] = resolvePathVariable(pathVarName, methodParam, webRequest, handler); + } else if (attrName != null) { + WebDataBinder binder = + resolveModelAttribute(attrName, methodParam, implicitModel, webRequest, handler); + boolean assignBindingResult = (args.length > i + 1 && Errors.class.isAssignableFrom(paramTypes[i + 1])); + if (binder.getTarget() != null) { + doBind(binder, webRequest, validate, !assignBindingResult); + } + args[i] = binder.getTarget(); + if (assignBindingResult) { + args[i + 1] = binder.getBindingResult(); + i++; + } + implicitModel.putAll(binder.getBindingResult().getModel()); + } + } + + return args; + } + + protected void initBinder(Object handler, String attrName, WebDataBinder binder, NativeWebRequest webRequest) + throws Exception { + + if (this.bindingInitializer != null) { + this.bindingInitializer.initBinder(binder, webRequest); + } + if (handler != null) { + Set initBinderMethods = this.methodResolver.getInitBinderMethods(); + if (!initBinderMethods.isEmpty()) { + boolean debug = logger.isDebugEnabled(); + for (Method initBinderMethod : initBinderMethods) { + Method methodToInvoke = BridgeMethodResolver.findBridgedMethod(initBinderMethod); + String[] targetNames = AnnotationUtils.findAnnotation(initBinderMethod, InitBinder.class).value(); + if (targetNames.length == 0 || Arrays.asList(targetNames).contains(attrName)) { + Object[] initBinderArgs = + resolveInitBinderArguments(handler, methodToInvoke, binder, webRequest); + if (debug) { + logger.debug("Invoking init-binder method: " + methodToInvoke); + } + ReflectionUtils.makeAccessible(methodToInvoke); + Object returnValue = methodToInvoke.invoke(handler, initBinderArgs); + if (returnValue != null) { + throw new IllegalStateException( + "InitBinder methods must not have a return value: " + methodToInvoke); + } + } + } + } + } + } + + private Object[] resolveInitBinderArguments(Object handler, Method initBinderMethod, + WebDataBinder binder, NativeWebRequest webRequest) throws Exception { + + Class[] initBinderParams = initBinderMethod.getParameterTypes(); + Object[] initBinderArgs = new Object[initBinderParams.length]; + + for (int i = 0; i < initBinderArgs.length; i++) { + MethodParameter methodParam = new MethodParameter(initBinderMethod, i); + methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer); + GenericTypeResolver.resolveParameterType(methodParam, handler.getClass()); + String paramName = null; + boolean paramRequired = false; + String paramDefaultValue = null; + String pathVarName = null; + Annotation[] paramAnns = methodParam.getParameterAnnotations(); + + for (Annotation paramAnn : paramAnns) { + if (RequestParam.class.isInstance(paramAnn)) { + RequestParam requestParam = (RequestParam) paramAnn; + paramName = requestParam.value(); + paramRequired = requestParam.required(); + paramDefaultValue = parseDefaultValueAttribute(requestParam.defaultValue()); + break; + } else if (ModelAttribute.class.isInstance(paramAnn)) { + throw new IllegalStateException( + "@ModelAttribute is not supported on @InitBinder methods: " + initBinderMethod); + } else if (PathVariable.class.isInstance(paramAnn)) { + PathVariable pathVar = (PathVariable) paramAnn; + pathVarName = pathVar.value(); + } + } + + if (paramName == null && pathVarName == null) { + Object argValue = resolveCommonArgument(methodParam, webRequest); + if (argValue != WebArgumentResolver.UNRESOLVED) { + initBinderArgs[i] = argValue; + } else { + Class paramType = initBinderParams[i]; + if (paramType.isInstance(binder)) { + initBinderArgs[i] = binder; + } else if (BeanUtils.isSimpleProperty(paramType)) { + paramName = ""; + } else { + throw new IllegalStateException("Unsupported argument [" + paramType.getName() + + "] for @InitBinder method: " + initBinderMethod); + } + } + } + + if (paramName != null) { + initBinderArgs[i] = + resolveRequestParam(paramName, paramRequired, paramDefaultValue, methodParam, webRequest, null); + } else if (pathVarName != null) { + initBinderArgs[i] = resolvePathVariable(pathVarName, methodParam, webRequest, null); + } + } + + return initBinderArgs; + } + + @SuppressWarnings("unchecked") + private Object resolveRequestParam(String paramName, boolean required, String defaultValue, + MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall) + throws Exception { + + Class paramType = methodParam.getParameterType(); + if (Map.class.isAssignableFrom(paramType) && paramName.length() == 0) { + return resolveRequestParamMap((Class) paramType, webRequest); + } + if (paramName.length() == 0) { + paramName = getRequiredParameterName(methodParam); + } + Object paramValue = null; + MultipartRequest multipartRequest = webRequest.getNativeRequest(MultipartRequest.class); + if (multipartRequest != null) { + List files = multipartRequest.getFiles(paramName); + if (!files.isEmpty()) { + if (files.size() == 1 && !paramType.isArray() && !Collection.class.isAssignableFrom(paramType)) { + paramValue = files.get(0); + } else { + paramValue = files; + } + } + } + if (paramValue == null) { + String[] paramValues = webRequest.getParameterValues(paramName); + if (paramValues != null) { + if (paramValues.length == 1 && !paramType.isArray() && !Collection.class.isAssignableFrom(paramType)) { + paramValue = paramValues[0]; + } else { + paramValue = paramValues; + } + } + } + if (paramValue == null) { + if (defaultValue != null) { + paramValue = resolveDefaultValue(defaultValue); + } else if (required) { + raiseMissingParameterException(paramName, paramType); + } + paramValue = checkValue(paramName, paramValue, paramType); + } + WebDataBinder binder = createBinder(webRequest, null, paramName); + initBinder(handlerForInitBinderCall, paramName, binder, webRequest); + return binder.convertIfNecessary(paramValue, paramType, methodParam); + } + + private Map resolveRequestParamMap(Class mapType, NativeWebRequest webRequest) { + Map parameterMap = webRequest.getParameterMap(); + if (MultiValueMap.class.isAssignableFrom(mapType)) { + MultiValueMap result = new LinkedMultiValueMap(parameterMap.size()); + for (Map.Entry entry : parameterMap.entrySet()) { + for (String value : entry.getValue()) { + result.add(entry.getKey(), value); + } + } + return result; + } else { + Map result = new LinkedHashMap(parameterMap.size()); + for (Map.Entry entry : parameterMap.entrySet()) { + if (entry.getValue().length > 0) { + result.put(entry.getKey(), entry.getValue()[0]); + } + } + return result; + } + } + + @SuppressWarnings("unchecked") + private Object resolveRequestHeader(String headerName, boolean required, String defaultValue, + MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall) + throws Exception { + + Class paramType = methodParam.getParameterType(); + if (Map.class.isAssignableFrom(paramType)) { + return resolveRequestHeaderMap((Class) paramType, webRequest); + } + if (headerName.length() == 0) { + headerName = getRequiredParameterName(methodParam); + } + Object headerValue = null; + String[] headerValues = webRequest.getHeaderValues(headerName); + if (headerValues != null) { + headerValue = (headerValues.length == 1 ? headerValues[0] : headerValues); + } + if (headerValue == null) { + if (defaultValue != null) { + headerValue = resolveDefaultValue(defaultValue); + } else if (required) { + raiseMissingHeaderException(headerName, paramType); + } + headerValue = checkValue(headerName, headerValue, paramType); + } + WebDataBinder binder = createBinder(webRequest, null, headerName); + initBinder(handlerForInitBinderCall, headerName, binder, webRequest); + return binder.convertIfNecessary(headerValue, paramType, methodParam); + } + + private Map resolveRequestHeaderMap(Class mapType, NativeWebRequest webRequest) { + if (MultiValueMap.class.isAssignableFrom(mapType)) { + MultiValueMap result; + if (HttpHeaders.class.isAssignableFrom(mapType)) { + result = new HttpHeaders(); + } else { + result = new LinkedMultiValueMap(); + } + for (Iterator iterator = webRequest.getHeaderNames(); iterator.hasNext();) { + String headerName = iterator.next(); + for (String headerValue : webRequest.getHeaderValues(headerName)) { + result.add(headerName, headerValue); + } + } + return result; + } else { + Map result = new LinkedHashMap(); + for (Iterator iterator = webRequest.getHeaderNames(); iterator.hasNext();) { + String headerName = iterator.next(); + String headerValue = webRequest.getHeader(headerName); + result.put(headerName, headerValue); + } + return result; + } + } + + /** + * Resolves the given {@link RequestBody @RequestBody} annotation. + */ + protected Object resolveRequestBody(MethodParameter methodParam, NativeWebRequest webRequest, Object handler) + throws Exception { + + return readWithMessageConverters(methodParam, createHttpInputMessage(webRequest), methodParam.getParameterType()); + } + + private HttpEntity resolveHttpEntityRequest(MethodParameter methodParam, NativeWebRequest webRequest) + throws Exception { + + HttpInputMessage inputMessage = createHttpInputMessage(webRequest); + Class paramType = getHttpEntityType(methodParam); + Object body = readWithMessageConverters(methodParam, inputMessage, paramType); + return new HttpEntity(body, inputMessage.getHeaders()); + } + + private Object readWithMessageConverters(MethodParameter methodParam, HttpInputMessage inputMessage, Class paramType) + throws Exception { + + MediaType contentType = inputMessage.getHeaders().getContentType(); + if (contentType == null) { + StringBuilder builder = new StringBuilder(ClassUtils.getShortName(methodParam.getParameterType())); + String paramName = methodParam.getParameterName(); + if (paramName != null) { + builder.append(' '); + builder.append(paramName); + } + throw new HttpMediaTypeNotSupportedException( + "Cannot extract parameter (" + builder.toString() + "): no Content-Type found"); + } + + List allSupportedMediaTypes = new ArrayList(); + if (this.messageConverters != null) { + for (HttpMessageConverter messageConverter : this.messageConverters) { + allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes()); + if (messageConverter.canRead(paramType, contentType)) { + if (logger.isDebugEnabled()) { + logger.debug("Reading [" + paramType.getName() + "] as \"" + contentType + + "\" using [" + messageConverter + "]"); + } + return messageConverter.read(paramType, inputMessage); + } + } + } + throw new HttpMediaTypeNotSupportedException(contentType, allSupportedMediaTypes); + } + + private Class getHttpEntityType(MethodParameter methodParam) { + Assert.isAssignable(HttpEntity.class, methodParam.getParameterType()); + ParameterizedType type = (ParameterizedType) methodParam.getGenericParameterType(); + if (type.getActualTypeArguments().length == 1) { + Type typeArgument = type.getActualTypeArguments()[0]; + if (typeArgument instanceof Class) { + return (Class) typeArgument; + } else if (typeArgument instanceof GenericArrayType) { + Type componentType = ((GenericArrayType) typeArgument).getGenericComponentType(); + if (componentType instanceof Class) { + // Surely, there should be a nicer way to do this + Object array = Array.newInstance((Class) componentType, 0); + return array.getClass(); + } + } + } + throw new IllegalArgumentException( + "HttpEntity parameter (" + methodParam.getParameterName() + ") is not parameterized"); + + } + + private Object resolveCookieValue(String cookieName, boolean required, String defaultValue, + MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall) + throws Exception { + + Class paramType = methodParam.getParameterType(); + if (cookieName.length() == 0) { + cookieName = getRequiredParameterName(methodParam); + } + Object cookieValue = resolveCookieValue(cookieName, paramType, webRequest); + if (cookieValue == null) { + if (defaultValue != null) { + cookieValue = resolveDefaultValue(defaultValue); + } else if (required) { + raiseMissingCookieException(cookieName, paramType); + } + cookieValue = checkValue(cookieName, cookieValue, paramType); + } + WebDataBinder binder = createBinder(webRequest, null, cookieName); + initBinder(handlerForInitBinderCall, cookieName, binder, webRequest); + return binder.convertIfNecessary(cookieValue, paramType, methodParam); + } + + /** + * Resolves the given {@link CookieValue @CookieValue} annotation. + *

      Throws an UnsupportedOperationException by default. + */ + protected Object resolveCookieValue(String cookieName, Class paramType, NativeWebRequest webRequest) + throws Exception { + + throw new UnsupportedOperationException("@CookieValue not supported"); + } + + private Object resolvePathVariable(String pathVarName, MethodParameter methodParam, + NativeWebRequest webRequest, Object handlerForInitBinderCall) throws Exception { + + Class paramType = methodParam.getParameterType(); + if (pathVarName.length() == 0) { + pathVarName = getRequiredParameterName(methodParam); + } + String pathVarValue = resolvePathVariable(pathVarName, paramType, webRequest); + WebDataBinder binder = createBinder(webRequest, null, pathVarName); + initBinder(handlerForInitBinderCall, pathVarName, binder, webRequest); + return binder.convertIfNecessary(pathVarValue, paramType, methodParam); + } + + /** + * Resolves the given {@link PathVariable @PathVariable} annotation. + *

      Throws an UnsupportedOperationException by default. + */ + protected String resolvePathVariable(String pathVarName, Class paramType, NativeWebRequest webRequest) + throws Exception { + + throw new UnsupportedOperationException("@PathVariable not supported"); + } + + private String getRequiredParameterName(MethodParameter methodParam) { + String name = methodParam.getParameterName(); + if (name == null) { + throw new IllegalStateException( + "No parameter name specified for argument of type [" + methodParam.getParameterType().getName() + + "], and no parameter name information found in class file either."); + } + return name; + } + + private Object checkValue(String name, Object value, Class paramType) { + if (value == null) { + if (boolean.class.equals(paramType)) { + return Boolean.FALSE; + } else if (paramType.isPrimitive()) { + throw new IllegalStateException("Optional " + paramType + " parameter '" + name + + "' is not present but cannot be translated into a null value due to being declared as a " + + "primitive type. Consider declaring it as object wrapper for the corresponding primitive type."); + } + } + return value; + } + + private WebDataBinder resolveModelAttribute(String attrName, MethodParameter methodParam, + ExtendedModelMap implicitModel, NativeWebRequest webRequest, Object handler) throws Exception { + + // Bind request parameter onto object... + String name = attrName; + if ("".equals(name)) { + name = Conventions.getVariableNameForParameter(methodParam); + } + Class paramType = methodParam.getParameterType(); + Object bindObject; + if (implicitModel.containsKey(name)) { + bindObject = implicitModel.get(name); + } else if (this.methodResolver.isSessionAttribute(name, paramType)) { + bindObject = this.sessionAttributeStore.retrieveAttribute(webRequest, name); + if (bindObject == null) { + raiseSessionRequiredException("Session attribute '" + name + "' required - not found in session"); + } + } else { + bindObject = BeanUtils.instantiateClass(paramType); + } + WebDataBinder binder = createBinder(webRequest, bindObject, name); + initBinder(handler, name, binder, webRequest); + return binder; + } + + + /** + * Determine whether the given value qualifies as a "binding candidate", i.e. might potentially be subject to + * bean-style data binding later on. + */ + protected boolean isBindingCandidate(Object value) { + return (value != null && !value.getClass().isArray() && !(value instanceof Collection) && + !(value instanceof Map) && !BeanUtils.isSimpleValueType(value.getClass())); + } + + protected void raiseMissingParameterException(String paramName, Class paramType) throws Exception { + throw new IllegalStateException("Missing parameter '" + paramName + "' of type [" + paramType.getName() + "]"); + } + + protected void raiseMissingHeaderException(String headerName, Class paramType) throws Exception { + throw new IllegalStateException("Missing header '" + headerName + "' of type [" + paramType.getName() + "]"); + } + + protected void raiseMissingCookieException(String cookieName, Class paramType) throws Exception { + throw new IllegalStateException( + "Missing cookie value '" + cookieName + "' of type [" + paramType.getName() + "]"); + } + + protected void raiseSessionRequiredException(String message) throws Exception { + throw new IllegalStateException(message); + } + + protected WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName) + throws Exception { + + return new WebRequestDataBinder(target, objectName); + } + + private void doBind(WebDataBinder binder, NativeWebRequest webRequest, boolean validate, boolean failOnErrors) + throws Exception { + + doBind(binder, webRequest); + if (validate) { + binder.validate(); + } + if (failOnErrors && binder.getBindingResult().hasErrors()) { + throw new BindException(binder.getBindingResult()); + } + } + + protected void doBind(WebDataBinder binder, NativeWebRequest webRequest) throws Exception { + ((WebRequestDataBinder) binder).bind(webRequest); + } + + /** + * Return a {@link HttpInputMessage} for the given {@link NativeWebRequest}. + *

      Throws an UnsupportedOperation1Exception by default. + */ + protected HttpInputMessage createHttpInputMessage(NativeWebRequest webRequest) throws Exception { + throw new UnsupportedOperationException("@RequestBody not supported"); + } + + /** + * Return a {@link HttpOutputMessage} for the given {@link NativeWebRequest}. + *

      Throws an UnsupportedOperationException by default. + */ + protected HttpOutputMessage createHttpOutputMessage(NativeWebRequest webRequest) throws Exception { + throw new UnsupportedOperationException("@ResponseBody not supported"); + } + + protected String parseDefaultValueAttribute(String value) { + return (ValueConstants.DEFAULT_NONE.equals(value) ? null : value); + } + + protected Object resolveDefaultValue(String value) { + return value; + } + + protected Object resolveCommonArgument(MethodParameter methodParameter, NativeWebRequest webRequest) + throws Exception { + + // Invoke custom argument resolvers if present... + if (this.customArgumentResolvers != null) { + for (WebArgumentResolver argumentResolver : this.customArgumentResolvers) { + Object value = argumentResolver.resolveArgument(methodParameter, webRequest); + if (value != WebArgumentResolver.UNRESOLVED) { + return value; + } + } + } + + // Resolution of standard parameter types... + Class paramType = methodParameter.getParameterType(); + Object value = resolveStandardArgument(paramType, webRequest); + if (value != WebArgumentResolver.UNRESOLVED && !ClassUtils.isAssignableValue(paramType, value)) { + throw new IllegalStateException("Standard argument type [" + paramType.getName() + + "] resolved to incompatible value of type [" + (value != null ? value.getClass() : null) + + "]. Consider declaring the argument type in a less specific fashion."); + } + return value; + } + + protected Object resolveStandardArgument(Class parameterType, NativeWebRequest webRequest) throws Exception { + if (WebRequest.class.isAssignableFrom(parameterType)) { + return webRequest; + } + return WebArgumentResolver.UNRESOLVED; + } + + protected final void addReturnValueAsModelAttribute(Method handlerMethod, Class handlerType, + Object returnValue, ExtendedModelMap implicitModel) { + + ModelAttribute attr = AnnotationUtils.findAnnotation(handlerMethod, ModelAttribute.class); + String attrName = (attr != null ? attr.value() : ""); + if ("".equals(attrName)) { + Class resolvedType = GenericTypeResolver.resolveReturnType(handlerMethod, handlerType); + attrName = Conventions.getVariableNameForReturnType(handlerMethod, resolvedType, returnValue); + } + implicitModel.addAttribute(attrName, returnValue); + } } diff --git a/spring-data-document-parent/.project b/spring-data-document-parent/.project deleted file mode 100644 index a33fec0be..000000000 --- a/spring-data-document-parent/.project +++ /dev/null @@ -1,17 +0,0 @@ - - - spring-data-document-parent - - - - - - org.maven.ide.eclipse.maven2Builder - - - - - - org.maven.ide.eclipse.maven2Nature - - diff --git a/spring-data-document-parent/.settings/org.maven.ide.eclipse.prefs b/spring-data-document-parent/.settings/org.maven.ide.eclipse.prefs deleted file mode 100644 index 7ccc99204..000000000 --- a/spring-data-document-parent/.settings/org.maven.ide.eclipse.prefs +++ /dev/null @@ -1,9 +0,0 @@ -#Tue Jun 29 21:59:00 EDT 2010 -activeProfiles= -eclipse.preferences.version=1 -fullBuildGoals=process-test-resources -includeModules=false -resolveWorkspaceProjects=true -resourceFilterGoals=process-resources resources\:testResources -skipCompilerPlugin=true -version=1 diff --git a/spring-data-document-parent/pom.xml b/spring-data-document-parent/pom.xml index bbdab5f08..fb6f3de57 100644 --- a/spring-data-document-parent/pom.xml +++ b/spring-data-document-parent/pom.xml @@ -1,91 +1,92 @@ - 4.0.0 - org.springframework.data - spring-data-document-parent - Spring Data Document Parent - http://www.springsource.org/spring-data/data-document - 1.0.0.BUILD-SNAPSHOT - pom - - UTF-8 - - 4.8.1 - 1.2.15 - 1.8.4 - 1.5.10 - 1.6.1 - 3.0.5.RELEASE - 1.0.0.BUILD-SNAPSHOT - 1.6.11.M2 - - - - strict - - false - - - - fast - - true - true - - - - staging - - - spring-site-staging - file:///${java.io.tmpdir}/spring-data/data-document/docs - - - spring-milestone-staging - file:///${java.io.tmpdir}/spring-data/data-document/milestone - - - spring-snapshot-staging - file:///${java.io.tmpdir}/spring-data/data-document/snapshot - - - - - bootstrap - - - - - - http://www.springsource.com/download/community - - - static.springframework.org - scp://static.springframework.org/var/www/domains/springframework.org/static/htdocs/spring-data/data-document/docs/${project.version} - - - - spring-milestone - Spring Milestone Repository - s3://maven.springframework.org/milestone - - - spring-snapshot - Spring Snapshot Repository - s3://maven.springframework.org/snapshot - - - - - + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + 4.0.0 + org.springframework.data + spring-data-document-parent + Spring Data Document Parent + http://www.springsource.org/spring-data/data-document + 1.0.0.BUILD-SNAPSHOT + pom + + UTF-8 + + 4.8.1 + 1.2.15 + 1.8.4 + 1.5.10 + 1.6.1 + 3.0.5.RELEASE + 1.0.0.BUILD-SNAPSHOT + 1.6.11.M2 + + + + strict + + false + + + + fast + + true + true + + + + staging + + + spring-site-staging + file:///${java.io.tmpdir}/spring-data/data-document/docs + + + spring-milestone-staging + file:///${java.io.tmpdir}/spring-data/data-document/milestone + + + spring-snapshot-staging + file:///${java.io.tmpdir}/spring-data/data-document/snapshot + + + + + bootstrap + + + + + + http://www.springsource.com/download/community + + + static.springframework.org + + scp://static.springframework.org/var/www/domains/springframework.org/static/htdocs/spring-data/data-document/docs/${project.version} + + + + spring-milestone + Spring Milestone Repository + s3://maven.springframework.org/milestone + + + spring-snapshot + Spring Snapshot Repository + s3://maven.springframework.org/snapshot + + + + + diff --git a/spring-data-mongodb-cross-store/.classpath b/spring-data-mongodb-cross-store/.classpath deleted file mode 100644 index 0df52bfe5..000000000 --- a/spring-data-mongodb-cross-store/.classpath +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/spring-data-mongodb-cross-store/.project b/spring-data-mongodb-cross-store/.project deleted file mode 100644 index 20315de9a..000000000 --- a/spring-data-mongodb-cross-store/.project +++ /dev/null @@ -1,24 +0,0 @@ - - - spring-data-mongodb-cross-store - - - - - - org.eclipse.ajdt.core.ajbuilder - - - - - org.maven.ide.eclipse.maven2Builder - - - - - - org.eclipse.ajdt.ui.ajnature - org.eclipse.jdt.core.javanature - org.maven.ide.eclipse.maven2Nature - - diff --git a/spring-data-mongodb-cross-store/.settings/org.eclipse.jdt.core.prefs b/spring-data-mongodb-cross-store/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 644302d5c..000000000 --- a/spring-data-mongodb-cross-store/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,9 +0,0 @@ -#Tue Mar 01 09:48:37 EST 2011 -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 -org.eclipse.jdt.core.compiler.compliance=1.6 -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning -org.eclipse.jdt.core.compiler.source=1.6 diff --git a/spring-data-mongodb-cross-store/.settings/org.maven.ide.eclipse.prefs b/spring-data-mongodb-cross-store/.settings/org.maven.ide.eclipse.prefs deleted file mode 100644 index e53ed8823..000000000 --- a/spring-data-mongodb-cross-store/.settings/org.maven.ide.eclipse.prefs +++ /dev/null @@ -1,8 +0,0 @@ -#Mon Feb 28 16:25:59 EST 2011 -activeProfiles= -eclipse.preferences.version=1 -fullBuildGoals=process-test-resources -resolveWorkspaceProjects=true -resourceFilterGoals=process-resources resources\:testResources -skipCompilerPlugin=true -version=1 diff --git a/spring-data-mongodb-cross-store/pom.xml b/spring-data-mongodb-cross-store/pom.xml index e9151dc1f..437bcad25 100644 --- a/spring-data-mongodb-cross-store/pom.xml +++ b/spring-data-mongodb-cross-store/pom.xml @@ -115,72 +115,72 @@ 1.0.0.Final - - - - jboss-repository - JBoss Public Repository - http://repository.jboss.org/nexus/content/groups/public-jboss - - - spring-maven-snapshot - - true - - Springframework Maven SNAPSHOT Repository - http://maven.springframework.org/snapshot - - - - - spring-maven-milestones - Springframework Maven Milestone Repository - http://maven.springframework.org/milestone - - - - - - org.codehaus.mojo - aspectj-maven-plugin - 1.2 - - - org.aspectj - aspectjrt - ${aspectj.version} - - - org.aspectj - aspectjtools - ${aspectj.version} - - - - - - compile - test-compile - - - - - true - - - org.springframework - spring-aspects - - - org.springframework.data - spring-data-commons-aspects - - - 1.6 - 1.6 - - - - + + + + jboss-repository + JBoss Public Repository + http://repository.jboss.org/nexus/content/groups/public-jboss + + + spring-maven-snapshot + + true + + Springframework Maven SNAPSHOT Repository + http://maven.springframework.org/snapshot + + + + + spring-maven-milestones + Springframework Maven Milestone Repository + http://maven.springframework.org/milestone + + + + + + org.codehaus.mojo + aspectj-maven-plugin + 1.2 + + + org.aspectj + aspectjrt + ${aspectj.version} + + + org.aspectj + aspectjtools + ${aspectj.version} + + + + + + compile + test-compile + + + + + true + + + org.springframework + spring-aspects + + + org.springframework.data + spring-data-commons-aspects + + + 1.6 + 1.6 + + + + diff --git a/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/DocumentEntity.java b/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/DocumentEntity.java index b3130164e..2b690df97 100644 --- a/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/DocumentEntity.java +++ b/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/DocumentEntity.java @@ -8,7 +8,7 @@ import java.lang.annotation.Target; /** * Annotation to denote an object that should be transparently persisted * using MongoDB - * + * * @author Thomas Risberg */ diff --git a/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/MongoChangeSetPersister.java b/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/MongoChangeSetPersister.java index a46d456c9..6801b8b83 100644 --- a/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/MongoChangeSetPersister.java +++ b/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/MongoChangeSetPersister.java @@ -1,7 +1,9 @@ package org.springframework.persistence.document; -import java.util.Map; - +import com.mongodb.BasicDBObject; +import com.mongodb.DBCollection; +import com.mongodb.DBObject; +import com.mongodb.MongoException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -14,111 +16,104 @@ import org.springframework.persistence.support.ChangeSetBacked; import org.springframework.persistence.support.ChangeSetPersister; import org.springframework.util.ClassUtils; -import com.mongodb.BasicDBObject; -import com.mongodb.DB; -import com.mongodb.DBCollection; -import com.mongodb.DBObject; -import com.mongodb.Mongo; -import com.mongodb.MongoException; - //import edu.emory.mathcs.backport.java.util.Arrays; public class MongoChangeSetPersister implements ChangeSetPersister { - protected final Log log = LogFactory.getLog(getClass()); + protected final Log log = LogFactory.getLog(getClass()); - @Autowired - private MongoTemplate mongoTemplate; - - @Autowired - private ConversionService conversionService; - - @Override - public void getPersistentState(Class entityClass, Object id, ChangeSet changeSet) - throws DataAccessException, NotFoundException { - String collection = ClassUtils.getShortName(entityClass).toLowerCase(); - DBObject q = new BasicDBObject(); - q.put("_id", id); - try { - DBObject dbo = mongoTemplate.getCollection(collection).findOne(q); - log.debug("Found DBObject: " + dbo); - if (dbo == null) { - throw new NotFoundException(); - } - String classShortName = ClassUtils.getShortName(entityClass); - for (Object property : dbo.toMap().keySet()) { - String propertyKey = (String) property; - String propertyName = propertyKey.startsWith(classShortName) ? propertyKey.substring(propertyKey.indexOf(classShortName) - + classShortName.length() + 1) : propertyKey; - // System.err.println("Mongo persisted property [" + propertyName + "] :: " + propertyKey + " = " + dbo.get(propertyKey)); - if (propertyKey.startsWith("_")) { - // Id or class - changeSet.set(propertyKey, dbo.get(propertyKey)); - } else { - //throw new IllegalStateException("Unknown property [" + propertyName + "] found in MongoDB store"); - changeSet.set(propertyKey, dbo.get(propertyKey)); - } - } - } catch (MongoException ex) { - throw new DataAccessResourceFailureException("Can't read from Mongo", ex); - } - } - - @Override - public Object getPersistentId(Class entityClass, - ChangeSet cs) throws DataAccessException { - log.debug("getPersistentId called on " + entityClass); - if (cs == null) { - return null; - } - if (cs.getValues().get(ChangeSetPersister.ID_KEY) == null) { - // Not yet persistent - return null; - } - Object o = cs.getValues().get(ChangeSetPersister.ID_KEY); - return o; - } - - @Override - public Object persistState(Class entityClass, ChangeSet cs) throws DataAccessException { - log.info("PERSIST::"+cs); - cs.set(CLASS_KEY, entityClass.getName()); - String idstr = cs.get(ID_KEY, String.class, this.conversionService); - Object id = null; - if (idstr != null) { - id = idstr; - } - if (id == null) { - log.info("Flush: entity make persistent; data store will assign id"); - cs.set("_class", entityClass.getName()); - String collection = entityClass.getSimpleName().toLowerCase(); - DBCollection dbc = mongoTemplate.getCollection(collection); - DBObject dbo = mapChangeSetToDbObject(cs); - if (dbc == null) { - dbc = mongoTemplate.createCollection(collection); - } - dbc.save(dbo); - id = dbo.get(ID_KEY); - log.info("Data store assigned id: " + id); - } else { - log.info("Flush: entity already persistent with id=" + id); - String collection = entityClass.getName(); - DBCollection dbc = mongoTemplate.getCollection(collection); - DBObject dbo = mapChangeSetToDbObject(cs); - if (dbc == null) { - throw new DataAccessResourceFailureException("Expected to find a collection named '" + collection +"'. It was not found, so ChangeSet can't be persisted."); - } - dbc.save(dbo); - } + @Autowired + private MongoTemplate mongoTemplate; - return 0L; - } + @Autowired + private ConversionService conversionService; - private DBObject mapChangeSetToDbObject(ChangeSet cs) { - BasicDBObject dbo = new BasicDBObject(); - for (String property : cs.getValues().keySet()) { - dbo.put(property, cs.getValues().get(property)); - } - return dbo; - } + @Override + public void getPersistentState(Class entityClass, Object id, ChangeSet changeSet) + throws DataAccessException, NotFoundException { + String collection = ClassUtils.getShortName(entityClass).toLowerCase(); + DBObject q = new BasicDBObject(); + q.put("_id", id); + try { + DBObject dbo = mongoTemplate.getCollection(collection).findOne(q); + log.debug("Found DBObject: " + dbo); + if (dbo == null) { + throw new NotFoundException(); + } + String classShortName = ClassUtils.getShortName(entityClass); + for (Object property : dbo.toMap().keySet()) { + String propertyKey = (String) property; + String propertyName = propertyKey.startsWith(classShortName) ? propertyKey.substring(propertyKey.indexOf(classShortName) + + classShortName.length() + 1) : propertyKey; + // System.err.println("Mongo persisted property [" + propertyName + "] :: " + propertyKey + " = " + dbo.get(propertyKey)); + if (propertyKey.startsWith("_")) { + // Id or class + changeSet.set(propertyKey, dbo.get(propertyKey)); + } else { + //throw new IllegalStateException("Unknown property [" + propertyName + "] found in MongoDB store"); + changeSet.set(propertyKey, dbo.get(propertyKey)); + } + } + } catch (MongoException ex) { + throw new DataAccessResourceFailureException("Can't read from Mongo", ex); + } + } + + @Override + public Object getPersistentId(Class entityClass, + ChangeSet cs) throws DataAccessException { + log.debug("getPersistentId called on " + entityClass); + if (cs == null) { + return null; + } + if (cs.getValues().get(ChangeSetPersister.ID_KEY) == null) { + // Not yet persistent + return null; + } + Object o = cs.getValues().get(ChangeSetPersister.ID_KEY); + return o; + } + + @Override + public Object persistState(Class entityClass, ChangeSet cs) throws DataAccessException { + log.info("PERSIST::" + cs); + cs.set(CLASS_KEY, entityClass.getName()); + String idstr = cs.get(ID_KEY, String.class, this.conversionService); + Object id = null; + if (idstr != null) { + id = idstr; + } + if (id == null) { + log.info("Flush: entity make persistent; data store will assign id"); + cs.set("_class", entityClass.getName()); + String collection = entityClass.getSimpleName().toLowerCase(); + DBCollection dbc = mongoTemplate.getCollection(collection); + DBObject dbo = mapChangeSetToDbObject(cs); + if (dbc == null) { + dbc = mongoTemplate.createCollection(collection); + } + dbc.save(dbo); + id = dbo.get(ID_KEY); + log.info("Data store assigned id: " + id); + } else { + log.info("Flush: entity already persistent with id=" + id); + String collection = entityClass.getName(); + DBCollection dbc = mongoTemplate.getCollection(collection); + DBObject dbo = mapChangeSetToDbObject(cs); + if (dbc == null) { + throw new DataAccessResourceFailureException("Expected to find a collection named '" + collection + "'. It was not found, so ChangeSet can't be persisted."); + } + dbc.save(dbo); + } + + return 0L; + } + + private DBObject mapChangeSetToDbObject(ChangeSet cs) { + BasicDBObject dbo = new BasicDBObject(); + for (String property : cs.getValues().keySet()) { + dbo.put(property, cs.getValues().get(property)); + } + return dbo; + } } diff --git a/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/MongoDocumentBacking.aj b/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/MongoDocumentBacking.aj index 914c1efcf..133e482b7 100644 --- a/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/MongoDocumentBacking.aj +++ b/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/MongoDocumentBacking.aj @@ -4,7 +4,7 @@ import org.springframework.persistence.support.AbstractDeferredUpdateMixinFields /** * Aspect to turn an object annotated with DocumentEntity into a document entity using Mongo. - * + * * @author Thomas Risberg */ public aspect MongoDocumentBacking extends AbstractDeferredUpdateMixinFields { diff --git a/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/MongoEntityOperations.java b/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/MongoEntityOperations.java index 7e09692d7..b735456b7 100644 --- a/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/MongoEntityOperations.java +++ b/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/MongoEntityOperations.java @@ -13,69 +13,66 @@ import org.springframework.persistence.support.ChangeSetPersister.NotFoundExcept import org.springframework.persistence.support.EntityInstantiator; import org.springframework.persistence.support.HashMapChangeSet; -import com.mongodb.DB; - public class MongoEntityOperations extends OrderedEntityOperations { - - @Autowired - private MongoTemplate mongoTemplate; - - private EntityInstantiator entityInstantiator; - private MongoChangeSetPersister changeSetPersister; + @Autowired + private MongoTemplate mongoTemplate; - public void setEntityInstantiator(EntityInstantiator entityInstantiator) { - this.entityInstantiator = entityInstantiator; - } + private EntityInstantiator entityInstantiator; - @Autowired - public void setChangeSetPersister(MongoChangeSetPersister changeSetPersister) { - this.changeSetPersister = changeSetPersister; - } + private MongoChangeSetPersister changeSetPersister; + + public void setEntityInstantiator(EntityInstantiator entityInstantiator) { + this.entityInstantiator = entityInstantiator; + } + + @Autowired + public void setChangeSetPersister(MongoChangeSetPersister changeSetPersister) { + this.changeSetPersister = changeSetPersister; + } - @Override - public boolean cacheInEntity() { - return true; - } + @Override + public boolean cacheInEntity() { + return true; + } - @Override - public ChangeSetBacked findEntity(Class entityClass, Object key) throws DataAccessException { - try { - ChangeSet cs = new HashMapChangeSet(); - changeSetPersister.getPersistentState(entityClass, key, cs); - return entityInstantiator.createEntityFromState(cs, entityClass); - } - catch (NotFoundException ex) { - return null; - } - } + @Override + public ChangeSetBacked findEntity(Class entityClass, Object key) throws DataAccessException { + try { + ChangeSet cs = new HashMapChangeSet(); + changeSetPersister.getPersistentState(entityClass, key, cs); + return entityInstantiator.createEntityFromState(cs, entityClass); + } catch (NotFoundException ex) { + return null; + } + } - @Override - public Object findUniqueKey(ChangeSetBacked entity) throws DataAccessException { - return entity.getId(); - } + @Override + public Object findUniqueKey(ChangeSetBacked entity) throws DataAccessException { + return entity.getId(); + } - @Override - public boolean isTransactional() { - // TODO - return false; - } + @Override + public boolean isTransactional() { + // TODO + return false; + } - @Override - public boolean isTransient(ChangeSetBacked entity) throws DataAccessException { - return entity.getId() == null; - } + @Override + public boolean isTransient(ChangeSetBacked entity) throws DataAccessException { + return entity.getId() == null; + } - @Override - public Object makePersistent(Object owner, ChangeSetBacked entity, Field f, RelatedEntity fs) throws DataAccessException { - changeSetPersister.persistState(entity.getClass(), entity.getChangeSet()); - return entity.getId(); - } + @Override + public Object makePersistent(Object owner, ChangeSetBacked entity, Field f, RelatedEntity fs) throws DataAccessException { + changeSetPersister.persistState(entity.getClass(), entity.getChangeSet()); + return entity.getId(); + } - @Override - public boolean supports(Class entityClass, RelatedEntity fs) { - return entityClass.isAnnotationPresent(DocumentEntity.class); - } + @Override + public boolean supports(Class entityClass, RelatedEntity fs) { + return entityClass.isAnnotationPresent(DocumentEntity.class); + } } diff --git a/spring-data-mongodb-cross-store/src/test/java/org/springframework/data/document/persistence/CrossStoreMongoTests.java b/spring-data-mongodb-cross-store/src/test/java/org/springframework/data/document/persistence/CrossStoreMongoTests.java index 137ea7eaf..215639511 100644 --- a/spring-data-mongodb-cross-store/src/test/java/org/springframework/data/document/persistence/CrossStoreMongoTests.java +++ b/spring-data-mongodb-cross-store/src/test/java/org/springframework/data/document/persistence/CrossStoreMongoTests.java @@ -3,6 +3,7 @@ package org.springframework.data.document.persistence; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; +import com.mongodb.*; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -17,122 +18,116 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.transaction.annotation.Transactional; -import com.mongodb.DBCollection; -import com.mongodb.DBCursor; -import com.mongodb.DBObject; -import com.mongodb.Mongo; -import com.mongodb.MongoException; - @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:/META-INF/spring/applicationContext.xml") public class CrossStoreMongoTests { - @Autowired - private Mongo mongo; + @Autowired + private Mongo mongo; - @Autowired - private MongoTemplate mongoTemplate; - - private EntityManager entityManager; - - private String colName = MongoPerson.class.getSimpleName().toLowerCase(); + @Autowired + private MongoTemplate mongoTemplate; - - @PersistenceContext - public void setEntityManager(EntityManager entityManager) { - this.entityManager = entityManager; + private EntityManager entityManager; + + private String colName = MongoPerson.class.getSimpleName().toLowerCase(); + + + @PersistenceContext + public void setEntityManager(EntityManager entityManager) { + this.entityManager = entityManager; + } + + private void clearData(String collectionName) { + DBCollection col = this.mongoTemplate.getCollection(collectionName); + if (col != null) { + this.mongoTemplate.dropCollection(collectionName); } + } - private void clearData(String collectionName) { - DBCollection col = this.mongoTemplate.getCollection(collectionName); - if (col != null) { - this.mongoTemplate.dropCollection(collectionName); - } - } - - @Test - @Transactional - @Rollback(false) - public void testUserConstructor() { - clearData(colName); - int age = 33; - MongoPerson p = new MongoPerson("Thomas", age); - Assert.assertEquals(age, p.getAge()); - p.birthday(); - Assert.assertEquals(1 + age, p.getAge()); - } + @Test + @Transactional + @Rollback(false) + public void testUserConstructor() { + clearData(colName); + int age = 33; + MongoPerson p = new MongoPerson("Thomas", age); + Assert.assertEquals(age, p.getAge()); + p.birthday(); + Assert.assertEquals(1 + age, p.getAge()); + } - @Test - @Transactional - public void testInstantiatedFinder() throws MongoException { - DBCollection col = this.mongoTemplate.getCollection(colName); - DBObject dbo = col.findOne(); - Object _id = dbo.get("_id"); - MongoPerson found = MongoPerson.findPerson(_id); - Assert.assertNotNull(found); - Assert.assertEquals(_id, found.getId()); - System.out.println("Loaded MongoPerson data: " + found); - } + @Test + @Transactional + public void testInstantiatedFinder() throws MongoException { + DBCollection col = this.mongoTemplate.getCollection(colName); + DBObject dbo = col.findOne(); + Object _id = dbo.get("_id"); + MongoPerson found = MongoPerson.findPerson(_id); + Assert.assertNotNull(found); + Assert.assertEquals(_id, found.getId()); + System.out.println("Loaded MongoPerson data: " + found); + } - @Test - @Transactional - @Rollback(false) - public void testCreateMongoToJpaEntityRelationship() { - clearData(colName); - Account a = new Account(); - a.setName("My Account"); - a.setFriendlyName("My Test Acct."); - a.setBalance(123.45F); - a.setId(2L); - MongoPerson p = new MongoPerson("Jack", 22); - entityManager.persist(a); - p.setAccount(a); - } + @Test + @Transactional + @Rollback(false) + public void testCreateMongoToJpaEntityRelationship() { + clearData(colName); + Account a = new Account(); + a.setName("My Account"); + a.setFriendlyName("My Test Acct."); + a.setBalance(123.45F); + a.setId(2L); + MongoPerson p = new MongoPerson("Jack", 22); + entityManager.persist(a); + p.setAccount(a); + } - @Test - @Transactional - public void testReadMongoToJpaEntityRelationship() { - DBCollection col = this.mongoTemplate.getCollection(colName); - DBCursor dbc = col.find(); - Object _id = null; - for (DBObject dbo : dbc) { - System.out.println(dbo); - if ("Jack".equals(dbo.get("name"))) { - _id = dbo.get("_id"); - break; - } - } - System.out.println(_id); - MongoPerson found = MongoPerson.findPerson(_id); - System.out.println(found); - if (found != null) - System.out.println(found.getAccount()); - } + @Test + @Transactional + public void testReadMongoToJpaEntityRelationship() { + DBCollection col = this.mongoTemplate.getCollection(colName); + DBCursor dbc = col.find(); + Object _id = null; + for (DBObject dbo : dbc) { + System.out.println(dbo); + if ("Jack".equals(dbo.get("name"))) { + _id = dbo.get("_id"); + break; + } + } + System.out.println(_id); + MongoPerson found = MongoPerson.findPerson(_id); + System.out.println(found); + if (found != null) + System.out.println(found.getAccount()); + } - @Test - @Transactional - @Rollback(false) - public void testCreateJpaToMongoEntityRelationship() { - clearData("resume"); - Person p = new Person("Thomas", 20); - Resume r = new Resume(); - r.addEducation("Skanstulls High School, 1975"); - r.addEducation("Univ. of Stockholm, 1980"); - r.addJob("DiMark, DBA, 1990-2000"); - r.addJob("VMware, Developer, 2007-"); - p.setResume(r); - p.setId(1L); - entityManager.persist(p); - } + @Test + @Transactional + @Rollback(false) + public void testCreateJpaToMongoEntityRelationship() { + clearData("resume"); + Person p = new Person("Thomas", 20); + Resume r = new Resume(); + r.addEducation("Skanstulls High School, 1975"); + r.addEducation("Univ. of Stockholm, 1980"); + r.addJob("DiMark, DBA, 1990-2000"); + r.addJob("VMware, Developer, 2007-"); + p.setResume(r); + p.setId(1L); + entityManager.persist(p); + } - @Test - @Transactional - public void testReadJpaToMongoEntityRelationship() { - Person found = entityManager.find(Person.class, 1L); - System.out.println(found); + @Test + @Transactional + public void testReadJpaToMongoEntityRelationship() { + Person found = entityManager.find(Person.class, 1L); + System.out.println(found); // TODO: This part isn't working yet - there is no reference to the Momgo _id stored in the db // if (found != null) // System.out.println(found.getResume()); - } + } } diff --git a/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/Account.java b/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/Account.java index 56b340bcf..2b41a7ad3 100644 --- a/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/Account.java +++ b/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/Account.java @@ -5,61 +5,62 @@ import javax.persistence.Id; @Entity public class Account { - - @Id private Long id; - private String name; + @Id + private Long id; - private float balance; + private String name; - private String friendlyName; + private float balance; - private String whatever; + private String friendlyName; - public Long getId() { - return id; - } + private String whatever; - public void setId(Long id) { - this.id = id; - } + public Long getId() { + return id; + } - public String getName() { - return name; - } + public void setId(Long id) { + this.id = id; + } - public void setName(String name) { - this.name = name; - } + public String getName() { + return name; + } - public float getBalance() { - return balance; - } + public void setName(String name) { + this.name = name; + } - public void setBalance(float balance) { - this.balance = balance; - } + public float getBalance() { + return balance; + } - public String getFriendlyName() { - return friendlyName; - } + public void setBalance(float balance) { + this.balance = balance; + } - public void setFriendlyName(String friendlyName) { - this.friendlyName = friendlyName; - } + public String getFriendlyName() { + return friendlyName; + } - public String getWhatever() { - return whatever; - } + public void setFriendlyName(String friendlyName) { + this.friendlyName = friendlyName; + } - public void setWhatever(String whatever) { - this.whatever = whatever; - } + public String getWhatever() { + return whatever; + } - @Override - public String toString() { - return "Account [id=" + id + ", name=" + name + ", balance=" + balance - + ", friendlyName=" + friendlyName + "]"; - } + public void setWhatever(String whatever) { + this.whatever = whatever; + } + + @Override + public String toString() { + return "Account [id=" + id + ", name=" + name + ", balance=" + balance + + ", friendlyName=" + friendlyName + "]"; + } } diff --git a/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/MongoPerson.java b/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/MongoPerson.java index 0603beb86..7b123a977 100644 --- a/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/MongoPerson.java +++ b/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/MongoPerson.java @@ -2,62 +2,62 @@ package org.springframework.persistence.document.test; import org.springframework.persistence.RelatedEntity; import org.springframework.persistence.document.DocumentEntity; - + @DocumentEntity public class MongoPerson { - - // TODO only public because of AspectJ bug - public String name; - - public int age; - - public java.util.Date birthDate; - // TODO only public to check weaving bug-- - // seems to work whereas private didn't - @RelatedEntity - public Account account; + // TODO only public because of AspectJ bug + public String name; - public MongoPerson(String name, int age) { - this.name = name; - this.age = age; - this.birthDate = new java.util.Date(); - } + public int age; - public void birthday() { - ++age; - } + public java.util.Date birthDate; - public String getName() { - return name; - } + // TODO only public to check weaving bug-- + // seems to work whereas private didn't + @RelatedEntity + public Account account; - public void setName(String name) { - this.name = name; - } + public MongoPerson(String name, int age) { + this.name = name; + this.age = age; + this.birthDate = new java.util.Date(); + } - public int getAge() { - return age; - } + public void birthday() { + ++age; + } - public void setAge(int age) { - this.age = age; - } + public String getName() { + return name; + } - public java.util.Date getBirthDate() { - return birthDate; - } + public void setName(String name) { + this.name = name; + } - public void setBirthDate(java.util.Date birthDate) { - this.birthDate = birthDate; - } + public int getAge() { + return age; + } - public Account getAccount() { - return account; - } + public void setAge(int age) { + this.age = age; + } - public void setAccount(Account account) { - this.account = account; - } + public java.util.Date getBirthDate() { + return birthDate; + } + + public void setBirthDate(java.util.Date birthDate) { + this.birthDate = birthDate; + } + + public Account getAccount() { + return account; + } + + public void setAccount(Account account) { + this.account = account; + } } diff --git a/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/MongoPerson_Roo_Mongo_Entity.aj b/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/MongoPerson_Roo_Mongo_Entity.aj index 3cd14ee18..cb7751aa7 100644 --- a/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/MongoPerson_Roo_Mongo_Entity.aj +++ b/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/MongoPerson_Roo_Mongo_Entity.aj @@ -3,58 +3,52 @@ package org.springframework.persistence.document.test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Configurable; import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.persistence.support.ChangeSet; -import org.springframework.persistence.support.ChangeSetBacked; -import org.springframework.persistence.support.ChangeSetConfiguration; -import org.springframework.persistence.support.ChangeSetPersister; -import org.springframework.persistence.support.ChangeSetSynchronizer; -import org.springframework.persistence.support.HashMapChangeSet; +import org.springframework.persistence.support.*; import org.springframework.persistence.support.ChangeSetPersister.NotFoundException; /** * EXAMPLE OF CODE THAT SHOULD BE GENERATED BY ROO BESIDES EACH MONGOENTITY CLASS - * + * * Note: Combines X_Roo_Entity with X_Roo_Finder, as * we need only a single aspect for entities. - * + * * @author Thomas Risberg * */ privileged aspect MongoPerson_Roo_Mongo_Entity { - - private static ChangeSetPersister changeSetPersister() { - return new MongoConfigurationHolder().changeSetConfig.getChangeSetPersister(); - } - - private static ChangeSetSynchronizer changeSetManager() { - return new MongoConfigurationHolder().changeSetConfig.getChangeSetManager(); - } - @Configurable - public static class MongoConfigurationHolder { - @Autowired - @Qualifier("mongoChangeSetConfiguration") - public ChangeSetConfiguration changeSetConfig; - } + private static ChangeSetPersister changeSetPersister() { + return new MongoConfigurationHolder().changeSetConfig.getChangeSetPersister(); + } - /** - * Add constructor that takes ChangeSet. - * @param ChangeSet - */ - public MongoPerson.new(ChangeSet cs) { - super(); - setChangeSet(cs); - } + private static ChangeSetSynchronizer changeSetManager() { + return new MongoConfigurationHolder().changeSetConfig.getChangeSetManager(); + } - public static MongoPerson MongoPerson.findPerson(Object id) { - ChangeSet rv = new HashMapChangeSet(); - try { - changeSetPersister().getPersistentState(MongoPerson.class, id, rv); - return new MongoPerson(rv); - } - catch (NotFoundException ex) { - return null; - } - } + @Configurable + public static class MongoConfigurationHolder { + @Autowired + @Qualifier("mongoChangeSetConfiguration") + public ChangeSetConfiguration changeSetConfig; + } + + /** + * Add constructor that takes ChangeSet. + * @param ChangeSet + */ + public MongoPerson.new(ChangeSet cs) { + super(); + setChangeSet(cs); + } + + public static MongoPerson MongoPerson.findPerson(Object id) { + ChangeSet rv = new HashMapChangeSet(); + try { + changeSetPersister().getPersistentState(MongoPerson.class, id, rv); + return new MongoPerson(rv); + } catch (NotFoundException ex) { + return null; + } + } } diff --git a/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/Person.java b/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/Person.java index 070fa11e3..71d323b91 100644 --- a/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/Person.java +++ b/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/Person.java @@ -4,73 +4,74 @@ import javax.persistence.Entity; import javax.persistence.Id; import org.springframework.persistence.RelatedEntity; - + @Entity public class Person { - - @Id Long id; - - private String name; - - private int age; - - private java.util.Date birthDate; -// @Document // need to decide what the annotation here should be - @RelatedEntity - public Resume resume; + @Id + Long id; - public Person() { - } + private String name; - public Person(String name, int age) { - this.name = name; - this.age = age; - this.birthDate = new java.util.Date(); - } + private int age; - public void birthday() { - ++age; - } + private java.util.Date birthDate; - public Long getId() { - return id; - } + // @Document // need to decide what the annotation here should be + @RelatedEntity + public Resume resume; - public void setId(Long id) { - this.id = id; - } + public Person() { + } - public String getName() { - return name; - } + public Person(String name, int age) { + this.name = name; + this.age = age; + this.birthDate = new java.util.Date(); + } - public void setName(String name) { - this.name = name; - } + public void birthday() { + ++age; + } - public int getAge() { - return age; - } + public Long getId() { + return id; + } - public void setAge(int age) { - this.age = age; - } + public void setId(Long id) { + this.id = id; + } - public java.util.Date getBirthDate() { - return birthDate; - } + public String getName() { + return name; + } - public void setBirthDate(java.util.Date birthDate) { - this.birthDate = birthDate; - } + public void setName(String name) { + this.name = name; + } - public Resume getResume() { - return resume; - } + public int getAge() { + return age; + } - public void setResume(Resume resume) { - this.resume = resume; - } + public void setAge(int age) { + this.age = age; + } + + public java.util.Date getBirthDate() { + return birthDate; + } + + public void setBirthDate(java.util.Date birthDate) { + this.birthDate = birthDate; + } + + public Resume getResume() { + return resume; + } + + public void setResume(Resume resume) { + this.resume = resume; + } } diff --git a/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/Resume.java b/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/Resume.java index dc751afb4..f7eaa3fd5 100644 --- a/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/Resume.java +++ b/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/Resume.java @@ -5,29 +5,29 @@ import org.springframework.persistence.document.DocumentEntity; @DocumentEntity public class Resume { - private String education = ""; - - private String jobs = ""; + private String education = ""; - public String getEducation() { - return education; - } + private String jobs = ""; - public void addEducation(String education) { - this.education = this.education + (this.education.length() > 0 ? "; " : "") + education; - } + public String getEducation() { + return education; + } - public String getJobs() { - return jobs; - } + public void addEducation(String education) { + this.education = this.education + (this.education.length() > 0 ? "; " : "") + education; + } - public void addJob(String job) { - this.jobs = this.jobs + (this.jobs.length() > 0 ? "; " : "") + job; - } + public String getJobs() { + return jobs; + } + + public void addJob(String job) { + this.jobs = this.jobs + (this.jobs.length() > 0 ? "; " : "") + job; + } + + @Override + public String toString() { + return "Resume [education=" + education + ", jobs=" + jobs + "]"; + } - @Override - public String toString() { - return "Resume [education=" + education + ", jobs=" + jobs + "]"; - } - } diff --git a/spring-data-mongodb-cross-store/src/test/resources/META-INF/persistence.xml b/spring-data-mongodb-cross-store/src/test/resources/META-INF/persistence.xml index 232536c0d..294794afa 100644 --- a/spring-data-mongodb-cross-store/src/test/resources/META-INF/persistence.xml +++ b/spring-data-mongodb-cross-store/src/test/resources/META-INF/persistence.xml @@ -1,13 +1,15 @@ - - - org.hibernate.ejb.HibernatePersistence - org.springframework.persistence.document.test.Account - - - - - - - + + + org.hibernate.ejb.HibernatePersistence + org.springframework.persistence.document.test.Account + + + + + + + diff --git a/spring-data-mongodb-cross-store/src/test/resources/META-INF/spring/applicationContext.xml b/spring-data-mongodb-cross-store/src/test/resources/META-INF/spring/applicationContext.xml index 8b359c8b8..807f56a55 100644 --- a/spring-data-mongodb-cross-store/src/test/resources/META-INF/spring/applicationContext.xml +++ b/spring-data-mongodb-cross-store/src/test/resources/META-INF/spring/applicationContext.xml @@ -1,98 +1,99 @@ - + - - - - + + + + - - - - - - - - - - - - - - - + - - - - - - - + + + + + - + - - - + - - - - - + - - - - - - + - - - - - - - - - - - - + + + + + + + - - - - - - + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-data-mongodb/.classpath b/spring-data-mongodb/.classpath deleted file mode 100644 index 40f8440e7..000000000 --- a/spring-data-mongodb/.classpath +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/spring-data-mongodb/.project b/spring-data-mongodb/.project deleted file mode 100644 index 942129127..000000000 --- a/spring-data-mongodb/.project +++ /dev/null @@ -1,36 +0,0 @@ - - - spring-data-mongodb - - - - - - org.eclipse.wst.common.project.facet.core.builder - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.maven.ide.eclipse.maven2Builder - - - - - org.eclipse.wst.validation.validationbuilder - - - - - - org.eclipse.jem.workbench.JavaEMFNature - org.eclipse.wst.common.modulecore.ModuleCoreNature - org.eclipse.jdt.core.javanature - org.maven.ide.eclipse.maven2Nature - org.eclipse.wst.common.project.facet.core.nature - - diff --git a/spring-data-mongodb/.settings/org.eclipse.jdt.core.prefs b/spring-data-mongodb/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index b3ef56f5a..000000000 --- a/spring-data-mongodb/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,9 +0,0 @@ -#Wed Mar 09 13:51:37 EST 2011 -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 -org.eclipse.jdt.core.compiler.compliance=1.6 -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning -org.eclipse.jdt.core.compiler.source=1.6 diff --git a/spring-data-mongodb/.settings/org.eclipse.wst.common.component b/spring-data-mongodb/.settings/org.eclipse.wst.common.component deleted file mode 100644 index d56de02bd..000000000 --- a/spring-data-mongodb/.settings/org.eclipse.wst.common.component +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/spring-data-mongodb/.settings/org.eclipse.wst.common.project.facet.core.xml b/spring-data-mongodb/.settings/org.eclipse.wst.common.project.facet.core.xml deleted file mode 100644 index 5c9bd7532..000000000 --- a/spring-data-mongodb/.settings/org.eclipse.wst.common.project.facet.core.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/spring-data-mongodb/.settings/org.maven.ide.eclipse.prefs b/spring-data-mongodb/.settings/org.maven.ide.eclipse.prefs deleted file mode 100644 index 5545b44b1..000000000 --- a/spring-data-mongodb/.settings/org.maven.ide.eclipse.prefs +++ /dev/null @@ -1,9 +0,0 @@ -#Wed Oct 06 14:49:46 EDT 2010 -activeProfiles= -eclipse.preferences.version=1 -fullBuildGoals=process-test-resources -includeModules=false -resolveWorkspaceProjects=true -resourceFilterGoals=process-resources resources\:testResources -skipCompilerPlugin=true -version=1 diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/CannotGetMongoDbConnectionException.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/CannotGetMongoDbConnectionException.java index 6595b89c8..d9e2505ca 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/CannotGetMongoDbConnectionException.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/CannotGetMongoDbConnectionException.java @@ -19,13 +19,13 @@ import org.springframework.dao.DataAccessResourceFailureException; public class CannotGetMongoDbConnectionException extends DataAccessResourceFailureException { - private static final long serialVersionUID = 1172099106475265589L; + private static final long serialVersionUID = 1172099106475265589L; - public CannotGetMongoDbConnectionException(String msg, Throwable cause) { - super(msg, cause); - } + public CannotGetMongoDbConnectionException(String msg, Throwable cause) { + super(msg, cause); + } - public CannotGetMongoDbConnectionException(String msg) { - super(msg); - } + public CannotGetMongoDbConnectionException(String msg) { + super(msg); + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/CollectionCallback.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/CollectionCallback.java index b100e6638..8c29a6178 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/CollectionCallback.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/CollectionCallback.java @@ -15,13 +15,12 @@ */ package org.springframework.data.document.mongodb; -import org.springframework.dao.DataAccessException; - import com.mongodb.DBCollection; import com.mongodb.MongoException; +import org.springframework.dao.DataAccessException; public interface CollectionCallback { - T doInCollection(DBCollection collection) throws MongoException, DataAccessException; - + T doInCollection(DBCollection collection) throws MongoException, DataAccessException; + } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/CollectionOptions.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/CollectionOptions.java index 15795b8e6..52f4769f0 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/CollectionOptions.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/CollectionOptions.java @@ -16,56 +16,56 @@ package org.springframework.data.document.mongodb; /** - * Provides a simple wrapper to encapsulate the variety of settings you can use when creating a collection. - * - * @author Thomas Risberg + * Provides a simple wrapper to encapsulate the variety of settings you can use when creating a collection. * + * @author Thomas Risberg */ public class CollectionOptions { - - private Integer maxDocuments; - - private Integer size; - - private Boolean capped; - - /** - * Constructs a new CollectionOptions instance. - * @param size the collection size in bytes, this data space is preallocated - * @param maxDocuments the maximum number of documents in the collection. - * @param capped true to created a "capped" collection (fixed size with auto-FIFO behavior - * based on insertion order), false otherwise. - */ - public CollectionOptions(Integer size, Integer maxDocuments, Boolean capped) { - super(); - this.maxDocuments = maxDocuments; - this.size = size; - this.capped = capped; - } - public Integer getMaxDocuments() { - return maxDocuments; - } + private Integer maxDocuments; - public void setMaxDocuments(Integer maxDocuments) { - this.maxDocuments = maxDocuments; - } + private Integer size; - public Integer getSize() { - return size; - } + private Boolean capped; - public void setSize(Integer size) { - this.size = size; - } + /** + * Constructs a new CollectionOptions instance. + * + * @param size the collection size in bytes, this data space is preallocated + * @param maxDocuments the maximum number of documents in the collection. + * @param capped true to created a "capped" collection (fixed size with auto-FIFO behavior + * based on insertion order), false otherwise. + */ + public CollectionOptions(Integer size, Integer maxDocuments, Boolean capped) { + super(); + this.maxDocuments = maxDocuments; + this.size = size; + this.capped = capped; + } + + public Integer getMaxDocuments() { + return maxDocuments; + } + + public void setMaxDocuments(Integer maxDocuments) { + this.maxDocuments = maxDocuments; + } + + public Integer getSize() { + return size; + } + + public void setSize(Integer size) { + this.size = size; + } + + public Boolean getCapped() { + return capped; + } + + public void setCapped(Boolean capped) { + this.capped = capped; + } - public Boolean getCapped() { - return capped; - } - public void setCapped(Boolean capped) { - this.capped = capped; - } - - } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/CursorPreparer.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/CursorPreparer.java index b12ac7349..9d07c0684 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/CursorPreparer.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/CursorPreparer.java @@ -20,15 +20,15 @@ import com.mongodb.DBCursor; /** * Simple callback interface to allow customization of a {@link DBCursor}. - * + * * @author Oliver Gierke */ public interface CursorPreparer { - /** - * Prepare the given cursor (apply limits, skips and so on). Returns th eprepared cursor. - * - * @param cursor - */ - DBCursor prepare(DBCursor cursor); + /** + * Prepare the given cursor (apply limits, skips and so on). Returns th eprepared cursor. + * + * @param cursor + */ + DBCursor prepare(DBCursor cursor); } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/DbCallback.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/DbCallback.java index a54efdd0f..4ea233359 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/DbCallback.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/DbCallback.java @@ -15,12 +15,11 @@ */ package org.springframework.data.document.mongodb; -import org.springframework.dao.DataAccessException; - import com.mongodb.DB; import com.mongodb.MongoException; +import org.springframework.dao.DataAccessException; public interface DbCallback { - T doInDB(DB db) throws MongoException, DataAccessException; + T doInDB(DB db) throws MongoException, DataAccessException; } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/DbHolder.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/DbHolder.java index 596cd31dc..d6f713aa1 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/DbHolder.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/DbHolder.java @@ -3,69 +3,68 @@ package org.springframework.data.document.mongodb; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import com.mongodb.DB; import org.springframework.transaction.support.ResourceHolderSupport; import org.springframework.util.Assert; -import com.mongodb.DB; - class DbHolder extends ResourceHolderSupport { - private static final Object DEFAULT_KEY = new Object(); + private static final Object DEFAULT_KEY = new Object(); - private final Map dbMap = new ConcurrentHashMap(); + private final Map dbMap = new ConcurrentHashMap(); - public DbHolder(DB db) { - addDB(db); - } + public DbHolder(DB db) { + addDB(db); + } - public DbHolder(Object key, DB db) { - addDB(key, db); - } + public DbHolder(Object key, DB db) { + addDB(key, db); + } - public DB getDB() { - return getDB(DEFAULT_KEY); - } + public DB getDB() { + return getDB(DEFAULT_KEY); + } - public DB getDB(Object key) { - return this.dbMap.get(key); - } + public DB getDB(Object key) { + return this.dbMap.get(key); + } - public DB getAnyDB() { - if (!this.dbMap.isEmpty()) { - return this.dbMap.values().iterator().next(); - } - return null; - } + public DB getAnyDB() { + if (!this.dbMap.isEmpty()) { + return this.dbMap.values().iterator().next(); + } + return null; + } - public void addDB(DB session) { - addDB(DEFAULT_KEY, session); - } + public void addDB(DB session) { + addDB(DEFAULT_KEY, session); + } - public void addDB(Object key, DB session) { - Assert.notNull(key, "Key must not be null"); - Assert.notNull(session, "DB must not be null"); - this.dbMap.put(key, session); - } + public void addDB(Object key, DB session) { + Assert.notNull(key, "Key must not be null"); + Assert.notNull(session, "DB must not be null"); + this.dbMap.put(key, session); + } - public DB removeDB(Object key) { - return this.dbMap.remove(key); - } + public DB removeDB(Object key) { + return this.dbMap.remove(key); + } - public boolean containsDB(DB session) { - return this.dbMap.containsValue(session); - } + public boolean containsDB(DB session) { + return this.dbMap.containsValue(session); + } - public boolean isEmpty() { - return this.dbMap.isEmpty(); - } + public boolean isEmpty() { + return this.dbMap.isEmpty(); + } - public boolean doesNotHoldNonDefaultDB() { - synchronized (this.dbMap) { - return this.dbMap.isEmpty() || - (this.dbMap.size() == 1 && this.dbMap.containsKey(DEFAULT_KEY)); - } - } + public boolean doesNotHoldNonDefaultDB() { + synchronized (this.dbMap) { + return this.dbMap.isEmpty() || + (this.dbMap.size() == 1 && this.dbMap.containsKey(DEFAULT_KEY)); + } + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoAdmin.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoAdmin.java index eac359332..4b20e5c76 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoAdmin.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoAdmin.java @@ -15,80 +15,80 @@ */ package org.springframework.data.document.mongodb; +import com.mongodb.DB; +import com.mongodb.Mongo; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.jmx.export.annotation.ManagedOperation; import org.springframework.jmx.export.annotation.ManagedResource; -import com.mongodb.DB; -import com.mongodb.Mongo; - /** * Mongo server administration exposed via JMX annotations - * - * @author Mark Pollack * + * @author Mark Pollack */ -@ManagedResource(description="Mongo Admin Operations") +@ManagedResource(description = "Mongo Admin Operations") public class MongoAdmin implements MongoAdminOperations { - /** Logger available to subclasses */ - protected final Log logger = LogFactory.getLog(getClass()); - - private Mongo mongo; - private String username; - private String password; - - public MongoAdmin(Mongo mongo) { - this.mongo = mongo; - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoAdminOperations#dropDatabase(java.lang.String) - */ - @ManagedOperation - public void dropDatabase(String databaseName) { - mongo.getDB(databaseName).dropDatabase(); - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoAdminOperations#createDatabase(java.lang.String) - */ - @ManagedOperation - public void createDatabase(String databaseName) { - mongo.getDB(databaseName); - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoAdminOperations#getDatabaseStats(java.lang.String) - */ - @ManagedOperation - public String getDatabaseStats(String databaseName) { - return mongo.getDB("testAdminDb").getStats().toString(); - } - - /** - * Sets the username to use to connect to the Mongo database - * - * @param username The username to use - */ - public void setUsername(String username) { - this.username = username; - } + /** + * Logger available to subclasses + */ + protected final Log logger = LogFactory.getLog(getClass()); - /** - * Sets the password to use to authenticate with the Mongo database. - * - * @param password The password to use - */ - public void setPassword(String password) { - - this.password = password; - } - - - public DB getDb(String databaseName) { - return MongoDbUtils.getDB(mongo, databaseName, username, password == null ? null : password.toCharArray()); - } + private Mongo mongo; + private String username; + private String password; + + public MongoAdmin(Mongo mongo) { + this.mongo = mongo; + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoAdminOperations#dropDatabase(java.lang.String) + */ + @ManagedOperation + public void dropDatabase(String databaseName) { + mongo.getDB(databaseName).dropDatabase(); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoAdminOperations#createDatabase(java.lang.String) + */ + @ManagedOperation + public void createDatabase(String databaseName) { + mongo.getDB(databaseName); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoAdminOperations#getDatabaseStats(java.lang.String) + */ + @ManagedOperation + public String getDatabaseStats(String databaseName) { + return mongo.getDB("testAdminDb").getStats().toString(); + } + + /** + * Sets the username to use to connect to the Mongo database + * + * @param username The username to use + */ + public void setUsername(String username) { + this.username = username; + } + + /** + * Sets the password to use to authenticate with the Mongo database. + * + * @param password The password to use + */ + public void setPassword(String password) { + + this.password = password; + } + + + public DB getDb(String databaseName) { + return MongoDbUtils.getDB(mongo, databaseName, username, password == null ? null : password.toCharArray()); + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoAdminOperations.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoAdminOperations.java index 40113cbd6..4d1b799c0 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoAdminOperations.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoAdminOperations.java @@ -4,13 +4,13 @@ import org.springframework.jmx.export.annotation.ManagedOperation; public interface MongoAdminOperations { - @ManagedOperation - public abstract void dropDatabase(String databaseName); + @ManagedOperation + public abstract void dropDatabase(String databaseName); - @ManagedOperation - public abstract void createDatabase(String databaseName); + @ManagedOperation + public abstract void createDatabase(String databaseName); - @ManagedOperation - public abstract String getDatabaseStats(String databaseName); + @ManagedOperation + public abstract String getDatabaseStats(String databaseName); } \ No newline at end of file diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoDbUtils.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoDbUtils.java index 57c392281..d690ecc4e 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoDbUtils.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoDbUtils.java @@ -16,151 +16,148 @@ package org.springframework.data.document.mongodb; +import com.mongodb.DB; +import com.mongodb.Mongo; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.util.Assert; -import com.mongodb.DB; -import com.mongodb.Mongo; - /** * Helper class featuring helper methods for internal MongoDb classes. - * + *

      *

      Mainly intended for internal use within the framework. * * @author Thomas Risberg * @author Graeme Rocher * @author Oliver Gierke - * * @since 1.0 */ public abstract class MongoDbUtils { - private static final Log LOGGER = LogFactory.getLog(MongoDbUtils.class); - - /** - * Private constructor to prevent instantiation. - */ - private MongoDbUtils() { - - } + private static final Log LOGGER = LogFactory.getLog(MongoDbUtils.class); - /** - * Obtains a {@link DB} connection for the given {@link Mongo} instance and database name - * - * @param mongo The {@link Mongo} instance - * @param databaseName The database name - * @return The {@link DB} connection - */ - public static DB getDB(Mongo mongo, String databaseName) { - return doGetDB(mongo, databaseName,null,null, true); - } + /** + * Private constructor to prevent instantiation. + */ + private MongoDbUtils() { - /** - * - * Obtains a {@link DB} connection for the given {@link Mongo} instance and database name - * - * @param mongo The {@link Mongo} instance - * @param databaseName The database name - * @param username The username to authenticate with - * @param password The password to authenticate with - * @return The {@link DB} connection - */ - public static DB getDB(Mongo mongo, String databaseName, String username, char[] password) { - return doGetDB(mongo, databaseName,username,password, true); - } + } - public static DB doGetDB(Mongo mongo, String databaseName, String username, char[] password, boolean allowCreate) { - Assert.notNull(mongo, "No Mongo instance specified"); + /** + * Obtains a {@link DB} connection for the given {@link Mongo} instance and database name + * + * @param mongo The {@link Mongo} instance + * @param databaseName The database name + * @return The {@link DB} connection + */ + public static DB getDB(Mongo mongo, String databaseName) { + return doGetDB(mongo, databaseName, null, null, true); + } - DbHolder dbHolder = (DbHolder) TransactionSynchronizationManager.getResource(mongo); - if (dbHolder != null && !dbHolder.isEmpty()) { - // pre-bound Mongo DB - DB db = null; - if (TransactionSynchronizationManager.isSynchronizationActive() && - dbHolder.doesNotHoldNonDefaultDB()) { - // Spring transaction management is active -> - db = dbHolder.getDB(); - if (db != null && !dbHolder.isSynchronizedWithTransaction()) { - LOGGER.debug("Registering Spring transaction synchronization for existing Mongo DB"); - TransactionSynchronizationManager.registerSynchronization(new MongoSynchronization(dbHolder, mongo)); - dbHolder.setSynchronizedWithTransaction(true); - } - } - if (db != null) { - return db; - } - } + /** + * Obtains a {@link DB} connection for the given {@link Mongo} instance and database name + * + * @param mongo The {@link Mongo} instance + * @param databaseName The database name + * @param username The username to authenticate with + * @param password The password to authenticate with + * @return The {@link DB} connection + */ + public static DB getDB(Mongo mongo, String databaseName, String username, char[] password) { + return doGetDB(mongo, databaseName, username, password, true); + } - LOGGER.debug("Opening Mongo DB"); - DB db = mongo.getDB(databaseName); - boolean creadentialsGiven = username != null && password != null; - - if(creadentialsGiven && !db.authenticate(username, password)) { - throw new CannotGetMongoDbConnectionException("Failed to authenticate with Mongo using the given credentials"); - } - - // Use same Session for further Mongo actions within the transaction. - // Thread object will get removed by synchronization at transaction completion. - if (TransactionSynchronizationManager.isSynchronizationActive()) { - // We're within a Spring-managed transaction, possibly from JtaTransactionManager. - LOGGER.debug("Registering Spring transaction synchronization for new Hibernate Session"); - DbHolder holderToUse = dbHolder; - if (holderToUse == null) { - holderToUse = new DbHolder(db); - } - else { - holderToUse.addDB(db); - } - TransactionSynchronizationManager.registerSynchronization(new MongoSynchronization(holderToUse, mongo)); - holderToUse.setSynchronizedWithTransaction(true); - if (holderToUse != dbHolder) { - TransactionSynchronizationManager.bindResource(mongo, holderToUse); - } - } + public static DB doGetDB(Mongo mongo, String databaseName, String username, char[] password, boolean allowCreate) { + Assert.notNull(mongo, "No Mongo instance specified"); - // Check whether we are allowed to return the DB. - if (!allowCreate && !isDBTransactional(db, mongo)) { - throw new IllegalStateException("No Mongo DB bound to thread, " + - "and configuration does not allow creation of non-transactional one here"); - } + DbHolder dbHolder = (DbHolder) TransactionSynchronizationManager.getResource(mongo); + if (dbHolder != null && !dbHolder.isEmpty()) { + // pre-bound Mongo DB + DB db = null; + if (TransactionSynchronizationManager.isSynchronizationActive() && + dbHolder.doesNotHoldNonDefaultDB()) { + // Spring transaction management is active -> + db = dbHolder.getDB(); + if (db != null && !dbHolder.isSynchronizedWithTransaction()) { + LOGGER.debug("Registering Spring transaction synchronization for existing Mongo DB"); + TransactionSynchronizationManager.registerSynchronization(new MongoSynchronization(dbHolder, mongo)); + dbHolder.setSynchronizedWithTransaction(true); + } + } + if (db != null) { + return db; + } + } - return db; - } - + LOGGER.debug("Opening Mongo DB"); + DB db = mongo.getDB(databaseName); + boolean creadentialsGiven = username != null && password != null; - /** - * Return whether the given DB instance is transactional, that is, - * bound to the current thread by Spring's transaction facilities. - * @param db the DB to check - * @param mongo the Mongo instance that the DB was created with - * (may be null) - * @return whether the DB is transactional - */ - public static boolean isDBTransactional(DB db, Mongo mongo) { - if (mongo == null) { - return false; - } - DbHolder dbHolder = - (DbHolder) TransactionSynchronizationManager.getResource(mongo); - return (dbHolder != null && dbHolder.containsDB(db)); - } - - /** - * Perform actual closing of the Mongo DB object, - * catching and logging any cleanup exceptions thrown. - * @param db the DB to close (may be null) - */ - public static void closeDB(DB db) { - if (db != null) { - LOGGER.debug("Closing Mongo DB object"); - try { - db.requestDone(); - } - catch (Throwable ex) { - LOGGER.debug("Unexpected exception on closing Mongo DB object", ex); - } - } - } + if (creadentialsGiven && !db.authenticate(username, password)) { + throw new CannotGetMongoDbConnectionException("Failed to authenticate with Mongo using the given credentials"); + } + + // Use same Session for further Mongo actions within the transaction. + // Thread object will get removed by synchronization at transaction completion. + if (TransactionSynchronizationManager.isSynchronizationActive()) { + // We're within a Spring-managed transaction, possibly from JtaTransactionManager. + LOGGER.debug("Registering Spring transaction synchronization for new Hibernate Session"); + DbHolder holderToUse = dbHolder; + if (holderToUse == null) { + holderToUse = new DbHolder(db); + } else { + holderToUse.addDB(db); + } + TransactionSynchronizationManager.registerSynchronization(new MongoSynchronization(holderToUse, mongo)); + holderToUse.setSynchronizedWithTransaction(true); + if (holderToUse != dbHolder) { + TransactionSynchronizationManager.bindResource(mongo, holderToUse); + } + } + + // Check whether we are allowed to return the DB. + if (!allowCreate && !isDBTransactional(db, mongo)) { + throw new IllegalStateException("No Mongo DB bound to thread, " + + "and configuration does not allow creation of non-transactional one here"); + } + + return db; + } + + + /** + * Return whether the given DB instance is transactional, that is, + * bound to the current thread by Spring's transaction facilities. + * + * @param db the DB to check + * @param mongo the Mongo instance that the DB was created with + * (may be null) + * @return whether the DB is transactional + */ + public static boolean isDBTransactional(DB db, Mongo mongo) { + if (mongo == null) { + return false; + } + DbHolder dbHolder = + (DbHolder) TransactionSynchronizationManager.getResource(mongo); + return (dbHolder != null && dbHolder.containsDB(db)); + } + + /** + * Perform actual closing of the Mongo DB object, + * catching and logging any cleanup exceptions thrown. + * + * @param db the DB to close (may be null) + */ + public static void closeDB(DB db) { + if (db != null) { + LOGGER.debug("Closing Mongo DB object"); + try { + db.requestDone(); + } catch (Throwable ex) { + LOGGER.debug("Unexpected exception on closing Mongo DB object", ex); + } + } + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoExceptionTranslator.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoExceptionTranslator.java index 381708793..ecf9caad4 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoExceptionTranslator.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoExceptionTranslator.java @@ -15,52 +15,50 @@ */ package org.springframework.data.document.mongodb; +import com.mongodb.MongoException; +import com.mongodb.MongoException.DuplicateKey; +import com.mongodb.MongoException.Network; import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.dao.support.PersistenceExceptionTranslator; import org.springframework.data.document.UncategorizedDocumentStoreException; -import com.mongodb.MongoException; -import com.mongodb.MongoException.DuplicateKey; -import com.mongodb.MongoException.Network; - /** * Simple {@link PersistenceExceptionTranslator} for Mongo. Convert the given runtime exception to an appropriate * exception from the {@code org.springframework.dao} hierarchy. Return {@literal null} if no translation is * appropriate: any other exception may have resulted from user code, and should not be translated. + * * @param ex runtime exception that occurred - * @return the corresponding DataAccessException instance, or {@literal null} if the exception should not be translated - * - * * @author Oliver Gierke + * @return the corresponding DataAccessException instance, or {@literal null} if the exception should not be translated */ public class MongoExceptionTranslator implements PersistenceExceptionTranslator { - /* - * (non-Javadoc) - * - * @see org.springframework.dao.support.PersistenceExceptionTranslator# - * translateExceptionIfPossible(java.lang.RuntimeException) - */ - public DataAccessException translateExceptionIfPossible(RuntimeException ex) { + /* + * (non-Javadoc) + * + * @see org.springframework.dao.support.PersistenceExceptionTranslator# + * translateExceptionIfPossible(java.lang.RuntimeException) + */ + public DataAccessException translateExceptionIfPossible(RuntimeException ex) { - // Check for well-known MongoException subclasses. + // Check for well-known MongoException subclasses. - // All other MongoExceptions - if (ex instanceof DuplicateKey) { - return new DataIntegrityViolationException(ex.getMessage(), ex); - } - if (ex instanceof Network) { - return new DataAccessResourceFailureException(ex.getMessage(), ex); - } - if (ex instanceof MongoException) { - return new UncategorizedDocumentStoreException(ex.getMessage(), ex); - } + // All other MongoExceptions + if (ex instanceof DuplicateKey) { + return new DataIntegrityViolationException(ex.getMessage(), ex); + } + if (ex instanceof Network) { + return new DataAccessResourceFailureException(ex.getMessage(), ex); + } + if (ex instanceof MongoException) { + return new UncategorizedDocumentStoreException(ex.getMessage(), ex); + } - // If we get here, we have an exception that resulted from user code, - // rather than the persistence provider, so we return null to indicate - // that translation should not occur. - return null; - } + // If we get here, we have an exception that resulted from user code, + // rather than the persistence provider, so we return null to indicate + // that translation should not occur. + return null; + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoFactoryBean.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoFactoryBean.java index 4e2bec879..36ccfe9fc 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoFactoryBean.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoFactoryBean.java @@ -18,6 +18,9 @@ package org.springframework.data.document.mongodb; import java.util.List; +import com.mongodb.Mongo; +import com.mongodb.MongoOptions; +import com.mongodb.ServerAddress; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.FactoryBean; @@ -26,112 +29,103 @@ import org.springframework.dao.DataAccessException; import org.springframework.dao.support.PersistenceExceptionTranslator; import org.springframework.util.Assert; -import com.mongodb.Mongo; -import com.mongodb.MongoOptions; -import com.mongodb.ServerAddress; - /** * Convenient factory for configuring MongoDB. * * @author Thomas Risberg * @author Graeme Rocher - * * @since 1.0 */ public class MongoFactoryBean implements FactoryBean, InitializingBean, PersistenceExceptionTranslator { - - /** - * Logger, available to subclasses. - */ - protected final Log logger = LogFactory.getLog(getClass()); - private Mongo mongo; - private MongoOptions mongoOptions; - private String host; - private Integer port; - private List replicaSetSeeds; - private List replicaPair; + /** + * Logger, available to subclasses. + */ + protected final Log logger = LogFactory.getLog(getClass()); - private PersistenceExceptionTranslator exceptionTranslator = new MongoExceptionTranslator(); - - public void setMongoOptions(MongoOptions mongoOptions) { - this.mongoOptions = mongoOptions; - } + private Mongo mongo; + private MongoOptions mongoOptions; + private String host; + private Integer port; + private List replicaSetSeeds; + private List replicaPair; - public void setReplicaSetSeeds(List replicaSetSeeds) { - this.replicaSetSeeds = replicaSetSeeds; - } - - public void setReplicaPair(List replicaPair) { - this.replicaPair = replicaPair; - } + private PersistenceExceptionTranslator exceptionTranslator = new MongoExceptionTranslator(); - public void setHost(String host) { - this.host = host; - } + public void setMongoOptions(MongoOptions mongoOptions) { + this.mongoOptions = mongoOptions; + } - public void setPort(int port) { - this.port = port; - } + public void setReplicaSetSeeds(List replicaSetSeeds) { + this.replicaSetSeeds = replicaSetSeeds; + } - public PersistenceExceptionTranslator getExceptionTranslator() { - return exceptionTranslator; - } + public void setReplicaPair(List replicaPair) { + this.replicaPair = replicaPair; + } - public void setExceptionTranslator( - PersistenceExceptionTranslator exceptionTranslator) { - this.exceptionTranslator = exceptionTranslator; - } + public void setHost(String host) { + this.host = host; + } - public Mongo getObject() throws Exception { - Assert.notNull(mongo, "Mongo must not be null"); - return mongo; - } + public void setPort(int port) { + this.port = port; + } - public Class getObjectType() { - return Mongo.class; - } + public PersistenceExceptionTranslator getExceptionTranslator() { + return exceptionTranslator; + } - public boolean isSingleton() { - return false; - } + public void setExceptionTranslator( + PersistenceExceptionTranslator exceptionTranslator) { + this.exceptionTranslator = exceptionTranslator; + } - public void afterPropertiesSet() throws Exception { - // apply defaults - convenient when used to configure for tests - // in an application context - if (mongo == null) { - - if (host == null) { - logger.warn("Property host not specified. Using default configuration"); - mongo = new Mongo(); - } - else { - ServerAddress defaultOptions = new ServerAddress(); - if(mongoOptions == null) mongoOptions = new MongoOptions(); - if(replicaPair != null) { - if(replicaPair.size() < 2) { - throw new CannotGetMongoDbConnectionException("A replica pair must have two server entries"); - } - mongo = new Mongo(replicaPair.get(0), replicaPair.get(1), mongoOptions); - } - else if(replicaSetSeeds != null) { - mongo = new Mongo(replicaSetSeeds, mongoOptions); - } - else { - String mongoHost = host != null ? host : defaultOptions.getHost(); - if(port != null) { - mongo = new Mongo(new ServerAddress(mongoHost, port), mongoOptions); - } - else { - mongo = new Mongo(mongoHost, mongoOptions); - } - } - } - } - } + public Mongo getObject() throws Exception { + Assert.notNull(mongo, "Mongo must not be null"); + return mongo; + } - public DataAccessException translateExceptionIfPossible(RuntimeException ex) { - return exceptionTranslator.translateExceptionIfPossible(ex); - } + public Class getObjectType() { + return Mongo.class; + } + + public boolean isSingleton() { + return false; + } + + public void afterPropertiesSet() throws Exception { + // apply defaults - convenient when used to configure for tests + // in an application context + if (mongo == null) { + + if (host == null) { + logger.warn("Property host not specified. Using default configuration"); + mongo = new Mongo(); + } else { + ServerAddress defaultOptions = new ServerAddress(); + if (mongoOptions == null) mongoOptions = new MongoOptions(); + if (replicaPair != null) { + if (replicaPair.size() < 2) { + throw new CannotGetMongoDbConnectionException("A replica pair must have two server entries"); + } + mongo = new Mongo(replicaPair.get(0), replicaPair.get(1), mongoOptions); + } else if (replicaSetSeeds != null) { + mongo = new Mongo(replicaSetSeeds, mongoOptions); + } else { + String mongoHost = host != null ? host : defaultOptions.getHost(); + if (port != null) { + mongo = new Mongo(new ServerAddress(mongoHost, port), mongoOptions); + } else { + mongo = new Mongo(mongoHost, mongoOptions); + } + } + } + } + } + + public DataAccessException translateExceptionIfPossible(RuntimeException ex) { + return exceptionTranslator.translateExceptionIfPossible(ex); + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoOperations.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoOperations.java index 19eec28f1..8bbb651f8 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoOperations.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoOperations.java @@ -18,602 +18,611 @@ package org.springframework.data.document.mongodb; import java.util.List; import java.util.Set; -import org.springframework.data.document.mongodb.query.IndexDefinition; -import org.springframework.data.document.mongodb.query.Query; -import org.springframework.data.document.mongodb.query.Update; - import com.mongodb.CommandResult; import com.mongodb.DBCollection; import com.mongodb.DBObject; import com.mongodb.WriteResult; +import org.springframework.data.document.mongodb.query.IndexDefinition; +import org.springframework.data.document.mongodb.query.Query; +import org.springframework.data.document.mongodb.query.Update; /** * Interface that specifies a basic set of MongoDB operations. Implemented by {@link MongoTemplate}. * Not often used but a useful option for extensibility and testability (as it can be easily mocked, stubbed, or be * the target of a JDK proxy). - * + * * @author Thomas Risberg * @author Mark Pollack * @author Oliver Gierke */ public interface MongoOperations { - /** - * The default collection name used by this template. - * @return - */ - String getDefaultCollectionName(); + /** + * The default collection name used by this template. + * + * @return + */ + String getDefaultCollectionName(); - /** - * The default collection used by this template. - * @return The default collection used by this template - */ - DBCollection getDefaultCollection(); - - /** - * Execute the a MongoDB command expressed as a JSON string. This will call the method - * JSON.parse that is part of the MongoDB driver to convert the JSON string to a DBObject. - * Any errors that result from executing this command will be converted into Spring's DAO - * exception hierarchy. - * @param jsonCommand a MongoDB command expressed as a JSON string. - */ - CommandResult executeCommand(String jsonCommand); + /** + * The default collection used by this template. + * + * @return The default collection used by this template + */ + DBCollection getDefaultCollection(); - /** - * Execute a MongoDB command. Any errors that result from executing this command will be converted - * into Spring's DAO exception hierarchy. - * @param command a MongoDB command - */ - CommandResult executeCommand(DBObject command); + /** + * Execute the a MongoDB command expressed as a JSON string. This will call the method + * JSON.parse that is part of the MongoDB driver to convert the JSON string to a DBObject. + * Any errors that result from executing this command will be converted into Spring's DAO + * exception hierarchy. + * + * @param jsonCommand a MongoDB command expressed as a JSON string. + */ + CommandResult executeCommand(String jsonCommand); - /** - * Executes a {@link DbCallback} translating any exceptions as necessary. - * - * Allows for returning a result object, that is a domain object or a collection of domain objects. - * - * @param return type - * @param action callback object that specifies the MongoDB actions to perform on the passed in DB instance. - * - * @return a result object returned by the action or null - */ - T execute(DbCallback action); + /** + * Execute a MongoDB command. Any errors that result from executing this command will be converted + * into Spring's DAO exception hierarchy. + * + * @param command a MongoDB command + */ + CommandResult executeCommand(DBObject command); - /** - * Executes the given {@link CollectionCallback} on the default collection. - * - * Allows for returning a result object, that is a domain object or a collection of domain objects. - * - * @param return type - * @param action callback object that specifies the MongoDB action - * @return a result object returned by the action or null - */ - T execute(CollectionCallback action); + /** + * Executes a {@link DbCallback} translating any exceptions as necessary. + *

      + * Allows for returning a result object, that is a domain object or a collection of domain objects. + * + * @param return type + * @param action callback object that specifies the MongoDB actions to perform on the passed in DB instance. + * @return a result object returned by the action or null + */ + T execute(DbCallback action); - /** - * Executes the given {@link CollectionCallback} on the collection of the given name. - * - * Allows for returning a result object, that is a domain object or a collection of domain objects. - * - * @param return type - * @param collectionName the name of the collection that specifies which DBCollection instance will be passed into - * @param action callback object that specifies the MongoDB action - * the callback action. - * @return a result object returned by the action or null - */ - T execute(String collectionName, CollectionCallback action); + /** + * Executes the given {@link CollectionCallback} on the default collection. + *

      + * Allows for returning a result object, that is a domain object or a collection of domain objects. + * + * @param return type + * @param action callback object that specifies the MongoDB action + * @return a result object returned by the action or null + */ + T execute(CollectionCallback action); - /** - * Executes the given {@link DbCallback} within the same connection to the database so as to ensure - * consistency in a write heavy environment where you may read the data that you wrote. See the - * comments on {@see Java Driver Concurrency} - * - * Allows for returning a result object, that is a domain object or a collection of domain objects. - * - * @param return type - * @param action callback that specified the MongoDB actions to perform on the DB instance - * @return a result object returned by the action or null - */ - T executeInSession(DbCallback action); + /** + * Executes the given {@link CollectionCallback} on the collection of the given name. + *

      + * Allows for returning a result object, that is a domain object or a collection of domain objects. + * + * @param return type + * @param collectionName the name of the collection that specifies which DBCollection instance will be passed into + * @param action callback object that specifies the MongoDB action + * the callback action. + * @return a result object returned by the action or null + */ + T execute(String collectionName, CollectionCallback action); - /** - * Create an uncapped collection with the provided name. - * @param collectionName name of the collection - * @return the created collection - */ - DBCollection createCollection(String collectionName); + /** + * Executes the given {@link DbCallback} within the same connection to the database so as to ensure + * consistency in a write heavy environment where you may read the data that you wrote. See the + * comments on {@see Java Driver Concurrency} + *

      + * Allows for returning a result object, that is a domain object or a collection of domain objects. + * + * @param return type + * @param action callback that specified the MongoDB actions to perform on the DB instance + * @return a result object returned by the action or null + */ + T executeInSession(DbCallback action); - /** - * Create a collect with the provided name and options. - * @param collectionName name of the collection - * @param collectionOptions options to use when creating the collection. - * @return the created collection - */ - DBCollection createCollection(String collectionName, CollectionOptions collectionOptions); + /** + * Create an uncapped collection with the provided name. + * + * @param collectionName name of the collection + * @return the created collection + */ + DBCollection createCollection(String collectionName); - /** - * A set of collection names. - * @return list of collection names - */ - Set getCollectionNames(); - - /** - * Get a collection by name, creating it if it doesn't exist. - * - * Translate any exceptions as necessary. - * - * @param collectionName name of the collection - * @return an existing collection or a newly created one. - */ - DBCollection getCollection(String collectionName); + /** + * Create a collect with the provided name and options. + * + * @param collectionName name of the collection + * @param collectionOptions options to use when creating the collection. + * @return the created collection + */ + DBCollection createCollection(String collectionName, CollectionOptions collectionOptions); - /** - * Check to see if a collection with a given name exists. - * - * Translate any exceptions as necessary. - * - * @param collectionName name of the collection - * @return true if a collection with the given name is found, false otherwise. - */ - boolean collectionExists(String collectionName); + /** + * A set of collection names. + * + * @return list of collection names + */ + Set getCollectionNames(); - /** - * Drop the collection with the given name. - * - * Translate any exceptions as necessary. - * - * @param collectionName name of the collection to drop/delete. - */ - void dropCollection(String collectionName); + /** + * Get a collection by name, creating it if it doesn't exist. + *

      + * Translate any exceptions as necessary. + * + * @param collectionName name of the collection + * @return an existing collection or a newly created one. + */ + DBCollection getCollection(String collectionName); - /** - * Query for a list of objects of type T from the default collection. - * - * The object is converted from the MongoDB native representation using an instance of - * {@see MongoConverter}. Unless configured otherwise, an - * instance of SimpleMongoConverter will be used. - * - * If your collection does not contain a homogeneous collection of types, this operation will not be an efficient - * way to map objects since the test for class type is done in the client and not on the server. - * - * @param targetClass the parameterized type of the returned list - * @return the converted collection - */ - List getCollection(Class targetClass); + /** + * Check to see if a collection with a given name exists. + *

      + * Translate any exceptions as necessary. + * + * @param collectionName name of the collection + * @return true if a collection with the given name is found, false otherwise. + */ + boolean collectionExists(String collectionName); - /** - * Query for a list of objects of type T from the specified collection. - * - * The object is converted from the MongoDB native representation using an instance of - * {@see MongoConverter}. Unless configured otherwise, an - * instance of SimpleMongoConverter will be used. - * - * If your collection does not contain a homogeneous collection of types, this operation will not be an efficient - * way to map objects since the test for class type is done in the client and not on the server. - * @param collectionName name of the collection to retrieve the objects from - * @param targetClass the parameterized type of the returned list. - * @return the converted collection - */ - List getCollection(String collectionName, Class targetClass); + /** + * Drop the collection with the given name. + *

      + * Translate any exceptions as necessary. + * + * @param collectionName name of the collection to drop/delete. + */ + void dropCollection(String collectionName); - /** - * Query for a list of objects of type T from the specified collection, mapping the DBObject using - * the provided MongoReader. - * - * @param collectionName name of the collection to retrieve the objects from - * @param targetClass the parameterized type of the returned list. - * @param reader the MongoReader to convert from DBObject to an object. - * @return the converted collection - */ - List getCollection(String collectionName, Class targetClass, - MongoReader reader); - - /** - * Ensure that an index for the provided {@link IndexDefinition} exists for the default collection. - * If not it will be created. - * - * @param index - */ - void ensureIndex(IndexDefinition indexDefinition); + /** + * Query for a list of objects of type T from the default collection. + *

      + * The object is converted from the MongoDB native representation using an instance of + * {@see MongoConverter}. Unless configured otherwise, an + * instance of SimpleMongoConverter will be used. + *

      + * If your collection does not contain a homogeneous collection of types, this operation will not be an efficient + * way to map objects since the test for class type is done in the client and not on the server. + * + * @param targetClass the parameterized type of the returned list + * @return the converted collection + */ + List getCollection(Class targetClass); - /** - * Ensure that an index for the provided {@link IndexDefinition} exists. If not it will be - * created. - * - * @param collectionName - * @param index - */ - void ensureIndex(String collectionName, IndexDefinition indexDefinition); + /** + * Query for a list of objects of type T from the specified collection. + *

      + * The object is converted from the MongoDB native representation using an instance of + * {@see MongoConverter}. Unless configured otherwise, an + * instance of SimpleMongoConverter will be used. + *

      + * If your collection does not contain a homogeneous collection of types, this operation will not be an efficient + * way to map objects since the test for class type is done in the client and not on the server. + * + * @param collectionName name of the collection to retrieve the objects from + * @param targetClass the parameterized type of the returned list. + * @return the converted collection + */ + List getCollection(String collectionName, Class targetClass); - /** - * Map the results of an ad-hoc query on the default MongoDB collection to a single instance of an object - * of the specified type. - * - * The object is converted from the MongoDB native representation using an instance of - * {@see MongoConverter}. Unless configured otherwise, an - * instance of SimpleMongoConverter will be used. - * - * The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more - * feature rich {@link Query}. - * - * @param query the query class that specifies the criteria used to find a record and also an optional fields specification - * @param targetClass the parameterized type of the returned list. - * @return the converted object - */ - T findOne(Query query, Class targetClass); + /** + * Query for a list of objects of type T from the specified collection, mapping the DBObject using + * the provided MongoReader. + * + * @param collectionName name of the collection to retrieve the objects from + * @param targetClass the parameterized type of the returned list. + * @param reader the MongoReader to convert from DBObject to an object. + * @return the converted collection + */ + List getCollection(String collectionName, Class targetClass, + MongoReader reader); - /** - * Map the results of an ad-hoc query on the default MongoDB collection to a single instance of an object - * of the specified type. - * - * The object is converted from the MongoDB native representation using an instance of - * {@see MongoConverter}. Unless configured otherwise, an - * instance of SimpleMongoConverter will be used. - * - * The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more - * feature rich {@link Query}. - * - * @param query the query class that specifies the criteria used to find a record and also an optional fields specification - * @param targetClass the parameterized type of the returned list. - * @param reader the MongoReader to convert from DBObject to an object. - * @return the converted object - */ - T findOne(Query query, Class targetClass, - MongoReader reader); + /** + * Ensure that an index for the provided {@link IndexDefinition} exists for the default collection. + * If not it will be created. + * + * @param index + */ + void ensureIndex(IndexDefinition indexDefinition); - /** - * Map the results of an ad-hoc query on the specified collection to a single instance of an object - * of the specified type. - * - * The object is converted from the MongoDB native representation using an instance of - * {@see MongoConverter}. Unless configured otherwise, an - * instance of SimpleMongoConverter will be used. - * - * The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more - * feature rich {@link Query}. - * - * @param collectionName name of the collection to retrieve the objects from - * @param query the query class that specifies the criteria used to find a record and also an optional fields specification - * @param targetClass the parameterized type of the returned list. - * @return the converted object - */ - T findOne(String collectionName, Query query, - Class targetClass); + /** + * Ensure that an index for the provided {@link IndexDefinition} exists. If not it will be + * created. + * + * @param collectionName + * @param index + */ + void ensureIndex(String collectionName, IndexDefinition indexDefinition); - /** - * Map the results of an ad-hoc query on the specified collection to a single instance of an object - * of the specified type. - * - * The object is converted from the MongoDB native representation using an instance of - * {@see MongoConverter}. Unless configured otherwise, an - * instance of SimpleMongoConverter will be used. - * - * The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more - * feature rich {@link Query}. - * - * @param collectionName name of the collection to retrieve the objects from - * @param query the query class that specifies the criteria used to find a record and also an optional fields specification - * @param targetClass the parameterized type of the returned list. - * @param reader the MongoReader to convert from DBObject to an object. - * @return the converted object - */ - T findOne(String collectionName, Query query, - Class targetClass, MongoReader reader); + /** + * Map the results of an ad-hoc query on the default MongoDB collection to a single instance of an object + * of the specified type. + *

      + * The object is converted from the MongoDB native representation using an instance of + * {@see MongoConverter}. Unless configured otherwise, an + * instance of SimpleMongoConverter will be used. + *

      + * The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more + * feature rich {@link Query}. + * + * @param query the query class that specifies the criteria used to find a record and also an optional fields specification + * @param targetClass the parameterized type of the returned list. + * @return the converted object + */ + T findOne(Query query, Class targetClass); - /** - * Map the results of an ad-hoc query on the default MongoDB collection to a List of the specified type. - * - * The object is converted from the MongoDB native representation using an instance of - * {@see MongoConverter}. Unless configured otherwise, an - * instance of SimpleMongoConverter will be used. - * - * The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more - * feature rich {@link Query}. - * - * @param query the query class that specifies the criteria used to find a record and also an optional fields specification - * @param targetClass the parameterized type of the returned list. - * @return the List of converted objects - */ - List find(Query query, Class targetClass); + /** + * Map the results of an ad-hoc query on the default MongoDB collection to a single instance of an object + * of the specified type. + *

      + * The object is converted from the MongoDB native representation using an instance of + * {@see MongoConverter}. Unless configured otherwise, an + * instance of SimpleMongoConverter will be used. + *

      + * The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more + * feature rich {@link Query}. + * + * @param query the query class that specifies the criteria used to find a record and also an optional fields specification + * @param targetClass the parameterized type of the returned list. + * @param reader the MongoReader to convert from DBObject to an object. + * @return the converted object + */ + T findOne(Query query, Class targetClass, + MongoReader reader); - /** - * Map the results of an ad-hoc query on the default MongoDB collection to a List of the specified type. - * - * The object is converted from the MongoDB native representation using an instance of - * {@see MongoConverter}. Unless configured otherwise, an - * instance of SimpleMongoConverter will be used. - * - * The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more - * feature rich {@link Query}. - * - * @param query the query class that specifies the criteria used to find a record and also an optional fields specification - * @param targetClass the parameterized type of the returned list. - * @param reader the MongoReader to convert from DBObject to an object. - * @return the List of converted objects - */ - List find(Query query, Class targetClass, - MongoReader reader); + /** + * Map the results of an ad-hoc query on the specified collection to a single instance of an object + * of the specified type. + *

      + * The object is converted from the MongoDB native representation using an instance of + * {@see MongoConverter}. Unless configured otherwise, an + * instance of SimpleMongoConverter will be used. + *

      + * The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more + * feature rich {@link Query}. + * + * @param collectionName name of the collection to retrieve the objects from + * @param query the query class that specifies the criteria used to find a record and also an optional fields specification + * @param targetClass the parameterized type of the returned list. + * @return the converted object + */ + T findOne(String collectionName, Query query, + Class targetClass); - /** - * Map the results of an ad-hoc query on the specified collection to a List of the specified type. - * - * The object is converted from the MongoDB native representation using an instance of - * {@see MongoConverter}. Unless configured otherwise, an - * instance of SimpleMongoConverter will be used. - * - * The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more - * feature rich {@link Query}. - * - * @param collectionName name of the collection to retrieve the objects from - * @param query the query class that specifies the criteria used to find a record and also an optional fields specification - * @param targetClass the parameterized type of the returned list. - * @return the List of converted objects - */ - List find(String collectionName, Query query, - Class targetClass); + /** + * Map the results of an ad-hoc query on the specified collection to a single instance of an object + * of the specified type. + *

      + * The object is converted from the MongoDB native representation using an instance of + * {@see MongoConverter}. Unless configured otherwise, an + * instance of SimpleMongoConverter will be used. + *

      + * The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more + * feature rich {@link Query}. + * + * @param collectionName name of the collection to retrieve the objects from + * @param query the query class that specifies the criteria used to find a record and also an optional fields specification + * @param targetClass the parameterized type of the returned list. + * @param reader the MongoReader to convert from DBObject to an object. + * @return the converted object + */ + T findOne(String collectionName, Query query, + Class targetClass, MongoReader reader); - /** - * Map the results of an ad-hoc query on the specified collection to a List of the specified type. - * - * The object is converted from the MongoDB native representation using an instance of - * {@see MongoConverter}. Unless configured otherwise, an - * instance of SimpleMongoConverter will be used. - * - * The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more - * feature rich {@link Query}. - * - * @param collectionName name of the collection to retrieve the objects from - * @param query the query class that specifies the criteria used to find a record and also an optional fields specification - * @param targetClass the parameterized type of the returned list. - * @param reader the MongoReader to convert from DBObject to an object. - * @return the List of converted objects - */ - List find(String collectionName, Query query, - Class targetClass, MongoReader reader); + /** + * Map the results of an ad-hoc query on the default MongoDB collection to a List of the specified type. + *

      + * The object is converted from the MongoDB native representation using an instance of + * {@see MongoConverter}. Unless configured otherwise, an + * instance of SimpleMongoConverter will be used. + *

      + * The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more + * feature rich {@link Query}. + * + * @param query the query class that specifies the criteria used to find a record and also an optional fields specification + * @param targetClass the parameterized type of the returned list. + * @return the List of converted objects + */ + List find(Query query, Class targetClass); + + /** + * Map the results of an ad-hoc query on the default MongoDB collection to a List of the specified type. + *

      + * The object is converted from the MongoDB native representation using an instance of + * {@see MongoConverter}. Unless configured otherwise, an + * instance of SimpleMongoConverter will be used. + *

      + * The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more + * feature rich {@link Query}. + * + * @param query the query class that specifies the criteria used to find a record and also an optional fields specification + * @param targetClass the parameterized type of the returned list. + * @param reader the MongoReader to convert from DBObject to an object. + * @return the List of converted objects + */ + List find(Query query, Class targetClass, + MongoReader reader); + + /** + * Map the results of an ad-hoc query on the specified collection to a List of the specified type. + *

      + * The object is converted from the MongoDB native representation using an instance of + * {@see MongoConverter}. Unless configured otherwise, an + * instance of SimpleMongoConverter will be used. + *

      + * The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more + * feature rich {@link Query}. + * + * @param collectionName name of the collection to retrieve the objects from + * @param query the query class that specifies the criteria used to find a record and also an optional fields specification + * @param targetClass the parameterized type of the returned list. + * @return the List of converted objects + */ + List find(String collectionName, Query query, + Class targetClass); + + /** + * Map the results of an ad-hoc query on the specified collection to a List of the specified type. + *

      + * The object is converted from the MongoDB native representation using an instance of + * {@see MongoConverter}. Unless configured otherwise, an + * instance of SimpleMongoConverter will be used. + *

      + * The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more + * feature rich {@link Query}. + * + * @param collectionName name of the collection to retrieve the objects from + * @param query the query class that specifies the criteria used to find a record and also an optional fields specification + * @param targetClass the parameterized type of the returned list. + * @param reader the MongoReader to convert from DBObject to an object. + * @return the List of converted objects + */ + List find(String collectionName, Query query, + Class targetClass, MongoReader reader); - /** - * Map the results of an ad-hoc query on the specified collection to a List of the specified type. - * - * The object is converted from the MongoDB native representation using an instance of - * {@see MongoConverter}. Unless configured otherwise, an - * instance of SimpleMongoConverter will be used. - * - * The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more - * feature rich {@link Query}. - * - * @param collectionName name of the collection to retrieve the objects from - * @param query the query class that specifies the criteria used to find a record and also an optional fields specification - * @param targetClass the parameterized type of the returned list. - * @param preparer allows for customization of the DBCursor used when iterating over the result set, - * (apply limits, skips and so on). - * @return the List of converted objects. - */ - List find(String collectionName, Query query, Class targetClass, CursorPreparer preparer); + /** + * Map the results of an ad-hoc query on the specified collection to a List of the specified type. + *

      + * The object is converted from the MongoDB native representation using an instance of + * {@see MongoConverter}. Unless configured otherwise, an + * instance of SimpleMongoConverter will be used. + *

      + * The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more + * feature rich {@link Query}. + * + * @param collectionName name of the collection to retrieve the objects from + * @param query the query class that specifies the criteria used to find a record and also an optional fields specification + * @param targetClass the parameterized type of the returned list. + * @param preparer allows for customization of the DBCursor used when iterating over the result set, + * (apply limits, skips and so on). + * @return the List of converted objects. + */ + List find(String collectionName, Query query, Class targetClass, CursorPreparer preparer); - /** - * Insert the object into the default collection. - * - * The object is converted to the MongoDB native representation using an instance of - * {@see MongoConverter}. Unless configured otherwise, an - * instance of SimpleMongoConverter will be used. - * - * If you object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property - * is a String then MongoDB ObjectId will be used to populate that string. Otherwise, the conversion from - * ObjectId to your property type will be handled by Spring's BeanWrapper class that leverages Spring 3.0's - * new Type Conversion API. - * See Spring 3 Type Conversion" - * for more details. - * - * - * Insert is used to initially store the object into the database. - * To update an existing object use the save method. - * - * @param objectToSave the object to store in the collection. - */ - void insert(Object objectToSave); + /** + * Insert the object into the default collection. + *

      + * The object is converted to the MongoDB native representation using an instance of + * {@see MongoConverter}. Unless configured otherwise, an + * instance of SimpleMongoConverter will be used. + *

      + * If you object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property + * is a String then MongoDB ObjectId will be used to populate that string. Otherwise, the conversion from + * ObjectId to your property type will be handled by Spring's BeanWrapper class that leverages Spring 3.0's + * new Type Conversion API. + * See Spring 3 Type Conversion" + * for more details. + *

      + *

      + * Insert is used to initially store the object into the database. + * To update an existing object use the save method. + * + * @param objectToSave the object to store in the collection. + */ + void insert(Object objectToSave); - /** - * Insert the object into the specified collection. - * - * The object is converted to the MongoDB native representation using an instance of - * {@see MongoConverter}. Unless configured otherwise, an - * instance of SimpleMongoConverter will be used. - * - * Insert is used to initially store the object into the - * database. To update an existing object use the save method. - * - * @param collectionName name of the collection to store the object in - * @param objectToSave the object to store in the collection - */ - void insert(String collectionName, Object objectToSave); + /** + * Insert the object into the specified collection. + *

      + * The object is converted to the MongoDB native representation using an instance of + * {@see MongoConverter}. Unless configured otherwise, an + * instance of SimpleMongoConverter will be used. + *

      + * Insert is used to initially store the object into the + * database. To update an existing object use the save method. + * + * @param collectionName name of the collection to store the object in + * @param objectToSave the object to store in the collection + */ + void insert(String collectionName, Object objectToSave); - /** - * Insert the object into the default collection. - * - * The object is converted to the MongoDB native representation using an instance of - * {@see MongoWriter} - * - * Insert is used to initially store the object into the - * database. To update an existing object use the save method. - * - * @param the type of the object to insert - * @param objectToSave the object to store in the collection - * @param writer the writer to convert the object to save into a DBObject - */ - void insert(T objectToSave, MongoWriter writer); + /** + * Insert the object into the default collection. + *

      + * The object is converted to the MongoDB native representation using an instance of + * {@see MongoWriter} + *

      + * Insert is used to initially store the object into the + * database. To update an existing object use the save method. + * + * @param the type of the object to insert + * @param objectToSave the object to store in the collection + * @param writer the writer to convert the object to save into a DBObject + */ + void insert(T objectToSave, MongoWriter writer); - /** - * Insert the object into the specified collection. - * - * The object is converted to the MongoDB native representation using an instance of - * {@see MongoWriter} - * - * Insert is used to initially store the object into the - * database. To update an existing object use the save method. - * - * @param the type of the object to insert - * @param collectionName name of the collection to store the object in - * @param objectToSave the object to store in the collection - * @param writer the writer to convert the object to save into a DBObject - */ - void insert(String collectionName, T objectToSave, MongoWriter writer); + /** + * Insert the object into the specified collection. + *

      + * The object is converted to the MongoDB native representation using an instance of + * {@see MongoWriter} + *

      + * Insert is used to initially store the object into the + * database. To update an existing object use the save method. + * + * @param the type of the object to insert + * @param collectionName name of the collection to store the object in + * @param objectToSave the object to store in the collection + * @param writer the writer to convert the object to save into a DBObject + */ + void insert(String collectionName, T objectToSave, MongoWriter writer); - /** - * Insert a list of objects into the default collection in a single batch write to the database. - * - * @param listToSave the list of objects to save. - */ - void insertList(List listToSave); + /** + * Insert a list of objects into the default collection in a single batch write to the database. + * + * @param listToSave the list of objects to save. + */ + void insertList(List listToSave); - /** - * Insert a list of objects into the specified collection in a single batch write to the database. - * @param collectionName name of the collection to store the object in - * @param listToSave the list of objects to save. - */ - void insertList(String collectionName, List listToSave); + /** + * Insert a list of objects into the specified collection in a single batch write to the database. + * + * @param collectionName name of the collection to store the object in + * @param listToSave the list of objects to save. + */ + void insertList(String collectionName, List listToSave); - /** - * Insert a list of objects into the default collection using the provided MongoWriter instance - * - * @param the type of object being saved - * @param listToSave the list of objects to save. - * @param writer the writer to convert the object to save into a DBObject - */ - void insertList(List listToSave, MongoWriter writer); + /** + * Insert a list of objects into the default collection using the provided MongoWriter instance + * + * @param the type of object being saved + * @param listToSave the list of objects to save. + * @param writer the writer to convert the object to save into a DBObject + */ + void insertList(List listToSave, MongoWriter writer); - /** - * Insert a list of objects into the specified collection using the provided MongoWriter instance - * - * @param the type of object being saved - * @param collectionName name of the collection to store the object in - * @param listToSave the list of objects to save. - * @param writer the writer to convert the object to save into a DBObject - */ - void insertList(String collectionName, List listToSave, MongoWriter writer); + /** + * Insert a list of objects into the specified collection using the provided MongoWriter instance + * + * @param the type of object being saved + * @param collectionName name of the collection to store the object in + * @param listToSave the list of objects to save. + * @param writer the writer to convert the object to save into a DBObject + */ + void insertList(String collectionName, List listToSave, MongoWriter writer); - /** - * Save the object to the default collection. This will perform an insert if the object is not already - * present, that is an 'upsert'. - * - * The object is converted to the MongoDB native representation using an instance of - * {@see MongoConverter}. Unless configured otherwise, an - * instance of SimpleMongoConverter will be used. - * - * If you object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property - * is a String then MongoDB ObjectId will be used to populate that string. Otherwise, the conversion from - * ObjectId to your property type will be handled by Spring's BeanWrapper class that leverages Spring 3.0's - * new Type Conversion API. - * See Spring 3 Type Conversion" - * for more details. - * - * @param objectToSave the object to store in the collection - */ - void save(Object objectToSave); + /** + * Save the object to the default collection. This will perform an insert if the object is not already + * present, that is an 'upsert'. + *

      + * The object is converted to the MongoDB native representation using an instance of + * {@see MongoConverter}. Unless configured otherwise, an + * instance of SimpleMongoConverter will be used. + *

      + * If you object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property + * is a String then MongoDB ObjectId will be used to populate that string. Otherwise, the conversion from + * ObjectId to your property type will be handled by Spring's BeanWrapper class that leverages Spring 3.0's + * new Type Conversion API. + * See Spring 3 Type Conversion" + * for more details. + * + * @param objectToSave the object to store in the collection + */ + void save(Object objectToSave); - /** - * Save the object to the specified collection. This will perform an insert if the object is not already - * present, that is an 'upsert'. - * - * The object is converted to the MongoDB native representation using an instance of - * {@see MongoConverter}. Unless configured otherwise, an - * instance of SimpleMongoConverter will be used. - * - * If you object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property - * is a String then MongoDB ObjectId will be used to populate that string. Otherwise, the conversion from - * ObjectId to your property type will be handled by Spring's BeanWrapper class that leverages Spring 3.0's - * new Type Cobnversion API. - * See Spring 3 Type Conversion" - * for more details. - * - * @param collectionName name of the collection to store the object in - * @param objectToSave the object to store in the collection - */ - void save(String collectionName, Object objectToSave); + /** + * Save the object to the specified collection. This will perform an insert if the object is not already + * present, that is an 'upsert'. + *

      + * The object is converted to the MongoDB native representation using an instance of + * {@see MongoConverter}. Unless configured otherwise, an + * instance of SimpleMongoConverter will be used. + *

      + * If you object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property + * is a String then MongoDB ObjectId will be used to populate that string. Otherwise, the conversion from + * ObjectId to your property type will be handled by Spring's BeanWrapper class that leverages Spring 3.0's + * new Type Cobnversion API. + * See Spring 3 Type Conversion" + * for more details. + * + * @param collectionName name of the collection to store the object in + * @param objectToSave the object to store in the collection + */ + void save(String collectionName, Object objectToSave); - /** - * Save the object into the default collection using the provided writer. - * This will perform an insert if the object is not already - * present, that is an 'upsert'. - * - * The object is converted to the MongoDB native representation using an instance of - * {@see MongoWriter} - * - * @param the type of the object to insert - * @param objectToSave the object to store in the collection - * @param writer the writer to convert the object to save into a DBObject - */ - void save(T objectToSave, MongoWriter writer); + /** + * Save the object into the default collection using the provided writer. + * This will perform an insert if the object is not already + * present, that is an 'upsert'. + *

      + * The object is converted to the MongoDB native representation using an instance of + * {@see MongoWriter} + * + * @param the type of the object to insert + * @param objectToSave the object to store in the collection + * @param writer the writer to convert the object to save into a DBObject + */ + void save(T objectToSave, MongoWriter writer); - /** - * Save the object into the specified collection using the provided writer. - * This will perform an insert if the object is not already - * present, that is an 'upsert'. - * - * The object is converted to the MongoDB native representation using an instance of - * {@see MongoWriter} - * - * @param the type of the object to insert - * @param collectionName name of the collection to store the object in - * @param objectToSave the object to store in the collection - * @param writer the writer to convert the object to save into a DBObject - */ - void save(String collectionName, T objectToSave, MongoWriter writer); + /** + * Save the object into the specified collection using the provided writer. + * This will perform an insert if the object is not already + * present, that is an 'upsert'. + *

      + * The object is converted to the MongoDB native representation using an instance of + * {@see MongoWriter} + * + * @param the type of the object to insert + * @param collectionName name of the collection to store the object in + * @param objectToSave the object to store in the collection + * @param writer the writer to convert the object to save into a DBObject + */ + void save(String collectionName, T objectToSave, MongoWriter writer); - /** - * Updates the first object that is found in the default collection that matches the query document - * with the provided updated document. - * - * @param queryDoc the query document that specifies the criteria used to select a record to be updated - * @param updateDoc the update document that contains the updated object or $ operators to manipulate the - * existing object. - */ - WriteResult updateFirst(Query query, Update update); + /** + * Updates the first object that is found in the default collection that matches the query document + * with the provided updated document. + * + * @param queryDoc the query document that specifies the criteria used to select a record to be updated + * @param updateDoc the update document that contains the updated object or $ operators to manipulate the + * existing object. + */ + WriteResult updateFirst(Query query, Update update); - /** - * Updates the first object that is found in the specified collection that matches the query document criteria - * with the provided updated document. - * - * @param collectionName name of the collection to update the object in - * @param queryDoc the query document that specifies the criteria used to select a record to be updated - * @param updateDoc the update document that contains the updated object or $ operators to manipulate the - * existing object. - */ - WriteResult updateFirst(String collectionName, Query query, - Update update); + /** + * Updates the first object that is found in the specified collection that matches the query document criteria + * with the provided updated document. + * + * @param collectionName name of the collection to update the object in + * @param queryDoc the query document that specifies the criteria used to select a record to be updated + * @param updateDoc the update document that contains the updated object or $ operators to manipulate the + * existing object. + */ + WriteResult updateFirst(String collectionName, Query query, + Update update); - /** - * Updates all objects that are found in the default collection that matches the query document criteria - * with the provided updated document. - * - * @param queryDoc the query document that specifies the criteria used to select a record to be updated - * @param updateDoc the update document that contains the updated object or $ operators to manipulate the - * existing object. - */ - WriteResult updateMulti(Query query, Update update); + /** + * Updates all objects that are found in the default collection that matches the query document criteria + * with the provided updated document. + * + * @param queryDoc the query document that specifies the criteria used to select a record to be updated + * @param updateDoc the update document that contains the updated object or $ operators to manipulate the + * existing object. + */ + WriteResult updateMulti(Query query, Update update); - /** - * Updates all objects that are found in the specified collection that matches the query document criteria - * with the provided updated document. - * - * @param collectionName name of the collection to update the object in - * @param queryDoc the query document that specifies the criteria used to select a record to be updated - * @param updateDoc the update document that contains the updated object or $ operators to manipulate the - * existing object. - */ - WriteResult updateMulti(String collectionName, Query query, - Update update); + /** + * Updates all objects that are found in the specified collection that matches the query document criteria + * with the provided updated document. + * + * @param collectionName name of the collection to update the object in + * @param queryDoc the query document that specifies the criteria used to select a record to be updated + * @param updateDoc the update document that contains the updated object or $ operators to manipulate the + * existing object. + */ + WriteResult updateMulti(String collectionName, Query query, + Update update); - /** - * Remove all documents from the default collection that match the provided query document criteria. - * @param queryDoc the query document that specifies the criteria used to remove a record - */ - void remove(Query query); + /** + * Remove all documents from the default collection that match the provided query document criteria. + * + * @param queryDoc the query document that specifies the criteria used to remove a record + */ + void remove(Query query); - /** - * Remove all documents from the specified collection that match the provided query document criteria. - * @param collectionName name of the collection where the objects will removed - * @param queryDoc the query document that specifies the criteria used to remove a record - */ - void remove(String collectionName, Query query); + /** + * Remove all documents from the specified collection that match the provided query document criteria. + * + * @param collectionName name of the collection where the objects will removed + * @param queryDoc the query document that specifies the criteria used to remove a record + */ + void remove(String collectionName, Query query); } \ No newline at end of file diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoOptionsFactoryBean.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoOptionsFactoryBean.java index 0c12f3202..e9baffd9d 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoOptionsFactoryBean.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoOptionsFactoryBean.java @@ -15,123 +15,120 @@ */ package org.springframework.data.document.mongodb; +import com.mongodb.MongoOptions; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; - -import com.mongodb.MongoOptions; - /** * A factory bean for consruction a MongoOptions instance - * - * @author Graeme Rocher * + * @author Graeme Rocher */ -public class MongoOptionsFactoryBean implements FactoryBean, InitializingBean{ +public class MongoOptionsFactoryBean implements FactoryBean, InitializingBean { - private static final MongoOptions MONGO_OPTIONS = new MongoOptions(); - /** - number of connections allowed per host - will block if run out - */ - private int connectionsPerHost = MONGO_OPTIONS.connectionsPerHost; + private static final MongoOptions MONGO_OPTIONS = new MongoOptions(); + /** + * number of connections allowed per host + * will block if run out + */ + private int connectionsPerHost = MONGO_OPTIONS.connectionsPerHost; - /** - multiplier for connectionsPerHost for # of threads that can block - if connectionsPerHost is 10, and threadsAllowedToBlockForConnectionMultiplier is 5, - then 50 threads can block - more than that and an exception will be throw - */ - private int threadsAllowedToBlockForConnectionMultiplier = MONGO_OPTIONS.threadsAllowedToBlockForConnectionMultiplier; - - /** - * max wait time of a blocking thread for a connection - */ - private int maxWaitTime = MONGO_OPTIONS.maxWaitTime; + /** + * multiplier for connectionsPerHost for # of threads that can block + * if connectionsPerHost is 10, and threadsAllowedToBlockForConnectionMultiplier is 5, + * then 50 threads can block + * more than that and an exception will be throw + */ + private int threadsAllowedToBlockForConnectionMultiplier = MONGO_OPTIONS.threadsAllowedToBlockForConnectionMultiplier; - /** - connect timeout in milliseconds. 0 is default and infinite - */ - private int connectTimeout = MONGO_OPTIONS.connectTimeout; + /** + * max wait time of a blocking thread for a connection + */ + private int maxWaitTime = MONGO_OPTIONS.maxWaitTime; - /** - socket timeout. 0 is default and infinite - */ - private int socketTimeout = MONGO_OPTIONS.socketTimeout; - - /** - this controls whether or not on a connect, the system retries automatically - */ - private boolean autoConnectRetry = MONGO_OPTIONS.autoConnectRetry; - - - /** - number of connections allowed per host - will block if run out - */ - public void setConnectionsPerHost(int connectionsPerHost) { - this.connectionsPerHost = connectionsPerHost; - } + /** + * connect timeout in milliseconds. 0 is default and infinite + */ + private int connectTimeout = MONGO_OPTIONS.connectTimeout; - /** - multiplier for connectionsPerHost for # of threads that can block - if connectionsPerHost is 10, and threadsAllowedToBlockForConnectionMultiplier is 5, - then 50 threads can block - more than that and an exception will be throw - */ - public void setThreadsAllowedToBlockForConnectionMultiplier( - int threadsAllowedToBlockForConnectionMultiplier) { - this.threadsAllowedToBlockForConnectionMultiplier = threadsAllowedToBlockForConnectionMultiplier; - } + /** + * socket timeout. 0 is default and infinite + */ + private int socketTimeout = MONGO_OPTIONS.socketTimeout; - /** - * max wait time of a blocking thread for a connection - */ - public void setMaxWaitTime(int maxWaitTime) { - this.maxWaitTime = maxWaitTime; - } + /** + * this controls whether or not on a connect, the system retries automatically + */ + private boolean autoConnectRetry = MONGO_OPTIONS.autoConnectRetry; - /** - connect timeout in milliseconds. 0 is default and infinite - */ - public void setConnectTimeout(int connectTimeout) { - this.connectTimeout = connectTimeout; - } - /** - socket timeout. 0 is default and infinite - */ - public void setSocketTimeout(int socketTimeout) { - this.socketTimeout = socketTimeout; - } + /** + * number of connections allowed per host + * will block if run out + */ + public void setConnectionsPerHost(int connectionsPerHost) { + this.connectionsPerHost = connectionsPerHost; + } - /** - this controls whether or not on a connect, the system retries automatically - */ - public void setAutoConnectRetry(boolean autoConnectRetry) { - this.autoConnectRetry = autoConnectRetry; - } + /** + * multiplier for connectionsPerHost for # of threads that can block + * if connectionsPerHost is 10, and threadsAllowedToBlockForConnectionMultiplier is 5, + * then 50 threads can block + * more than that and an exception will be throw + */ + public void setThreadsAllowedToBlockForConnectionMultiplier( + int threadsAllowedToBlockForConnectionMultiplier) { + this.threadsAllowedToBlockForConnectionMultiplier = threadsAllowedToBlockForConnectionMultiplier; + } - public void afterPropertiesSet() { - MONGO_OPTIONS.connectionsPerHost = connectionsPerHost; - MONGO_OPTIONS.threadsAllowedToBlockForConnectionMultiplier = threadsAllowedToBlockForConnectionMultiplier; - MONGO_OPTIONS.maxWaitTime = maxWaitTime; - MONGO_OPTIONS.connectTimeout = connectTimeout; - MONGO_OPTIONS.socketTimeout = socketTimeout; - MONGO_OPTIONS.autoConnectRetry = autoConnectRetry; - - } + /** + * max wait time of a blocking thread for a connection + */ + public void setMaxWaitTime(int maxWaitTime) { + this.maxWaitTime = maxWaitTime; + } - public MongoOptions getObject() { - return MONGO_OPTIONS; - } + /** + * connect timeout in milliseconds. 0 is default and infinite + */ + public void setConnectTimeout(int connectTimeout) { + this.connectTimeout = connectTimeout; + } - public Class getObjectType() { - return MongoOptions.class; - } + /** + * socket timeout. 0 is default and infinite + */ + public void setSocketTimeout(int socketTimeout) { + this.socketTimeout = socketTimeout; + } - public boolean isSingleton() { - return true; - } + /** + * this controls whether or not on a connect, the system retries automatically + */ + public void setAutoConnectRetry(boolean autoConnectRetry) { + this.autoConnectRetry = autoConnectRetry; + } + + public void afterPropertiesSet() { + MONGO_OPTIONS.connectionsPerHost = connectionsPerHost; + MONGO_OPTIONS.threadsAllowedToBlockForConnectionMultiplier = threadsAllowedToBlockForConnectionMultiplier; + MONGO_OPTIONS.maxWaitTime = maxWaitTime; + MONGO_OPTIONS.connectTimeout = connectTimeout; + MONGO_OPTIONS.socketTimeout = socketTimeout; + MONGO_OPTIONS.autoConnectRetry = autoConnectRetry; + + } + + public MongoOptions getObject() { + return MONGO_OPTIONS; + } + + public Class getObjectType() { + return MongoOptions.class; + } + + public boolean isSingleton() { + return true; + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoPropertyDescriptors.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoPropertyDescriptors.java index 0192f1eb6..2ea985ffb 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoPropertyDescriptors.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoPropertyDescriptors.java @@ -15,16 +15,16 @@ */ package org.springframework.data.document.mongodb; -import org.bson.types.ObjectId; -import org.springframework.beans.BeanUtils; -import org.springframework.util.Assert; - import java.beans.PropertyDescriptor; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.math.BigInteger; import java.util.*; +import org.bson.types.ObjectId; +import org.springframework.beans.BeanUtils; +import org.springframework.util.Assert; + /** * An iterable of {@link MongoPropertyDescriptor}s that allows dedicated access to the {@link MongoPropertyDescriptor} * that captures the id-property. diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoSynchronization.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoSynchronization.java index 9d494bdc7..5111b2729 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoSynchronization.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoSynchronization.java @@ -5,8 +5,8 @@ import org.springframework.transaction.support.ResourceHolderSynchronization; class MongoSynchronization extends ResourceHolderSynchronization { - public MongoSynchronization(ResourceHolder resourceHolder, - Object resourceKey) { - super(resourceHolder, resourceKey); - } + public MongoSynchronization(ResourceHolder resourceHolder, + Object resourceKey) { + super(resourceHolder, resourceKey); + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoTemplate.java index 7943357d0..2936d3950 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoTemplate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoTemplate.java @@ -23,6 +23,8 @@ import java.util.Collections; import java.util.List; import java.util.Set; +import com.mongodb.*; +import com.mongodb.util.JSON; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.bson.types.ObjectId; @@ -33,28 +35,14 @@ import org.springframework.core.convert.ConversionFailedException; import org.springframework.dao.DataAccessException; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.data.document.mongodb.MongoPropertyDescriptors.MongoPropertyDescriptor; -import org.springframework.data.document.mongodb.convert.MappingMongoConverter; +import org.springframework.data.document.mongodb.convert.MongoConverter; +import org.springframework.data.document.mongodb.convert.SimpleMongoConverter; import org.springframework.data.document.mongodb.query.IndexDefinition; import org.springframework.data.document.mongodb.query.Query; import org.springframework.data.document.mongodb.query.Update; -import org.springframework.data.document.mongodb.convert.MongoConverter; -import org.springframework.data.document.mongodb.convert.SimpleMongoConverter; -import org.springframework.data.mapping.model.MappingConfigurationBuilder; import org.springframework.jca.cci.core.ConnectionCallback; import org.springframework.util.Assert; -import com.mongodb.BasicDBObject; -import com.mongodb.CommandResult; -import com.mongodb.DB; -import com.mongodb.DBCollection; -import com.mongodb.DBCursor; -import com.mongodb.DBObject; -import com.mongodb.Mongo; -import com.mongodb.MongoException; -import com.mongodb.WriteConcern; -import com.mongodb.WriteResult; -import com.mongodb.util.JSON; - /** * Primary implementation of {@link MongoOperations}. * @@ -64,1084 +52,1074 @@ import com.mongodb.util.JSON; * @author Oliver Gierke */ public class MongoTemplate implements InitializingBean, MongoOperations { - - private static final Log LOGGER = LogFactory.getLog(MongoTemplate.class); - - private static final String ID = "_id"; - - /* - * WriteConcern to be used for write operations if it has been specified. Otherwise - * we should not use a WriteConcern defaulting to the one set for the DB or Collection. - */ - private WriteConcern writeConcern = null; - - /* - * WriteResultChecking to be used for write operations if it has been specified. Otherwise - * we should not do any checking. - */ - private WriteResultChecking writeResultChecking = WriteResultChecking.NONE; - - private final MongoConverter mongoConverter; - private final Mongo mongo; - private final MongoExceptionTranslator exceptionTranslator = new MongoExceptionTranslator(); - - private String defaultCollectionName; - private String databaseName; - private String username; - private String password; - - - /** - * Constructor used for a basic template configuration - * @param mongo - * @param databaseName - */ - public MongoTemplate(Mongo mongo, String databaseName) { - this(mongo, databaseName, null, null, null, null); - } - - /** - * Constructor used for a basic template configuration with a specific {@link com.mongodb.WriteConcern} - * to be used for all database write operations - * @param mongo - * @param databaseName - * @param writeConcern - */ - public MongoTemplate(Mongo mongo, String databaseName, WriteConcern writeConcern, WriteResultChecking writeResultChecking) { - this(mongo, databaseName, null, null, writeConcern, writeResultChecking); - } - - /** - * Constructor used for a basic template configuration with a default collection name - * @param mongo - * @param databaseName - * @param defaultCollectionName - */ - public MongoTemplate(Mongo mongo, String databaseName, String defaultCollectionName) { - this(mongo, databaseName, defaultCollectionName, null, null, null); - } - - /** - * Constructor used for a basic template configuration with a default collection name and - * with a specific {@link com.mongodb.WriteConcern} to be used for all database write operations - * @param mongo - * @param databaseName - * @param defaultCollectionName - * @param writeConcern - */ - public MongoTemplate(Mongo mongo, String databaseName, String defaultCollectionName, WriteConcern writeConcern, WriteResultChecking writeResultChecking) { - this(mongo, databaseName, defaultCollectionName, null, writeConcern, writeResultChecking); - } - - /** - * Constructor used for a template configuration with a default collection name and a custom {@link org.springframework.data.document.mongodb.convert.MongoConverter} - * @param mongo - * @param databaseName - * @param defaultCollectionName - * @param mongoConverter - */ - public MongoTemplate(Mongo mongo, String databaseName, String defaultCollectionName, MongoConverter mongoConverter) { - this(mongo, databaseName, defaultCollectionName, mongoConverter, null, null); - } - - /** - * Constructor used for a template configuration with a default collection name and a custom {@link MongoConverter} - * and with a specific {@link com.mongodb.WriteConcern} to be used for all database write operations - * @param mongo - * @param databaseName - * @param defaultCollectionName - * @param mongoConverter - * @param writeConcern - * @param writeResultChecking - */ - public MongoTemplate(Mongo mongo, String databaseName, String defaultCollectionName, MongoConverter mongoConverter, WriteConcern writeConcern, WriteResultChecking writeResultChecking) { - - Assert.notNull(mongo); - Assert.notNull(databaseName); - - this.mongoConverter = mongoConverter == null ? new SimpleMongoConverter() : mongoConverter; - this.defaultCollectionName = defaultCollectionName; - this.mongo = mongo; - this.databaseName = databaseName; - this.writeConcern = writeConcern; - if (writeResultChecking != null) { - this.writeResultChecking = writeResultChecking; - } - } - - - /** - * Sets the username to use to connect to the Mongo database - * - * @param username The username to use - */ - public void setUsername(String username) { - this.username = username; - } - - /** - * Sets the password to use to authenticate with the Mongo database. - * - * @param password The password to use - */ - public void setPassword(String password) { - - this.password = password; - } - - /** - * Sets the name of the default collection to be used. - * - * @param defaultCollectionName - */ - public void setDefaultCollectionName(String defaultCollectionName) { - this.defaultCollectionName = defaultCollectionName; - } - - /** - * Sets the database name to be used. - * - * @param databaseName - */ - public void setDatabaseName(String databaseName) { - Assert.notNull(databaseName); - this.databaseName = databaseName; - } - - /** - * Returns the default {@link org.springframework.data.document.mongodb.convert.MongoConverter}. - * - * @return - */ - public MongoConverter getConverter() { - return this.mongoConverter; - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#getDefaultCollectionName() - */ - public String getDefaultCollectionName() { - return defaultCollectionName; - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#getDefaultCollection() - */ - public DBCollection getDefaultCollection() { - - return execute(new DbCallback() { - public DBCollection doInDB(DB db) throws MongoException, DataAccessException { - return db.getCollection(getDefaultCollectionName()); - } - }); - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#executeCommand(java.lang.String) - */ - public CommandResult executeCommand(String jsonCommand) { - return executeCommand((DBObject)JSON.parse(jsonCommand)); - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#executeCommand(com.mongodb.DBObject) - */ - public CommandResult executeCommand(final DBObject command) { - - CommandResult result = execute(new DbCallback() { - public CommandResult doInDB(DB db) throws MongoException, DataAccessException { - return db.command(command); - } - }); - - String error = result.getErrorMessage(); - if (error != null) { - // TODO: allow configuration of logging level / throw - // throw new InvalidDataAccessApiUsageException("Command execution of " + - // command.toString() + " failed: " + error); - LOGGER.warn("Command execution of " + - command.toString() + " failed: " + error); - } - return result; - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#execute(org.springframework.data.document.mongodb.DBCallback) - */ - public T execute(DbCallback action) { - - Assert.notNull(action); - - try { - DB db = getDb(); - return action.doInDB(db); - } catch (MongoException e) { - throw potentiallyConvertRuntimeException(e); - } - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#execute(org.springframework.data.document.mongodb.CollectionCallback) - */ - public T execute(CollectionCallback callback) { - return execute(getDefaultCollectionName(), callback); - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#execute(org.springframework.data.document.mongodb.CollectionCallback, java.lang.String) - */ - public T execute(String collectionName, CollectionCallback callback) { - - Assert.notNull(callback); - - try { - DBCollection collection = getDb().getCollection(collectionName); - return callback.doInCollection(collection); - } catch (MongoException e) { - throw potentiallyConvertRuntimeException(e); - } - } - - /** - * Central callback executing method to do queries against the datastore that requires reading a single object from a - * collection of objects. It will take the following steps

      1. Execute the given {@link ConnectionCallback} for a - * {@link DBObject}.
      2. Apply the given - * {@link DbObjectCallback} to each of the {@link DBObject}s to obtain the result.
        1. - * - * @param - * @param collectionCallback the callback to retrieve the {@link DBObject} with - * @param objectCallback the {@link DbObjectCallback} to transform {@link DBObject}s into the actual domain type - * @param collectionName the collection to be queried - * @return - */ - private T execute(CollectionCallback collectionCallback, - DbObjectCallback objectCallback, String collectionName) { - - try { - T result = objectCallback.doWith(collectionCallback.doInCollection(getCollection(collectionName))); - return result; - } catch (MongoException e) { - throw potentiallyConvertRuntimeException(e); - } - } - - /** - * Central callback executing method to do queries against the datastore that requires reading a collection of - * objects. It will take the following steps
          1. Execute the given {@link ConnectionCallback} for a - * {@link DBCursor}.
          2. Prepare that {@link DBCursor} with the given {@link CursorPreparer} (will be skipped - * if {@link CursorPreparer} is {@literal null}
          3. Iterate over the {@link DBCursor} and applies the given - * {@link DbObjectCallback} to each of the {@link DBObject}s collecting the actual result {@link List}.
            1. - * - * @param - * @param collectionCallback the callback to retrieve the {@link DBCursor} with - * @param preparer the {@link CursorPreparer} to potentially modify the {@link DBCursor} before ireating over it - * @param objectCallback the {@link DbObjectCallback} to transform {@link DBObject}s into the actual domain type - * @param collectionName the collection to be queried - * @return - */ - private List executeEach(CollectionCallback collectionCallback, CursorPreparer preparer, - DbObjectCallback objectCallback, String collectionName) { - - try { - DBCursor cursor = collectionCallback.doInCollection(getCollection(collectionName)); - - if (preparer != null) { - cursor = preparer.prepare(cursor); - } - - List result = new ArrayList(); - - for (DBObject object : cursor) { - result.add(objectCallback.doWith(object)); - } - - return result; - } catch (MongoException e) { - throw potentiallyConvertRuntimeException(e); - } - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#executeInSession(org.springframework.data.document.mongodb.DBCallback) - */ - public T executeInSession(final DbCallback action) { - - return execute(new DbCallback() { - public T doInDB(DB db) throws MongoException, DataAccessException { - try { - db.requestStart(); - return action.doInDB(db); - } finally { - db.requestDone(); - } - } - }); - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#createCollection(java.lang.String) - */ - public DBCollection createCollection(final String collectionName) { - return doCreateCollection(collectionName, new BasicDBObject()); - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#createCollection(java.lang.String, org.springframework.data.document.mongodb.CollectionOptions) - */ - public DBCollection createCollection(final String collectionName, final CollectionOptions collectionOptions) { - return doCreateCollection(collectionName, convertToDbObject(collectionOptions)); - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#getCollection(java.lang.String) - */ - public DBCollection getCollection(final String collectionName) { - return execute(new DbCallback() { - public DBCollection doInDB(DB db) throws MongoException, DataAccessException { - return db.getCollection(collectionName); - } - }); - } - - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#collectionExists(java.lang.String) - */ - public boolean collectionExists(final String collectionName) { - return execute(new DbCallback() { - public Boolean doInDB(DB db) throws MongoException, DataAccessException { - return db.collectionExists(collectionName); - } - }); - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#dropCollection(java.lang.String) - */ - public void dropCollection(String collectionName) { - - execute(collectionName, new CollectionCallback() { - public Void doInCollection(DBCollection collection) throws MongoException, DataAccessException { - collection.drop(); - return null; - } - }); - } - - // Indexing methods - - public void ensureIndex(IndexDefinition indexDefinition) { - ensureIndex(getDefaultCollectionName(), indexDefinition); - } - - public void ensureIndex(String collectionName, final IndexDefinition indexDefinition) { - execute(collectionName, new CollectionCallback() { - public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException { - DBObject indexOptions = indexDefinition.getIndexOptions(); - if (indexOptions != null) { - collection.ensureIndex(indexDefinition.getIndexObject(), indexOptions); - } - else { - collection.ensureIndex(indexDefinition.getIndexObject()); - } - return null; - } - }); - } - - // Find methods that take a Query to express the query and that return a single object. - - public T findOne(Query query, Class targetClass) { - return findOne(getDefaultCollectionName(), query, targetClass); - } - - public T findOne(Query query, Class targetClass, - MongoReader reader) { - return findOne(getDefaultCollectionName(), query, targetClass, reader); - } - - public T findOne(String collectionName, Query query, - Class targetClass) { - return findOne(collectionName, query, targetClass, null); - } - - public T findOne(String collectionName, Query query, - Class targetClass, MongoReader reader) { - return doFindOne(collectionName, query.getQueryObject(), query.getFieldsObject(), targetClass, reader); - } - - // Find methods that take a Query to express the query and that return a List of objects. - - public List find(Query query, Class targetClass) { - return find(getDefaultCollectionName(), query, targetClass); - } - - public List find(Query query, Class targetClass, MongoReader reader) { - return find(getDefaultCollectionName(), query, targetClass, reader); - } - - public List find(String collectionName, final Query query, Class targetClass) { - CursorPreparer cursorPreparer = null; - if (query.getSkip() > 0 || query.getLimit() > 0 || query.getSortObject() != null) { - cursorPreparer = new CursorPreparer() { - - public DBCursor prepare(DBCursor cursor) { - DBCursor cursorToUse = cursor; - try { - if (query.getSkip() > 0) { - cursorToUse = cursorToUse.skip(query.getSkip()); - } - if (query.getLimit() > 0) { - cursorToUse = cursorToUse.limit(query.getLimit()); - } - if (query.getSortObject() != null) { - cursorToUse = cursorToUse.sort(query.getSortObject()); - } - } catch (MongoException e) { - throw potentiallyConvertRuntimeException(e); - } - return cursorToUse; - } - }; - } - return doFind(collectionName, query.getQueryObject(), query.getFieldsObject(), targetClass, cursorPreparer); - } - - public List find(String collectionName, Query query, Class targetClass, MongoReader reader) { - return doFind(collectionName, query.getQueryObject(), query.getFieldsObject(), targetClass, reader); - } - - public List find(String collectionName, Query query, - Class targetClass, CursorPreparer preparer) { - return doFind(collectionName, query.getQueryObject(), query.getFieldsObject(), targetClass, preparer); - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#insert(java.lang.Object) - */ - public void insert(Object objectToSave) { - insert(getRequiredDefaultCollectionName(), objectToSave); - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#insert(java.lang.String, java.lang.Object) - */ - public void insert(String collectionName, Object objectToSave) { - insert(collectionName, objectToSave, this.mongoConverter); - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#insert(T, org.springframework.data.document.mongodb.MongoWriter) - */ - public void insert(T objectToSave, MongoWriter writer) { - insert(getDefaultCollectionName(), objectToSave, writer); - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#insert(java.lang.String, T, org.springframework.data.document.mongodb.MongoWriter) - */ - public void insert(String collectionName, T objectToSave, MongoWriter writer) { - BasicDBObject dbDoc = new BasicDBObject(); - writer.write(objectToSave, dbDoc); - Object id = insertDBObject(collectionName, dbDoc); - populateIdIfNecessary(objectToSave, id); - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#insertList(java.util.List) - */ - public void insertList(List listToSave) { - insertList(getRequiredDefaultCollectionName(), listToSave); - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#insertList(java.lang.String, java.util.List) - */ - public void insertList(String collectionName, List listToSave) { - insertList(collectionName, listToSave, this.mongoConverter); - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#insertList(java.util.List, org.springframework.data.document.mongodb.MongoWriter) - */ - public void insertList(List listToSave, MongoWriter writer) { - insertList(getDefaultCollectionName(), listToSave, writer); - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#insertList(java.lang.String, java.util.List, org.springframework.data.document.mongodb.MongoWriter) - */ - public void insertList(String collectionName, List listToSave, MongoWriter writer) { - - Assert.notNull(writer); - - List dbObjectList = new ArrayList(); - for (T o : listToSave) { - BasicDBObject dbDoc = new BasicDBObject(); - writer.write(o, dbDoc); - dbObjectList.add(dbDoc); - } - List ids = insertDBObjectList(collectionName, dbObjectList); - for (int i = 0; i < listToSave.size(); i++) { - if (i < ids.size()) { - populateIdIfNecessary(listToSave.get(i), ids.get(i)); - } - } - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#save(java.lang.Object) - */ - public void save(Object objectToSave) { - save(getRequiredDefaultCollectionName(), objectToSave); - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#save(java.lang.String, java.lang.Object) - */ - public void save(String collectionName, Object objectToSave) { - save(collectionName, objectToSave, this.mongoConverter); - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#save(T, org.springframework.data.document.mongodb.MongoWriter) - */ - public void save(T objectToSave, MongoWriter writer) { - save(getDefaultCollectionName(), objectToSave, writer); - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#save(java.lang.String, T, org.springframework.data.document.mongodb.MongoWriter) - */ - public void save(String collectionName, T objectToSave, MongoWriter writer) { - BasicDBObject dbDoc = new BasicDBObject(); - writer.write(objectToSave, dbDoc); - ObjectId id = saveDBObject(collectionName, dbDoc); - populateIdIfNecessary(objectToSave, id); - } - - - protected Object insertDBObject(String collectionName, final DBObject dbDoc) { - - if (dbDoc.keySet().isEmpty()) { - return null; - } - - return execute(collectionName, new CollectionCallback() { - public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException { - if (writeConcern == null) { - collection.insert(dbDoc); - } - else { - collection.insert(dbDoc, writeConcern); - } - return dbDoc.get(ID); - } - }); - } - - protected List insertDBObjectList(String collectionName, final List dbDocList) { - - if (dbDocList.isEmpty()) { - return Collections.emptyList(); - } - - execute(collectionName, new CollectionCallback() { - public Void doInCollection(DBCollection collection) throws MongoException, DataAccessException { - if (writeConcern == null) { - collection.insert(dbDocList); - } - else { - collection.insert(dbDocList.toArray((DBObject[]) new BasicDBObject[dbDocList.size()]), writeConcern); - } - return null; - } - }); - - List ids = new ArrayList(); - for (DBObject dbo : dbDocList) { - Object id = dbo.get(ID); - if (id instanceof ObjectId) { - ids.add((ObjectId) id); - } - else { - // no id was generated - ids.add(null); - } - } - return ids; - } - - protected ObjectId saveDBObject(String collectionName, final DBObject dbDoc) { - - if (dbDoc.keySet().isEmpty()) { - return null; - } - - return execute(collectionName, new CollectionCallback() { - public ObjectId doInCollection(DBCollection collection) throws MongoException, DataAccessException { - if (writeConcern == null) { - collection.save(dbDoc); - } - else { - collection.save(dbDoc, writeConcern); - } - return (ObjectId) dbDoc.get(ID); - } - }); - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#updateFirst(com.mongodb.DBObject, com.mongodb.DBObject) - */ - public WriteResult updateFirst(Query query, Update update) { - return updateFirst(getRequiredDefaultCollectionName(), query, update); - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#updateFirst(java.lang.String, com.mongodb.DBObject, com.mongodb.DBObject) - */ - public WriteResult updateFirst(String collectionName, final Query query, final Update update) { - return execute(collectionName, new CollectionCallback() { - public WriteResult doInCollection(DBCollection collection) throws MongoException, DataAccessException { - WriteResult wr; - if (writeConcern == null) { - wr = collection.update(query.getQueryObject(), update.getUpdateObject()); - } - else { - wr = collection.update(query.getQueryObject(), update.getUpdateObject(), false, false, writeConcern); - } - handleAnyWriteResultErrors(wr, query.getQueryObject(), "update with '" +update.getUpdateObject() + "'"); - return wr; - } - }); - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#updateMulti(com.mongodb.DBObject, com.mongodb.DBObject) - */ - public WriteResult updateMulti(Query query, Update update) { - return updateMulti(getRequiredDefaultCollectionName(), query, update); - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#updateMulti(java.lang.String, com.mongodb.DBObject, com.mongodb.DBObject) - */ - public WriteResult updateMulti(String collectionName, final Query query, final Update update) { - return execute(collectionName, new CollectionCallback() { - public WriteResult doInCollection(DBCollection collection) throws MongoException, DataAccessException { - WriteResult wr = null; - if (writeConcern == null) { - wr = collection.updateMulti(query.getQueryObject(), update.getUpdateObject()); - } - else { - wr = collection.update(query.getQueryObject(), update.getUpdateObject(), false, true, writeConcern); - } - handleAnyWriteResultErrors(wr, query.getQueryObject(), "update with '" +update.getUpdateObject() + "'"); - return wr; - } - }); - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#remove(com.mongodb.DBObject) - */ - public void remove(Query query) { - remove(getRequiredDefaultCollectionName(), query); - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#remove(java.lang.String, com.mongodb.DBObject) - */ - public void remove(String collectionName, final Query query) { - execute(collectionName, new CollectionCallback() { - public Void doInCollection(DBCollection collection) throws MongoException, DataAccessException { - WriteResult wr = null; - if (writeConcern == null) { - wr = collection.remove(query.getQueryObject()); - } - else { - wr = collection.remove(query.getQueryObject(), writeConcern); - } - handleAnyWriteResultErrors(wr, query.getQueryObject(), "remove"); - return null; - } - }); - } - - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperations#getCollection(java.lang.Class) - */ - public List getCollection(Class targetClass) { - return executeEach(new FindCallback(null), null, new ReadDbObjectCallback(mongoConverter, targetClass), - getDefaultCollectionName()); - } - - public List getCollection(String collectionName, Class targetClass) { - return executeEach(new FindCallback(null), null, new ReadDbObjectCallback(mongoConverter, targetClass), - collectionName); - } - - public Set getCollectionNames() { - return execute(new DbCallback>() { - public Set doInDB(DB db) throws MongoException, DataAccessException { - return db.getCollectionNames(); - } - }); - } - - public List getCollection(String collectionName, Class targetClass, MongoReader reader) { - return executeEach(new FindCallback(null), null, new ReadDbObjectCallback(reader, targetClass), - collectionName); - } - - public DB getDb() { - return MongoDbUtils.getDB(mongo, databaseName, username, password == null ? null : password.toCharArray()); - } - - /** - * Create the specified collection using the provided options - * @param collectionName - * @param collectionOptions - * @return the collection that was created - */ - protected DBCollection doCreateCollection(final String collectionName, final DBObject collectionOptions) { - return execute(new DbCallback() { - public DBCollection doInDB(DB db) throws MongoException, DataAccessException { - return db.createCollection(collectionName, collectionOptions); - } - }); - } - - /** - * Map the results of an ad-hoc query on the default MongoDB collection to an object using the provided MongoReader - * - * The query document is specified as a standard DBObject and so is the fields specification. - * - * @param collectionName name of the collection to retrieve the objects from - * @param query the query document that specifies the criteria used to find a record - * @param fields the document that specifies the fields to be returned - * @param targetClass the parameterized type of the returned list. - * @param reader the MongoReader to convert from DBObject to an object. - * @return the List of converted objects. - */ - protected T doFindOne(String collectionName, DBObject query, DBObject fields, Class targetClass, MongoReader reader) { - MongoReader readerToUse = reader; - if (readerToUse == null) { - readerToUse = this.mongoConverter; - } - substituteMappedIdIfNecessary(query, targetClass, readerToUse); - return execute(new FindOneCallback(query, fields), new ReadDbObjectCallback(readerToUse, targetClass), - collectionName); - } - - /** - * Map the results of an ad-hoc query on the default MongoDB collection to a List of the specified type. - * - * The object is converted from the MongoDB native representation using an instance of - * {@see MongoConverter}. Unless configured otherwise, an - * instance of SimpleMongoConverter will be used. - * - * The query document is specified as a standard DBObject and so is the fields specification. - * - * Can be overridden by subclasses. - * - * @param collectionName name of the collection to retrieve the objects from - * @param query the query document that specifies the criteria used to find a record - * @param fields the document that specifies the fields to be returned - * @param targetClass the parameterized type of the returned list. - * @param preparer allows for customization of the DBCursor used when iterating over the result set, - * (apply limits, skips and so on). - * @return the List of converted objects. - */ - protected List doFind(String collectionName, DBObject query, DBObject fields, Class targetClass, CursorPreparer preparer) { - substituteMappedIdIfNecessary(query, targetClass, mongoConverter); - return executeEach(new FindCallback(query, fields), preparer, new ReadDbObjectCallback(mongoConverter, targetClass), - collectionName); - } - - /** - * Map the results of an ad-hoc query on the default MongoDB collection to a List using the provided MongoReader - * - * The query document is specified as a standard DBObject and so is the fields specification. - * - * @param collectionName name of the collection to retrieve the objects from - * @param query the query document that specifies the criteria used to find a record - * @param fields the document that specifies the fields to be returned - * @param targetClass the parameterized type of the returned list. - * @param reader the MongoReader to convert from DBObject to an object. - * @return the List of converted objects. - */ - protected List doFind(String collectionName, DBObject query, DBObject fields, Class targetClass, MongoReader reader) { - substituteMappedIdIfNecessary(query, targetClass, reader); - return executeEach(new FindCallback(query, fields), null, new ReadDbObjectCallback(reader, targetClass), - collectionName); - } - - protected DBObject convertToDbObject(CollectionOptions collectionOptions) { - DBObject dbo = new BasicDBObject(); - if (collectionOptions != null) { - if (collectionOptions.getCapped() != null) { - dbo.put("capped", collectionOptions.getCapped().booleanValue()); - } - if (collectionOptions.getSize() != null) { - dbo.put("size", collectionOptions.getSize().intValue()); - } - if (collectionOptions.getMaxDocuments() != null ) { - dbo.put("max", collectionOptions.getMaxDocuments().intValue()); - } - } - return dbo; - } - - /** - * Populates the id property of the saved object, if it's not set already. - * - * @param savedObject - * @param id - */ - protected void populateIdIfNecessary(Object savedObject, Object id) { - - if (id == null) { - return; - } - - ConfigurablePropertyAccessor bw = PropertyAccessorFactory.forDirectFieldAccess(savedObject); - MongoPropertyDescriptor idDescriptor = new MongoPropertyDescriptors(savedObject.getClass()).getIdDescriptor(); - - if (idDescriptor == null) { - return; - } - - if (bw.getPropertyValue(idDescriptor.getName()) == null) { - Object target = null; - if (id instanceof ObjectId) { - target = this.mongoConverter.convertObjectId((ObjectId)id, idDescriptor.getPropertyType()); - } - else { - target = id; - } - bw.setPropertyValue(idDescriptor.getName(), target); - } - } - - /** - * Substitutes the id key if it is found in he query. Any 'id' keys will be replaced with '_id' and the value converted - * to an ObjectId if possible. This conversion should match the way that the id fields are converted during read - * operations. - * - * @param query - * @param targetClass - * @param reader - */ - protected void substituteMappedIdIfNecessary(DBObject query, Class targetClass, MongoReader reader) { - MongoConverter converter = null; - if (reader instanceof SimpleMongoConverter) { - converter = (MongoConverter) reader; - } - else { - return; - } - String idKey = null; - if (query.containsField("id")) { - idKey = "id"; - } - if (query.containsField("_id")) { - idKey = "_id"; - } - if (idKey == null) { - // no ids in this query - return; - } - final MongoPropertyDescriptor descriptor; - try { - descriptor = new MongoPropertyDescriptor(new PropertyDescriptor(idKey, targetClass)); - } catch (IntrospectionException e) { - // no property descriptor for this key - return; - } - if (descriptor.isIdProperty() && descriptor.isOfIdType()) { - Object value = query.get(idKey); - ObjectId newValue = null; - try { - if (value instanceof String && ObjectId.isValid((String)value)) { - newValue = converter.convertObjectId(value); - } - } catch (ConversionFailedException iae) { - LOGGER.warn("Unable to convert the String " + value + " to an ObjectId"); - } - query.removeField(idKey); - if (newValue != null) { - query.put(MongoPropertyDescriptor.ID_KEY, newValue); - } - else { - query.put(MongoPropertyDescriptor.ID_KEY, value); - } - } - } - - - private String getRequiredDefaultCollectionName() { - String name = getDefaultCollectionName(); - if (name == null) { - throw new IllegalStateException( - "No 'defaultCollection' or 'defaultCollectionName' specified. Check configuration of MongoTemplate."); - } - return name; - } - - /** - * Checks and handles any errors. - * - * TODO: current implementation logs errors - will be configurable to log warning, errors or - * throw exception in later versions - * - */ - private void handleAnyWriteResultErrors(WriteResult wr, DBObject query, String operation) { - if (WriteResultChecking.NONE == this.writeResultChecking) { - return; - } - String error = wr.getError(); - int n = wr.getN(); - if (error != null) { - String message = "Execution of '" + operation + - (query == null ? "" : "' using '" + query.toString() + "' query") + " failed: " + error; - if (WriteResultChecking.EXCEPTION == this.writeResultChecking) { - throw new DataIntegrityViolationException(message); - } - else { - LOGGER.error(message); - } - } - else if(n == 0) { - String message = "Execution of '" + operation + - (query == null ? "" : "' using '" + query.toString() + "' query") + " did not succeed: 0 documents updated"; - if (WriteResultChecking.EXCEPTION == this.writeResultChecking) { - throw new DataIntegrityViolationException(message); - } - else { - LOGGER.warn(message); - } - } - - } - - /** - * Tries to convert the given {@link RuntimeException} into a {@link DataAccessException} but returns the original - * exception if the conversation failed. Thus allows safe rethrowing of the return value. - * - * @param ex - * @return - */ - private RuntimeException potentiallyConvertRuntimeException(RuntimeException ex) { - RuntimeException resolved = this.exceptionTranslator.translateExceptionIfPossible(ex); - return resolved == null ? ex : resolved; - } - - /* - * (non-Javadoc) - * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() - */ - public void afterPropertiesSet() { - if (this.getDefaultCollectionName() != null) { - if (!collectionExists(getDefaultCollectionName())) { - createCollection(getDefaultCollectionName(), null); - } - } - } - - - /** - * Simple {@link CollectionCallback} that takes a query {@link DBObject} plus an optional fields specification - * {@link DBObject} and executes that against the {@link DBCollection}. - * - * @author Oliver Gierke - * @author Thomas Risberg - */ - private static class FindOneCallback implements CollectionCallback { - - private final DBObject query; - - private final DBObject fields; - - public FindOneCallback(DBObject query, DBObject fields) { - this.query = query; - this.fields = fields; - } - - public DBObject doInCollection(DBCollection collection) throws MongoException, DataAccessException { - if (fields == null) { - return collection.findOne(query); - } - else { - return collection.findOne(query, fields); - } - } - } - - /** - * Simple {@link CollectionCallback} that takes a query {@link DBObject} plus an optional fields specification - * {@link DBObject} and executes that against the {@link DBCollection}. - * - * @author Oliver Gierke - * @author Thomas Risberg - */ - private static class FindCallback implements CollectionCallback { - - private final DBObject query; - - private final DBObject fields; - - public FindCallback(DBObject query) { - this(query, null); - } - - public FindCallback(DBObject query, DBObject fields) { - this.query = query; - this.fields = fields; - } - - public DBCursor doInCollection(DBCollection collection) throws MongoException, DataAccessException { - if (fields == null) { - return collection.find(query); - } - else { - return collection.find(query, fields); - } - } - } - - /** - * Simple internal callback to allow operations on a {@link DBObject}. - * - * @author Oliver Gierke - */ - - private interface DbObjectCallback { - - T doWith(DBObject object); - } - - /** - * Simple {@link DbObjectCallback} that will transform {@link DBObject} into the given target type using the given - * {@link MongoReader}. - * - * @author Oliver Gierke - */ - private static class ReadDbObjectCallback implements DbObjectCallback { - - private final MongoReader reader; - private final Class type; - - public ReadDbObjectCallback(MongoReader reader, Class type) { - this.reader = reader; - this.type = type; - } - - public T doWith(DBObject object) { - return reader.read(type, object); - } - } + + private static final Log LOGGER = LogFactory.getLog(MongoTemplate.class); + + private static final String ID = "_id"; + + /* + * WriteConcern to be used for write operations if it has been specified. Otherwise + * we should not use a WriteConcern defaulting to the one set for the DB or Collection. + */ + private WriteConcern writeConcern = null; + + /* + * WriteResultChecking to be used for write operations if it has been specified. Otherwise + * we should not do any checking. + */ + private WriteResultChecking writeResultChecking = WriteResultChecking.NONE; + + private final MongoConverter mongoConverter; + private final Mongo mongo; + private final MongoExceptionTranslator exceptionTranslator = new MongoExceptionTranslator(); + + private String defaultCollectionName; + private String databaseName; + private String username; + private String password; + + + /** + * Constructor used for a basic template configuration + * + * @param mongo + * @param databaseName + */ + public MongoTemplate(Mongo mongo, String databaseName) { + this(mongo, databaseName, null, null, null, null); + } + + /** + * Constructor used for a basic template configuration with a specific {@link com.mongodb.WriteConcern} + * to be used for all database write operations + * + * @param mongo + * @param databaseName + * @param writeConcern + */ + public MongoTemplate(Mongo mongo, String databaseName, WriteConcern writeConcern, WriteResultChecking writeResultChecking) { + this(mongo, databaseName, null, null, writeConcern, writeResultChecking); + } + + /** + * Constructor used for a basic template configuration with a default collection name + * + * @param mongo + * @param databaseName + * @param defaultCollectionName + */ + public MongoTemplate(Mongo mongo, String databaseName, String defaultCollectionName) { + this(mongo, databaseName, defaultCollectionName, null, null, null); + } + + /** + * Constructor used for a basic template configuration with a default collection name and + * with a specific {@link com.mongodb.WriteConcern} to be used for all database write operations + * + * @param mongo + * @param databaseName + * @param defaultCollectionName + * @param writeConcern + */ + public MongoTemplate(Mongo mongo, String databaseName, String defaultCollectionName, WriteConcern writeConcern, WriteResultChecking writeResultChecking) { + this(mongo, databaseName, defaultCollectionName, null, writeConcern, writeResultChecking); + } + + /** + * Constructor used for a template configuration with a default collection name and a custom {@link org.springframework.data.document.mongodb.convert.MongoConverter} + * + * @param mongo + * @param databaseName + * @param defaultCollectionName + * @param mongoConverter + */ + public MongoTemplate(Mongo mongo, String databaseName, String defaultCollectionName, MongoConverter mongoConverter) { + this(mongo, databaseName, defaultCollectionName, mongoConverter, null, null); + } + + /** + * Constructor used for a template configuration with a default collection name and a custom {@link MongoConverter} + * and with a specific {@link com.mongodb.WriteConcern} to be used for all database write operations + * + * @param mongo + * @param databaseName + * @param defaultCollectionName + * @param mongoConverter + * @param writeConcern + * @param writeResultChecking + */ + public MongoTemplate(Mongo mongo, String databaseName, String defaultCollectionName, MongoConverter mongoConverter, WriteConcern writeConcern, WriteResultChecking writeResultChecking) { + + Assert.notNull(mongo); + Assert.notNull(databaseName); + + this.mongoConverter = mongoConverter == null ? new SimpleMongoConverter() : mongoConverter; + this.defaultCollectionName = defaultCollectionName; + this.mongo = mongo; + this.databaseName = databaseName; + this.writeConcern = writeConcern; + if (writeResultChecking != null) { + this.writeResultChecking = writeResultChecking; + } + } + + + /** + * Sets the username to use to connect to the Mongo database + * + * @param username The username to use + */ + public void setUsername(String username) { + this.username = username; + } + + /** + * Sets the password to use to authenticate with the Mongo database. + * + * @param password The password to use + */ + public void setPassword(String password) { + + this.password = password; + } + + /** + * Sets the name of the default collection to be used. + * + * @param defaultCollectionName + */ + public void setDefaultCollectionName(String defaultCollectionName) { + this.defaultCollectionName = defaultCollectionName; + } + + /** + * Sets the database name to be used. + * + * @param databaseName + */ + public void setDatabaseName(String databaseName) { + Assert.notNull(databaseName); + this.databaseName = databaseName; + } + + /** + * Returns the default {@link org.springframework.data.document.mongodb.convert.MongoConverter}. + * + * @return + */ + public MongoConverter getConverter() { + return this.mongoConverter; + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#getDefaultCollectionName() + */ + public String getDefaultCollectionName() { + return defaultCollectionName; + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#getDefaultCollection() + */ + public DBCollection getDefaultCollection() { + + return execute(new DbCallback() { + public DBCollection doInDB(DB db) throws MongoException, DataAccessException { + return db.getCollection(getDefaultCollectionName()); + } + }); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#executeCommand(java.lang.String) + */ + public CommandResult executeCommand(String jsonCommand) { + return executeCommand((DBObject) JSON.parse(jsonCommand)); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#executeCommand(com.mongodb.DBObject) + */ + public CommandResult executeCommand(final DBObject command) { + + CommandResult result = execute(new DbCallback() { + public CommandResult doInDB(DB db) throws MongoException, DataAccessException { + return db.command(command); + } + }); + + String error = result.getErrorMessage(); + if (error != null) { + // TODO: allow configuration of logging level / throw + // throw new InvalidDataAccessApiUsageException("Command execution of " + + // command.toString() + " failed: " + error); + LOGGER.warn("Command execution of " + + command.toString() + " failed: " + error); + } + return result; + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#execute(org.springframework.data.document.mongodb.DBCallback) + */ + public T execute(DbCallback action) { + + Assert.notNull(action); + + try { + DB db = getDb(); + return action.doInDB(db); + } catch (MongoException e) { + throw potentiallyConvertRuntimeException(e); + } + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#execute(org.springframework.data.document.mongodb.CollectionCallback) + */ + public T execute(CollectionCallback callback) { + return execute(getDefaultCollectionName(), callback); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#execute(org.springframework.data.document.mongodb.CollectionCallback, java.lang.String) + */ + public T execute(String collectionName, CollectionCallback callback) { + + Assert.notNull(callback); + + try { + DBCollection collection = getDb().getCollection(collectionName); + return callback.doInCollection(collection); + } catch (MongoException e) { + throw potentiallyConvertRuntimeException(e); + } + } + + /** + * Central callback executing method to do queries against the datastore that requires reading a single object from a + * collection of objects. It will take the following steps
              1. Execute the given {@link ConnectionCallback} for a + * {@link DBObject}.
              2. Apply the given + * {@link DbObjectCallback} to each of the {@link DBObject}s to obtain the result.
                1. + * + * @param + * @param collectionCallback the callback to retrieve the {@link DBObject} with + * @param objectCallback the {@link DbObjectCallback} to transform {@link DBObject}s into the actual domain type + * @param collectionName the collection to be queried + * @return + */ + private T execute(CollectionCallback collectionCallback, + DbObjectCallback objectCallback, String collectionName) { + + try { + T result = objectCallback.doWith(collectionCallback.doInCollection(getCollection(collectionName))); + return result; + } catch (MongoException e) { + throw potentiallyConvertRuntimeException(e); + } + } + + /** + * Central callback executing method to do queries against the datastore that requires reading a collection of + * objects. It will take the following steps
                  1. Execute the given {@link ConnectionCallback} for a + * {@link DBCursor}.
                  2. Prepare that {@link DBCursor} with the given {@link CursorPreparer} (will be skipped + * if {@link CursorPreparer} is {@literal null}
                  3. Iterate over the {@link DBCursor} and applies the given + * {@link DbObjectCallback} to each of the {@link DBObject}s collecting the actual result {@link List}.
                    1. + * + * @param + * @param collectionCallback the callback to retrieve the {@link DBCursor} with + * @param preparer the {@link CursorPreparer} to potentially modify the {@link DBCursor} before ireating over it + * @param objectCallback the {@link DbObjectCallback} to transform {@link DBObject}s into the actual domain type + * @param collectionName the collection to be queried + * @return + */ + private List executeEach(CollectionCallback collectionCallback, CursorPreparer preparer, + DbObjectCallback objectCallback, String collectionName) { + + try { + DBCursor cursor = collectionCallback.doInCollection(getCollection(collectionName)); + + if (preparer != null) { + cursor = preparer.prepare(cursor); + } + + List result = new ArrayList(); + + for (DBObject object : cursor) { + result.add(objectCallback.doWith(object)); + } + + return result; + } catch (MongoException e) { + throw potentiallyConvertRuntimeException(e); + } + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#executeInSession(org.springframework.data.document.mongodb.DBCallback) + */ + public T executeInSession(final DbCallback action) { + + return execute(new DbCallback() { + public T doInDB(DB db) throws MongoException, DataAccessException { + try { + db.requestStart(); + return action.doInDB(db); + } finally { + db.requestDone(); + } + } + }); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#createCollection(java.lang.String) + */ + public DBCollection createCollection(final String collectionName) { + return doCreateCollection(collectionName, new BasicDBObject()); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#createCollection(java.lang.String, org.springframework.data.document.mongodb.CollectionOptions) + */ + public DBCollection createCollection(final String collectionName, final CollectionOptions collectionOptions) { + return doCreateCollection(collectionName, convertToDbObject(collectionOptions)); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#getCollection(java.lang.String) + */ + public DBCollection getCollection(final String collectionName) { + return execute(new DbCallback() { + public DBCollection doInDB(DB db) throws MongoException, DataAccessException { + return db.getCollection(collectionName); + } + }); + } + + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#collectionExists(java.lang.String) + */ + public boolean collectionExists(final String collectionName) { + return execute(new DbCallback() { + public Boolean doInDB(DB db) throws MongoException, DataAccessException { + return db.collectionExists(collectionName); + } + }); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#dropCollection(java.lang.String) + */ + public void dropCollection(String collectionName) { + + execute(collectionName, new CollectionCallback() { + public Void doInCollection(DBCollection collection) throws MongoException, DataAccessException { + collection.drop(); + return null; + } + }); + } + + // Indexing methods + + public void ensureIndex(IndexDefinition indexDefinition) { + ensureIndex(getDefaultCollectionName(), indexDefinition); + } + + public void ensureIndex(String collectionName, final IndexDefinition indexDefinition) { + execute(collectionName, new CollectionCallback() { + public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException { + DBObject indexOptions = indexDefinition.getIndexOptions(); + if (indexOptions != null) { + collection.ensureIndex(indexDefinition.getIndexObject(), indexOptions); + } else { + collection.ensureIndex(indexDefinition.getIndexObject()); + } + return null; + } + }); + } + + // Find methods that take a Query to express the query and that return a single object. + + public T findOne(Query query, Class targetClass) { + return findOne(getDefaultCollectionName(), query, targetClass); + } + + public T findOne(Query query, Class targetClass, + MongoReader reader) { + return findOne(getDefaultCollectionName(), query, targetClass, reader); + } + + public T findOne(String collectionName, Query query, + Class targetClass) { + return findOne(collectionName, query, targetClass, null); + } + + public T findOne(String collectionName, Query query, + Class targetClass, MongoReader reader) { + return doFindOne(collectionName, query.getQueryObject(), query.getFieldsObject(), targetClass, reader); + } + + // Find methods that take a Query to express the query and that return a List of objects. + + public List find(Query query, Class targetClass) { + return find(getDefaultCollectionName(), query, targetClass); + } + + public List find(Query query, Class targetClass, MongoReader reader) { + return find(getDefaultCollectionName(), query, targetClass, reader); + } + + public List find(String collectionName, final Query query, Class targetClass) { + CursorPreparer cursorPreparer = null; + if (query.getSkip() > 0 || query.getLimit() > 0 || query.getSortObject() != null) { + cursorPreparer = new CursorPreparer() { + + public DBCursor prepare(DBCursor cursor) { + DBCursor cursorToUse = cursor; + try { + if (query.getSkip() > 0) { + cursorToUse = cursorToUse.skip(query.getSkip()); + } + if (query.getLimit() > 0) { + cursorToUse = cursorToUse.limit(query.getLimit()); + } + if (query.getSortObject() != null) { + cursorToUse = cursorToUse.sort(query.getSortObject()); + } + } catch (MongoException e) { + throw potentiallyConvertRuntimeException(e); + } + return cursorToUse; + } + }; + } + return doFind(collectionName, query.getQueryObject(), query.getFieldsObject(), targetClass, cursorPreparer); + } + + public List find(String collectionName, Query query, Class targetClass, MongoReader reader) { + return doFind(collectionName, query.getQueryObject(), query.getFieldsObject(), targetClass, reader); + } + + public List find(String collectionName, Query query, + Class targetClass, CursorPreparer preparer) { + return doFind(collectionName, query.getQueryObject(), query.getFieldsObject(), targetClass, preparer); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#insert(java.lang.Object) + */ + public void insert(Object objectToSave) { + insert(getRequiredDefaultCollectionName(), objectToSave); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#insert(java.lang.String, java.lang.Object) + */ + public void insert(String collectionName, Object objectToSave) { + insert(collectionName, objectToSave, this.mongoConverter); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#insert(T, org.springframework.data.document.mongodb.MongoWriter) + */ + public void insert(T objectToSave, MongoWriter writer) { + insert(getDefaultCollectionName(), objectToSave, writer); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#insert(java.lang.String, T, org.springframework.data.document.mongodb.MongoWriter) + */ + public void insert(String collectionName, T objectToSave, MongoWriter writer) { + BasicDBObject dbDoc = new BasicDBObject(); + writer.write(objectToSave, dbDoc); + Object id = insertDBObject(collectionName, dbDoc); + populateIdIfNecessary(objectToSave, id); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#insertList(java.util.List) + */ + public void insertList(List listToSave) { + insertList(getRequiredDefaultCollectionName(), listToSave); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#insertList(java.lang.String, java.util.List) + */ + public void insertList(String collectionName, List listToSave) { + insertList(collectionName, listToSave, this.mongoConverter); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#insertList(java.util.List, org.springframework.data.document.mongodb.MongoWriter) + */ + public void insertList(List listToSave, MongoWriter writer) { + insertList(getDefaultCollectionName(), listToSave, writer); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#insertList(java.lang.String, java.util.List, org.springframework.data.document.mongodb.MongoWriter) + */ + public void insertList(String collectionName, List listToSave, MongoWriter writer) { + + Assert.notNull(writer); + + List dbObjectList = new ArrayList(); + for (T o : listToSave) { + BasicDBObject dbDoc = new BasicDBObject(); + writer.write(o, dbDoc); + dbObjectList.add(dbDoc); + } + List ids = insertDBObjectList(collectionName, dbObjectList); + for (int i = 0; i < listToSave.size(); i++) { + if (i < ids.size()) { + populateIdIfNecessary(listToSave.get(i), ids.get(i)); + } + } + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#save(java.lang.Object) + */ + public void save(Object objectToSave) { + save(getRequiredDefaultCollectionName(), objectToSave); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#save(java.lang.String, java.lang.Object) + */ + public void save(String collectionName, Object objectToSave) { + save(collectionName, objectToSave, this.mongoConverter); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#save(T, org.springframework.data.document.mongodb.MongoWriter) + */ + public void save(T objectToSave, MongoWriter writer) { + save(getDefaultCollectionName(), objectToSave, writer); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#save(java.lang.String, T, org.springframework.data.document.mongodb.MongoWriter) + */ + public void save(String collectionName, T objectToSave, MongoWriter writer) { + BasicDBObject dbDoc = new BasicDBObject(); + writer.write(objectToSave, dbDoc); + ObjectId id = saveDBObject(collectionName, dbDoc); + populateIdIfNecessary(objectToSave, id); + } + + + protected Object insertDBObject(String collectionName, final DBObject dbDoc) { + + if (dbDoc.keySet().isEmpty()) { + return null; + } + + return execute(collectionName, new CollectionCallback() { + public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException { + if (writeConcern == null) { + collection.insert(dbDoc); + } else { + collection.insert(dbDoc, writeConcern); + } + return dbDoc.get(ID); + } + }); + } + + protected List insertDBObjectList(String collectionName, final List dbDocList) { + + if (dbDocList.isEmpty()) { + return Collections.emptyList(); + } + + execute(collectionName, new CollectionCallback() { + public Void doInCollection(DBCollection collection) throws MongoException, DataAccessException { + if (writeConcern == null) { + collection.insert(dbDocList); + } else { + collection.insert(dbDocList.toArray((DBObject[]) new BasicDBObject[dbDocList.size()]), writeConcern); + } + return null; + } + }); + + List ids = new ArrayList(); + for (DBObject dbo : dbDocList) { + Object id = dbo.get(ID); + if (id instanceof ObjectId) { + ids.add((ObjectId) id); + } else { + // no id was generated + ids.add(null); + } + } + return ids; + } + + protected ObjectId saveDBObject(String collectionName, final DBObject dbDoc) { + + if (dbDoc.keySet().isEmpty()) { + return null; + } + + return execute(collectionName, new CollectionCallback() { + public ObjectId doInCollection(DBCollection collection) throws MongoException, DataAccessException { + if (writeConcern == null) { + collection.save(dbDoc); + } else { + collection.save(dbDoc, writeConcern); + } + return (ObjectId) dbDoc.get(ID); + } + }); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#updateFirst(com.mongodb.DBObject, com.mongodb.DBObject) + */ + public WriteResult updateFirst(Query query, Update update) { + return updateFirst(getRequiredDefaultCollectionName(), query, update); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#updateFirst(java.lang.String, com.mongodb.DBObject, com.mongodb.DBObject) + */ + public WriteResult updateFirst(String collectionName, final Query query, final Update update) { + return execute(collectionName, new CollectionCallback() { + public WriteResult doInCollection(DBCollection collection) throws MongoException, DataAccessException { + WriteResult wr; + if (writeConcern == null) { + wr = collection.update(query.getQueryObject(), update.getUpdateObject()); + } else { + wr = collection.update(query.getQueryObject(), update.getUpdateObject(), false, false, writeConcern); + } + handleAnyWriteResultErrors(wr, query.getQueryObject(), "update with '" + update.getUpdateObject() + "'"); + return wr; + } + }); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#updateMulti(com.mongodb.DBObject, com.mongodb.DBObject) + */ + public WriteResult updateMulti(Query query, Update update) { + return updateMulti(getRequiredDefaultCollectionName(), query, update); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#updateMulti(java.lang.String, com.mongodb.DBObject, com.mongodb.DBObject) + */ + public WriteResult updateMulti(String collectionName, final Query query, final Update update) { + return execute(collectionName, new CollectionCallback() { + public WriteResult doInCollection(DBCollection collection) throws MongoException, DataAccessException { + WriteResult wr = null; + if (writeConcern == null) { + wr = collection.updateMulti(query.getQueryObject(), update.getUpdateObject()); + } else { + wr = collection.update(query.getQueryObject(), update.getUpdateObject(), false, true, writeConcern); + } + handleAnyWriteResultErrors(wr, query.getQueryObject(), "update with '" + update.getUpdateObject() + "'"); + return wr; + } + }); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#remove(com.mongodb.DBObject) + */ + public void remove(Query query) { + remove(getRequiredDefaultCollectionName(), query); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#remove(java.lang.String, com.mongodb.DBObject) + */ + public void remove(String collectionName, final Query query) { + execute(collectionName, new CollectionCallback() { + public Void doInCollection(DBCollection collection) throws MongoException, DataAccessException { + WriteResult wr = null; + if (writeConcern == null) { + wr = collection.remove(query.getQueryObject()); + } else { + wr = collection.remove(query.getQueryObject(), writeConcern); + } + handleAnyWriteResultErrors(wr, query.getQueryObject(), "remove"); + return null; + } + }); + } + + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperations#getCollection(java.lang.Class) + */ + public List getCollection(Class targetClass) { + return executeEach(new FindCallback(null), null, new ReadDbObjectCallback(mongoConverter, targetClass), + getDefaultCollectionName()); + } + + public List getCollection(String collectionName, Class targetClass) { + return executeEach(new FindCallback(null), null, new ReadDbObjectCallback(mongoConverter, targetClass), + collectionName); + } + + public Set getCollectionNames() { + return execute(new DbCallback>() { + public Set doInDB(DB db) throws MongoException, DataAccessException { + return db.getCollectionNames(); + } + }); + } + + public List getCollection(String collectionName, Class targetClass, MongoReader reader) { + return executeEach(new FindCallback(null), null, new ReadDbObjectCallback(reader, targetClass), + collectionName); + } + + public DB getDb() { + return MongoDbUtils.getDB(mongo, databaseName, username, password == null ? null : password.toCharArray()); + } + + /** + * Create the specified collection using the provided options + * + * @param collectionName + * @param collectionOptions + * @return the collection that was created + */ + protected DBCollection doCreateCollection(final String collectionName, final DBObject collectionOptions) { + return execute(new DbCallback() { + public DBCollection doInDB(DB db) throws MongoException, DataAccessException { + return db.createCollection(collectionName, collectionOptions); + } + }); + } + + /** + * Map the results of an ad-hoc query on the default MongoDB collection to an object using the provided MongoReader + *

                      + * The query document is specified as a standard DBObject and so is the fields specification. + * + * @param collectionName name of the collection to retrieve the objects from + * @param query the query document that specifies the criteria used to find a record + * @param fields the document that specifies the fields to be returned + * @param targetClass the parameterized type of the returned list. + * @param reader the MongoReader to convert from DBObject to an object. + * @return the List of converted objects. + */ + protected T doFindOne(String collectionName, DBObject query, DBObject fields, Class targetClass, MongoReader reader) { + MongoReader readerToUse = reader; + if (readerToUse == null) { + readerToUse = this.mongoConverter; + } + substituteMappedIdIfNecessary(query, targetClass, readerToUse); + return execute(new FindOneCallback(query, fields), new ReadDbObjectCallback(readerToUse, targetClass), + collectionName); + } + + /** + * Map the results of an ad-hoc query on the default MongoDB collection to a List of the specified type. + *

                      + * The object is converted from the MongoDB native representation using an instance of + * {@see MongoConverter}. Unless configured otherwise, an + * instance of SimpleMongoConverter will be used. + *

                      + * The query document is specified as a standard DBObject and so is the fields specification. + *

                      + * Can be overridden by subclasses. + * + * @param collectionName name of the collection to retrieve the objects from + * @param query the query document that specifies the criteria used to find a record + * @param fields the document that specifies the fields to be returned + * @param targetClass the parameterized type of the returned list. + * @param preparer allows for customization of the DBCursor used when iterating over the result set, + * (apply limits, skips and so on). + * @return the List of converted objects. + */ + protected List doFind(String collectionName, DBObject query, DBObject fields, Class targetClass, CursorPreparer preparer) { + substituteMappedIdIfNecessary(query, targetClass, mongoConverter); + return executeEach(new FindCallback(query, fields), preparer, new ReadDbObjectCallback(mongoConverter, targetClass), + collectionName); + } + + /** + * Map the results of an ad-hoc query on the default MongoDB collection to a List using the provided MongoReader + *

                      + * The query document is specified as a standard DBObject and so is the fields specification. + * + * @param collectionName name of the collection to retrieve the objects from + * @param query the query document that specifies the criteria used to find a record + * @param fields the document that specifies the fields to be returned + * @param targetClass the parameterized type of the returned list. + * @param reader the MongoReader to convert from DBObject to an object. + * @return the List of converted objects. + */ + protected List doFind(String collectionName, DBObject query, DBObject fields, Class targetClass, MongoReader reader) { + substituteMappedIdIfNecessary(query, targetClass, reader); + return executeEach(new FindCallback(query, fields), null, new ReadDbObjectCallback(reader, targetClass), + collectionName); + } + + protected DBObject convertToDbObject(CollectionOptions collectionOptions) { + DBObject dbo = new BasicDBObject(); + if (collectionOptions != null) { + if (collectionOptions.getCapped() != null) { + dbo.put("capped", collectionOptions.getCapped().booleanValue()); + } + if (collectionOptions.getSize() != null) { + dbo.put("size", collectionOptions.getSize().intValue()); + } + if (collectionOptions.getMaxDocuments() != null) { + dbo.put("max", collectionOptions.getMaxDocuments().intValue()); + } + } + return dbo; + } + + /** + * Populates the id property of the saved object, if it's not set already. + * + * @param savedObject + * @param id + */ + protected void populateIdIfNecessary(Object savedObject, Object id) { + + if (id == null) { + return; + } + + ConfigurablePropertyAccessor bw = PropertyAccessorFactory.forDirectFieldAccess(savedObject); + MongoPropertyDescriptor idDescriptor = new MongoPropertyDescriptors(savedObject.getClass()).getIdDescriptor(); + + if (idDescriptor == null) { + return; + } + + if (bw.getPropertyValue(idDescriptor.getName()) == null) { + Object target = null; + if (id instanceof ObjectId) { + target = this.mongoConverter.convertObjectId((ObjectId) id, idDescriptor.getPropertyType()); + } else { + target = id; + } + bw.setPropertyValue(idDescriptor.getName(), target); + } + } + + /** + * Substitutes the id key if it is found in he query. Any 'id' keys will be replaced with '_id' and the value converted + * to an ObjectId if possible. This conversion should match the way that the id fields are converted during read + * operations. + * + * @param query + * @param targetClass + * @param reader + */ + protected void substituteMappedIdIfNecessary(DBObject query, Class targetClass, MongoReader reader) { + MongoConverter converter = null; + if (reader instanceof SimpleMongoConverter) { + converter = (MongoConverter) reader; + } else { + return; + } + String idKey = null; + if (query.containsField("id")) { + idKey = "id"; + } + if (query.containsField("_id")) { + idKey = "_id"; + } + if (idKey == null) { + // no ids in this query + return; + } + final MongoPropertyDescriptor descriptor; + try { + descriptor = new MongoPropertyDescriptor(new PropertyDescriptor(idKey, targetClass)); + } catch (IntrospectionException e) { + // no property descriptor for this key + return; + } + if (descriptor.isIdProperty() && descriptor.isOfIdType()) { + Object value = query.get(idKey); + ObjectId newValue = null; + try { + if (value instanceof String && ObjectId.isValid((String) value)) { + newValue = converter.convertObjectId(value); + } + } catch (ConversionFailedException iae) { + LOGGER.warn("Unable to convert the String " + value + " to an ObjectId"); + } + query.removeField(idKey); + if (newValue != null) { + query.put(MongoPropertyDescriptor.ID_KEY, newValue); + } else { + query.put(MongoPropertyDescriptor.ID_KEY, value); + } + } + } + + + private String getRequiredDefaultCollectionName() { + String name = getDefaultCollectionName(); + if (name == null) { + throw new IllegalStateException( + "No 'defaultCollection' or 'defaultCollectionName' specified. Check configuration of MongoTemplate."); + } + return name; + } + + /** + * Checks and handles any errors. + *

                      + * TODO: current implementation logs errors - will be configurable to log warning, errors or + * throw exception in later versions + */ + private void handleAnyWriteResultErrors(WriteResult wr, DBObject query, String operation) { + if (WriteResultChecking.NONE == this.writeResultChecking) { + return; + } + String error = wr.getError(); + int n = wr.getN(); + if (error != null) { + String message = "Execution of '" + operation + + (query == null ? "" : "' using '" + query.toString() + "' query") + " failed: " + error; + if (WriteResultChecking.EXCEPTION == this.writeResultChecking) { + throw new DataIntegrityViolationException(message); + } else { + LOGGER.error(message); + } + } else if (n == 0) { + String message = "Execution of '" + operation + + (query == null ? "" : "' using '" + query.toString() + "' query") + " did not succeed: 0 documents updated"; + if (WriteResultChecking.EXCEPTION == this.writeResultChecking) { + throw new DataIntegrityViolationException(message); + } else { + LOGGER.warn(message); + } + } + + } + + /** + * Tries to convert the given {@link RuntimeException} into a {@link DataAccessException} but returns the original + * exception if the conversation failed. Thus allows safe rethrowing of the return value. + * + * @param ex + * @return + */ + private RuntimeException potentiallyConvertRuntimeException(RuntimeException ex) { + RuntimeException resolved = this.exceptionTranslator.translateExceptionIfPossible(ex); + return resolved == null ? ex : resolved; + } + + /* + * (non-Javadoc) + * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() + */ + public void afterPropertiesSet() { + if (this.getDefaultCollectionName() != null) { + if (!collectionExists(getDefaultCollectionName())) { + createCollection(getDefaultCollectionName(), null); + } + } + } + + + /** + * Simple {@link CollectionCallback} that takes a query {@link DBObject} plus an optional fields specification + * {@link DBObject} and executes that against the {@link DBCollection}. + * + * @author Oliver Gierke + * @author Thomas Risberg + */ + private static class FindOneCallback implements CollectionCallback { + + private final DBObject query; + + private final DBObject fields; + + public FindOneCallback(DBObject query, DBObject fields) { + this.query = query; + this.fields = fields; + } + + public DBObject doInCollection(DBCollection collection) throws MongoException, DataAccessException { + if (fields == null) { + return collection.findOne(query); + } else { + return collection.findOne(query, fields); + } + } + } + + /** + * Simple {@link CollectionCallback} that takes a query {@link DBObject} plus an optional fields specification + * {@link DBObject} and executes that against the {@link DBCollection}. + * + * @author Oliver Gierke + * @author Thomas Risberg + */ + private static class FindCallback implements CollectionCallback { + + private final DBObject query; + + private final DBObject fields; + + public FindCallback(DBObject query) { + this(query, null); + } + + public FindCallback(DBObject query, DBObject fields) { + this.query = query; + this.fields = fields; + } + + public DBCursor doInCollection(DBCollection collection) throws MongoException, DataAccessException { + if (fields == null) { + return collection.find(query); + } else { + return collection.find(query, fields); + } + } + } + + /** + * Simple internal callback to allow operations on a {@link DBObject}. + * + * @author Oliver Gierke + */ + + private interface DbObjectCallback { + + T doWith(DBObject object); + } + + /** + * Simple {@link DbObjectCallback} that will transform {@link DBObject} into the given target type using the given + * {@link MongoReader}. + * + * @author Oliver Gierke + */ + private static class ReadDbObjectCallback implements DbObjectCallback { + + private final MongoReader reader; + private final Class type; + + public ReadDbObjectCallback(MongoReader reader, Class type) { + this.reader = reader; + this.type = type; + } + + public T doWith(DBObject object) { + return reader.read(type, object); + } + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoWriter.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoWriter.java index 923297049..2949ffa39 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoWriter.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoWriter.java @@ -19,19 +19,19 @@ import com.mongodb.DBObject; /** * A MongoWriter is responsible for converting an object of type T to the native MongoDB representation DBObject. - * - * @author Mark Pollack - * @author Thomas Risberg * * @param the type of the object to convert to a DBObject + * @author Mark Pollack + * @author Thomas Risberg */ public interface MongoWriter { - /** - * Write the given object of type T to the native MongoDB object representation DBObject. - * @param t The object to convert to a DBObject - * @param dbo The DBObject to use for writing. - */ - void write(T t, DBObject dbo); - + /** + * Write the given object of type T to the native MongoDB object representation DBObject. + * + * @param t The object to convert to a DBObject + * @param dbo The DBObject to use for writing. + */ + void write(T t, DBObject dbo); + } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/WriteResultChecking.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/WriteResultChecking.java index d2bb144f7..2a577d174 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/WriteResultChecking.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/WriteResultChecking.java @@ -1,5 +1,5 @@ package org.springframework.data.document.mongodb; public enum WriteResultChecking { - NONE, LOG, EXCEPTION + NONE, LOG, EXCEPTION } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoJmxParser.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoJmxParser.java index c3e54a1fa..dcba033e1 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoJmxParser.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoJmxParser.java @@ -22,55 +22,48 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.data.document.mongodb.MongoAdmin; -import org.springframework.data.document.mongodb.monitor.AssertMetrics; -import org.springframework.data.document.mongodb.monitor.BackgroundFlushingMetrics; -import org.springframework.data.document.mongodb.monitor.BtreeIndexCounters; -import org.springframework.data.document.mongodb.monitor.ConnectionMetrics; -import org.springframework.data.document.mongodb.monitor.GlobalLockMetrics; -import org.springframework.data.document.mongodb.monitor.MemoryMetrics; -import org.springframework.data.document.mongodb.monitor.OperationCounters; -import org.springframework.data.document.mongodb.monitor.ServerInfo; +import org.springframework.data.document.mongodb.monitor.*; import org.springframework.util.StringUtils; import org.w3c.dom.Element; public class MongoJmxParser implements BeanDefinitionParser { - public BeanDefinition parse(Element element, ParserContext parserContext) { - String name = element.getAttribute("mongo-ref"); - if (!StringUtils.hasText(name)) { - name = "mongo"; - } - registerJmxComponents(name, element, parserContext); - return null; - } + public BeanDefinition parse(Element element, ParserContext parserContext) { + String name = element.getAttribute("mongo-ref"); + if (!StringUtils.hasText(name)) { + name = "mongo"; + } + registerJmxComponents(name, element, parserContext); + return null; + } - protected void registerJmxComponents(String mongoRefName, Element element, ParserContext parserContext) { - Object eleSource = parserContext.extractSource(element); + protected void registerJmxComponents(String mongoRefName, Element element, ParserContext parserContext) { + Object eleSource = parserContext.extractSource(element); - CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource); - - createBeanDefEntry(AssertMetrics.class, compositeDef, mongoRefName, eleSource, parserContext); - createBeanDefEntry(BackgroundFlushingMetrics.class, compositeDef, mongoRefName, eleSource, parserContext); - createBeanDefEntry(BtreeIndexCounters.class, compositeDef, mongoRefName, eleSource, parserContext); - createBeanDefEntry(ConnectionMetrics.class, compositeDef, mongoRefName, eleSource, parserContext); - createBeanDefEntry(GlobalLockMetrics.class, compositeDef, mongoRefName, eleSource, parserContext); - createBeanDefEntry(MemoryMetrics.class, compositeDef, mongoRefName, eleSource, parserContext); - createBeanDefEntry(OperationCounters.class, compositeDef, mongoRefName, eleSource, parserContext); - createBeanDefEntry(ServerInfo.class, compositeDef, mongoRefName, eleSource, parserContext); - createBeanDefEntry(MongoAdmin.class, compositeDef, mongoRefName, eleSource, parserContext); - - - parserContext.registerComponent(compositeDef); - - } + CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource); + + createBeanDefEntry(AssertMetrics.class, compositeDef, mongoRefName, eleSource, parserContext); + createBeanDefEntry(BackgroundFlushingMetrics.class, compositeDef, mongoRefName, eleSource, parserContext); + createBeanDefEntry(BtreeIndexCounters.class, compositeDef, mongoRefName, eleSource, parserContext); + createBeanDefEntry(ConnectionMetrics.class, compositeDef, mongoRefName, eleSource, parserContext); + createBeanDefEntry(GlobalLockMetrics.class, compositeDef, mongoRefName, eleSource, parserContext); + createBeanDefEntry(MemoryMetrics.class, compositeDef, mongoRefName, eleSource, parserContext); + createBeanDefEntry(OperationCounters.class, compositeDef, mongoRefName, eleSource, parserContext); + createBeanDefEntry(ServerInfo.class, compositeDef, mongoRefName, eleSource, parserContext); + createBeanDefEntry(MongoAdmin.class, compositeDef, mongoRefName, eleSource, parserContext); + + + parserContext.registerComponent(compositeDef); + + } + + protected void createBeanDefEntry(Class clazz, CompositeComponentDefinition compositeDef, String mongoRefName, Object eleSource, ParserContext parserContext) { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz); + builder.getRawBeanDefinition().setSource(eleSource); + builder.addConstructorArgReference(mongoRefName); + BeanDefinition assertDef = builder.getBeanDefinition(); + String assertName = parserContext.getReaderContext().registerWithGeneratedName(assertDef); + compositeDef.addNestedComponent(new BeanComponentDefinition(assertDef, assertName)); + } - protected void createBeanDefEntry(Class clazz, CompositeComponentDefinition compositeDef, String mongoRefName, Object eleSource, ParserContext parserContext) { - BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz); - builder.getRawBeanDefinition().setSource(eleSource); - builder.addConstructorArgReference(mongoRefName); - BeanDefinition assertDef = builder.getBeanDefinition(); - String assertName = parserContext.getReaderContext().registerWithGeneratedName(assertDef); - compositeDef.addNestedComponent(new BeanComponentDefinition(assertDef, assertName)); - } - } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoMappingConverterParser.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoMappingConverterParser.java index da0d6830b..19c88c1f0 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoMappingConverterParser.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoMappingConverterParser.java @@ -47,7 +47,7 @@ public class MongoMappingConverterParser extends AbstractSingleBeanDefinitionPar @Override protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { super.doParse(element, parserContext, builder); - + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoParser.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoParser.java index 9e6de9692..547731007 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoParser.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoParser.java @@ -28,67 +28,67 @@ import org.springframework.util.xml.DomUtils; import org.w3c.dom.Element; /** - * Parser for <mongo;gt; definitions. If no name - * + * Parser for <mongo;gt; definitions. If no name + * * @author Mark Pollack */ public class MongoParser extends AbstractSingleBeanDefinitionParser { - protected Class getBeanClass(Element element) { - return MongoFactoryBean.class; - } + protected Class getBeanClass(Element element) { + return MongoFactoryBean.class; + } - @Override - protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { - super.doParse(element, builder); + @Override + protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + super.doParse(element, builder); - setPropertyValue(element, builder, "port", "port"); - setPropertyValue(element, builder, "host", "host"); - - parseOptions(parserContext, element, builder); - - } + setPropertyValue(element, builder, "port", "port"); + setPropertyValue(element, builder, "host", "host"); - /** - * Parses the options sub-element. Populates the given attribute factory with the proper attributes. - * - * @param element - * @param attrBuilder - * @return true if parsing actually occured, false otherwise - */ - private boolean parseOptions(ParserContext parserContext, Element element, - BeanDefinitionBuilder mongoBuilder) { - Element optionsElement = DomUtils.getChildElementByTagName(element, "options"); - if (optionsElement == null) - return false; - - BeanDefinitionBuilder optionsDefBuilder = BeanDefinitionBuilder.genericBeanDefinition(MongoOptionsFactoryBean.class); + parseOptions(parserContext, element, builder); - setPropertyValue(optionsElement, optionsDefBuilder, "connectionsPerHost", "connectionsPerHost"); - setPropertyValue(optionsElement, optionsDefBuilder, "threadsAllowedToBlockForConnectionMultiplier", "threadsAllowedToBlockForConnectionMultiplier"); - setPropertyValue(optionsElement, optionsDefBuilder, "maxWaitTime", "maxWaitTime"); - setPropertyValue(optionsElement, optionsDefBuilder, "connectTimeout", "connectTimeout"); - setPropertyValue(optionsElement, optionsDefBuilder, "socketTimeout", "socketTimeout"); - setPropertyValue(optionsElement, optionsDefBuilder, "autoConnectRetry", "autoConnectRetry"); - - mongoBuilder.addPropertyValue("mongoOptions", optionsDefBuilder.getBeanDefinition()); - return true; - } + } - @Override - protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) - throws BeanDefinitionStoreException { - String name = super.resolveId(element, definition, parserContext); - if (!StringUtils.hasText(name)) { - name = "mongo"; - } - return name; - } - - private void setPropertyValue(Element element, BeanDefinitionBuilder builder, String attrName, String propertyName) { - String attr = element.getAttribute(attrName); - if (StringUtils.hasText(attr)) { - builder.addPropertyValue(propertyName, attr); - } - } + /** + * Parses the options sub-element. Populates the given attribute factory with the proper attributes. + * + * @param element + * @param attrBuilder + * @return true if parsing actually occured, false otherwise + */ + private boolean parseOptions(ParserContext parserContext, Element element, + BeanDefinitionBuilder mongoBuilder) { + Element optionsElement = DomUtils.getChildElementByTagName(element, "options"); + if (optionsElement == null) + return false; + + BeanDefinitionBuilder optionsDefBuilder = BeanDefinitionBuilder.genericBeanDefinition(MongoOptionsFactoryBean.class); + + setPropertyValue(optionsElement, optionsDefBuilder, "connectionsPerHost", "connectionsPerHost"); + setPropertyValue(optionsElement, optionsDefBuilder, "threadsAllowedToBlockForConnectionMultiplier", "threadsAllowedToBlockForConnectionMultiplier"); + setPropertyValue(optionsElement, optionsDefBuilder, "maxWaitTime", "maxWaitTime"); + setPropertyValue(optionsElement, optionsDefBuilder, "connectTimeout", "connectTimeout"); + setPropertyValue(optionsElement, optionsDefBuilder, "socketTimeout", "socketTimeout"); + setPropertyValue(optionsElement, optionsDefBuilder, "autoConnectRetry", "autoConnectRetry"); + + mongoBuilder.addPropertyValue("mongoOptions", optionsDefBuilder.getBeanDefinition()); + return true; + } + + @Override + protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) + throws BeanDefinitionStoreException { + String name = super.resolveId(element, definition, parserContext); + if (!StringUtils.hasText(name)) { + name = "mongo"; + } + return name; + } + + private void setPropertyValue(Element element, BeanDefinitionBuilder builder, String attrName, String propertyName) { + String attr = element.getAttribute(attrName); + if (StringUtils.hasText(attr)) { + builder.addPropertyValue(propertyName, attr); + } + } } \ No newline at end of file diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoRepositoryConfigDefinitionParser.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoRepositoryConfigDefinitionParser.java index 602314a92..a66f006c3 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoRepositoryConfigDefinitionParser.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoRepositoryConfigDefinitionParser.java @@ -24,43 +24,43 @@ import org.w3c.dom.Element; /** * {@link org.springframework.beans.factory.xml.BeanDefinitionParser} to create * Mongo DB repositories from classpath scanning or manual definition. - * + * * @author Oliver Gierke */ public class MongoRepositoryConfigDefinitionParser - extends - AbstractRepositoryConfigDefinitionParser { + extends + AbstractRepositoryConfigDefinitionParser { - /* - * (non-Javadoc) - * - * @see org.springframework.data.repository.config. - * AbstractRepositoryConfigDefinitionParser - * #getGlobalRepositoryConfigInformation(org.w3c.dom.Element) - */ - @Override - protected SimpleMongoRepositoryConfiguration getGlobalRepositoryConfigInformation( - Element element) { + /* + * (non-Javadoc) + * + * @see org.springframework.data.repository.config. + * AbstractRepositoryConfigDefinitionParser + * #getGlobalRepositoryConfigInformation(org.w3c.dom.Element) + */ + @Override + protected SimpleMongoRepositoryConfiguration getGlobalRepositoryConfigInformation( + Element element) { - return new SimpleMongoRepositoryConfiguration(element); - } + return new SimpleMongoRepositoryConfiguration(element); + } - /* - * (non-Javadoc) - * - * @see org.springframework.data.repository.config. - * AbstractRepositoryConfigDefinitionParser - * #postProcessBeanDefinition(org.springframework - * .data.repository.config.SingleRepositoryConfigInformation, - * org.springframework.beans.factory.support.BeanDefinitionBuilder, - * java.lang.Object) - */ - @Override - protected void postProcessBeanDefinition( - MongoRepositoryConfiguration context, - BeanDefinitionBuilder builder, Object beanSource) { + /* + * (non-Javadoc) + * + * @see org.springframework.data.repository.config. + * AbstractRepositoryConfigDefinitionParser + * #postProcessBeanDefinition(org.springframework + * .data.repository.config.SingleRepositoryConfigInformation, + * org.springframework.beans.factory.support.BeanDefinitionBuilder, + * java.lang.Object) + */ + @Override + protected void postProcessBeanDefinition( + MongoRepositoryConfiguration context, + BeanDefinitionBuilder builder, Object beanSource) { - builder.addPropertyReference("template", context.getMongoTemplateRef()); - } + builder.addPropertyReference("template", context.getMongoTemplateRef()); + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoRepositoryNamespaceHandler.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoRepositoryNamespaceHandler.java index 2299a91df..29f8fa93e 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoRepositoryNamespaceHandler.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoRepositoryNamespaceHandler.java @@ -21,22 +21,22 @@ import org.springframework.beans.factory.xml.NamespaceHandlerSupport; /** * {@link org.springframework.beans.factory.xml.NamespaceHandler} for Mongo DB * based repositories. - * + * * @author Oliver Gierke */ public class MongoRepositoryNamespaceHandler extends NamespaceHandlerSupport { - /* - * (non-Javadoc) - * - * @see org.springframework.beans.factory.xml.NamespaceHandler#init() - */ - public void init() { + /* + * (non-Javadoc) + * + * @see org.springframework.beans.factory.xml.NamespaceHandler#init() + */ + public void init() { - registerBeanDefinitionParser("repositories", - new MongoRepositoryConfigDefinitionParser()); - - registerBeanDefinitionParser("mongo", new MongoParser()); - registerBeanDefinitionParser("jmx", new MongoJmxParser()); - } + registerBeanDefinitionParser("repositories", + new MongoRepositoryConfigDefinitionParser()); + + registerBeanDefinitionParser("mongo", new MongoParser()); + registerBeanDefinitionParser("jmx", new MongoJmxParser()); + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MappingMongoConverter.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MappingMongoConverter.java index 016a61b37..63cdcc36e 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MappingMongoConverter.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MappingMongoConverter.java @@ -16,6 +16,11 @@ package org.springframework.data.document.mongodb.convert; +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.math.BigInteger; +import java.util.*; + import com.mongodb.BasicDBList; import com.mongodb.BasicDBObject; import com.mongodb.DBObject; @@ -40,15 +45,9 @@ import org.springframework.expression.Expression; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; -import java.lang.reflect.Array; -import java.lang.reflect.InvocationTargetException; -import java.math.BigInteger; -import java.util.*; - /** * @author Jon Brisbin */ -@SuppressWarnings({"unchecked"}) public class MappingMongoConverter implements MongoConverter, ApplicationContextAware { private static final String CUSTOM_TYPE_KEY = "_class"; @@ -112,6 +111,7 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext return conversionService.convert(id, ObjectId.class); } + @SuppressWarnings({"unchecked"}) public S read(Class clazz, final DBObject dbo) { if (null == dbo) { return null; @@ -143,17 +143,17 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext if (persistentEntity == null) { persistentEntity = mappingContext.addPersistentEntity(clazz); } - + return read(persistentEntity, dbo); } - + private S read(PersistentEntity entity, final DBObject dbo) { - + final StandardEvaluationContext spelCtx = new StandardEvaluationContext(); if (null != applicationContext) { spelCtx.setBeanResolver(new BeanFactoryResolver(applicationContext)); } - String[] keySet = dbo.keySet().toArray(new String[] {}); + String[] keySet = dbo.keySet().toArray(new String[]{}); for (String key : keySet) { spelCtx.setVariable(key, dbo.get(key)); } @@ -208,7 +208,7 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext throw new MappingException(e.getMessage(), e); } } - + if (ctorParamNames.contains(prop.getName())) { return; } @@ -261,13 +261,13 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext PersistentEntity entity = mappingContext.getPersistentEntity(obj.getClass()); write(obj, dbo, entity); } - + protected void write(final Object obj, final DBObject dbo, PersistentEntity entity) { - + if (obj == null) { return; } - + if (null == entity) { // Must not have explictly added this entity yet entity = mappingContext.addPersistentEntity(obj.getClass()); @@ -358,6 +358,7 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext } } + @SuppressWarnings({"unchecked"}) protected void writePropertyInternal(PersistentProperty prop, Object obj, DBObject dbo) { org.springframework.data.document.mongodb.mapping.DBRef dbref = prop.getField() .getAnnotation(org.springframework.data.document.mongodb.mapping.DBRef.class); @@ -457,6 +458,7 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext return dbo; } + @SuppressWarnings({"unchecked"}) protected Object getValueInternal(PersistentProperty prop, DBObject dbo, StandardEvaluationContext ctx, Value spelExpr) { String name = prop.getName(); Object o; @@ -471,11 +473,11 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext Object dbObj = from.get(name); if (dbObj instanceof DBObject) { if (prop.isMap() && dbObj instanceof DBObject) { - + // We have to find a potentially stored class to be used first. Class toType = findTypeToBeUsed((DBObject) dbObj); Map m = new LinkedHashMap(); - + for (Map.Entry entry : ((Map) ((DBObject) dbObj).toMap()).entrySet()) { if (entry.getKey().equals(CUSTOM_TYPE_KEY)) { continue; @@ -505,7 +507,7 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext } return Arrays.asList(items); } - + // It's a complex object, have to read it in if (dbo.containsField("_class")) { try { @@ -524,16 +526,16 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext } return o; } - + /** * Returns the type to be used to convert the DBObject given to. - * + * * @param dbObject * @return */ private Class findTypeToBeUsed(DBObject dbObject) { Object classToBeUsed = dbObject.get(CUSTOM_TYPE_KEY); - + try { return Class.forName(classToBeUsed.toString()); } catch (ClassNotFoundException e) { diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MongoBeanWrapper.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MongoBeanWrapper.java index f676332b1..c56553cec 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MongoBeanWrapper.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MongoBeanWrapper.java @@ -15,7 +15,8 @@ */ package org.springframework.data.document.mongodb.convert; -import static org.springframework.beans.PropertyAccessorFactory.*; +import static org.springframework.beans.PropertyAccessorFactory.forBeanPropertyAccess; +import static org.springframework.beans.PropertyAccessorFactory.forDirectFieldAccess; import org.springframework.beans.BeanWrapper; import org.springframework.beans.ConfigurablePropertyAccessor; @@ -27,67 +28,67 @@ import org.springframework.util.Assert; /** * Custom Mongo specific {@link BeanWrapper} to allow access to bean properties via {@link MongoPropertyDescriptor}s. - * + * * @author Oliver Gierke */ class MongoBeanWrapper { - private final ConfigurablePropertyAccessor accessor; - private final MongoPropertyDescriptors descriptors; - private final boolean fieldAccess; + private final ConfigurablePropertyAccessor accessor; + private final MongoPropertyDescriptors descriptors; + private final boolean fieldAccess; - /** - * Creates a new {@link MongoBeanWrapper} for the given target object and {@link ConversionService}. - * - * @param target - * @param conversionService - * @param fieldAccess - */ - public MongoBeanWrapper(Object target, ConversionService conversionService, boolean fieldAccess) { + /** + * Creates a new {@link MongoBeanWrapper} for the given target object and {@link ConversionService}. + * + * @param target + * @param conversionService + * @param fieldAccess + */ + public MongoBeanWrapper(Object target, ConversionService conversionService, boolean fieldAccess) { - Assert.notNull(target); - Assert.notNull(conversionService); + Assert.notNull(target); + Assert.notNull(conversionService); - this.fieldAccess = fieldAccess; - this.accessor = fieldAccess ? forDirectFieldAccess(target) : forBeanPropertyAccess(target); - this.accessor.setConversionService(conversionService); - this.descriptors = new MongoPropertyDescriptors(target.getClass()); - } + this.fieldAccess = fieldAccess; + this.accessor = fieldAccess ? forDirectFieldAccess(target) : forBeanPropertyAccess(target); + this.accessor.setConversionService(conversionService); + this.descriptors = new MongoPropertyDescriptors(target.getClass()); + } - /** - * Returns all {@link MongoPropertyDescriptors.MongoPropertyDescriptor}s for the underlying target object. - * - * @return - */ - public MongoPropertyDescriptors getDescriptors() { - return this.descriptors; - } + /** + * Returns all {@link MongoPropertyDescriptors.MongoPropertyDescriptor}s for the underlying target object. + * + * @return + */ + public MongoPropertyDescriptors getDescriptors() { + return this.descriptors; + } - /** - * Returns the value of the underlying object for the given property. - * - * @param descriptor - * @return - */ - public Object getValue(MongoPropertyDescriptors.MongoPropertyDescriptor descriptor) { - Assert.notNull(descriptor); - return accessor.getPropertyValue(descriptor.getName()); - } + /** + * Returns the value of the underlying object for the given property. + * + * @param descriptor + * @return + */ + public Object getValue(MongoPropertyDescriptors.MongoPropertyDescriptor descriptor) { + Assert.notNull(descriptor); + return accessor.getPropertyValue(descriptor.getName()); + } - /** - * Sets the property of the underlying object to the given value. - * - * @param descriptor - * @param value - */ - public void setValue(MongoPropertyDescriptors.MongoPropertyDescriptor descriptor, Object value) { - Assert.notNull(descriptor); - try { - accessor.setPropertyValue(descriptor.getName(), value); - } catch (NotWritablePropertyException e) { - if (!fieldAccess) { - throw e; - } - } - } + /** + * Sets the property of the underlying object to the given value. + * + * @param descriptor + * @param value + */ + public void setValue(MongoPropertyDescriptors.MongoPropertyDescriptor descriptor, Object value) { + Assert.notNull(descriptor); + try { + accessor.setPropertyValue(descriptor.getName(), value); + } catch (NotWritablePropertyException e) { + if (!fieldAccess) { + throw e; + } + } + } } \ No newline at end of file diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/SimpleMongoConverter.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/SimpleMongoConverter.java index 84f4529f6..61c51853e 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/SimpleMongoConverter.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/SimpleMongoConverter.java @@ -15,6 +15,12 @@ */ package org.springframework.data.document.mongodb.convert; +import java.lang.reflect.*; +import java.math.BigInteger; +import java.util.*; +import java.util.Map.Entry; +import java.util.regex.Pattern; + import com.mongodb.BasicDBList; import com.mongodb.BasicDBObject; import com.mongodb.DBObject; @@ -34,12 +40,6 @@ import org.springframework.data.document.mongodb.MongoPropertyDescriptors.MongoP import org.springframework.util.Assert; import org.springframework.util.comparator.CompoundComparator; -import java.lang.reflect.*; -import java.math.BigInteger; -import java.util.*; -import java.util.Map.Entry; -import java.util.regex.Pattern; - /** * Basic {@link MongoConverter} implementation to convert between domain classes and {@link DBObject}s. * diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/DBRef.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/DBRef.java index 0029cc077..81cbe03a8 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/DBRef.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/DBRef.java @@ -16,13 +16,13 @@ package org.springframework.data.document.mongodb.mapping; -import org.springframework.data.annotation.Reference; - import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.springframework.data.annotation.Reference; + /** * @author Jon Brisbin */ diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/Document.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/Document.java index 7be66ab83..cd3e3f6aa 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/Document.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/Document.java @@ -32,5 +32,5 @@ import java.lang.annotation.Target; public @interface Document { String collection() default ""; - + } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoMappingConfigurationBuilder.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoMappingConfigurationBuilder.java index e1689008c..0345526be 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoMappingConfigurationBuilder.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoMappingConfigurationBuilder.java @@ -16,6 +16,12 @@ package org.springframework.data.document.mongodb.mapping; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + import com.mongodb.BasicDBObject; import com.mongodb.DBCollection; import com.mongodb.DBObject; @@ -35,12 +41,6 @@ import org.springframework.data.mapping.MappingBeanHelper; import org.springframework.data.mapping.model.*; import org.springframework.data.util.TypeInformation; -import java.beans.PropertyDescriptor; -import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - /** * @author Jon Brisbin */ @@ -78,7 +78,7 @@ public class MongoMappingConfigurationBuilder extends BasicMappingConfigurationB @Override public PersistentEntity createPersistentEntity(TypeInformation typeInformation, MappingContext mappingContext) throws MappingConfigurationException { - + MongoPersistentEntity entity = new MongoPersistentEntity(mappingContext, typeInformation); Class type = typeInformation.getType(); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoPersistentEntity.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoPersistentEntity.java index dee231fd8..63b1ff8ac 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoPersistentEntity.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoPersistentEntity.java @@ -27,7 +27,7 @@ public class MongoPersistentEntity extends BasicPersistentEntity { protected String collection; - + public MongoPersistentEntity(MappingContext mappingContext, TypeInformation typeInformation) { super(mappingContext, typeInformation); } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoPersistentProperty.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoPersistentProperty.java index 4d89918bd..eac7fd102 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoPersistentProperty.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoPersistentProperty.java @@ -29,7 +29,7 @@ import org.springframework.data.util.TypeInformation; * Mongo specific * {@link org.springframework.data.mapping.model.PersistentProperty} * implementation. - * + * * @author Oliver Gierke */ public class MongoPersistentProperty extends BasicPersistentProperty { @@ -48,19 +48,19 @@ public class MongoPersistentProperty extends BasicPersistentProperty { /** * Creates a new {@link MongoPersistentProperty}. - * + * * @param field * @param propertyDescriptor * @param owningTypeInformation */ public MongoPersistentProperty(Field field, - PropertyDescriptor propertyDescriptor, TypeInformation owningTypeInformation) { + PropertyDescriptor propertyDescriptor, TypeInformation owningTypeInformation) { super(field, propertyDescriptor, owningTypeInformation); } /** * Also considers fields as id that are of supported id type and name. - * + * * @see #SUPPORTED_ID_PROPERTY_NAMES * @see #SUPPORTED_ID_TYPES */ diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/AbstractMonitor.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/AbstractMonitor.java index e0aca0899..ec94808b8 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/AbstractMonitor.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/AbstractMonitor.java @@ -15,59 +15,57 @@ */ package org.springframework.data.document.mongodb.monitor; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.data.document.mongodb.MongoDbUtils; - import com.mongodb.CommandResult; import com.mongodb.DB; import com.mongodb.Mongo; import com.mongodb.MongoException; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.data.document.mongodb.MongoDbUtils; /** * Base class to encapsulate common configuration settings when connecting to a database - * - * @author Mark Pollack * + * @author Mark Pollack */ public abstract class AbstractMonitor { - private final Log logger = LogFactory.getLog(getClass()); - - protected Mongo mongo; - private String username; - private String password; - - - /** - * Sets the username to use to connect to the Mongo database - * - * @param username The username to use - */ - public void setUsername(String username) { - this.username = username; - } + private final Log logger = LogFactory.getLog(getClass()); - /** - * Sets the password to use to authenticate with the Mongo database. - * - * @param password The password to use - */ - public void setPassword(String password) { - - this.password = password; - } - - public CommandResult getServerStatus() { - CommandResult result = getDb("admin").command("serverStatus"); - if (!result.ok()) { - logger.error("Could not query for server status. Command Result = " + result); - throw new MongoException("could not query for server status. Command Result = " + result); - } - return result; - } - - public DB getDb(String databaseName) { - return MongoDbUtils.getDB(mongo, databaseName, username, password == null ? null : password.toCharArray()); - } + protected Mongo mongo; + private String username; + private String password; + + + /** + * Sets the username to use to connect to the Mongo database + * + * @param username The username to use + */ + public void setUsername(String username) { + this.username = username; + } + + /** + * Sets the password to use to authenticate with the Mongo database. + * + * @param password The password to use + */ + public void setPassword(String password) { + + this.password = password; + } + + public CommandResult getServerStatus() { + CommandResult result = getDb("admin").command("serverStatus"); + if (!result.ok()) { + logger.error("Could not query for server status. Command Result = " + result); + throw new MongoException("could not query for server status. Command Result = " + result); + } + return result; + } + + public DB getDb(String databaseName) { + return MongoDbUtils.getDB(mongo, databaseName, username, password == null ? null : password.toCharArray()); + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/AssertMetrics.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/AssertMetrics.java index b9bd6f5ca..fd7ad4c39 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/AssertMetrics.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/AssertMetrics.java @@ -15,55 +15,53 @@ */ package org.springframework.data.document.mongodb.monitor; +import com.mongodb.DBObject; +import com.mongodb.Mongo; import org.springframework.jmx.export.annotation.ManagedMetric; import org.springframework.jmx.export.annotation.ManagedResource; import org.springframework.jmx.support.MetricType; -import com.mongodb.DBObject; -import com.mongodb.Mongo; - /** * JMX Metrics for assertions - * - * @author Mark Pollack * + * @author Mark Pollack */ -@ManagedResource(description="Assertion Metrics") +@ManagedResource(description = "Assertion Metrics") public class AssertMetrics extends AbstractMonitor { - public AssertMetrics(Mongo mongo) { - this.mongo = mongo; - } - - @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Regular") - public int getRegular() { - return getBtree("regular"); - } - - @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Warning") - public int getWarning() { - return getBtree("warning"); - } - - @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Msg") - public int getMsg() { - return getBtree("msg"); - } - - @ManagedMetric(metricType = MetricType.COUNTER, displayName = "User") - public int getUser() { - return getBtree("user"); - } - - @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Rollovers") - public int getRollovers() { - return getBtree("rollovers"); - } - - private int getBtree(String key) { - DBObject asserts = (DBObject) getServerStatus().get("asserts"); - //Class c = btree.get(key).getClass(); - return (Integer) asserts.get(key); - } - + public AssertMetrics(Mongo mongo) { + this.mongo = mongo; + } + + @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Regular") + public int getRegular() { + return getBtree("regular"); + } + + @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Warning") + public int getWarning() { + return getBtree("warning"); + } + + @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Msg") + public int getMsg() { + return getBtree("msg"); + } + + @ManagedMetric(metricType = MetricType.COUNTER, displayName = "User") + public int getUser() { + return getBtree("user"); + } + + @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Rollovers") + public int getRollovers() { + return getBtree("rollovers"); + } + + private int getBtree(String key) { + DBObject asserts = (DBObject) getServerStatus().get("asserts"); + //Class c = btree.get(key).getClass(); + return (Integer) asserts.get(key); + } + } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/BackgroundFlushingMetrics.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/BackgroundFlushingMetrics.java index aed6413f2..4958e7354 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/BackgroundFlushingMetrics.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/BackgroundFlushingMetrics.java @@ -17,64 +17,62 @@ package org.springframework.data.document.mongodb.monitor; import java.util.Date; +import com.mongodb.DBObject; +import com.mongodb.Mongo; import org.springframework.jmx.export.annotation.ManagedMetric; import org.springframework.jmx.export.annotation.ManagedResource; import org.springframework.jmx.support.MetricType; -import com.mongodb.DBObject; -import com.mongodb.Mongo; - /** * JMX Metrics for Background Flushing - * - * @author Mark Pollack * + * @author Mark Pollack */ -@ManagedResource(description="Background Flushing Metrics") +@ManagedResource(description = "Background Flushing Metrics") public class BackgroundFlushingMetrics extends AbstractMonitor { - public BackgroundFlushingMetrics(Mongo mongo) { - this.mongo = mongo; - } - - @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Flushes") - public int getFlushes() { - return getFlushingData("flushes", java.lang.Integer.class); - } - - @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Total ms", unit="ms") - public int getTotalMs() { - return getFlushingData("total_ms", java.lang.Integer.class); - } - - @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Average ms", unit="ms") - public double getAverageMs() { - return getFlushingData("average_ms", java.lang.Double.class); - } - - @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Last Ms", unit="ms") - public int getLastMs() { - return getFlushingData("last_ms", java.lang.Integer.class); - } - - - @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Last finished") - public Date getLastFinished() { - return getLast(); - } - - @SuppressWarnings("unchecked") - private T getFlushingData(String key, Class targetClass) { - DBObject mem = (DBObject) getServerStatus().get("backgroundFlushing"); - return (T) mem.get(key); - } - - private Date getLast() { - DBObject bgFlush = (DBObject) getServerStatus().get("backgroundFlushing"); - Date lastFinished = (Date)bgFlush.get("last_finished"); - return lastFinished; - } - + public BackgroundFlushingMetrics(Mongo mongo) { + this.mongo = mongo; + } + + @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Flushes") + public int getFlushes() { + return getFlushingData("flushes", java.lang.Integer.class); + } + + @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Total ms", unit = "ms") + public int getTotalMs() { + return getFlushingData("total_ms", java.lang.Integer.class); + } + + @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Average ms", unit = "ms") + public double getAverageMs() { + return getFlushingData("average_ms", java.lang.Double.class); + } + + @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Last Ms", unit = "ms") + public int getLastMs() { + return getFlushingData("last_ms", java.lang.Integer.class); + } + + + @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Last finished") + public Date getLastFinished() { + return getLast(); + } + + @SuppressWarnings("unchecked") + private T getFlushingData(String key, Class targetClass) { + DBObject mem = (DBObject) getServerStatus().get("backgroundFlushing"); + return (T) mem.get(key); + } + + private Date getLast() { + DBObject bgFlush = (DBObject) getServerStatus().get("backgroundFlushing"); + Date lastFinished = (Date) bgFlush.get("last_finished"); + return lastFinished; + } + } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/BtreeIndexCounters.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/BtreeIndexCounters.java index cc9051156..4a7d0f5e2 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/BtreeIndexCounters.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/BtreeIndexCounters.java @@ -15,62 +15,60 @@ */ package org.springframework.data.document.mongodb.monitor; +import com.mongodb.DBObject; +import com.mongodb.Mongo; import org.springframework.jmx.export.annotation.ManagedMetric; import org.springframework.jmx.export.annotation.ManagedResource; import org.springframework.jmx.support.MetricType; -import com.mongodb.DBObject; -import com.mongodb.Mongo; - /** * JMX Metrics for B-tree index counters - * - * @author Mark Pollack * + * @author Mark Pollack */ -@ManagedResource(description="Btree Metrics") +@ManagedResource(description = "Btree Metrics") public class BtreeIndexCounters extends AbstractMonitor { - public BtreeIndexCounters(Mongo mongo) { - this.mongo = mongo; - } - - @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Accesses") - public int getAccesses() { - return getBtree("accesses"); - } - - @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Hits") - public int getHits() { - return getBtree("hits"); - } - - @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Misses") - public int getMisses() { - return getBtree("misses"); - } - - @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Resets") - public int getResets() { - return getBtree("resets"); - } - - @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Miss Ratio") - public int getMissRatio() { - return getBtree("missRatio"); - } - - private int getBtree(String key) { - DBObject indexCounters = (DBObject) getServerStatus().get("indexCounters"); - if (indexCounters.get("note") != null) { - String message = (String) indexCounters.get("note"); - if (message.contains("not supported")) { - return -1; - } - } - DBObject btree = (DBObject) indexCounters.get("btree"); - //Class c = btree.get(key).getClass(); - return (Integer) btree.get(key); - } - + public BtreeIndexCounters(Mongo mongo) { + this.mongo = mongo; + } + + @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Accesses") + public int getAccesses() { + return getBtree("accesses"); + } + + @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Hits") + public int getHits() { + return getBtree("hits"); + } + + @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Misses") + public int getMisses() { + return getBtree("misses"); + } + + @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Resets") + public int getResets() { + return getBtree("resets"); + } + + @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Miss Ratio") + public int getMissRatio() { + return getBtree("missRatio"); + } + + private int getBtree(String key) { + DBObject indexCounters = (DBObject) getServerStatus().get("indexCounters"); + if (indexCounters.get("note") != null) { + String message = (String) indexCounters.get("note"); + if (message.contains("not supported")) { + return -1; + } + } + DBObject btree = (DBObject) indexCounters.get("btree"); + //Class c = btree.get(key).getClass(); + return (Integer) btree.get(key); + } + } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/ConnectionMetrics.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/ConnectionMetrics.java index bd9e809ec..4b5cdd988 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/ConnectionMetrics.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/ConnectionMetrics.java @@ -15,41 +15,39 @@ */ package org.springframework.data.document.mongodb.monitor; +import com.mongodb.DBObject; +import com.mongodb.Mongo; import org.springframework.jmx.export.annotation.ManagedMetric; import org.springframework.jmx.export.annotation.ManagedResource; import org.springframework.jmx.support.MetricType; -import com.mongodb.DBObject; -import com.mongodb.Mongo; - /** * JMX Metrics for Connections - * - * @author Mark Pollack * + * @author Mark Pollack */ -@ManagedResource(description="Connection metrics") +@ManagedResource(description = "Connection metrics") public class ConnectionMetrics extends AbstractMonitor { - public ConnectionMetrics(Mongo mongo) { - this.mongo = mongo; - } - - @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Current Connections") - public int getCurrent() { - return getConnectionData("current", java.lang.Integer.class); - } - - @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Available Connections") - public int getAvailable() { - return getConnectionData("available", java.lang.Integer.class); - } - - @SuppressWarnings("unchecked") - private T getConnectionData(String key, Class targetClass) { - DBObject mem = (DBObject) getServerStatus().get("connections"); - //Class c = mem.get(key).getClass(); - return (T) mem.get(key); - } - + public ConnectionMetrics(Mongo mongo) { + this.mongo = mongo; + } + + @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Current Connections") + public int getCurrent() { + return getConnectionData("current", java.lang.Integer.class); + } + + @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Available Connections") + public int getAvailable() { + return getConnectionData("available", java.lang.Integer.class); + } + + @SuppressWarnings("unchecked") + private T getConnectionData(String key, Class targetClass) { + DBObject mem = (DBObject) getServerStatus().get("connections"); + //Class c = mem.get(key).getClass(); + return (T) mem.get(key); + } + } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/GlobalLockMetrics.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/GlobalLockMetrics.java index d19689a49..c157ac188 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/GlobalLockMetrics.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/GlobalLockMetrics.java @@ -15,66 +15,65 @@ */ package org.springframework.data.document.mongodb.monitor; +import com.mongodb.DBObject; +import com.mongodb.Mongo; import org.springframework.jmx.export.annotation.ManagedMetric; import org.springframework.jmx.export.annotation.ManagedResource; import org.springframework.jmx.support.MetricType; -import com.mongodb.DBObject; -import com.mongodb.Mongo; - /** * JMX Metrics for Global Locks - * @author Mark Pollack * + * @author Mark Pollack */ -@ManagedResource(description="Global Lock Metrics") +@ManagedResource(description = "Global Lock Metrics") public class GlobalLockMetrics extends AbstractMonitor { - public GlobalLockMetrics(Mongo mongo) { - this.mongo = mongo; - } - - @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Total time") - public double getTotalTime() { - return getGlobalLockData("totalTime", java.lang.Double.class); - } - - @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Lock time", unit="s") - public double getLockTime() { - return getGlobalLockData("lockTime", java.lang.Double.class); - } - - @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Lock time") - public double getLockTimeRatio() { - return getGlobalLockData("ratio", java.lang.Double.class); - } - - - @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Current Queue") - public int getCurrentQueueTotal() { - return getCurrentQueue("total"); - } - - @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Reader Queue") - public int getCurrentQueueReaders() { - return getCurrentQueue("readers"); - } - - @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Writer Queue") - public int getCurrentQueueWriters() { - return getCurrentQueue("writers"); - } - - @SuppressWarnings("unchecked") - private T getGlobalLockData(String key, Class targetClass) { - DBObject globalLock = (DBObject) getServerStatus().get("globalLock"); - return (T) globalLock.get(key); - } - - private int getCurrentQueue(String key) { - DBObject globalLock = (DBObject) getServerStatus().get("globalLock"); - DBObject currentQueue = (DBObject) globalLock.get("currentQueue"); - return (Integer) currentQueue.get(key); - } + public GlobalLockMetrics(Mongo mongo) { + this.mongo = mongo; + } + + @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Total time") + public double getTotalTime() { + return getGlobalLockData("totalTime", java.lang.Double.class); + } + + @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Lock time", unit = "s") + public double getLockTime() { + return getGlobalLockData("lockTime", java.lang.Double.class); + } + + @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Lock time") + public double getLockTimeRatio() { + return getGlobalLockData("ratio", java.lang.Double.class); + } + + + @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Current Queue") + public int getCurrentQueueTotal() { + return getCurrentQueue("total"); + } + + @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Reader Queue") + public int getCurrentQueueReaders() { + return getCurrentQueue("readers"); + } + + @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Writer Queue") + public int getCurrentQueueWriters() { + return getCurrentQueue("writers"); + } + + @SuppressWarnings("unchecked") + private T getGlobalLockData(String key, Class targetClass) { + DBObject globalLock = (DBObject) getServerStatus().get("globalLock"); + return (T) globalLock.get(key); + } + + private int getCurrentQueue(String key) { + DBObject globalLock = (DBObject) getServerStatus().get("globalLock"); + DBObject currentQueue = (DBObject) globalLock.get("currentQueue"); + return (Integer) currentQueue.get(key); + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/MemoryMetrics.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/MemoryMetrics.java index 1b3086ed3..b9d329945 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/MemoryMetrics.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/MemoryMetrics.java @@ -15,59 +15,58 @@ */ package org.springframework.data.document.mongodb.monitor; +import com.mongodb.DBObject; +import com.mongodb.Mongo; import org.springframework.jmx.export.annotation.ManagedMetric; import org.springframework.jmx.export.annotation.ManagedResource; import org.springframework.jmx.support.MetricType; -import com.mongodb.DBObject; -import com.mongodb.Mongo; - /** * JMX Metrics for Memory - * @author Mark Pollack * + * @author Mark Pollack */ -@ManagedResource(description="Memory Metrics") +@ManagedResource(description = "Memory Metrics") public class MemoryMetrics extends AbstractMonitor { - public MemoryMetrics(Mongo mongo) { - this.mongo = mongo; - } - - @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Memory address size") - public int getBits() { - return getMemData("bits", java.lang.Integer.class); - } - - @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Resident in Physical Memory", unit="MB") - public int getResidentSpace() { - return getMemData("resident", java.lang.Integer.class); - } - - @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Virtual Address Space", unit="MB") - public int getVirtualAddressSpace() { - return getMemData("virtual", java.lang.Integer.class); - } - - @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Is memory info supported on this platform") - public boolean getMemoryInfoSupported() { - return getMemData("supported", java.lang.Boolean.class); - } - - - @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Memory Mapped Space", unit="MB") - public int getMemoryMappedSpace() { - return getMemData("mapped", java.lang.Integer.class); - } - - - @SuppressWarnings("unchecked") - private T getMemData(String key, Class targetClass) { - DBObject mem = (DBObject) getServerStatus().get("mem"); - //Class c = mem.get(key).getClass(); - return (T) mem.get(key); - } - + public MemoryMetrics(Mongo mongo) { + this.mongo = mongo; + } + + @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Memory address size") + public int getBits() { + return getMemData("bits", java.lang.Integer.class); + } + + @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Resident in Physical Memory", unit = "MB") + public int getResidentSpace() { + return getMemData("resident", java.lang.Integer.class); + } + + @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Virtual Address Space", unit = "MB") + public int getVirtualAddressSpace() { + return getMemData("virtual", java.lang.Integer.class); + } + + @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Is memory info supported on this platform") + public boolean getMemoryInfoSupported() { + return getMemData("supported", java.lang.Boolean.class); + } + + + @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Memory Mapped Space", unit = "MB") + public int getMemoryMappedSpace() { + return getMemData("mapped", java.lang.Integer.class); + } + + + @SuppressWarnings("unchecked") + private T getMemData(String key, Class targetClass) { + DBObject mem = (DBObject) getServerStatus().get("mem"); + //Class c = mem.get(key).getClass(); + return (T) mem.get(key); + } + } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/OperationCounters.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/OperationCounters.java index c9b68c61e..297d60fa6 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/OperationCounters.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/OperationCounters.java @@ -15,58 +15,57 @@ */ package org.springframework.data.document.mongodb.monitor; +import com.mongodb.DBObject; +import com.mongodb.Mongo; import org.springframework.jmx.export.annotation.ManagedMetric; import org.springframework.jmx.export.annotation.ManagedResource; import org.springframework.jmx.support.MetricType; -import com.mongodb.DBObject; -import com.mongodb.Mongo; - /** * JMX Metrics for Operation counters - * @author Mark Pollack * + * @author Mark Pollack */ -@ManagedResource(description="Operation Counters") +@ManagedResource(description = "Operation Counters") public class OperationCounters extends AbstractMonitor { - public OperationCounters(Mongo mongo) { - this.mongo = mongo; - } - - @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Insert operation count") - public int getInsertCount() { - return getOpCounter("insert"); - } - - @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Query operation count") - public int getQueryCount() { - return getOpCounter("query"); - } - - @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Update operation count") - public int getUpdateCount() { - return getOpCounter("update"); - } - - @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Delete operation count") - public int getDeleteCount() { - return getOpCounter("delete"); - } - - @ManagedMetric(metricType = MetricType.COUNTER, displayName = "GetMore operation count") - public int getGetMoreCount() { - return getOpCounter("getmore"); - } - - @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Command operation count") - public int getCommandCount() { - return getOpCounter("command"); - } - - private int getOpCounter(String key) { - DBObject opCounters = (DBObject) getServerStatus().get("opcounters"); - return (Integer) opCounters.get(key); - } + public OperationCounters(Mongo mongo) { + this.mongo = mongo; + } + + @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Insert operation count") + public int getInsertCount() { + return getOpCounter("insert"); + } + + @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Query operation count") + public int getQueryCount() { + return getOpCounter("query"); + } + + @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Update operation count") + public int getUpdateCount() { + return getOpCounter("update"); + } + + @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Delete operation count") + public int getDeleteCount() { + return getOpCounter("delete"); + } + + @ManagedMetric(metricType = MetricType.COUNTER, displayName = "GetMore operation count") + public int getGetMoreCount() { + return getOpCounter("getmore"); + } + + @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Command operation count") + public int getCommandCount() { + return getOpCounter("command"); + } + + private int getOpCounter(String key) { + DBObject opCounters = (DBObject) getServerStatus().get("opcounters"); + return (Integer) opCounters.get(key); + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/ServerInfo.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/ServerInfo.java index 7e53b422e..4e79a84f6 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/ServerInfo.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/ServerInfo.java @@ -18,52 +18,49 @@ package org.springframework.data.document.mongodb.monitor; import java.net.InetAddress; import java.net.UnknownHostException; +import com.mongodb.Mongo; import org.springframework.jmx.export.annotation.ManagedMetric; import org.springframework.jmx.export.annotation.ManagedOperation; import org.springframework.jmx.export.annotation.ManagedResource; import org.springframework.jmx.support.MetricType; -import com.mongodb.Mongo; - /** - * Expose basic server information via JMX - * - * @author Mark Pollack + * Expose basic server information via JMX * + * @author Mark Pollack */ -@ManagedResource(description="Server Information") +@ManagedResource(description = "Server Information") public class ServerInfo extends AbstractMonitor { - - public ServerInfo(Mongo mongo) { - this.mongo = mongo; - } - - @ManagedOperation(description="Server host name") - public String getHostName() throws UnknownHostException { - return InetAddress.getLocalHost().getHostName(); - } - - @ManagedMetric(displayName="Uptime Estimate") - public double getUptimeEstimate() - { - return (Double)getServerStatus().get("uptimeEstimate"); - } + public ServerInfo(Mongo mongo) { + this.mongo = mongo; + } - @ManagedOperation(description="MongoDB Server Version") - public String getVersion() { - return (String) getServerStatus().get("version"); - } - - @ManagedOperation(description="Local Time") - public String getLocalTime() { - return (String) getServerStatus().get("localTime"); - } - - - @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Server uptime in seconds", unit="seconds") - public double getUptime() { - return (Double) getServerStatus().get("uptime"); - } + + @ManagedOperation(description = "Server host name") + public String getHostName() throws UnknownHostException { + return InetAddress.getLocalHost().getHostName(); + } + + @ManagedMetric(displayName = "Uptime Estimate") + public double getUptimeEstimate() { + return (Double) getServerStatus().get("uptimeEstimate"); + } + + @ManagedOperation(description = "MongoDB Server Version") + public String getVersion() { + return (String) getServerStatus().get("version"); + } + + @ManagedOperation(description = "Local Time") + public String getLocalTime() { + return (String) getServerStatus().get("localTime"); + } + + + @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Server uptime in seconds", unit = "seconds") + public double getUptime() { + return (Double) getServerStatus().get("uptime"); + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/BasicQuery.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/BasicQuery.java index 29656d072..549ae5092 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/BasicQuery.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/BasicQuery.java @@ -20,72 +20,72 @@ import com.mongodb.util.JSON; public class BasicQuery extends Query { - private DBObject queryObject = null; - - private DBObject fieldsObject = null; - - private DBObject sortObject = null; + private DBObject queryObject = null; - private int skip; + private DBObject fieldsObject = null; - private int limit; - - public BasicQuery(String query) { - super(); - this.queryObject = (DBObject) JSON.parse(query); - } - - public BasicQuery(DBObject queryObject) { - super(); - this.queryObject = queryObject; - } + private DBObject sortObject = null; - public BasicQuery(String query, String fields) { - this.queryObject = (DBObject) JSON.parse(query); - this.fieldsObject = (DBObject) JSON.parse(fields); - } - - public BasicQuery(DBObject queryObject, DBObject fieldsObject) { - this.queryObject = queryObject; - this.fieldsObject = fieldsObject; - } + private int skip; - @Override - public Query and(Criteria criteria) { - this.queryObject.putAll(criteria.getCriteriaObject()); - return this; - } + private int limit; - public DBObject getQueryObject() { - return this.queryObject; - } + public BasicQuery(String query) { + super(); + this.queryObject = (DBObject) JSON.parse(query); + } - public DBObject getFieldsObject() { - return fieldsObject; - } + public BasicQuery(DBObject queryObject) { + super(); + this.queryObject = queryObject; + } - public DBObject getSortObject() { - return sortObject; - } + public BasicQuery(String query, String fields) { + this.queryObject = (DBObject) JSON.parse(query); + this.fieldsObject = (DBObject) JSON.parse(fields); + } - public void setSortObject(DBObject sortObject) { - this.sortObject = sortObject; - } + public BasicQuery(DBObject queryObject, DBObject fieldsObject) { + this.queryObject = queryObject; + this.fieldsObject = fieldsObject; + } - public int getSkip() { - return skip; - } + @Override + public Query and(Criteria criteria) { + this.queryObject.putAll(criteria.getCriteriaObject()); + return this; + } - public void setSkip(int skip) { - this.skip = skip; - } + public DBObject getQueryObject() { + return this.queryObject; + } - public int getLimit() { - return this.limit; - } + public DBObject getFieldsObject() { + return fieldsObject; + } - public void setLimit(int limit) { - this.limit = limit; - } + public DBObject getSortObject() { + return sortObject; + } + + public void setSortObject(DBObject sortObject) { + this.sortObject = sortObject; + } + + public int getSkip() { + return skip; + } + + public void setSkip(int skip) { + this.skip = skip; + } + + public int getLimit() { + return this.limit; + } + + public void setLimit(int limit) { + this.limit = limit; + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/BasicUpdate.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/BasicUpdate.java index 84a2adb03..da0b2bde4 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/BasicUpdate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/BasicUpdate.java @@ -23,93 +23,93 @@ import com.mongodb.util.JSON; public class BasicUpdate extends Update { - private DBObject updateObject = null; - - public BasicUpdate(String updateString) { - super(); - this.updateObject = (DBObject) JSON.parse(updateString); - } - - public BasicUpdate(DBObject updateObject) { - super(); - this.updateObject = updateObject; - } + private DBObject updateObject = null; - @Override - public Update set(String key, Object value) { - updateObject.put("$set", Collections.singletonMap(key, convertValueIfNecessary(value))); - return this; - } + public BasicUpdate(String updateString) { + super(); + this.updateObject = (DBObject) JSON.parse(updateString); + } - @Override - public Update unset(String key) { - updateObject.put("$unset", Collections.singletonMap(key, 1)); - return this; - } + public BasicUpdate(DBObject updateObject) { + super(); + this.updateObject = updateObject; + } - @Override - public Update inc(String key, Number inc) { - updateObject.put("$inc", Collections.singletonMap(key, inc)); - return this; - } + @Override + public Update set(String key, Object value) { + updateObject.put("$set", Collections.singletonMap(key, convertValueIfNecessary(value))); + return this; + } - @Override - public Update push(String key, Object value) { - updateObject.put("$push", Collections.singletonMap(key, convertValueIfNecessary(value))); - return this; - } + @Override + public Update unset(String key) { + updateObject.put("$unset", Collections.singletonMap(key, 1)); + return this; + } - @Override - public Update pushAll(String key, Object[] values) { - Object[] convertedValues = new Object[values.length]; - for (int i = 0; i < values.length; i++) { - convertedValues[i] = convertValueIfNecessary(values[i]); - } - DBObject keyValue = new BasicDBObject(); - keyValue.put(key, convertedValues); - updateObject.put("$pushAll", keyValue); - return this; - } + @Override + public Update inc(String key, Number inc) { + updateObject.put("$inc", Collections.singletonMap(key, inc)); + return this; + } - @Override - public Update addToSet(String key, Object value) { - updateObject.put("$addToSet", Collections.singletonMap(key, convertValueIfNecessary(value))); - return this; - } + @Override + public Update push(String key, Object value) { + updateObject.put("$push", Collections.singletonMap(key, convertValueIfNecessary(value))); + return this; + } - @Override - public Update pop(String key, Position pos) { - updateObject.put("$pop", Collections.singletonMap(key, (pos == Position.FIRST ? -1 : 1))); - return this; - } + @Override + public Update pushAll(String key, Object[] values) { + Object[] convertedValues = new Object[values.length]; + for (int i = 0; i < values.length; i++) { + convertedValues[i] = convertValueIfNecessary(values[i]); + } + DBObject keyValue = new BasicDBObject(); + keyValue.put(key, convertedValues); + updateObject.put("$pushAll", keyValue); + return this; + } - @Override - public Update pull(String key, Object value) { - updateObject.put("$pull", Collections.singletonMap(key, convertValueIfNecessary(value))); - return this; - } + @Override + public Update addToSet(String key, Object value) { + updateObject.put("$addToSet", Collections.singletonMap(key, convertValueIfNecessary(value))); + return this; + } - @Override - public Update pullAll(String key, Object[] values) { - Object[] convertedValues = new Object[values.length]; - for (int i = 0; i < values.length; i++) { - convertedValues[i] = convertValueIfNecessary(values[i]); - } - DBObject keyValue = new BasicDBObject(); - keyValue.put(key, convertedValues); - updateObject.put("$pullAll", keyValue); - return this; - } + @Override + public Update pop(String key, Position pos) { + updateObject.put("$pop", Collections.singletonMap(key, (pos == Position.FIRST ? -1 : 1))); + return this; + } - @Override - public Update rename(String oldName, String newName) { - updateObject.put("$rename", Collections.singletonMap(oldName, newName)); - return this; - } + @Override + public Update pull(String key, Object value) { + updateObject.put("$pull", Collections.singletonMap(key, convertValueIfNecessary(value))); + return this; + } - @Override - public DBObject getUpdateObject() { - return updateObject; - } + @Override + public Update pullAll(String key, Object[] values) { + Object[] convertedValues = new Object[values.length]; + for (int i = 0; i < values.length; i++) { + convertedValues[i] = convertValueIfNecessary(values[i]); + } + DBObject keyValue = new BasicDBObject(); + keyValue.put(key, convertedValues); + updateObject.put("$pullAll", keyValue); + return this; + } + + @Override + public Update rename(String oldName, String newName) { + updateObject.put("$rename", Collections.singletonMap(oldName, newName)); + return this; + } + + @Override + public DBObject getUpdateObject() { + return updateObject; + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Criteria.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Criteria.java index 621eff83a..966835448 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Criteria.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Criteria.java @@ -19,245 +19,242 @@ import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; -import org.springframework.data.document.InvalidDocumentStoreApiUsageException; - import com.mongodb.BasicDBObject; import com.mongodb.DBObject; +import org.springframework.data.document.InvalidDocumentStoreApiUsageException; public class Criteria implements CriteriaDefinition { - - private String key; - - private LinkedHashMap criteria = new LinkedHashMap(); - private Object isValue = null; - - - public Criteria(String key) { - this.key = key; - } + private String key; + + private LinkedHashMap criteria = new LinkedHashMap(); + + private Object isValue = null; - /** - * Static factory method to create a Criteria using the provided key - * - * @param key - * @return - */ - public static Criteria where(String key) { - return new Criteria(key); - } + public Criteria(String key) { + this.key = key; + } - /** - * Creates a criterion using the $is operator - * - * @param o - * @return - */ - public Criteria is(Object o) { - if (isValue != null) { - throw new InvalidDocumentStoreApiUsageException("Multiple 'is' values declared."); - } - this.isValue = o; - return this; - } - /** - * Creates a criterion using the $lt operator - * - * @param o - * @return - */ - public Criteria lt(Object o) { - criteria.put("$lt", o); - return this; - } - - /** - * Creates a criterion using the $lte operator - * - * @param o - * @return - */ - public Criteria lte(Object o) { - criteria.put("$lte", o); - return this; - } - - /** - * Creates a criterion using the $gt operator - * - * @param o - * @return - */ - public Criteria gt(Object o) { - criteria.put("$gt", o); - return this; - } - - /** - * Creates a criterion using the $gte operator - * - * @param o - * @return - */ - public Criteria gte(Object o) { - criteria.put("$gte", o); - return this; - } - - /** - * Creates a criterion using the $in operator - * @param o - * @return - */ - public Criteria in(Object... o) { - criteria.put("$in", o); - return this; - } + /** + * Static factory method to create a Criteria using the provided key + * + * @param key + * @return + */ + public static Criteria where(String key) { + return new Criteria(key); + } - /** - * Creates a criterion using the $nin operator - * - * @param o - * @return - */ - public Criteria nin(Object... o) { - criteria.put("$nin", o); - return this; - } + /** + * Creates a criterion using the $is operator + * + * @param o + * @return + */ + public Criteria is(Object o) { + if (isValue != null) { + throw new InvalidDocumentStoreApiUsageException("Multiple 'is' values declared."); + } + this.isValue = o; + return this; + } - /** - * Creates a criterion using the $mod operator - * - * @param value - * @param remainder - * @return - */ - public Criteria mod(Number value, Number remainder) { - List l = new ArrayList(); - l.add(value); - l.add(remainder); - criteria.put("$mod", l); - return this; - } + /** + * Creates a criterion using the $lt operator + * + * @param o + * @return + */ + public Criteria lt(Object o) { + criteria.put("$lt", o); + return this; + } - /** - * Creates a criterion using the $all operator - * - * @param o - * @return - */ - public Criteria all(Object o) { - criteria.put("$is", o); - return this; - } + /** + * Creates a criterion using the $lte operator + * + * @param o + * @return + */ + public Criteria lte(Object o) { + criteria.put("$lte", o); + return this; + } - /** - * Creates a criterion using the $size operator - * - * @param s - * @return - */ - public Criteria size(int s) { - criteria.put("$size", s); - return this; - } + /** + * Creates a criterion using the $gt operator + * + * @param o + * @return + */ + public Criteria gt(Object o) { + criteria.put("$gt", o); + return this; + } - /** - * Creates a criterion using the $exists operator - * - * @param b - * @return - */ - public Criteria exists(boolean b) { - criteria.put("$exists", b); - return this; - } + /** + * Creates a criterion using the $gte operator + * + * @param o + * @return + */ + public Criteria gte(Object o) { + criteria.put("$gte", o); + return this; + } - /** - * Creates a criterion using the $type operator - * - * @param t - * @return - */ - public Criteria type(int t) { - criteria.put("$type", t); - return this; - } + /** + * Creates a criterion using the $in operator + * + * @param o + * @return + */ + public Criteria in(Object... o) { + criteria.put("$in", o); + return this; + } - /** - * Creates a criterion using the $not meta operator which affects the clause directly following - * - * @return - */ - public Criteria not() { - criteria.put("$not", null); - return this; - } - - /** - * Creates a criterion using a $regex - * - * @param re - * @return - */ - public Criteria regex(String re) { - criteria.put("$regex", re); - return this; - } + /** + * Creates a criterion using the $nin operator + * + * @param o + * @return + */ + public Criteria nin(Object... o) { + criteria.put("$nin", o); + return this; + } - /** - * Creates an or query using the $or operator for all of the provided queries - * - * @param queries - */ - public void or(List queries) { - criteria.put("$or", queries); - } - - public String getKey() { - return this.key; - } + /** + * Creates a criterion using the $mod operator + * + * @param value + * @param remainder + * @return + */ + public Criteria mod(Number value, Number remainder) { + List l = new ArrayList(); + l.add(value); + l.add(remainder); + criteria.put("$mod", l); + return this; + } - /* (non-Javadoc) - * @see org.springframework.datastore.document.mongodb.query.Criteria#getCriteriaObject(java.lang.String) - */ - public DBObject getCriteriaObject() { - DBObject dbo = new BasicDBObject(); - boolean not = false; - for (String k : this.criteria.keySet()) { - if (not) { - DBObject notDbo = new BasicDBObject(); - notDbo.put(k, convertValueIfNecessary(this.criteria.get(k))); - dbo.put("$not", notDbo); - not = false; - } - else { - if ("$not".equals(k)) { - not = true; - } - else { - dbo.put(k, convertValueIfNecessary(this.criteria.get(k))); - } - } - } - DBObject queryCriteria = new BasicDBObject(); - if (isValue != null) { - queryCriteria.put(this.key, convertValueIfNecessary(this.isValue)); - queryCriteria.putAll(dbo); - } - else { - queryCriteria.put(this.key, dbo); - } - return queryCriteria; - } - - private Object convertValueIfNecessary(Object value) { - if (value instanceof Enum) { - return ((Enum)value).name(); - } - return value; - } + /** + * Creates a criterion using the $all operator + * + * @param o + * @return + */ + public Criteria all(Object o) { + criteria.put("$is", o); + return this; + } + + /** + * Creates a criterion using the $size operator + * + * @param s + * @return + */ + public Criteria size(int s) { + criteria.put("$size", s); + return this; + } + + /** + * Creates a criterion using the $exists operator + * + * @param b + * @return + */ + public Criteria exists(boolean b) { + criteria.put("$exists", b); + return this; + } + + /** + * Creates a criterion using the $type operator + * + * @param t + * @return + */ + public Criteria type(int t) { + criteria.put("$type", t); + return this; + } + + /** + * Creates a criterion using the $not meta operator which affects the clause directly following + * + * @return + */ + public Criteria not() { + criteria.put("$not", null); + return this; + } + + /** + * Creates a criterion using a $regex + * + * @param re + * @return + */ + public Criteria regex(String re) { + criteria.put("$regex", re); + return this; + } + + /** + * Creates an or query using the $or operator for all of the provided queries + * + * @param queries + */ + public void or(List queries) { + criteria.put("$or", queries); + } + + public String getKey() { + return this.key; + } + + /* (non-Javadoc) + * @see org.springframework.datastore.document.mongodb.query.Criteria#getCriteriaObject(java.lang.String) + */ + public DBObject getCriteriaObject() { + DBObject dbo = new BasicDBObject(); + boolean not = false; + for (String k : this.criteria.keySet()) { + if (not) { + DBObject notDbo = new BasicDBObject(); + notDbo.put(k, convertValueIfNecessary(this.criteria.get(k))); + dbo.put("$not", notDbo); + not = false; + } else { + if ("$not".equals(k)) { + not = true; + } else { + dbo.put(k, convertValueIfNecessary(this.criteria.get(k))); + } + } + } + DBObject queryCriteria = new BasicDBObject(); + if (isValue != null) { + queryCriteria.put(this.key, convertValueIfNecessary(this.isValue)); + queryCriteria.putAll(dbo); + } else { + queryCriteria.put(this.key, dbo); + } + return queryCriteria; + } + + private Object convertValueIfNecessary(Object value) { + if (value instanceof Enum) { + return ((Enum) value).name(); + } + return value; + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/CriteriaDefinition.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/CriteriaDefinition.java index c99748964..3616cb41a 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/CriteriaDefinition.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/CriteriaDefinition.java @@ -19,6 +19,6 @@ import com.mongodb.DBObject; public interface CriteriaDefinition { - DBObject getCriteriaObject(); + DBObject getCriteriaObject(); } \ No newline at end of file diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Field.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Field.java index 67e360da2..2940192e8 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Field.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Field.java @@ -23,39 +23,39 @@ import com.mongodb.DBObject; public class Field { - - private Map criteria = new HashMap(); - - private Map slices = new HashMap(); - public Field include(String key) { - criteria.put(key, Integer.valueOf(1)); - return this; - } + private Map criteria = new HashMap(); - public Field exclude(String key) { - criteria.put(key, Integer.valueOf(0)); - return this; - } - - public Field slice(String key, int size) { - slices.put(key, Integer.valueOf(size)); - return this; - } + private Map slices = new HashMap(); - public Field slice(String key, int offset, int size) { - slices.put(key, new Integer[] {Integer.valueOf(offset), Integer.valueOf(size)}); - return this; - } + public Field include(String key) { + criteria.put(key, Integer.valueOf(1)); + return this; + } - public DBObject getFieldsObject() { - DBObject dbo = new BasicDBObject(); - for (String k : criteria.keySet()) { - dbo.put(k, (criteria.get(k))); - } - for (String k : slices.keySet()) { - dbo.put(k, new BasicDBObject("$slice" ,(slices.get(k)))); - } - return dbo; - } + public Field exclude(String key) { + criteria.put(key, Integer.valueOf(0)); + return this; + } + + public Field slice(String key, int size) { + slices.put(key, Integer.valueOf(size)); + return this; + } + + public Field slice(String key, int offset, int size) { + slices.put(key, new Integer[]{Integer.valueOf(offset), Integer.valueOf(size)}); + return this; + } + + public DBObject getFieldsObject() { + DBObject dbo = new BasicDBObject(); + for (String k : criteria.keySet()) { + dbo.put(k, (criteria.get(k))); + } + for (String k : slices.keySet()) { + dbo.put(k, new BasicDBObject("$slice", (slices.get(k)))); + } + return dbo; + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/GeospatialIndex.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/GeospatialIndex.java index 0d5982628..5a0901996 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/GeospatialIndex.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/GeospatialIndex.java @@ -20,58 +20,58 @@ import com.mongodb.DBObject; public class GeospatialIndex implements IndexDefinition { - - private String keyField; - - private String name; - - private Integer min = null; - private Integer max = null; + private String keyField; - public GeospatialIndex() { - } + private String name; - public GeospatialIndex(String key) { - keyField = key; - } + private Integer min = null; - public GeospatialIndex named(String name) { - this.name = name; - return this; - } + private Integer max = null; - public GeospatialIndex withMin(int min) { - this.min = Integer.valueOf(min); - return this; - } + public GeospatialIndex() { + } - public GeospatialIndex withMax(int max) { - this.max = Integer.valueOf(max); - return this; - } + public GeospatialIndex(String key) { + keyField = key; + } - public DBObject getIndexObject() { - DBObject dbo = new BasicDBObject(); - dbo.put(keyField, "2d"); - return dbo; - } - - public DBObject getIndexOptions() { - if (name == null && min == null && max == null) { - return null; - } - DBObject dbo = new BasicDBObject(); - if (name != null) { - dbo.put("name", name); - } - if (min != null) { - dbo.put("min", min); - } - if (max != null) { - dbo.put("max", max); - } - return dbo; - } + public GeospatialIndex named(String name) { + this.name = name; + return this; + } + + public GeospatialIndex withMin(int min) { + this.min = Integer.valueOf(min); + return this; + } + + public GeospatialIndex withMax(int max) { + this.max = Integer.valueOf(max); + return this; + } + + public DBObject getIndexObject() { + DBObject dbo = new BasicDBObject(); + dbo.put(keyField, "2d"); + return dbo; + } + + public DBObject getIndexOptions() { + if (name == null && min == null && max == null) { + return null; + } + DBObject dbo = new BasicDBObject(); + if (name != null) { + dbo.put("name", name); + } + if (min != null) { + dbo.put("min", min); + } + if (max != null) { + dbo.put("max", max); + } + return dbo; + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Index.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Index.java index f1693a610..6538ec8f7 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Index.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Index.java @@ -23,72 +23,72 @@ import com.mongodb.DBObject; public class Index implements IndexDefinition { - - public enum Duplicates { - RETAIN, - DROP - } - - private Map fieldSpec = new HashMap(); - - private String name; - - private boolean unique = false; - private boolean dropDuplicates = false; + public enum Duplicates { + RETAIN, + DROP + } - public Index() { - } + private Map fieldSpec = new HashMap(); - public Index(String key, Order order) { - fieldSpec.put(key, order); - } + private String name; - public Index on(String key, Order order) { - fieldSpec.put(key, order); - return this; - } - - public Index named(String name) { - this.name = name; - return this; - } + private boolean unique = false; - public Index unique() { - this.unique = true; - return this; - } + private boolean dropDuplicates = false; - public Index unique(Duplicates duplicates) { - if (duplicates == Duplicates.DROP) { - this.dropDuplicates = true; - } - return unique(); - } + public Index() { + } - public DBObject getIndexObject() { - DBObject dbo = new BasicDBObject(); - for (String k : fieldSpec.keySet()) { - dbo.put(k, (fieldSpec.get(k).equals(Order.ASCENDING) ? 1 : -1)); - } - return dbo; - } - - public DBObject getIndexOptions() { - if (name == null && !unique) { - return null; - } - DBObject dbo = new BasicDBObject(); - if (name != null) { - dbo.put("name", name); - } - if (unique) { - dbo.put("unique", true); - } - if (dropDuplicates) { - dbo.put("drop_dups", true); - } - return dbo; - } + public Index(String key, Order order) { + fieldSpec.put(key, order); + } + + public Index on(String key, Order order) { + fieldSpec.put(key, order); + return this; + } + + public Index named(String name) { + this.name = name; + return this; + } + + public Index unique() { + this.unique = true; + return this; + } + + public Index unique(Duplicates duplicates) { + if (duplicates == Duplicates.DROP) { + this.dropDuplicates = true; + } + return unique(); + } + + public DBObject getIndexObject() { + DBObject dbo = new BasicDBObject(); + for (String k : fieldSpec.keySet()) { + dbo.put(k, (fieldSpec.get(k).equals(Order.ASCENDING) ? 1 : -1)); + } + return dbo; + } + + public DBObject getIndexOptions() { + if (name == null && !unique) { + return null; + } + DBObject dbo = new BasicDBObject(); + if (name != null) { + dbo.put("name", name); + } + if (unique) { + dbo.put("unique", true); + } + if (dropDuplicates) { + dbo.put("drop_dups", true); + } + return dbo; + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/IndexDefinition.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/IndexDefinition.java index c23259ab0..e0092eb16 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/IndexDefinition.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/IndexDefinition.java @@ -4,8 +4,8 @@ import com.mongodb.DBObject; public interface IndexDefinition { - DBObject getIndexObject(); - - DBObject getIndexOptions(); + DBObject getIndexObject(); + + DBObject getIndexOptions(); } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/OrCriteria.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/OrCriteria.java index dc1565217..4676c2795 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/OrCriteria.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/OrCriteria.java @@ -15,32 +15,31 @@ */ package org.springframework.data.document.mongodb.query; -import org.bson.types.BasicBSONList; - import com.mongodb.BasicDBObject; import com.mongodb.DBObject; +import org.bson.types.BasicBSONList; public class OrCriteria implements CriteriaDefinition { - - Query[] queries = null; - - public OrCriteria(Query[] queries) { - super(); - this.queries = queries; - } + + Query[] queries = null; + + public OrCriteria(Query[] queries) { + super(); + this.queries = queries; + } - /* (non-Javadoc) - * @see org.springframework.datastore.document.mongodb.query.Criteria#getCriteriaObject(java.lang.String) - */ - public DBObject getCriteriaObject() { - DBObject dbo = new BasicDBObject(); - BasicBSONList l = new BasicBSONList(); - for (Query q : queries) { - l.add(q.getQueryObject()); - } - dbo.put("$or", l); - return dbo; - } + /* (non-Javadoc) + * @see org.springframework.datastore.document.mongodb.query.Criteria#getCriteriaObject(java.lang.String) + */ + public DBObject getCriteriaObject() { + DBObject dbo = new BasicDBObject(); + BasicBSONList l = new BasicBSONList(); + for (Query q : queries) { + l.add(q.getQueryObject()); + } + dbo.put("$or", l); + return dbo; + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/OrQuery.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/OrQuery.java index 7914cffed..8a94d2558 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/OrQuery.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/OrQuery.java @@ -2,8 +2,8 @@ package org.springframework.data.document.mongodb.query; public class OrQuery extends Query { - public OrQuery(Query... q) { - super.or(q); - } - + public OrQuery(Query... q) { + super.or(q); + } + } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Order.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Order.java index 8dbd7a198..b254caee3 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Order.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Order.java @@ -17,9 +17,9 @@ package org.springframework.data.document.mongodb.query; /** * An enum that specifies the ordering for sort or index specifications - * + * * @author trisberg */ public enum Order { - ASCENDING, DESCENDING + ASCENDING, DESCENDING } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Query.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Query.java index 6e8756e71..4078e92f7 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Query.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Query.java @@ -21,91 +21,91 @@ import com.mongodb.BasicDBObject; import com.mongodb.DBObject; public class Query { - - private LinkedHashMap criteria = new LinkedHashMap(); - - private Field fieldSpec; - - private Sort sort; - private int skip; + private LinkedHashMap criteria = new LinkedHashMap(); - private int limit; - - public Query() { - } - - public Query(Criteria criteria) { - and(criteria); - } + private Field fieldSpec; - public Query and(Criteria criteria) { - this.criteria.put(criteria.getKey(), criteria); - return this; - } + private Sort sort; - public Query or(Query... queries) { - this.criteria.put("$or", new OrCriteria(queries)); - return this; - } + private int skip; - public Field fields() { - synchronized (this) { - if (fieldSpec == null) { - this.fieldSpec = new Field(); - } - } - return this.fieldSpec; - } - - public Query skip(int skip) { - this.skip = skip; - return this; - } + private int limit; - public Query limit(int limit) { - this.limit = limit; - return this; - } - - public Sort sort() { - synchronized (this) { - if (this.sort == null) { - this.sort = new Sort(); - } - } - return this.sort; - } - - public DBObject getQueryObject() { - DBObject dbo = new BasicDBObject(); - for (String k : criteria.keySet()) { - CriteriaDefinition c = criteria.get(k); - DBObject cl = c.getCriteriaObject(); - dbo.putAll(cl); - } - return dbo; - } + public Query() { + } - public DBObject getFieldsObject() { - if (this.fieldSpec == null) { - return null; - } - return fieldSpec.getFieldsObject(); - } + public Query(Criteria criteria) { + and(criteria); + } - public DBObject getSortObject() { - if (this.sort == null) { - return null; - } - return this.sort.getSortObject(); - } + public Query and(Criteria criteria) { + this.criteria.put(criteria.getKey(), criteria); + return this; + } - public int getSkip() { - return this.skip; - } + public Query or(Query... queries) { + this.criteria.put("$or", new OrCriteria(queries)); + return this; + } - public int getLimit() { - return this.limit; - } + public Field fields() { + synchronized (this) { + if (fieldSpec == null) { + this.fieldSpec = new Field(); + } + } + return this.fieldSpec; + } + + public Query skip(int skip) { + this.skip = skip; + return this; + } + + public Query limit(int limit) { + this.limit = limit; + return this; + } + + public Sort sort() { + synchronized (this) { + if (this.sort == null) { + this.sort = new Sort(); + } + } + return this.sort; + } + + public DBObject getQueryObject() { + DBObject dbo = new BasicDBObject(); + for (String k : criteria.keySet()) { + CriteriaDefinition c = criteria.get(k); + DBObject cl = c.getCriteriaObject(); + dbo.putAll(cl); + } + return dbo; + } + + public DBObject getFieldsObject() { + if (this.fieldSpec == null) { + return null; + } + return fieldSpec.getFieldsObject(); + } + + public DBObject getSortObject() { + if (this.sort == null) { + return null; + } + return this.sort.getSortObject(); + } + + public int getSkip() { + return this.skip; + } + + public int getLimit() { + return this.limit; + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Sort.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Sort.java index a20c318bc..a4e61ae09 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Sort.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Sort.java @@ -23,27 +23,27 @@ import com.mongodb.DBObject; public class Sort { - - private Map fieldSpec = new HashMap(); - - public Sort() { - } - public Sort(String key, Order order) { - fieldSpec.put(key, order); - } + private Map fieldSpec = new HashMap(); - public Sort on(String key, Order order) { - fieldSpec.put(key, order); - return this; - } + public Sort() { + } - public DBObject getSortObject() { - DBObject dbo = new BasicDBObject(); - for (String k : fieldSpec.keySet()) { - dbo.put(k, (fieldSpec.get(k).equals(Order.ASCENDING) ? 1 : -1)); - } - return dbo; - } + public Sort(String key, Order order) { + fieldSpec.put(key, order); + } + + public Sort on(String key, Order order) { + fieldSpec.put(key, order); + return this; + } + + public DBObject getSortObject() { + DBObject dbo = new BasicDBObject(); + for (String k : fieldSpec.keySet()) { + dbo.put(k, (fieldSpec.get(k).equals(Order.ASCENDING) ? 1 : -1)); + } + return dbo; + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Update.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Update.java index 1d8005f51..e23467b80 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Update.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Update.java @@ -24,156 +24,156 @@ import com.mongodb.DBObject; public class Update { - public enum Position { - LAST, FIRST - } + public enum Position { + LAST, FIRST + } - private HashMap criteria = new LinkedHashMap(); + private HashMap criteria = new LinkedHashMap(); - /** - * Update using the $set update modifier - * - * @param key - * @param value - * @return - */ - public Update set(String key, Object value) { - criteria.put("$set", Collections.singletonMap(key, convertValueIfNecessary(value))); - return this; - } + /** + * Update using the $set update modifier + * + * @param key + * @param value + * @return + */ + public Update set(String key, Object value) { + criteria.put("$set", Collections.singletonMap(key, convertValueIfNecessary(value))); + return this; + } - /** - * Update using the $unset update modifier - * - * @param key - * @return - */ - public Update unset(String key) { - criteria.put("$unset", Collections.singletonMap(key, 1)); - return this; - } + /** + * Update using the $unset update modifier + * + * @param key + * @return + */ + public Update unset(String key) { + criteria.put("$unset", Collections.singletonMap(key, 1)); + return this; + } - /** - * Update using the $inc update modifier - * - * @param key - * @param inc - * @return - */ - public Update inc(String key, Number inc) { - criteria.put("$inc", Collections.singletonMap(key, inc)); - return this; - } + /** + * Update using the $inc update modifier + * + * @param key + * @param inc + * @return + */ + public Update inc(String key, Number inc) { + criteria.put("$inc", Collections.singletonMap(key, inc)); + return this; + } - /** - * Update using the $push update modifier - * - * @param key - * @param value - * @return - */ - public Update push(String key, Object value) { - criteria.put("$push", Collections.singletonMap(key, convertValueIfNecessary(value))); - return this; - } + /** + * Update using the $push update modifier + * + * @param key + * @param value + * @return + */ + public Update push(String key, Object value) { + criteria.put("$push", Collections.singletonMap(key, convertValueIfNecessary(value))); + return this; + } - /** - * Update using the $pushAll update modifier - * - * @param key - * @param values - * @return - */ - public Update pushAll(String key, Object[] values) { - Object[] convertedValues = new Object[values.length]; - for (int i = 0; i < values.length; i++) { - convertedValues[i] = convertValueIfNecessary(values[i]); - } - DBObject keyValue = new BasicDBObject(); - keyValue.put(key, convertedValues); - criteria.put("$pushAll", keyValue); - return this; - } + /** + * Update using the $pushAll update modifier + * + * @param key + * @param values + * @return + */ + public Update pushAll(String key, Object[] values) { + Object[] convertedValues = new Object[values.length]; + for (int i = 0; i < values.length; i++) { + convertedValues[i] = convertValueIfNecessary(values[i]); + } + DBObject keyValue = new BasicDBObject(); + keyValue.put(key, convertedValues); + criteria.put("$pushAll", keyValue); + return this; + } - /** - * Update using the $addToSet update modifier - * - * @param key - * @param value - * @return - */ - public Update addToSet(String key, Object value) { - criteria.put("$addToSet", Collections.singletonMap(key, convertValueIfNecessary(value))); - return this; - } + /** + * Update using the $addToSet update modifier + * + * @param key + * @param value + * @return + */ + public Update addToSet(String key, Object value) { + criteria.put("$addToSet", Collections.singletonMap(key, convertValueIfNecessary(value))); + return this; + } - /** - * Update using the $pop update modifier - * - * @param key - * @param pos - * @return - */ - public Update pop(String key, Position pos) { - criteria.put("$pop", Collections.singletonMap(key, (pos == Position.FIRST ? -1 : 1))); - return this; - } + /** + * Update using the $pop update modifier + * + * @param key + * @param pos + * @return + */ + public Update pop(String key, Position pos) { + criteria.put("$pop", Collections.singletonMap(key, (pos == Position.FIRST ? -1 : 1))); + return this; + } - /** - * Update using the $pull update modifier - * - * @param key - * @param value - * @return - */ - public Update pull(String key, Object value) { - criteria.put("$pull", Collections.singletonMap(key, convertValueIfNecessary(value))); - return this; - } + /** + * Update using the $pull update modifier + * + * @param key + * @param value + * @return + */ + public Update pull(String key, Object value) { + criteria.put("$pull", Collections.singletonMap(key, convertValueIfNecessary(value))); + return this; + } - /** - * Update using the $pullAll update modifier - * - * @param key - * @param values - * @return - */ - public Update pullAll(String key, Object[] values) { - Object[] convertedValues = new Object[values.length]; - for (int i = 0; i < values.length; i++) { - convertedValues[i] = convertValueIfNecessary(values[i]); - } - DBObject keyValue = new BasicDBObject(); - keyValue.put(key, convertedValues); - criteria.put("$pullAll", keyValue); - return this; - } + /** + * Update using the $pullAll update modifier + * + * @param key + * @param values + * @return + */ + public Update pullAll(String key, Object[] values) { + Object[] convertedValues = new Object[values.length]; + for (int i = 0; i < values.length; i++) { + convertedValues[i] = convertValueIfNecessary(values[i]); + } + DBObject keyValue = new BasicDBObject(); + keyValue.put(key, convertedValues); + criteria.put("$pullAll", keyValue); + return this; + } - /** - * Update using the $rename update modifier - * - * @param oldName - * @param newName - * @return - */ - public Update rename(String oldName, String newName) { - criteria.put("$rename", Collections.singletonMap(oldName, newName)); - return this; - } + /** + * Update using the $rename update modifier + * + * @param oldName + * @param newName + * @return + */ + public Update rename(String oldName, String newName) { + criteria.put("$rename", Collections.singletonMap(oldName, newName)); + return this; + } - public DBObject getUpdateObject() { - DBObject dbo = new BasicDBObject(); - for (String k : criteria.keySet()) { - dbo.put(k, criteria.get(k)); - } - return dbo; - } + public DBObject getUpdateObject() { + DBObject dbo = new BasicDBObject(); + for (String k : criteria.keySet()) { + dbo.put(k, criteria.get(k)); + } + return dbo; + } - protected Object convertValueIfNecessary(Object value) { - if (value instanceof Enum) { - return ((Enum)value).name(); - } - return value; - } + protected Object convertValueIfNecessary(Object value) { + if (value instanceof Enum) { + return ((Enum) value).name(); + } + return value; + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/AbstractMongoQuery.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/AbstractMongoQuery.java index 51ff7bb73..c65e110dc 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/AbstractMongoQuery.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/AbstractMongoQuery.java @@ -15,10 +15,13 @@ */ package org.springframework.data.document.mongodb.repository; -import static org.springframework.data.document.mongodb.repository.QueryUtils.*; +import static org.springframework.data.document.mongodb.repository.QueryUtils.applyPagination; import java.util.List; +import com.mongodb.DBCollection; +import com.mongodb.DBCursor; +import com.mongodb.DBObject; import org.springframework.data.document.mongodb.CollectionCallback; import org.springframework.data.document.mongodb.MongoTemplate; import org.springframework.data.document.mongodb.query.Query; @@ -29,170 +32,167 @@ import org.springframework.data.repository.query.ParametersParameterAccessor; import org.springframework.data.repository.query.RepositoryQuery; import org.springframework.util.Assert; -import com.mongodb.DBCollection; -import com.mongodb.DBCursor; -import com.mongodb.DBObject; - /** * Base class for {@link RepositoryQuery} implementations for Mongo. - * + * * @author Oliver Gierke */ public abstract class AbstractMongoQuery implements RepositoryQuery { - private final MongoQueryMethod method; - private final MongoTemplate template; + private final MongoQueryMethod method; + private final MongoTemplate template; - /** - * Creates a new {@link AbstractMongoQuery} from the given {@link MongoQueryMethod} and {@link MongoTemplate}. - * - * @param method - * @param template - */ - public AbstractMongoQuery(MongoQueryMethod method, MongoTemplate template) { + /** + * Creates a new {@link AbstractMongoQuery} from the given {@link MongoQueryMethod} and {@link MongoTemplate}. + * + * @param method + * @param template + */ + public AbstractMongoQuery(MongoQueryMethod method, MongoTemplate template) { - Assert.notNull(template); - Assert.notNull(method); + Assert.notNull(template); + Assert.notNull(method); - this.method = method; - this.template = template; - } - - /* (non-Javadoc) - * @see org.springframework.data.repository.query.RepositoryQuery#getQueryMethod() - */ - public MongoQueryMethod getQueryMethod() { - - return method; - } + this.method = method; + this.template = template; + } - /* - * (non-Javadoc) - * - * @see org.springframework.data.repository.query.RepositoryQuery#execute(java .lang.Object[]) - */ - public Object execute(Object[] parameters) { + /* (non-Javadoc) + * @see org.springframework.data.repository.query.RepositoryQuery#getQueryMethod() + */ + public MongoQueryMethod getQueryMethod() { - ParameterAccessor accessor = new ParametersParameterAccessor(method.getParameters(), parameters); - Query query = createQuery(new ConvertingParameterAccessor(template.getConverter(), accessor)); + return method; + } - switch (method.getType()) { - case COLLECTION: - return new CollectionExecution().execute(query); - case PAGING: - return new PagedExecution(accessor.getPageable()).execute(query); - default: - return new SingleEntityExecution().execute(query); - } - } + /* + * (non-Javadoc) + * + * @see org.springframework.data.repository.query.RepositoryQuery#execute(java .lang.Object[]) + */ + public Object execute(Object[] parameters) { - /** - * Create a {@link Query} instance using the given {@link ParameterAccessor} - * @param accessor - * @param converter - * @return - */ - protected abstract Query createQuery(ConvertingParameterAccessor accessor); + ParameterAccessor accessor = new ParametersParameterAccessor(method.getParameters(), parameters); + Query query = createQuery(new ConvertingParameterAccessor(template.getConverter(), accessor)); - private abstract class Execution { + switch (method.getType()) { + case COLLECTION: + return new CollectionExecution().execute(query); + case PAGING: + return new PagedExecution(accessor.getPageable()).execute(query); + default: + return new SingleEntityExecution().execute(query); + } + } - abstract Object execute(Query query); + /** + * Create a {@link Query} instance using the given {@link ParameterAccessor} + * + * @param accessor + * @param converter + * @return + */ + protected abstract Query createQuery(ConvertingParameterAccessor accessor); - protected List readCollection(Query query) { + private abstract class Execution { - MongoEntityInformation metadata = method.getEntityInformation(); + abstract Object execute(Query query); - String collectionName = metadata.getCollectionName(); - return template.find(collectionName, query, metadata.getJavaType()); - } - } + protected List readCollection(Query query) { - /** - * {@link Execution} for collection returning queries. - * - * @author Oliver Gierke - */ - class CollectionExecution extends Execution { + MongoEntityInformation metadata = method.getEntityInformation(); - /* - * (non-Javadoc) - * - * @see org.springframework.data.document.mongodb.repository.MongoQuery.Execution #execute(com.mongodb.DBObject) - */ - @Override - public Object execute(Query query) { + String collectionName = metadata.getCollectionName(); + return template.find(collectionName, query, metadata.getJavaType()); + } + } - return readCollection(query); - } - } + /** + * {@link Execution} for collection returning queries. + * + * @author Oliver Gierke + */ + class CollectionExecution extends Execution { - /** - * {@link Execution} for pagination queries. - * - * @author Oliver Gierke - */ - class PagedExecution extends Execution { + /* + * (non-Javadoc) + * + * @see org.springframework.data.document.mongodb.repository.MongoQuery.Execution #execute(com.mongodb.DBObject) + */ + @Override + public Object execute(Query query) { - private final Pageable pageable; + return readCollection(query); + } + } - /** - * Creates a new {@link PagedExecution}. - * - * @param pageable - */ - public PagedExecution(Pageable pageable) { + /** + * {@link Execution} for pagination queries. + * + * @author Oliver Gierke + */ + class PagedExecution extends Execution { - Assert.notNull(pageable); - this.pageable = pageable; - } + private final Pageable pageable; - /* - * (non-Javadoc) - * - * @see org.springframework.data.document.mongodb.repository.MongoQuery.Execution #execute(com.mongodb.DBObject) - */ - @Override - @SuppressWarnings({ "rawtypes", "unchecked" }) - Object execute(Query query) { + /** + * Creates a new {@link PagedExecution}. + * + * @param pageable + */ + public PagedExecution(Pageable pageable) { - MongoEntityInformation metadata = method.getEntityInformation(); - int count = getCollectionCursor(metadata.getCollectionName(), query.getQueryObject()).count(); + Assert.notNull(pageable); + this.pageable = pageable; + } - List result = template.find(metadata.getCollectionName(), applyPagination(query, pageable), - metadata.getJavaType()); + /* + * (non-Javadoc) + * + * @see org.springframework.data.document.mongodb.repository.MongoQuery.Execution #execute(com.mongodb.DBObject) + */ + @Override + @SuppressWarnings({"rawtypes", "unchecked"}) + Object execute(Query query) { - return new PageImpl(result, pageable, count); - } + MongoEntityInformation metadata = method.getEntityInformation(); + int count = getCollectionCursor(metadata.getCollectionName(), query.getQueryObject()).count(); - private DBCursor getCollectionCursor(String collectionName, final DBObject query) { + List result = template.find(metadata.getCollectionName(), applyPagination(query, pageable), + metadata.getJavaType()); - return template.execute(collectionName, new CollectionCallback() { + return new PageImpl(result, pageable, count); + } - public DBCursor doInCollection(DBCollection collection) { + private DBCursor getCollectionCursor(String collectionName, final DBObject query) { - return collection.find(query); - } - }); - } - } + return template.execute(collectionName, new CollectionCallback() { - /** - * {@link Execution} to return a single entity. - * - * @author Oliver Gierke - */ - class SingleEntityExecution extends Execution { + public DBCursor doInCollection(DBCollection collection) { - /* - * (non-Javadoc) - * - * @see org.springframework.data.document.mongodb.repository.MongoQuery.Execution #execute(com.mongodb.DBObject) - */ - @Override - Object execute(Query query) { + return collection.find(query); + } + }); + } + } - List result = readCollection(query); - return result.isEmpty() ? null : result.get(0); - } - } + /** + * {@link Execution} to return a single entity. + * + * @author Oliver Gierke + */ + class SingleEntityExecution extends Execution { + + /* + * (non-Javadoc) + * + * @see org.springframework.data.document.mongodb.repository.MongoQuery.Execution #execute(com.mongodb.DBObject) + */ + @Override + Object execute(Query query) { + + List result = readCollection(query); + return result.isEmpty() ? null : result.get(0); + } + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/ConvertingParameterAccessor.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/ConvertingParameterAccessor.java index 308d91abd..bc56d7d31 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/ConvertingParameterAccessor.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/ConvertingParameterAccessor.java @@ -17,163 +17,162 @@ package org.springframework.data.document.mongodb.repository; import java.util.Iterator; +import com.mongodb.BasicDBObject; +import com.mongodb.DBObject; import org.springframework.data.document.mongodb.MongoWriter; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.repository.query.ParameterAccessor; -import com.mongodb.BasicDBObject; -import com.mongodb.DBObject; - /** * Custom {@link ParameterAccessor} that uses a {@link MongoWriter} to serialize parameters into Mongo format. - * + * * @author Oliver Gierke */ public class ConvertingParameterAccessor implements ParameterAccessor { - private final MongoWriter writer; - private final ParameterAccessor delegate; + private final MongoWriter writer; + private final ParameterAccessor delegate; - /** - * Creates a new {@link ConvertingParameterAccessor} with the given {@link MongoWriter} and delegate. - * - * @param writer - */ - public ConvertingParameterAccessor(MongoWriter writer, ParameterAccessor delegate) { - this.writer = writer; - this.delegate = delegate; - } + /** + * Creates a new {@link ConvertingParameterAccessor} with the given {@link MongoWriter} and delegate. + * + * @param writer + */ + public ConvertingParameterAccessor(MongoWriter writer, ParameterAccessor delegate) { + this.writer = writer; + this.delegate = delegate; + } - /* - * (non-Javadoc) - * - * @see java.lang.Iterable#iterator() - */ - public Iterator iterator() { - return new ConvertingIterator(delegate.iterator()); - } + /* + * (non-Javadoc) + * + * @see java.lang.Iterable#iterator() + */ + public Iterator iterator() { + return new ConvertingIterator(delegate.iterator()); + } - /* - * (non-Javadoc) - * - * @see org.springframework.data.repository.query.ParameterAccessor#getPageable() - */ - public Pageable getPageable() { - return delegate.getPageable(); - } + /* + * (non-Javadoc) + * + * @see org.springframework.data.repository.query.ParameterAccessor#getPageable() + */ + public Pageable getPageable() { + return delegate.getPageable(); + } - /* - * (non-Javadoc) - * - * @see org.springframework.data.repository.query.ParameterAccessor#getSort() - */ - public Sort getSort() { - return delegate.getSort(); - } - - /* (non-Javadoc) - * @see org.springframework.data.repository.query.ParameterAccessor#getBindableParameter(int) - */ - public Object getBindableValue(int index) { - - return getConvertedValue(delegate.getBindableValue(index)); - } - - /** - * Converts the given value with the underlying {@link MongoWriter}. - * - * @param value - * @return - */ - private Object getConvertedValue(Object value) { - - DBObject result = new BasicDBObject(); - writer.write(value.getClass().isEnum() ? new EnumValueHolder((Enum) value) : new ValueHolder(value), result); - return result.get("value"); - } + /* + * (non-Javadoc) + * + * @see org.springframework.data.repository.query.ParameterAccessor#getSort() + */ + public Sort getSort() { + return delegate.getSort(); + } - /** - * Custom {@link Iterator} to convert items before returning them. - * - * @author Oliver Gierke - */ - private class ConvertingIterator implements Iterator { + /* (non-Javadoc) + * @see org.springframework.data.repository.query.ParameterAccessor#getBindableParameter(int) + */ + public Object getBindableValue(int index) { - private final Iterator delegate; + return getConvertedValue(delegate.getBindableValue(index)); + } - /** - * Creates a new {@link ConvertingIterator} for the given delegate. - * - * @param delegate - */ - public ConvertingIterator(Iterator delegate) { - this.delegate = delegate; - } + /** + * Converts the given value with the underlying {@link MongoWriter}. + * + * @param value + * @return + */ + private Object getConvertedValue(Object value) { - /* - * (non-Javadoc) - * - * @see java.util.Iterator#hasNext() - */ - public boolean hasNext() { - return delegate.hasNext(); - } + DBObject result = new BasicDBObject(); + writer.write(value.getClass().isEnum() ? new EnumValueHolder((Enum) value) : new ValueHolder(value), result); + return result.get("value"); + } - /* - * (non-Javadoc) - * - * @see java.util.Iterator#next() - */ - public Object next() { + /** + * Custom {@link Iterator} to convert items before returning them. + * + * @author Oliver Gierke + */ + private class ConvertingIterator implements Iterator { - return getConvertedValue(delegate.next()); - } + private final Iterator delegate; - /* - * (non-Javadoc) - * - * @see java.util.Iterator#remove() - */ - public void remove() { - delegate.remove(); - } - } + /** + * Creates a new {@link ConvertingIterator} for the given delegate. + * + * @param delegate + */ + public ConvertingIterator(Iterator delegate) { + this.delegate = delegate; + } - /** - * Simple value holder class to allow conversion and accessing the converted value in a deterministic way. - * - * @author Oliver Gierke - */ - private static class ValueHolder { + /* + * (non-Javadoc) + * + * @see java.util.Iterator#hasNext() + */ + public boolean hasNext() { + return delegate.hasNext(); + } - private Object value; + /* + * (non-Javadoc) + * + * @see java.util.Iterator#next() + */ + public Object next() { - public ValueHolder(Object value) { + return getConvertedValue(delegate.next()); + } - this.value = value; - } + /* + * (non-Javadoc) + * + * @see java.util.Iterator#remove() + */ + public void remove() { + delegate.remove(); + } + } - @SuppressWarnings("unused") - public Object getValue() { + /** + * Simple value holder class to allow conversion and accessing the converted value in a deterministic way. + * + * @author Oliver Gierke + */ + private static class ValueHolder { - return value; - } - } - - private static class EnumValueHolder { - - private Enum value; - - public EnumValueHolder(Enum value) { - this.value = value; - } - - /** - * @return the value - */ - public Enum getValue() { - return value; - } - } + private Object value; + + public ValueHolder(Object value) { + + this.value = value; + } + + @SuppressWarnings("unused") + public Object getValue() { + + return value; + } + } + + private static class EnumValueHolder { + + private Enum value; + + public EnumValueHolder(Enum value) { + this.value = value; + } + + /** + * @return the value + */ + public Enum getValue() { + return value; + } + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/MongoEntityInformation.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/MongoEntityInformation.java index 8b03b5a68..0583a54ba 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/MongoEntityInformation.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/MongoEntityInformation.java @@ -28,88 +28,88 @@ import org.springframework.util.StringUtils; /** * Expects the domain class to contain a field with a name out of the following * {@value #FIELD_NAMES}. - * + * * @author Oliver Gierke */ class MongoEntityInformation extends AbstractEntityInformation { - private static final List FIELD_NAMES = Arrays.asList("ID", "id", "_id"); - private Field field; + private static final List FIELD_NAMES = Arrays.asList("ID", "id", "_id"); + private Field field; - /** - * Creates a new {@link MongoEntityInformation}. - * - * @param domainClass - */ - public MongoEntityInformation(Class domainClass) { - - super(domainClass); + /** + * Creates a new {@link MongoEntityInformation}. + * + * @param domainClass + */ + public MongoEntityInformation(Class domainClass) { - for (String name : FIELD_NAMES) { + super(domainClass); - Field candidate = ReflectionUtils.findField(domainClass, name); + for (String name : FIELD_NAMES) { - if (candidate != null) { - ReflectionUtils.makeAccessible(candidate); - this.field = candidate; - break; - } - } + Field candidate = ReflectionUtils.findField(domainClass, name); - if (this.field == null) { - throw new IllegalArgumentException(String.format( - "Given domain class %s does not contain an id property!", - domainClass.getName())); - } - } - - - /** - * Returns the name of the collection the entity shall be persisted to. - * - * @return - */ - public String getCollectionName() { - - return StringUtils.uncapitalize(getJavaType().getSimpleName()); - } - - - /** - * Returns the attribute that the id will be persisted to. - * - * @return - */ - public String getIdAttribute() { - - return "_id"; + if (candidate != null) { + ReflectionUtils.makeAccessible(candidate); + this.field = candidate; + break; + } } - - /* - * (non-Javadoc) - * - * @see - * org.springframework.data.repository.support.IdAware#getId(java.lang.Object - * ) - */ - @SuppressWarnings("unchecked") - public ID getId(Object entity) { - - return (ID) ReflectionUtils.getField(field, entity); + if (this.field == null) { + throw new IllegalArgumentException(String.format( + "Given domain class %s does not contain an id property!", + domainClass.getName())); } + } - /* - * (non-Javadoc) - * - * @see - * org.springframework.data.repository.support.EntityInformation#getIdType() - */ - @SuppressWarnings("unchecked") - public Class getIdType() { + /** + * Returns the name of the collection the entity shall be persisted to. + * + * @return + */ + public String getCollectionName() { - return (Class) field.getType(); - } + return StringUtils.uncapitalize(getJavaType().getSimpleName()); + } + + + /** + * Returns the attribute that the id will be persisted to. + * + * @return + */ + public String getIdAttribute() { + + return "_id"; + } + + + /* + * (non-Javadoc) + * + * @see + * org.springframework.data.repository.support.IdAware#getId(java.lang.Object + * ) + */ + @SuppressWarnings("unchecked") + public ID getId(Object entity) { + + return (ID) ReflectionUtils.getField(field, entity); + } + + + /* + * (non-Javadoc) + * + * @see + * org.springframework.data.repository.support.EntityInformation#getIdType() + */ + @SuppressWarnings("unchecked") + public Class getIdType() { + + return (Class) field.getType(); + } } \ No newline at end of file diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/MongoQueryCreator.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/MongoQueryCreator.java index eef11343f..7ffa34380 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/MongoQueryCreator.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/MongoQueryCreator.java @@ -15,7 +15,7 @@ */ package org.springframework.data.document.mongodb.repository; -import static org.springframework.data.document.mongodb.query.Criteria.*; +import static org.springframework.data.document.mongodb.query.Criteria.where; import java.util.Collection; import java.util.Iterator; @@ -37,144 +37,144 @@ import org.springframework.data.repository.query.parser.PartTree; /** * Custom query creator to create Mongo criterias. - * + * * @author Oliver Gierke */ class MongoQueryCreator extends AbstractQueryCreator { - private static final Logger LOG = LoggerFactory.getLogger(MongoQueryCreator.class); + private static final Logger LOG = LoggerFactory.getLogger(MongoQueryCreator.class); - /** - * Creates a new {@link MongoQueryCreator} from the given {@link PartTree} - * and {@link ParametersParameterAccessor}. - * - * @param tree - * @param accessor - */ - public MongoQueryCreator(PartTree tree, ParameterAccessor accessor) { + /** + * Creates a new {@link MongoQueryCreator} from the given {@link PartTree} + * and {@link ParametersParameterAccessor}. + * + * @param tree + * @param accessor + */ + public MongoQueryCreator(PartTree tree, ParameterAccessor accessor) { - super(tree, accessor); + super(tree, accessor); + } + + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.query.parser.AbstractQueryCreator#create(org.springframework.data.repository.query.parser.Part, java.util.Iterator) + */ + @Override + protected Query create(Part part, Iterator iterator) { + + Criteria criteria = from(part.getType(), + where(part.getProperty().toDotPath()), iterator); + + return new Query(criteria); + } + + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.query.parser.AbstractQueryCreator#and(org.springframework.data.repository.query.parser.Part, java.lang.Object, java.util.Iterator) + */ + @Override + protected Query and(Part part, Query base, + Iterator iterator) { + + Criteria criteria = from(part.getType(), where(part.getProperty().toDotPath()), + iterator); + return base.and(criteria); + } + + + /* + * (non-Javadoc) + * + * @see + * org.springframework.data.repository.query.parser.AbstractQueryCreator + * #or(java.lang.Object, java.lang.Object) + */ + @Override + protected Query or(Query base, Query query) { + + return new Query().or(base, query); + } + + + /* + * (non-Javadoc) + * + * @see + * org.springframework.data.repository.query.parser.AbstractQueryCreator + * #complete(java.lang.Object, org.springframework.data.domain.Sort) + */ + @Override + protected Query complete(Query query, Sort sort) { + + if (LOG.isDebugEnabled()) { + LOG.debug("Created query " + query.getQueryObject()); } + return query; + } - /* - * (non-Javadoc) - * @see org.springframework.data.repository.query.parser.AbstractQueryCreator#create(org.springframework.data.repository.query.parser.Part, java.util.Iterator) - */ - @Override - protected Query create(Part part, Iterator iterator) { - Criteria criteria = from(part.getType(), - where(part.getProperty().toDotPath()), iterator); - - return new Query(criteria); + /** + * Populates the given {@link CriteriaDefinition} depending on the {@link Type} given. + * + * @param type + * @param criteria + * @param parameters + * @return + */ + private Criteria from(Type type, Criteria criteria, + Iterator parameters) { + + switch (type) { + case GREATER_THAN: + return criteria.gt(parameters.next()); + case LESS_THAN: + return criteria.lt(parameters.next()); + case BETWEEN: + return criteria.gt(parameters.next()).lt( + parameters.next()); + case IS_NOT_NULL: + return criteria.not().is(null); + case IS_NULL: + return criteria.is(null); + case NOT_IN: + return criteria.nin(nextAsArray(parameters)); + case IN: + return criteria.in(nextAsArray(parameters)); + case LIKE: + String value = parameters.next().toString(); + return criteria.is(toLikeRegex(value)); + case SIMPLE_PROPERTY: + return criteria.is(parameters.next()); + case NEGATING_SIMPLE_PROPERTY: + return criteria.not().is(parameters.next()); } + throw new IllegalArgumentException("Unsupported keyword!"); + } - /* - * (non-Javadoc) - * @see org.springframework.data.repository.query.parser.AbstractQueryCreator#and(org.springframework.data.repository.query.parser.Part, java.lang.Object, java.util.Iterator) - */ - @Override - protected Query and(Part part, Query base, - Iterator iterator) { - Criteria criteria = from(part.getType(), where(part.getProperty().toDotPath()), - iterator); - return base.and(criteria); + private Object[] nextAsArray(Iterator iterator) { + Object next = iterator.next(); + + if (next instanceof Collection) { + return ((Collection) next).toArray(); + } else if (next.getClass().isArray()) { + return (Object[]) next; } + return new Object[]{next}; + } - /* - * (non-Javadoc) - * - * @see - * org.springframework.data.repository.query.parser.AbstractQueryCreator - * #or(java.lang.Object, java.lang.Object) - */ - @Override - protected Query or(Query base, Query query) { - - return new Query().or(base, query); - } + private Pattern toLikeRegex(String source) { + + String regex = source.replaceAll("\\*", ".*"); + return Pattern.compile(regex); + } - /* - * (non-Javadoc) - * - * @see - * org.springframework.data.repository.query.parser.AbstractQueryCreator - * #complete(java.lang.Object, org.springframework.data.domain.Sort) - */ - @Override - protected Query complete(Query query, Sort sort) { - - if (LOG.isDebugEnabled()) { - LOG.debug("Created query " + query.getQueryObject()); - } - - return query; - } - - - /** - * Populates the given {@link CriteriaDefinition} depending on the {@link Type} given. - * - * @param type - * @param criteria - * @param parameters - * @return - */ - private Criteria from(Type type, Criteria criteria, - Iterator parameters) { - - switch (type) { - case GREATER_THAN: - return criteria.gt(parameters.next()); - case LESS_THAN: - return criteria.lt(parameters.next()); - case BETWEEN: - return criteria.gt(parameters.next()).lt( - parameters.next()); - case IS_NOT_NULL: - return criteria.not().is(null); - case IS_NULL: - return criteria.is(null); - case NOT_IN: - return criteria.nin(nextAsArray(parameters)); - case IN: - return criteria.in(nextAsArray(parameters)); - case LIKE: - String value = parameters.next().toString(); - return criteria.is(toLikeRegex(value)); - case SIMPLE_PROPERTY: - return criteria.is(parameters.next()); - case NEGATING_SIMPLE_PROPERTY: - return criteria.not().is(parameters.next()); - } - - throw new IllegalArgumentException("Unsupported keyword!"); - } - - - private Object[] nextAsArray(Iterator iterator) { - Object next = iterator.next(); - - if (next instanceof Collection) { - return ((Collection) next).toArray(); - } else if (next.getClass().isArray()) { - return (Object[]) next; - } - - return new Object[] { next }; - } - - private Pattern toLikeRegex(String source) { - - String regex = source.replaceAll("\\*", ".*"); - return Pattern.compile(regex); - } - - } \ No newline at end of file diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/MongoQueryMethod.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/MongoQueryMethod.java index 54d6f0606..b92963033 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/MongoQueryMethod.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/MongoQueryMethod.java @@ -23,77 +23,77 @@ import org.springframework.data.repository.util.ClassUtils; import org.springframework.util.StringUtils; /** - * * TODO - Extract methods for {@link #getAnnotatedQuery()} into superclass as it is currently copied from Spring Data * JPA + * * @author Oliver Gierke */ class MongoQueryMethod extends QueryMethod { - - private final Method method; - private final MongoEntityInformation entityInformation; - /** - * Creates a new {@link MongoQueryMethod} from the given {@link Method}. - * - * @param method - */ - public MongoQueryMethod(Method method, Class domainClass) { - super(method); - this.method = method; - this.entityInformation = new MongoEntityInformation(ClassUtils.getReturnedDomainClass(method)); - } + private final Method method; + private final MongoEntityInformation entityInformation; - - /** - * Returns whether the method has an annotated query. - * - * @return - */ - boolean hasAnnotatedQuery() { - return getAnnotatedQuery() != null; - } + /** + * Creates a new {@link MongoQueryMethod} from the given {@link Method}. + * + * @param method + */ + public MongoQueryMethod(Method method, Class domainClass) { + super(method); + this.method = method; + this.entityInformation = new MongoEntityInformation(ClassUtils.getReturnedDomainClass(method)); + } - /** - * Returns the query string declared in a {@link Query} annotation or {@literal null} if neither the annotation - * found nor the attribute was specified. - * - * @return - */ - String getAnnotatedQuery() { - String query = (String) AnnotationUtils.getValue(getQueryAnnotation()); - return StringUtils.hasText(query) ? query : null; - } - - /** - * Returns the field specification to be used for the query. - * - * @return - */ - String getFieldSpecification() { - - String value = (String) AnnotationUtils.getValue(getQueryAnnotation(), "fields"); - return StringUtils.hasText(value) ? value : null; - } - - - /* (non-Javadoc) - * @see org.springframework.data.repository.query.QueryMethod#getEntityMetadata() - */ - @Override - public MongoEntityInformation getEntityInformation() { - - return entityInformation; - } + /** + * Returns whether the method has an annotated query. + * + * @return + */ + boolean hasAnnotatedQuery() { + return getAnnotatedQuery() != null; + } - /** - * Returns the {@link Query} annotation that is applied to the method or {@code null} if none available. - * - * @return - */ - private Query getQueryAnnotation() { + /** + * Returns the query string declared in a {@link Query} annotation or {@literal null} if neither the annotation + * found nor the attribute was specified. + * + * @return + */ + String getAnnotatedQuery() { - return method.getAnnotation(Query.class); - } + String query = (String) AnnotationUtils.getValue(getQueryAnnotation()); + return StringUtils.hasText(query) ? query : null; + } + + /** + * Returns the field specification to be used for the query. + * + * @return + */ + String getFieldSpecification() { + + String value = (String) AnnotationUtils.getValue(getQueryAnnotation(), "fields"); + return StringUtils.hasText(value) ? value : null; + } + + + /* (non-Javadoc) + * @see org.springframework.data.repository.query.QueryMethod#getEntityMetadata() + */ + @Override + public MongoEntityInformation getEntityInformation() { + + return entityInformation; + } + + /** + * Returns the {@link Query} annotation that is applied to the method or {@code null} if none available. + * + * @return + */ + private Query getQueryAnnotation() { + + return method.getAnnotation(Query.class); + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/MongoRepository.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/MongoRepository.java index 67fd31489..50f3bc3e5 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/MongoRepository.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/MongoRepository.java @@ -23,22 +23,22 @@ import org.springframework.data.repository.PagingAndSortingRepository; /** * Mongo specific {@link org.springframework.data.repository.Repository} interface. - * + * * @author Oliver Gierke */ public interface MongoRepository extends PagingAndSortingRepository { - /* - * (non-Javadoc) - * - * @see org.springframework.data.repository.Repository#findAll() - */ - List findAll(); + /* + * (non-Javadoc) + * + * @see org.springframework.data.repository.Repository#findAll() + */ + List findAll(); - /* - * (non-Javadoc) - * - * @see org.springframework.data.repository.PagingAndSortingRepository#findAll(org.springframework.data.domain.Sort) - */ - List findAll(Sort sort); + /* + * (non-Javadoc) + * + * @see org.springframework.data.repository.PagingAndSortingRepository#findAll(org.springframework.data.domain.Sort) + */ + List findAll(Sort sort); } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/MongoRepositoryFactoryBean.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/MongoRepositoryFactoryBean.java index 00cb3d88a..25267b9cf 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/MongoRepositoryFactoryBean.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/MongoRepositoryFactoryBean.java @@ -40,196 +40,195 @@ import org.springframework.util.StringUtils; /** * {@link org.springframework.beans.factory.FactoryBean} to create {@link MongoRepository} instances. - * + * * @author Oliver Gierke */ public class MongoRepositoryFactoryBean, S, ID extends Serializable> extends RepositoryFactoryBeanSupport { - private MongoTemplate template; + private MongoTemplate template; - /** - * Configures the {@link MongoTemplate} to be used. - * - * @param template the template to set - */ - public void setTemplate(MongoTemplate template) { + /** + * Configures the {@link MongoTemplate} to be used. + * + * @param template the template to set + */ + public void setTemplate(MongoTemplate template) { - this.template = template; - } + this.template = template; + } - /* - * (non-Javadoc) - * - * @see org.springframework.data.repository.support.RepositoryFactoryBeanSupport #createRepositoryFactory() - */ - @Override - protected RepositoryFactorySupport createRepositoryFactory() { + /* + * (non-Javadoc) + * + * @see org.springframework.data.repository.support.RepositoryFactoryBeanSupport #createRepositoryFactory() + */ + @Override + protected RepositoryFactorySupport createRepositoryFactory() { - MongoRepositoryFactory factory = new MongoRepositoryFactory(template); - factory.addQueryCreationListener(new IndexEnsuringQueryCreationListener(template)); - return factory; - } + MongoRepositoryFactory factory = new MongoRepositoryFactory(template); + factory.addQueryCreationListener(new IndexEnsuringQueryCreationListener(template)); + return factory; + } - /* - * (non-Javadoc) - * - * @see org.springframework.data.repository.support.RepositoryFactoryBeanSupport #afterPropertiesSet() - */ - @Override - public void afterPropertiesSet() { + /* + * (non-Javadoc) + * + * @see org.springframework.data.repository.support.RepositoryFactoryBeanSupport #afterPropertiesSet() + */ + @Override + public void afterPropertiesSet() { - super.afterPropertiesSet(); - Assert.notNull(template, "MongoTemplate must not be null!"); - } + super.afterPropertiesSet(); + Assert.notNull(template, "MongoTemplate must not be null!"); + } - /** - * Repository to create {@link MongoRepository} instances. - * - * @author Oliver Gierke - */ - public static class MongoRepositoryFactory extends RepositoryFactorySupport { + /** + * Repository to create {@link MongoRepository} instances. + * + * @author Oliver Gierke + */ + public static class MongoRepositoryFactory extends RepositoryFactorySupport { - private final MongoTemplate template; + private final MongoTemplate template; - /** - * Creates a new {@link MongoRepositoryFactory} fwith the given {@link MongoTemplate}. - * - * @param template - */ - public MongoRepositoryFactory(MongoTemplate template) { + /** + * Creates a new {@link MongoRepositoryFactory} fwith the given {@link MongoTemplate}. + * + * @param template + */ + public MongoRepositoryFactory(MongoTemplate template) { - this.template = template; - } - - - - /* - * (non-Javadoc) - * - * @see org.springframework.data.repository.support.RepositoryFactorySupport#getRepositoryBaseClass() - */ - @Override - protected Class getRepositoryBaseClass(Class repositoryInterface) { - return SimpleMongoRepository.class; - } - - @Override - protected QueryLookupStrategy getQueryLookupStrategy(Key key) { - - return new MongoQueryLookupStrategy(); - } - - /** - * {@link QueryLookupStrategy} to create {@link PartTreeMongoQuery} instances. - * - * @author Oliver Gierke - */ - private class MongoQueryLookupStrategy implements QueryLookupStrategy { - - public RepositoryQuery resolveQuery(Method method, Class domainClass) { - - MongoQueryMethod queryMethod = new MongoQueryMethod(method, domainClass); - - if (queryMethod.hasAnnotatedQuery()) { - return new StringBasedMongoQuery(queryMethod, template); - } else { - return new PartTreeMongoQuery(queryMethod, template); - } - } - } - - /* - * (non-Javadoc) - * - * @see org.springframework.data.repository.support.RepositoryFactorySupport#validate(java.lang.Class, - * java.lang.Object) - */ - @Override - protected void validate(RepositoryMetadata metadata, Object customImplementation) { - - Class idClass = metadata.getIdClass(); - if (!MongoPropertyDescriptor.SUPPORTED_ID_CLASSES.contains(idClass)) { - throw new IllegalArgumentException(String.format("Unsupported id class! Only %s are supported!", - StringUtils.collectionToCommaDelimitedString(MongoPropertyDescriptor.SUPPORTED_ID_CLASSES))); - } - - super.validate(metadata, customImplementation); - } - - - /* (non-Javadoc) - * @see org.springframework.data.repository.support.RepositoryFactorySupport#getEntityInformation(java.lang.Class) - */ - @Override - public MongoEntityInformation getEntityInformation( - Class domainClass) { - - return new MongoEntityInformation(domainClass); - } + this.template = template; + } - /* - * (non-Javadoc) - * @see org.springframework.data.repository.support.RepositoryFactorySupport#getTargetRepository(org.springframework.data.repository.support.RepositoryMetadata) - */ - @Override - @SuppressWarnings({ "unchecked", "rawtypes" }) - protected Object getTargetRepository(RepositoryMetadata metadata) { + /* + * (non-Javadoc) + * + * @see org.springframework.data.repository.support.RepositoryFactorySupport#getRepositoryBaseClass() + */ + @Override + protected Class getRepositoryBaseClass(Class repositoryInterface) { + return SimpleMongoRepository.class; + } - MongoEntityInformation info = getEntityInformation( - metadata.getDomainClass()); - return new SimpleMongoRepository(info, template); - } - } + @Override + protected QueryLookupStrategy getQueryLookupStrategy(Key key) { - /** - * {@link QueryCreationListener} inspecting {@link PartTreeMongoQuery}s and creating an index for the properties it - * refers to. - * - * @author Oliver Gierke - */ - private static class IndexEnsuringQueryCreationListener implements QueryCreationListener { + return new MongoQueryLookupStrategy(); + } - private static final Logger LOG = LoggerFactory.getLogger(IndexEnsuringQueryCreationListener.class); - private final MongoOperations operations; + /** + * {@link QueryLookupStrategy} to create {@link PartTreeMongoQuery} instances. + * + * @author Oliver Gierke + */ + private class MongoQueryLookupStrategy implements QueryLookupStrategy { - public IndexEnsuringQueryCreationListener(MongoOperations operations) { - this.operations = operations; - } + public RepositoryQuery resolveQuery(Method method, Class domainClass) { - /* - * (non-Javadoc) - * - * @see - * org.springframework.data.repository.support.QueryCreationListener#onCreation(org.springframework.data.repository - * .query.RepositoryQuery) - */ - public void onCreation(PartTreeMongoQuery query) { + MongoQueryMethod queryMethod = new MongoQueryMethod(method, domainClass); - PartTree tree = query.getTree(); - Index index = new Index(); - index.named(query.getQueryMethod().getName()); - Sort sort = tree.getSort(); + if (queryMethod.hasAnnotatedQuery()) { + return new StringBasedMongoQuery(queryMethod, template); + } else { + return new PartTreeMongoQuery(queryMethod, template); + } + } + } - for (Part part : tree.getParts()) { - String property = part.getProperty().toDotPath(); - Order order = toOrder(sort, property); - index.on(property, order); - } + /* + * (non-Javadoc) + * + * @see org.springframework.data.repository.support.RepositoryFactorySupport#validate(java.lang.Class, + * java.lang.Object) + */ + @Override + protected void validate(RepositoryMetadata metadata, Object customImplementation) { - MongoEntityInformation metadata = query.getQueryMethod().getEntityInformation(); - operations.ensureIndex(metadata.getCollectionName(), index); - LOG.debug(String.format("Created index %s!", index.toString())); - } - - private static Order toOrder(Sort sort, String property) { - - if (sort == null) { - return Order.DESCENDING; - } - - org.springframework.data.domain.Sort.Order order = sort.getOrderFor(property); - return order == null ? Order.DESCENDING : order.isAscending() ? Order.ASCENDING : Order.DESCENDING; - } - } + Class idClass = metadata.getIdClass(); + if (!MongoPropertyDescriptor.SUPPORTED_ID_CLASSES.contains(idClass)) { + throw new IllegalArgumentException(String.format("Unsupported id class! Only %s are supported!", + StringUtils.collectionToCommaDelimitedString(MongoPropertyDescriptor.SUPPORTED_ID_CLASSES))); + } + + super.validate(metadata, customImplementation); + } + + + /* (non-Javadoc) + * @see org.springframework.data.repository.support.RepositoryFactorySupport#getEntityInformation(java.lang.Class) + */ + @Override + public MongoEntityInformation getEntityInformation( + Class domainClass) { + + return new MongoEntityInformation(domainClass); + } + + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.support.RepositoryFactorySupport#getTargetRepository(org.springframework.data.repository.support.RepositoryMetadata) + */ + @Override + @SuppressWarnings({"unchecked", "rawtypes"}) + protected Object getTargetRepository(RepositoryMetadata metadata) { + + MongoEntityInformation info = getEntityInformation( + metadata.getDomainClass()); + return new SimpleMongoRepository(info, template); + } + } + + /** + * {@link QueryCreationListener} inspecting {@link PartTreeMongoQuery}s and creating an index for the properties it + * refers to. + * + * @author Oliver Gierke + */ + private static class IndexEnsuringQueryCreationListener implements QueryCreationListener { + + private static final Logger LOG = LoggerFactory.getLogger(IndexEnsuringQueryCreationListener.class); + private final MongoOperations operations; + + public IndexEnsuringQueryCreationListener(MongoOperations operations) { + this.operations = operations; + } + + /* + * (non-Javadoc) + * + * @see + * org.springframework.data.repository.support.QueryCreationListener#onCreation(org.springframework.data.repository + * .query.RepositoryQuery) + */ + public void onCreation(PartTreeMongoQuery query) { + + PartTree tree = query.getTree(); + Index index = new Index(); + index.named(query.getQueryMethod().getName()); + Sort sort = tree.getSort(); + + for (Part part : tree.getParts()) { + String property = part.getProperty().toDotPath(); + Order order = toOrder(sort, property); + index.on(property, order); + } + + MongoEntityInformation metadata = query.getQueryMethod().getEntityInformation(); + operations.ensureIndex(metadata.getCollectionName(), index); + LOG.debug(String.format("Created index %s!", index.toString())); + } + + private static Order toOrder(Sort sort, String property) { + + if (sort == null) { + return Order.DESCENDING; + } + + org.springframework.data.domain.Sort.Order order = sort.getOrderFor(property); + return order == null ? Order.DESCENDING : order.isAscending() ? Order.ASCENDING : Order.DESCENDING; + } + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/PartTreeMongoQuery.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/PartTreeMongoQuery.java index 0ccf0f11f..7af92121d 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/PartTreeMongoQuery.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/PartTreeMongoQuery.java @@ -23,43 +23,43 @@ import org.springframework.data.repository.query.parser.PartTree; /** * {@link RepositoryQuery} implementation for Mongo. - * + * * @author Oliver Gierke */ public class PartTreeMongoQuery extends AbstractMongoQuery { - private final PartTree tree; + private final PartTree tree; - /** - * Creates a new {@link PartTreeMongoQuery} from the given {@link QueryMethod} and {@link MongoTemplate}. - * - * @param method - * @param template - */ - public PartTreeMongoQuery(MongoQueryMethod method, MongoTemplate template) { + /** + * Creates a new {@link PartTreeMongoQuery} from the given {@link QueryMethod} and {@link MongoTemplate}. + * + * @param method + * @param template + */ + public PartTreeMongoQuery(MongoQueryMethod method, MongoTemplate template) { - super(method, template); - this.tree = new PartTree(method.getName(), method.getEntityInformation().getJavaType()); - } - - /** - * @return the tree - */ - public PartTree getTree() { - return tree; - } + super(method, template); + this.tree = new PartTree(method.getName(), method.getEntityInformation().getJavaType()); + } - /* - * (non-Javadoc) - * - * @see - * org.springframework.data.document.mongodb.repository.AbstractMongoQuery#createQuery(org.springframework.data. - * document.mongodb.repository.ConvertingParameterAccessor) - */ - @Override - protected Query createQuery(ConvertingParameterAccessor accessor) { + /** + * @return the tree + */ + public PartTree getTree() { + return tree; + } - MongoQueryCreator creator = new MongoQueryCreator(tree, accessor); - return creator.createQuery(); - } + /* + * (non-Javadoc) + * + * @see + * org.springframework.data.document.mongodb.repository.AbstractMongoQuery#createQuery(org.springframework.data. + * document.mongodb.repository.ConvertingParameterAccessor) + */ + @Override + protected Query createQuery(ConvertingParameterAccessor accessor) { + + MongoQueryCreator creator = new MongoQueryCreator(tree, accessor); + return creator.createQuery(); + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/Query.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/Query.java index b30b06a9c..42326b172 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/Query.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/Query.java @@ -15,16 +15,12 @@ */ package org.springframework.data.document.mongodb.repository; -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; +import java.lang.annotation.*; /** * Annotation to declare finder queries directly on repository methods. - * + * * @author Oliver Gierke */ @Retention(RetentionPolicy.RUNTIME) @@ -32,7 +28,7 @@ import java.lang.annotation.Target; @Documented public @interface Query { - String value() default ""; - - String fields() default ""; + String value() default ""; + + String fields() default ""; } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/QueryUtils.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/QueryUtils.java index 39e6ba567..f4bc1de0a 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/QueryUtils.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/QueryUtils.java @@ -15,72 +15,71 @@ */ package org.springframework.data.document.mongodb.repository; +import com.mongodb.DBCursor; import org.springframework.data.document.mongodb.query.Query; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Order; -import com.mongodb.DBCursor; - /** * Collection of utility methods to apply sorting and pagination to a * {@link DBCursor}. - * + * * @author Oliver Gierke */ abstract class QueryUtils { - private QueryUtils() { + private QueryUtils() { + } + + + /** + * Applies the given {@link Pageable} to the given {@link Query}. Will do + * nothing if {@link Pageable} is {@literal null}. + * + * @param query + * @param pageable + * @return + */ + public static Query applyPagination(Query query, Pageable pageable) { + + if (pageable == null) { + return query; } + query.limit(pageable.getPageSize()); + query.skip(pageable.getOffset()); - /** - * Applies the given {@link Pageable} to the given {@link Query}. Will do - * nothing if {@link Pageable} is {@literal null}. - * - * @param query - * @param pageable - * @return - */ - public static Query applyPagination(Query query, Pageable pageable) { + return applySorting(query, pageable.getSort()); + } - if (pageable == null) { - return query; - } - query.limit(pageable.getPageSize()); - query.skip(pageable.getOffset()); + /** + * Applies the given {@link Sort} to the {@link Query}. Will do nothing if + * {@link Sort} is {@literal null}. + * + * @param query + * @param sort + * @return + */ + public static Query applySorting(Query query, Sort sort) { - return applySorting(query, pageable.getSort()); + if (sort == null) { + return query; } + org.springframework.data.document.mongodb.query.Sort bSort = + query.sort(); - /** - * Applies the given {@link Sort} to the {@link Query}. Will do nothing if - * {@link Sort} is {@literal null}. - * - * @param query - * @param sort - * @return - */ - public static Query applySorting(Query query, Sort sort) { - - if (sort == null) { - return query; - } - - org.springframework.data.document.mongodb.query.Sort bSort = - query.sort(); - - for (Order order : sort) { - bSort.on( - order.getProperty(), - order.isAscending() ? org.springframework.data.document.mongodb.query.Order.ASCENDING - : org.springframework.data.document.mongodb.query.Order.DESCENDING); - } - - return query; + for (Order order : sort) { + bSort.on( + order.getProperty(), + order.isAscending() ? org.springframework.data.document.mongodb.query.Order.ASCENDING + : org.springframework.data.document.mongodb.query.Order.DESCENDING); } + + return query; + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/SimpleMongoRepository.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/SimpleMongoRepository.java index 94e6e2008..18d5a0d35 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/SimpleMongoRepository.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/SimpleMongoRepository.java @@ -15,7 +15,7 @@ */ package org.springframework.data.document.mongodb.repository; -import static org.springframework.data.document.mongodb.query.Criteria.*; +import static org.springframework.data.document.mongodb.query.Criteria.where; import java.io.Serializable; import java.util.ArrayList; @@ -35,187 +35,187 @@ import org.springframework.util.Assert; /** * Repository base implementation for Mongo. - * + * * @author Oliver Gierke */ public class SimpleMongoRepository implements PagingAndSortingRepository { - private final MongoTemplate template; - private final MongoEntityInformation entityInformation; + private final MongoTemplate template; + private final MongoEntityInformation entityInformation; - /** - * Creates a ew {@link SimpleMongoRepository} for the given {@link MongoInformation} and {@link MongoTemplate}. - * - * @param metadata - * @param template - */ - public SimpleMongoRepository(MongoEntityInformation metadata, MongoTemplate template) { + /** + * Creates a ew {@link SimpleMongoRepository} for the given {@link MongoInformation} and {@link MongoTemplate}. + * + * @param metadata + * @param template + */ + public SimpleMongoRepository(MongoEntityInformation metadata, MongoTemplate template) { - Assert.notNull(template); - Assert.notNull(metadata); - this.entityInformation = metadata; - this.template = template; - } + Assert.notNull(template); + Assert.notNull(metadata); + this.entityInformation = metadata; + this.template = template; + } - /* - * (non-Javadoc) - * - * @see org.springframework.data.repository.Repository#save(java.lang.Object) - */ - public T save(T entity) { + /* + * (non-Javadoc) + * + * @see org.springframework.data.repository.Repository#save(java.lang.Object) + */ + public T save(T entity) { - template.save(entityInformation.getCollectionName(), entity); - return entity; - } + template.save(entityInformation.getCollectionName(), entity); + return entity; + } - /* - * (non-Javadoc) - * - * @see org.springframework.data.repository.Repository#save(java.lang.Iterable) - */ - public List save(Iterable entities) { + /* + * (non-Javadoc) + * + * @see org.springframework.data.repository.Repository#save(java.lang.Iterable) + */ + public List save(Iterable entities) { - List result = new ArrayList(); + List result = new ArrayList(); - for (T entity : entities) { - save(entity); - result.add(entity); - } + for (T entity : entities) { + save(entity); + result.add(entity); + } - return result; - } + return result; + } - /* - * (non-Javadoc) - * - * @see org.springframework.data.repository.Repository#findById(java.io.Serializable ) - */ - public T findOne(ID id) { - - return template.findOne(entityInformation.getCollectionName(), getIdQuery(id), entityInformation.getJavaType()); - } + /* + * (non-Javadoc) + * + * @see org.springframework.data.repository.Repository#findById(java.io.Serializable ) + */ + public T findOne(ID id) { - private Query getIdQuery(Object id) { + return template.findOne(entityInformation.getCollectionName(), getIdQuery(id), entityInformation.getJavaType()); + } - return new Query(getIdCriteria(id)); - } - - private Criteria getIdCriteria(Object id) { - ObjectId objectId = template.getConverter().convertObjectId(id); - return where(entityInformation.getIdAttribute()).is(objectId); - } + private Query getIdQuery(Object id) { + + return new Query(getIdCriteria(id)); + } + + private Criteria getIdCriteria(Object id) { + ObjectId objectId = template.getConverter().convertObjectId(id); + return where(entityInformation.getIdAttribute()).is(objectId); + } - /* - * (non-Javadoc) - * - * @see org.springframework.data.repository.Repository#exists(java.io.Serializable ) - */ - public boolean exists(ID id) { + /* + * (non-Javadoc) + * + * @see org.springframework.data.repository.Repository#exists(java.io.Serializable ) + */ + public boolean exists(ID id) { - return findOne(id) != null; - } + return findOne(id) != null; + } - /* - * (non-Javadoc) - * - * @see org.springframework.data.repository.Repository#count() - */ - public Long count() { + /* + * (non-Javadoc) + * + * @see org.springframework.data.repository.Repository#count() + */ + public Long count() { - return template.getCollection(entityInformation.getCollectionName()).count(); - } + return template.getCollection(entityInformation.getCollectionName()).count(); + } - /* - * (non-Javadoc) - * - * @see org.springframework.data.repository.Repository#delete(java.lang.Object) - */ - public void delete(T entity) { + /* + * (non-Javadoc) + * + * @see org.springframework.data.repository.Repository#delete(java.lang.Object) + */ + public void delete(T entity) { - template.remove(entityInformation.getCollectionName(), getIdQuery(entityInformation.getId(entity))); - } + template.remove(entityInformation.getCollectionName(), getIdQuery(entityInformation.getId(entity))); + } - /* - * (non-Javadoc) - * - * @see org.springframework.data.repository.Repository#delete(java.lang.Iterable) - */ - public void delete(Iterable entities) { + /* + * (non-Javadoc) + * + * @see org.springframework.data.repository.Repository#delete(java.lang.Iterable) + */ + public void delete(Iterable entities) { - for (T entity : entities) { - delete(entity); - } - } + for (T entity : entities) { + delete(entity); + } + } - /* - * (non-Javadoc) - * - * @see org.springframework.data.repository.Repository#deleteAll() - */ - public void deleteAll() { + /* + * (non-Javadoc) + * + * @see org.springframework.data.repository.Repository#deleteAll() + */ + public void deleteAll() { - template.dropCollection(entityInformation.getCollectionName()); - } - - /* (non-Javadoc) - * @see org.springframework.data.repository.Repository#findAll() - */ - public List findAll() { - return findAll(new Query()); - } + template.dropCollection(entityInformation.getCollectionName()); + } - /* - * (non-Javadoc) - * - * @see org.springframework.data.repository.PagingAndSortingRepository#findAll - * (org.springframework.data.domain.Pageable) - */ - public Page findAll(final Pageable pageable) { + /* (non-Javadoc) + * @see org.springframework.data.repository.Repository#findAll() + */ + public List findAll() { + return findAll(new Query()); + } - Long count = count(); - List list = findAll(QueryUtils.applyPagination(new Query(), pageable)); + /* + * (non-Javadoc) + * + * @see org.springframework.data.repository.PagingAndSortingRepository#findAll + * (org.springframework.data.domain.Pageable) + */ + public Page findAll(final Pageable pageable) { - return new PageImpl(list, pageable, count); - } + Long count = count(); + List list = findAll(QueryUtils.applyPagination(new Query(), pageable)); - /* - * (non-Javadoc) - * - * @see org.springframework.data.repository.PagingAndSortingRepository#findAll - * (org.springframework.data.domain.Sort) - */ - public List findAll(final Sort sort) { + return new PageImpl(list, pageable, count); + } - return findAll(QueryUtils.applySorting(new Query(), sort)); - } + /* + * (non-Javadoc) + * + * @see org.springframework.data.repository.PagingAndSortingRepository#findAll + * (org.springframework.data.domain.Sort) + */ + public List findAll(final Sort sort) { - /* - * (non-Javadoc) - * - * @see org.springframework.data.repository.Repository#findAll(java.lang.Iterable) - */ - public List findAll(Iterable ids) { + return findAll(QueryUtils.applySorting(new Query(), sort)); + } - Query query = null; + /* + * (non-Javadoc) + * + * @see org.springframework.data.repository.Repository#findAll(java.lang.Iterable) + */ + public List findAll(Iterable ids) { - for (ID id : ids) { - if (query == null) { - query = getIdQuery(id); - } else { - query = new Query().or(getIdQuery(id)); - } - } + Query query = null; - return findAll(query); - } + for (ID id : ids) { + if (query == null) { + query = getIdQuery(id); + } else { + query = new Query().or(getIdQuery(id)); + } + } - private List findAll(Query query) { + return findAll(query); + } - if (query == null) { - return Collections.emptyList(); - } + private List findAll(Query query) { - return template.find(entityInformation.getCollectionName(), query, entityInformation.getJavaType()); - } + if (query == null) { + return Collections.emptyList(); + } + + return template.find(entityInformation.getCollectionName(), query, entityInformation.getJavaType()); + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/StringBasedMongoQuery.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/StringBasedMongoQuery.java index 5e9202297..b50977e3b 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/StringBasedMongoQuery.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/StringBasedMongoQuery.java @@ -27,77 +27,77 @@ import org.springframework.data.document.mongodb.query.Query; /** * Query to use a plain JSON String to create the {@link Query} to actually execute. - * + * * @author Oliver Gierke */ public class StringBasedMongoQuery extends AbstractMongoQuery { - private static final Pattern PLACEHOLDER = Pattern.compile("\\?(\\d+)"); - private static final Logger LOG = LoggerFactory.getLogger(StringBasedMongoQuery.class); + private static final Pattern PLACEHOLDER = Pattern.compile("\\?(\\d+)"); + private static final Logger LOG = LoggerFactory.getLogger(StringBasedMongoQuery.class); - private final String query; - private final String fieldSpec; + private final String query; + private final String fieldSpec; - /** - * Creates a new {@link StringBasedMongoQuery}. - * - * @param method - * @param template - */ - public StringBasedMongoQuery(MongoQueryMethod method, MongoTemplate template) { - super(method, template); - this.query = method.getAnnotatedQuery(); - this.fieldSpec = method.getFieldSpecification(); - } + /** + * Creates a new {@link StringBasedMongoQuery}. + * + * @param method + * @param template + */ + public StringBasedMongoQuery(MongoQueryMethod method, MongoTemplate template) { + super(method, template); + this.query = method.getAnnotatedQuery(); + this.fieldSpec = method.getFieldSpecification(); + } - /* - * (non-Javadoc) - * - * @see - * org.springframework.data.document.mongodb.repository.AbstractMongoQuery#createQuery(org.springframework.data. - * repository.query.SimpleParameterAccessor, org.springframework.data.document.mongodb.support.convert.MongoConverter) - */ - @Override - protected Query createQuery(ConvertingParameterAccessor accessor) { + /* + * (non-Javadoc) + * + * @see + * org.springframework.data.document.mongodb.repository.AbstractMongoQuery#createQuery(org.springframework.data. + * repository.query.SimpleParameterAccessor, org.springframework.data.document.mongodb.support.convert.MongoConverter) + */ + @Override + protected Query createQuery(ConvertingParameterAccessor accessor) { - String queryString = replacePlaceholders(query, accessor); + String queryString = replacePlaceholders(query, accessor); - Query query = null; + Query query = null; - if (fieldSpec != null) { - String fieldString = replacePlaceholders(fieldSpec, accessor); - query = new BasicQuery(queryString, fieldString); - } else { - query = new BasicQuery(queryString); - } + if (fieldSpec != null) { + String fieldString = replacePlaceholders(fieldSpec, accessor); + query = new BasicQuery(queryString, fieldString); + } else { + query = new BasicQuery(queryString); + } - LOG.debug("Created query {}", query.getQueryObject()); + LOG.debug("Created query {}", query.getQueryObject()); - return query; - } + return query; + } - private String replacePlaceholders(String input, ConvertingParameterAccessor accessor) { + private String replacePlaceholders(String input, ConvertingParameterAccessor accessor) { - Matcher matcher = PLACEHOLDER.matcher(input); - String result = null; + Matcher matcher = PLACEHOLDER.matcher(input); + String result = null; - while (matcher.find()) { - String group = matcher.group(); - int index = Integer.parseInt(matcher.group(1)); - result = input.replace(group, getParameterWithIndex(accessor, index)); - } + while (matcher.find()) { + String group = matcher.group(); + int index = Integer.parseInt(matcher.group(1)); + result = input.replace(group, getParameterWithIndex(accessor, index)); + } - return result; - } + return result; + } - private String getParameterWithIndex(ConvertingParameterAccessor accessor, int index) { - Object parameter = accessor.getBindableValue(index); - if (parameter instanceof String || parameter.getClass().isEnum()) { - return String.format("\"%s\"", parameter); - } else if (parameter instanceof ObjectId){ - return String.format("{ '$oid' : '%s' }", parameter); - } - - return parameter.toString(); - } + private String getParameterWithIndex(ConvertingParameterAccessor accessor, int index) { + Object parameter = accessor.getBindableValue(index); + if (parameter instanceof String || parameter.getClass().isEnum()) { + return String.format("\"%s\"", parameter); + } else if (parameter instanceof ObjectId) { + return String.format("{ '$oid' : '%s' }", parameter); + } + + return parameter.toString(); + } } diff --git a/spring-data-mongodb/src/main/resources/org/springframework/data/document/mongodb/config/spring-mongo-1.0.xsd b/spring-data-mongodb/src/main/resources/org/springframework/data/document/mongodb/config/spring-mongo-1.0.xsd index 6cdf4ec87..3d800385d 100644 --- a/spring-data-mongodb/src/main/resources/org/springframework/data/document/mongodb/config/spring-mongo-1.0.xsd +++ b/spring-data-mongodb/src/main/resources/org/springframework/data/document/mongodb/config/spring-mongo-1.0.xsd @@ -1,182 +1,182 @@ + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:tool="http://www.springframework.org/schema/tool" + xmlns:context="http://www.springframework.org/schema/context" + xmlns:repository="http://www.springframework.org/schema/data/repository" + targetNamespace="http://www.springframework.org/schema/data/mongo" + elementFormDefault="qualified" attributeFormDefault="unqualified"> - - - + + + - - - + + - - - - - - - - - - - + + + + + + + + + + - - - - - - - - + + + + + + + + - - - - + + - - - - - + + + + - - - - - + + + + - - - - + + + + - - - - - - - The reference to a MongoTemplate. Will default to 'mongoTemplate'. - - - - - - - + + + + + + + The reference to a MongoTemplate. Will default to 'mongoTemplate'. + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - + + - - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + - - - - - + + + + - - - - - + + + + - - - - - + + + + - - - - - + + + + - - - + + + \ No newline at end of file diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/JmxServer.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/JmxServer.java index a7bc6f6a7..7cc1795ae 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/JmxServer.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/JmxServer.java @@ -20,17 +20,17 @@ import org.springframework.context.support.ClassPathXmlApplicationContext; /** * Server application than can be run as an app or unit test. - * + * * @author Mark Pollack */ public class JmxServer { - public static void main(String[] args) { - new JmxServer().run(); - } + public static void main(String[] args) { + new JmxServer().run(); + } - public void run() { - new ClassPathXmlApplicationContext(new String[] {"infrastructure.xml", "server-jmx.xml"} ); - } + public void run() { + new ClassPathXmlApplicationContext(new String[]{"infrastructure.xml", "server-jmx.xml"}); + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/MongoAdminIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/MongoAdminIntegrationTests.java index e0c4edd47..97c05146d 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/MongoAdminIntegrationTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/MongoAdminIntegrationTests.java @@ -15,6 +15,9 @@ */ package org.springframework.data.document.mongodb; +import com.mongodb.CommandResult; +import com.mongodb.DB; +import com.mongodb.Mongo; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.junit.Before; @@ -24,41 +27,36 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import com.mongodb.CommandResult; -import com.mongodb.DB; -import com.mongodb.Mongo; - /** - * * This test class assumes that you are already running the MongoDB server. - * + * * @author Mark Pollack */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:infrastructure.xml") public class MongoAdminIntegrationTests { - private static Log logger = LogFactory.getLog(MongoAdminIntegrationTests.class); + private static Log logger = LogFactory.getLog(MongoAdminIntegrationTests.class); - private MongoAdminOperations mongoAdmin; - - private DB testAdminDb; - - @Autowired - Mongo mongo; + private MongoAdminOperations mongoAdmin; - @Before - public void setUp() { - mongo.getDB("testAdminDb").dropDatabase(); - testAdminDb = mongo.getDB("testAdminDb"); - - } - - @Test - public void serverStats() { - //CommandResult result = testAdminDb.getStats(); - CommandResult result = mongo.getDB("admin").command("serverStatus"); - logger.info("stats = " + result); - } + private DB testAdminDb; + + @Autowired + Mongo mongo; + + @Before + public void setUp() { + mongo.getDB("testAdminDb").dropDatabase(); + testAdminDb = mongo.getDB("testAdminDb"); + + } + + @Test + public void serverStats() { + //CommandResult result = testAdminDb.getStats(); + CommandResult result = mongo.getDB("admin").command("serverStatus"); + logger.info("stats = " + result); + } } \ No newline at end of file diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/MongoOperationsUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/MongoOperationsUnitTests.java index 9427700b3..8eb0b0ac6 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/MongoOperationsUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/MongoOperationsUnitTests.java @@ -16,11 +16,14 @@ package org.springframework.data.document.mongodb; -import static org.junit.Assert.*; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.util.Arrays; import java.util.List; +import com.mongodb.BasicDBObject; +import com.mongodb.DBObject; import org.bson.types.ObjectId; import org.junit.Before; import org.junit.Test; @@ -28,328 +31,325 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import org.springframework.dao.DataAccessException; - -import com.mongodb.BasicDBObject; -import com.mongodb.DBObject; import org.springframework.data.document.mongodb.convert.MongoConverter; /** * Abstract base class for unit tests to specify behaviour we expect from {@link MongoOperations}. Subclasses return * instances of their implementation and thus can see if it correctly implements the {@link MongoOperations} interface. - * + * * @author Oliver Gierke */ @RunWith(MockitoJUnitRunner.class) public abstract class MongoOperationsUnitTests { - - @Mock - CollectionCallback collectionCallback; - @Mock - DbCallback dbCallback; - - MongoConverter converter; - Person person; - List persons; - - @Before - public final void operationsSetUp() { - - person = new Person("Oliver"); - persons = Arrays.asList(person); - - converter = new MongoConverter() { - - public void write(Object t, DBObject dbo) { - dbo.put("firstName", person.getFirstName()); - } - @SuppressWarnings({"unchecked"}) + @Mock + CollectionCallback collectionCallback; + @Mock + DbCallback dbCallback; + + MongoConverter converter; + Person person; + List persons; + + @Before + public final void operationsSetUp() { + + person = new Person("Oliver"); + persons = Arrays.asList(person); + + converter = new MongoConverter() { + + public void write(Object t, DBObject dbo) { + dbo.put("firstName", person.getFirstName()); + } + + @SuppressWarnings({"unchecked"}) public S read(Class clazz, DBObject dbo) { - return (S) person; - } - - public T convertObjectId(ObjectId id, Class targetType) { - return null; - } - - public ObjectId convertObjectId(Object id) { - return null; - } - }; - } - - - @Test(expected = IllegalArgumentException.class) - @SuppressWarnings({"unchecked", "rawtypes"}) - public void rejectsNullForCollectionCallback() { - - getOperations().execute((CollectionCallback) null); - } - - @Test(expected = IllegalArgumentException.class) - @SuppressWarnings({"unchecked", "rawtypes"}) - public void rejectsNullForCollectionCallback2() { - getOperations().execute("collection", (CollectionCallback) null); - } - - @Test(expected = IllegalArgumentException.class) - @SuppressWarnings({"unchecked", "rawtypes"}) - public void rejectsNullForDbCallback() { - getOperations().execute((DbCallback) null); - } + return (S) person; + } - @Test - public void convertsExceptionForCollectionExists() { - new Execution() { - @Override - public void doWith(MongoOperations operations) { - operations.collectionExists("foo"); - } - }.assertDataAccessException(); - } - - @Test - public void convertsExceptionForCreateCollection() { - new Execution() { - @Override - public void doWith(MongoOperations operations) { - operations.createCollection("foo"); - } - }.assertDataAccessException(); - } - - @Test - public void convertsExceptionForCreateCollection2() { - new Execution() { - @Override - public void doWith(MongoOperations operations) { - operations.createCollection("foo", new CollectionOptions(1, 1, true)); - } - }.assertDataAccessException(); - } - - @Test - public void convertsExceptionForDropCollection() { - new Execution() { - @Override - public void doWith(MongoOperations operations) { - operations.dropCollection("foo"); - } - }.assertDataAccessException(); - } - - @Test - public void convertsExceptionForExecuteCollectionCallback() { - new Execution() { - @Override - public void doWith(MongoOperations operations) { - operations.execute(collectionCallback); - } - }.assertDataAccessException(); - } - - @Test - public void convertsExceptionForExecuteDbCallback() { - new Execution() { - @Override - public void doWith(MongoOperations operations) { - operations.execute(dbCallback); - } - }.assertDataAccessException(); - } - - @Test - public void convertsExceptionForExecuteCollectionCallbackAndCollection() { - new Execution() { - @Override - public void doWith(MongoOperations operations) { - operations.execute("collection", collectionCallback); - } - }.assertDataAccessException(); - } - - @Test - public void convertsExceptionForExecuteCommand() { - new Execution() { - @Override - public void doWith(MongoOperations operations) { - operations.executeCommand(new BasicDBObject()); - } - }.assertDataAccessException(); - } - - @Test - public void convertsExceptionForExecuteStringCommand() { - new Execution() { - @Override - public void doWith(MongoOperations operations) { - operations.executeCommand(""); - } - }.assertDataAccessException(); - } - - @Test - public void convertsExceptionForExecuteInSession() { - new Execution() { - @Override - public void doWith(MongoOperations operations) { - operations.executeInSession(dbCallback); - } - }.assertDataAccessException(); - } - - @Test - public void convertsExceptionForGetCollection() { - new Execution() { - @Override - public void doWith(MongoOperations operations) { - operations.getCollection(Object.class); - } - }.assertDataAccessException(); - } - - @Test - public void convertsExceptionForGetCollectionWithCollectionName() { - new Execution() { - @Override - public void doWith(MongoOperations operations) { - operations.getCollection("collection"); - } - }.assertDataAccessException(); - } - - @Test - public void convertsExceptionForGetCollectionWithCollectionNameAndType() { - new Execution() { - @Override - public void doWith(MongoOperations operations) { - operations.getCollection("collection", Object.class); - } - }.assertDataAccessException(); - } - - @Test - public void convertsExceptionForGetCollectionWithCollectionNameTypeAndReader() { - new Execution() { - @Override - public void doWith(MongoOperations operations) { - operations.getCollection("collection", Object.class, converter); - } - }.assertDataAccessException(); - } - - @Test - public void convertsExceptionForGetCollectionNames() { - new Execution() { - @Override - public void doWith(MongoOperations operations) { - operations.getCollectionNames(); - } - }.assertDataAccessException(); - } - - @Test - public void convertsExceptionForGetDefaultCollection() { - new Execution() { - @Override - public void doWith(MongoOperations operations) { - operations.getDefaultCollection(); - } - }.assertDataAccessException(); - } - - @Test - public void convertsExceptionForInsert() { - new Execution() { - @Override - public void doWith(MongoOperations operations) { - operations.insert(person); - } - }.assertDataAccessException(); - } - - @Test - public void convertsExceptionForInsert2() { - new Execution() { - @Override - public void doWith(MongoOperations operations) { - operations.insert("collection", person); - } - }.assertDataAccessException(); - } - - @Test - public void convertsExceptionForInsert3() { - new Execution() { - @Override - public void doWith(MongoOperations operations) { - operations.insert("collection", person, converter); - } - }.assertDataAccessException(); - } - - - @Test - public void convertsExceptionForInsertList() throws Exception { - new Execution() { - @Override - public void doWith(MongoOperations operations) { - operations.insertList(persons); - } - }.assertDataAccessException(); - } - - @Test - public void convertsExceptionForGetInsertList2() throws Exception { - new Execution() { - @Override - public void doWith(MongoOperations operations) { - operations.insertList("collection", persons); - } - }.assertDataAccessException(); - } + public T convertObjectId(ObjectId id, Class targetType) { + return null; + } - @Test - public void convertsExceptionForGetInsertList3() throws Exception { - new Execution() { - @Override - public void doWith(MongoOperations operations) { - operations.insertList("collection", persons, converter); - } - }.assertDataAccessException(); - } - - private abstract class Execution { + public ObjectId convertObjectId(Object id) { + return null; + } + }; + } - public void assertDataAccessException() { - assertException(DataAccessException.class); - } - public void assertException(Class exception) { + @Test(expected = IllegalArgumentException.class) + @SuppressWarnings({"unchecked", "rawtypes"}) + public void rejectsNullForCollectionCallback() { - try { - doWith(getOperationsForExceptionHandling()); - fail("Expected " + exception + " but completed without any!"); - } catch (Exception e) { - assertTrue("Expected " + exception + " but got " + e, exception.isInstance(e)); - } - } + getOperations().execute((CollectionCallback) null); + } - public abstract void doWith(MongoOperations operations); - } + @Test(expected = IllegalArgumentException.class) + @SuppressWarnings({"unchecked", "rawtypes"}) + public void rejectsNullForCollectionCallback2() { + getOperations().execute("collection", (CollectionCallback) null); + } - /** - * Expects an {@link MongoOperations} instance that will be used to check that invoking methods on it will only - * cause {@link DataAccessException}s. - * - * @return - */ - protected abstract MongoOperations getOperationsForExceptionHandling(); - - /** - * Returns a plain {@link MongoOperations}. - * - * @return - */ - protected abstract MongoOperations getOperations(); + @Test(expected = IllegalArgumentException.class) + @SuppressWarnings({"unchecked", "rawtypes"}) + public void rejectsNullForDbCallback() { + getOperations().execute((DbCallback) null); + } + + @Test + public void convertsExceptionForCollectionExists() { + new Execution() { + @Override + public void doWith(MongoOperations operations) { + operations.collectionExists("foo"); + } + }.assertDataAccessException(); + } + + @Test + public void convertsExceptionForCreateCollection() { + new Execution() { + @Override + public void doWith(MongoOperations operations) { + operations.createCollection("foo"); + } + }.assertDataAccessException(); + } + + @Test + public void convertsExceptionForCreateCollection2() { + new Execution() { + @Override + public void doWith(MongoOperations operations) { + operations.createCollection("foo", new CollectionOptions(1, 1, true)); + } + }.assertDataAccessException(); + } + + @Test + public void convertsExceptionForDropCollection() { + new Execution() { + @Override + public void doWith(MongoOperations operations) { + operations.dropCollection("foo"); + } + }.assertDataAccessException(); + } + + @Test + public void convertsExceptionForExecuteCollectionCallback() { + new Execution() { + @Override + public void doWith(MongoOperations operations) { + operations.execute(collectionCallback); + } + }.assertDataAccessException(); + } + + @Test + public void convertsExceptionForExecuteDbCallback() { + new Execution() { + @Override + public void doWith(MongoOperations operations) { + operations.execute(dbCallback); + } + }.assertDataAccessException(); + } + + @Test + public void convertsExceptionForExecuteCollectionCallbackAndCollection() { + new Execution() { + @Override + public void doWith(MongoOperations operations) { + operations.execute("collection", collectionCallback); + } + }.assertDataAccessException(); + } + + @Test + public void convertsExceptionForExecuteCommand() { + new Execution() { + @Override + public void doWith(MongoOperations operations) { + operations.executeCommand(new BasicDBObject()); + } + }.assertDataAccessException(); + } + + @Test + public void convertsExceptionForExecuteStringCommand() { + new Execution() { + @Override + public void doWith(MongoOperations operations) { + operations.executeCommand(""); + } + }.assertDataAccessException(); + } + + @Test + public void convertsExceptionForExecuteInSession() { + new Execution() { + @Override + public void doWith(MongoOperations operations) { + operations.executeInSession(dbCallback); + } + }.assertDataAccessException(); + } + + @Test + public void convertsExceptionForGetCollection() { + new Execution() { + @Override + public void doWith(MongoOperations operations) { + operations.getCollection(Object.class); + } + }.assertDataAccessException(); + } + + @Test + public void convertsExceptionForGetCollectionWithCollectionName() { + new Execution() { + @Override + public void doWith(MongoOperations operations) { + operations.getCollection("collection"); + } + }.assertDataAccessException(); + } + + @Test + public void convertsExceptionForGetCollectionWithCollectionNameAndType() { + new Execution() { + @Override + public void doWith(MongoOperations operations) { + operations.getCollection("collection", Object.class); + } + }.assertDataAccessException(); + } + + @Test + public void convertsExceptionForGetCollectionWithCollectionNameTypeAndReader() { + new Execution() { + @Override + public void doWith(MongoOperations operations) { + operations.getCollection("collection", Object.class, converter); + } + }.assertDataAccessException(); + } + + @Test + public void convertsExceptionForGetCollectionNames() { + new Execution() { + @Override + public void doWith(MongoOperations operations) { + operations.getCollectionNames(); + } + }.assertDataAccessException(); + } + + @Test + public void convertsExceptionForGetDefaultCollection() { + new Execution() { + @Override + public void doWith(MongoOperations operations) { + operations.getDefaultCollection(); + } + }.assertDataAccessException(); + } + + @Test + public void convertsExceptionForInsert() { + new Execution() { + @Override + public void doWith(MongoOperations operations) { + operations.insert(person); + } + }.assertDataAccessException(); + } + + @Test + public void convertsExceptionForInsert2() { + new Execution() { + @Override + public void doWith(MongoOperations operations) { + operations.insert("collection", person); + } + }.assertDataAccessException(); + } + + @Test + public void convertsExceptionForInsert3() { + new Execution() { + @Override + public void doWith(MongoOperations operations) { + operations.insert("collection", person, converter); + } + }.assertDataAccessException(); + } + + + @Test + public void convertsExceptionForInsertList() throws Exception { + new Execution() { + @Override + public void doWith(MongoOperations operations) { + operations.insertList(persons); + } + }.assertDataAccessException(); + } + + @Test + public void convertsExceptionForGetInsertList2() throws Exception { + new Execution() { + @Override + public void doWith(MongoOperations operations) { + operations.insertList("collection", persons); + } + }.assertDataAccessException(); + } + + @Test + public void convertsExceptionForGetInsertList3() throws Exception { + new Execution() { + @Override + public void doWith(MongoOperations operations) { + operations.insertList("collection", persons, converter); + } + }.assertDataAccessException(); + } + + private abstract class Execution { + + public void assertDataAccessException() { + assertException(DataAccessException.class); + } + + public void assertException(Class exception) { + + try { + doWith(getOperationsForExceptionHandling()); + fail("Expected " + exception + " but completed without any!"); + } catch (Exception e) { + assertTrue("Expected " + exception + " but got " + e, exception.isInstance(e)); + } + } + + public abstract void doWith(MongoOperations operations); + } + + /** + * Expects an {@link MongoOperations} instance that will be used to check that invoking methods on it will only + * cause {@link DataAccessException}s. + * + * @return + */ + protected abstract MongoOperations getOperationsForExceptionHandling(); + + /** + * Returns a plain {@link MongoOperations}. + * + * @return + */ + protected abstract MongoOperations getOperations(); } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/MongoTemplateTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/MongoTemplateTests.java index 18ec12d60..4841984fb 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/MongoTemplateTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/MongoTemplateTests.java @@ -15,16 +15,15 @@ */ package org.springframework.data.document.mongodb; -import static org.hamcrest.Matchers.hasItem; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.endsWith; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.assertThat; - import static org.springframework.data.document.mongodb.query.Criteria.where; import java.util.List; +import com.mongodb.DBCollection; +import com.mongodb.DBObject; +import com.mongodb.WriteConcern; import org.bson.types.ObjectId; import org.junit.Before; import org.junit.Rule; @@ -33,23 +32,15 @@ import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.data.document.mongodb.query.Criteria; -import org.springframework.data.document.mongodb.query.Index; -import org.springframework.data.document.mongodb.query.Index.Duplicates; -import org.springframework.data.document.mongodb.query.Order; -import org.springframework.data.document.mongodb.query.Query; -import org.springframework.data.document.mongodb.query.Update; import org.springframework.data.document.mongodb.convert.MongoConverter; +import org.springframework.data.document.mongodb.query.*; +import org.springframework.data.document.mongodb.query.Index.Duplicates; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import com.mongodb.DBCollection; -import com.mongodb.DBObject; -import com.mongodb.WriteConcern; - /** * Integration test for {@link MongoTemplate}. - * + * * @author Oliver Gierke * @author Thomas Risberg */ @@ -57,157 +48,157 @@ import com.mongodb.WriteConcern; @ContextConfiguration("classpath:infrastructure.xml") public class MongoTemplateTests { - @Autowired - MongoTemplate template; + @Autowired + MongoTemplate template; - @Rule - public ExpectedException thrown = ExpectedException.none(); - - @Before - public void setUp() { - template.dropCollection(template.getDefaultCollectionName()); - } + @Rule + public ExpectedException thrown = ExpectedException.none(); - @Test - public void insertsSimpleEntityCorrectly() throws Exception { + @Before + public void setUp() { + template.dropCollection(template.getDefaultCollectionName()); + } - Person person = new Person("Oliver"); - person.setAge(25); - template.insert(person); - - MongoConverter converter = template.getConverter(); + @Test + public void insertsSimpleEntityCorrectly() throws Exception { - List result = template.find(new Query(Criteria.where("_id").is(converter.convertObjectId(person.getId()))), Person.class); - assertThat(result.size(), is(1)); - assertThat(result, hasItem(person)); - } + Person person = new Person("Oliver"); + person.setAge(25); + template.insert(person); - @Test - public void updateFailure() throws Exception { + MongoConverter converter = template.getConverter(); - MongoTemplate mongoTemplate = new MongoTemplate(template.getDb().getMongo(), "test", "people", - new WriteConcern(), WriteResultChecking.EXCEPTION); - - Person person = new Person("Oliver2"); - person.setAge(25); - mongoTemplate.insert(person); - - Query q = new Query(Criteria.where("BOGUS").gt(22)); - Update u = new Update().set("firstName", "Sven"); - thrown.expect(DataIntegrityViolationException.class); - thrown.expectMessage( endsWith("0 documents updated") ); - mongoTemplate.updateFirst(q, u); - - } + List result = template.find(new Query(Criteria.where("_id").is(converter.convertObjectId(person.getId()))), Person.class); + assertThat(result.size(), is(1)); + assertThat(result, hasItem(person)); + } - @Test - public void testEnsureIndex() throws Exception { + @Test + public void updateFailure() throws Exception { - Person p1 = new Person("Oliver"); - p1.setAge(25); - template.insert(p1); - Person p2 = new Person("Sven"); - p2.setAge(40); - template.insert(p2); - - template.ensureIndex(new Index().on("age", Order.DESCENDING).unique(Duplicates.DROP)); - - DBCollection coll = template.getCollection(template.getDefaultCollectionName()); - List indexInfo = coll.getIndexInfo(); - - assertThat(indexInfo.size(), is(2)); - String indexKey = null; - boolean unique = false; - boolean dropDupes = false; - for (DBObject ix : indexInfo) { - if ("age_-1".equals(ix.get("name"))) { - indexKey = ix.get("key").toString(); - unique = (Boolean) ix.get("unique"); - dropDupes = (Boolean) ix.get("drop_dups"); - } - } - assertThat(indexKey, is("{ \"age\" : -1}")); - assertThat(unique, is(true)); - assertThat(dropDupes, is(true)); - } + MongoTemplate mongoTemplate = new MongoTemplate(template.getDb().getMongo(), "test", "people", + new WriteConcern(), WriteResultChecking.EXCEPTION); - @Test - public void testProperHandlingOfDifferentIdTypes() throws Exception { - PersonWithIdPropertyOfTypeString p1 = new PersonWithIdPropertyOfTypeString(); - p1.setFirstName("Sven_1"); - p1.setAge(22); - template.insert(p1); - assertThat(p1.getId(), notNullValue()); - PersonWithIdPropertyOfTypeString p1q = template.findOne(new Query(where("id").is(p1.getId())), PersonWithIdPropertyOfTypeString.class); - assertThat(p1q, notNullValue()); - assertThat(p1q.getId(), is(p1.getId())); + Person person = new Person("Oliver2"); + person.setAge(25); + mongoTemplate.insert(person); - PersonWithIdPropertyOfTypeString p2 = new PersonWithIdPropertyOfTypeString(); - p2.setFirstName("Sven_2"); - p2.setAge(22); - p2.setId("TWO"); - template.insert(p2); - assertThat(p2.getId(), notNullValue()); - PersonWithIdPropertyOfTypeString p2q = template.findOne(new Query(where("id").is(p2.getId())), PersonWithIdPropertyOfTypeString.class); - assertThat(p2q, notNullValue()); - assertThat(p2q.getId(), is(p2.getId())); - - PersonWith_idPropertyOfTypeString p3 = new PersonWith_idPropertyOfTypeString(); - p3.setFirstName("Sven_3"); - p3.setAge(22); - template.insert(p3); - assertThat(p3.get_id(), notNullValue()); - PersonWith_idPropertyOfTypeString p3q = template.findOne(new Query(where("_id").is(p3.get_id())), PersonWith_idPropertyOfTypeString.class); - assertThat(p3q, notNullValue()); - assertThat(p3q.get_id(), is(p3.get_id())); + Query q = new Query(Criteria.where("BOGUS").gt(22)); + Update u = new Update().set("firstName", "Sven"); + thrown.expect(DataIntegrityViolationException.class); + thrown.expectMessage(endsWith("0 documents updated")); + mongoTemplate.updateFirst(q, u); - PersonWith_idPropertyOfTypeString p4 = new PersonWith_idPropertyOfTypeString(); - p4.setFirstName("Sven_4"); - p4.setAge(22); - p4.set_id("FOUR"); - template.insert(p4); - assertThat(p4.get_id(), notNullValue()); - PersonWith_idPropertyOfTypeString p4q = template.findOne(new Query(where("_id").is(p4.get_id())), PersonWith_idPropertyOfTypeString.class); - assertThat(p4q, notNullValue()); - assertThat(p4q.get_id(), is(p4.get_id())); + } - PersonWithIdPropertyOfTypeObjectId p5 = new PersonWithIdPropertyOfTypeObjectId(); - p5.setFirstName("Sven_5"); - p5.setAge(22); - template.insert(p5); - assertThat(p5.getId(), notNullValue()); - PersonWithIdPropertyOfTypeObjectId p5q = template.findOne(new Query(where("id").is(p5.getId())), PersonWithIdPropertyOfTypeObjectId.class); - assertThat(p5q, notNullValue()); - assertThat(p5q.getId(), is(p5.getId())); + @Test + public void testEnsureIndex() throws Exception { - PersonWithIdPropertyOfTypeObjectId p6 = new PersonWithIdPropertyOfTypeObjectId(); - p6.setFirstName("Sven_6"); - p6.setAge(22); - p6.setId(new ObjectId()); - template.insert(p6); - assertThat(p6.getId(), notNullValue()); - PersonWithIdPropertyOfTypeObjectId p6q = template.findOne(new Query(where("id").is(p6.getId())), PersonWithIdPropertyOfTypeObjectId.class); - assertThat(p6q, notNullValue()); - assertThat(p6q.getId(), is(p6.getId())); - - PersonWith_idPropertyOfTypeObjectId p7 = new PersonWith_idPropertyOfTypeObjectId(); - p7.setFirstName("Sven_7"); - p7.setAge(22); - template.insert(p7); - assertThat(p7.get_id(), notNullValue()); - PersonWith_idPropertyOfTypeObjectId p7q = template.findOne(new Query(where("_id").is(p7.get_id())), PersonWith_idPropertyOfTypeObjectId.class); - assertThat(p7q, notNullValue()); - assertThat(p7q.get_id(), is(p7.get_id())); + Person p1 = new Person("Oliver"); + p1.setAge(25); + template.insert(p1); + Person p2 = new Person("Sven"); + p2.setAge(40); + template.insert(p2); - PersonWith_idPropertyOfTypeObjectId p8 = new PersonWith_idPropertyOfTypeObjectId(); - p8.setFirstName("Sven_8"); - p8.setAge(22); - p8.set_id(new ObjectId()); - template.insert(p8); - assertThat(p8.get_id(), notNullValue()); - PersonWith_idPropertyOfTypeObjectId p8q = template.findOne(new Query(where("_id").is(p8.get_id())), PersonWith_idPropertyOfTypeObjectId.class); - assertThat(p8q, notNullValue()); - assertThat(p8q.get_id(), is(p8.get_id())); - } + template.ensureIndex(new Index().on("age", Order.DESCENDING).unique(Duplicates.DROP)); + + DBCollection coll = template.getCollection(template.getDefaultCollectionName()); + List indexInfo = coll.getIndexInfo(); + + assertThat(indexInfo.size(), is(2)); + String indexKey = null; + boolean unique = false; + boolean dropDupes = false; + for (DBObject ix : indexInfo) { + if ("age_-1".equals(ix.get("name"))) { + indexKey = ix.get("key").toString(); + unique = (Boolean) ix.get("unique"); + dropDupes = (Boolean) ix.get("drop_dups"); + } + } + assertThat(indexKey, is("{ \"age\" : -1}")); + assertThat(unique, is(true)); + assertThat(dropDupes, is(true)); + } + + @Test + public void testProperHandlingOfDifferentIdTypes() throws Exception { + PersonWithIdPropertyOfTypeString p1 = new PersonWithIdPropertyOfTypeString(); + p1.setFirstName("Sven_1"); + p1.setAge(22); + template.insert(p1); + assertThat(p1.getId(), notNullValue()); + PersonWithIdPropertyOfTypeString p1q = template.findOne(new Query(where("id").is(p1.getId())), PersonWithIdPropertyOfTypeString.class); + assertThat(p1q, notNullValue()); + assertThat(p1q.getId(), is(p1.getId())); + + PersonWithIdPropertyOfTypeString p2 = new PersonWithIdPropertyOfTypeString(); + p2.setFirstName("Sven_2"); + p2.setAge(22); + p2.setId("TWO"); + template.insert(p2); + assertThat(p2.getId(), notNullValue()); + PersonWithIdPropertyOfTypeString p2q = template.findOne(new Query(where("id").is(p2.getId())), PersonWithIdPropertyOfTypeString.class); + assertThat(p2q, notNullValue()); + assertThat(p2q.getId(), is(p2.getId())); + + PersonWith_idPropertyOfTypeString p3 = new PersonWith_idPropertyOfTypeString(); + p3.setFirstName("Sven_3"); + p3.setAge(22); + template.insert(p3); + assertThat(p3.get_id(), notNullValue()); + PersonWith_idPropertyOfTypeString p3q = template.findOne(new Query(where("_id").is(p3.get_id())), PersonWith_idPropertyOfTypeString.class); + assertThat(p3q, notNullValue()); + assertThat(p3q.get_id(), is(p3.get_id())); + + PersonWith_idPropertyOfTypeString p4 = new PersonWith_idPropertyOfTypeString(); + p4.setFirstName("Sven_4"); + p4.setAge(22); + p4.set_id("FOUR"); + template.insert(p4); + assertThat(p4.get_id(), notNullValue()); + PersonWith_idPropertyOfTypeString p4q = template.findOne(new Query(where("_id").is(p4.get_id())), PersonWith_idPropertyOfTypeString.class); + assertThat(p4q, notNullValue()); + assertThat(p4q.get_id(), is(p4.get_id())); + + PersonWithIdPropertyOfTypeObjectId p5 = new PersonWithIdPropertyOfTypeObjectId(); + p5.setFirstName("Sven_5"); + p5.setAge(22); + template.insert(p5); + assertThat(p5.getId(), notNullValue()); + PersonWithIdPropertyOfTypeObjectId p5q = template.findOne(new Query(where("id").is(p5.getId())), PersonWithIdPropertyOfTypeObjectId.class); + assertThat(p5q, notNullValue()); + assertThat(p5q.getId(), is(p5.getId())); + + PersonWithIdPropertyOfTypeObjectId p6 = new PersonWithIdPropertyOfTypeObjectId(); + p6.setFirstName("Sven_6"); + p6.setAge(22); + p6.setId(new ObjectId()); + template.insert(p6); + assertThat(p6.getId(), notNullValue()); + PersonWithIdPropertyOfTypeObjectId p6q = template.findOne(new Query(where("id").is(p6.getId())), PersonWithIdPropertyOfTypeObjectId.class); + assertThat(p6q, notNullValue()); + assertThat(p6q.getId(), is(p6.getId())); + + PersonWith_idPropertyOfTypeObjectId p7 = new PersonWith_idPropertyOfTypeObjectId(); + p7.setFirstName("Sven_7"); + p7.setAge(22); + template.insert(p7); + assertThat(p7.get_id(), notNullValue()); + PersonWith_idPropertyOfTypeObjectId p7q = template.findOne(new Query(where("_id").is(p7.get_id())), PersonWith_idPropertyOfTypeObjectId.class); + assertThat(p7q, notNullValue()); + assertThat(p7q.get_id(), is(p7.get_id())); + + PersonWith_idPropertyOfTypeObjectId p8 = new PersonWith_idPropertyOfTypeObjectId(); + p8.setFirstName("Sven_8"); + p8.setAge(22); + p8.set_id(new ObjectId()); + template.insert(p8); + assertThat(p8.get_id(), notNullValue()); + PersonWith_idPropertyOfTypeObjectId p8q = template.findOne(new Query(where("_id").is(p8.get_id())), PersonWith_idPropertyOfTypeObjectId.class); + assertThat(p8q, notNullValue()); + assertThat(p8q.get_id(), is(p8.get_id())); + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/MongoTemplateUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/MongoTemplateUnitTests.java index d0802ea48..e3c0e0ba1 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/MongoTemplateUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/MongoTemplateUnitTests.java @@ -15,9 +15,12 @@ */ package org.springframework.data.document.mongodb; -import static org.junit.Assert.*; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.*; +import com.mongodb.DB; +import com.mongodb.Mongo; +import com.mongodb.MongoException; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -27,83 +30,79 @@ import org.springframework.dao.DataAccessException; import org.springframework.data.document.mongodb.convert.SimpleMongoConverter; import org.springframework.test.util.ReflectionTestUtils; -import com.mongodb.DB; -import com.mongodb.Mongo; -import com.mongodb.MongoException; - /** * Unit tests for {@link MongoTemplate}. - * + * * @author Oliver Gierke */ @RunWith(MockitoJUnitRunner.class) public class MongoTemplateUnitTests extends MongoOperationsUnitTests { - MongoTemplate template; + MongoTemplate template; - @Mock - Mongo mongo; + @Mock + Mongo mongo; - @Mock - DB db; + @Mock + DB db; - @Before - public void setUp() { - this.template = new MongoTemplate(mongo, "database", "default"); - } + @Before + public void setUp() { + this.template = new MongoTemplate(mongo, "database", "default"); + } - @Test(expected = IllegalArgumentException.class) - public void rejectsNullDatabaseName() throws Exception { - new MongoTemplate(mongo, null); - } + @Test(expected = IllegalArgumentException.class) + public void rejectsNullDatabaseName() throws Exception { + new MongoTemplate(mongo, null); + } - @Test(expected = IllegalArgumentException.class) - public void rejectsNullMongo() throws Exception { - new MongoTemplate(null, "database"); - } + @Test(expected = IllegalArgumentException.class) + public void rejectsNullMongo() throws Exception { + new MongoTemplate(null, "database"); + } - @Test(expected = DataAccessException.class) - public void removeHandlesMongoExceptionProperly() throws Exception { - MongoTemplate template = mockOutGetDb(); - when(db.getCollection("collection")).thenThrow(new MongoException("Exception!")); + @Test(expected = DataAccessException.class) + public void removeHandlesMongoExceptionProperly() throws Exception { + MongoTemplate template = mockOutGetDb(); + when(db.getCollection("collection")).thenThrow(new MongoException("Exception!")); - template.remove("collection", null); - } + template.remove("collection", null); + } - @Test - public void defaultsConverterToSimpleMongoConverter() throws Exception { - MongoTemplate template = new MongoTemplate(mongo, "database"); - assertTrue(ReflectionTestUtils.getField(template, "mongoConverter") instanceof SimpleMongoConverter); - } + @Test + public void defaultsConverterToSimpleMongoConverter() throws Exception { + MongoTemplate template = new MongoTemplate(mongo, "database"); + assertTrue(ReflectionTestUtils.getField(template, "mongoConverter") instanceof SimpleMongoConverter); + } - /** - * Mocks out the {@link MongoTemplate#getDb()} method to return the {@link DB} mock instead of executing the actual - * behaviour. - * - * @return - */ - private MongoTemplate mockOutGetDb() { + /** + * Mocks out the {@link MongoTemplate#getDb()} method to return the {@link DB} mock instead of executing the actual + * behaviour. + * + * @return + */ + private MongoTemplate mockOutGetDb() { - MongoTemplate template = spy(this.template); - stub(template.getDb()).toReturn(db); - return template; - } + MongoTemplate template = spy(this.template); + stub(template.getDb()).toReturn(db); + return template; + } - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperationsUnitTests#getOperations() - */ - @Override - protected MongoOperations getOperationsForExceptionHandling() { - MongoTemplate template = spy(this.template); - stub(template.getDb()).toThrow(new MongoException("Error!")); - return template; - } - - /* (non-Javadoc) - * @see org.springframework.data.document.mongodb.MongoOperationsUnitTests#getOperations() - */ - @Override - protected MongoOperations getOperations() { - return this.template; - } + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperationsUnitTests#getOperations() + */ + @Override + protected MongoOperations getOperationsForExceptionHandling() { + MongoTemplate template = spy(this.template); + stub(template.getDb()).toThrow(new MongoException("Error!")); + return template; + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoOperationsUnitTests#getOperations() + */ + @Override + protected MongoOperations getOperations() { + return this.template; + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/Person.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/Person.java index 78bddbef2..5fccae20d 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/Person.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/Person.java @@ -19,86 +19,86 @@ import org.bson.types.ObjectId; public class Person { - private final ObjectId id; - - private String firstName; + private final ObjectId id; - private int age; - - private Person friend; - - public Person() { - this.id = new ObjectId(); - } - - public Person(ObjectId id, String firstname) { - this.id = id; - this.firstName = firstname; - } - - public Person(String firstname) { - this(); - this.firstName = firstname; - } + private String firstName; - public ObjectId getId() { - return id; - } - - public String getFirstName() { - return firstName; - } + private int age; - public void setFirstName(String firstName) { - this.firstName = firstName; - } + private Person friend; - public int getAge() { - return age; - } + public Person() { + this.id = new ObjectId(); + } - public void setAge(int age) { - this.age = age; - } + public Person(ObjectId id, String firstname) { + this.id = id; + this.firstName = firstname; + } - public Person getFriend() { - return friend; - } + public Person(String firstname) { + this(); + this.firstName = firstname; + } - public void setFriend(Person friend) { - this.friend = friend; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object obj) { - if (obj == this) { - return true; - } + public ObjectId getId() { + return id; + } - if (obj == null) { - return false; - } + public String getFirstName() { + return firstName; + } - if (!(getClass().equals(obj.getClass()))) { - return false; - } + public void setFirstName(String firstName) { + this.firstName = firstName; + } - Person that = (Person) obj; + public int getAge() { + return age; + } - return this.id == null ? false : this.id.equals(that.id); - } - - - /* (non-Javadoc) - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - return id.hashCode(); - } + public void setAge(int age) { + this.age = age; + } + + public Person getFriend() { + return friend; + } + + public void setFriend(Person friend) { + this.friend = friend; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + + if (obj == null) { + return false; + } + + if (!(getClass().equals(obj.getClass()))) { + return false; + } + + Person that = (Person) obj; + + return this.id == null ? false : this.id.equals(that.id); + } + + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return id.hashCode(); + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/PersonWithIdPropertyOfTypeObjectId.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/PersonWithIdPropertyOfTypeObjectId.java index 90b7b85bd..af89dc68e 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/PersonWithIdPropertyOfTypeObjectId.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/PersonWithIdPropertyOfTypeObjectId.java @@ -19,34 +19,34 @@ import org.bson.types.ObjectId; public class PersonWithIdPropertyOfTypeObjectId { - private ObjectId id; - - private String firstName; + private ObjectId id; - private int age; + private String firstName; - public ObjectId getId() { - return id; - } + private int age; - public void setId(ObjectId id) { - this.id = id; - } + public ObjectId getId() { + return id; + } - public String getFirstName() { - return firstName; - } + public void setId(ObjectId id) { + this.id = id; + } - public void setFirstName(String firstName) { - this.firstName = firstName; - } + public String getFirstName() { + return firstName; + } - public int getAge() { - return age; - } + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } - public void setAge(int age) { - this.age = age; - } - } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/PersonWithIdPropertyOfTypeString.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/PersonWithIdPropertyOfTypeString.java index f69db5aed..ef4739449 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/PersonWithIdPropertyOfTypeString.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/PersonWithIdPropertyOfTypeString.java @@ -18,34 +18,34 @@ package org.springframework.data.document.mongodb; public class PersonWithIdPropertyOfTypeString { - private String id; - - private String firstName; + private String id; - private int age; + private String firstName; - public String getId() { - return id; - } + private int age; - public void setId(String id) { - this.id = id; - } + public String getId() { + return id; + } - public String getFirstName() { - return firstName; - } + public void setId(String id) { + this.id = id; + } - public void setFirstName(String firstName) { - this.firstName = firstName; - } + public String getFirstName() { + return firstName; + } - public int getAge() { - return age; - } + public void setFirstName(String firstName) { + this.firstName = firstName; + } - public void setAge(int age) { - this.age = age; - } + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/PersonWith_idPropertyOfTypeObjectId.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/PersonWith_idPropertyOfTypeObjectId.java index c8d9d2db6..0e72f2e4b 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/PersonWith_idPropertyOfTypeObjectId.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/PersonWith_idPropertyOfTypeObjectId.java @@ -19,34 +19,34 @@ import org.bson.types.ObjectId; public class PersonWith_idPropertyOfTypeObjectId { - private ObjectId _id; - - private String firstName; + private ObjectId _id; - private int age; + private String firstName; - public ObjectId get_id() { - return _id; - } + private int age; - public void set_id(ObjectId _id) { - this._id = _id; - } + public ObjectId get_id() { + return _id; + } - public String getFirstName() { - return firstName; - } + public void set_id(ObjectId _id) { + this._id = _id; + } - public void setFirstName(String firstName) { - this.firstName = firstName; - } + public String getFirstName() { + return firstName; + } - public int getAge() { - return age; - } + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } - public void setAge(int age) { - this.age = age; - } - } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/PersonWith_idPropertyOfTypeString.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/PersonWith_idPropertyOfTypeString.java index b5ab8c8ff..b1e2fa6dc 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/PersonWith_idPropertyOfTypeString.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/PersonWith_idPropertyOfTypeString.java @@ -18,34 +18,34 @@ package org.springframework.data.document.mongodb; public class PersonWith_idPropertyOfTypeString { - private String _id; - - private String firstName; + private String _id; - private int age; + private String firstName; - public String get_id() { - return _id; - } + private int age; - public void set_id(String _id) { - this._id = _id; - } + public String get_id() { + return _id; + } - public String getFirstName() { - return firstName; - } + public void set_id(String _id) { + this._id = _id; + } - public void setFirstName(String firstName) { - this.firstName = firstName; - } + public String getFirstName() { + return firstName; + } - public int getAge() { - return age; - } + public void setFirstName(String firstName) { + this.firstName = firstName; + } - public void setAge(int age) { - this.age = age; - } + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/Portfolio.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/Portfolio.java index f958eb201..4d8ec3e43 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/Portfolio.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/Portfolio.java @@ -21,43 +21,53 @@ import java.util.Map; public class Portfolio { - private String portfolioName; - private User user; - private List trades; - private Map positions; - private Map portfolioManagers; - - public Map getPortfolioManagers() { - return portfolioManagers; - } - public void setPortfolioManagers(Map portfolioManagers) { - this.portfolioManagers = portfolioManagers; - } - public Map getPositions() { - return positions; - } - public void setPositions(Map positions) { - this.positions = positions; - } - public Portfolio() { - trades = new ArrayList(); - } - public String getPortfolioName() { - return portfolioName; - } - public void setPortfolioName(String portfolioName) { - this.portfolioName = portfolioName; - } - public List getTrades() { - return trades; - } - public void setTrades(List trades) { - this.trades = trades; - } - public User getUser() { - return user; - } - public void setUser(User user) { - this.user = user; - } + private String portfolioName; + private User user; + private List trades; + private Map positions; + private Map portfolioManagers; + + public Map getPortfolioManagers() { + return portfolioManagers; + } + + public void setPortfolioManagers(Map portfolioManagers) { + this.portfolioManagers = portfolioManagers; + } + + public Map getPositions() { + return positions; + } + + public void setPositions(Map positions) { + this.positions = positions; + } + + public Portfolio() { + trades = new ArrayList(); + } + + public String getPortfolioName() { + return portfolioName; + } + + public void setPortfolioName(String portfolioName) { + this.portfolioName = portfolioName; + } + + public List getTrades() { + return trades; + } + + public void setTrades(List trades) { + this.trades = trades; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/SimpleMongoConverterTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/SimpleMongoConverterTests.java index 60f4e7db1..892f1b3e5 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/SimpleMongoConverterTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/SimpleMongoConverterTests.java @@ -15,6 +15,16 @@ */ package org.springframework.data.document.mongodb; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +import java.lang.reflect.Field; +import java.math.BigInteger; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import com.mongodb.BasicDBObject; import com.mongodb.DBObject; import com.mongodb.util.JSON; @@ -25,16 +35,6 @@ import org.springframework.data.document.mongodb.SomeEnumTest.StringEnum; import org.springframework.data.document.mongodb.convert.SimpleMongoConverter; import org.springframework.util.ReflectionUtils; -import java.lang.reflect.Field; -import java.math.BigInteger; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; - public class SimpleMongoConverterTests { static final String SIMPLE_JSON = "{ \"map\" : { \"foo\" : 3 , \"bar\" : 4}, \"number\" : 15 }"; diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/SomeEnumTest.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/SomeEnumTest.java index c2a8b03fb..3a9e0a8c5 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/SomeEnumTest.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/SomeEnumTest.java @@ -1,64 +1,64 @@ package org.springframework.data.document.mongodb; public class SomeEnumTest { - - public enum StringEnum { - ONE, TWO, FIVE; - } - public enum NumberEnum { - ONE (1), TWO (2), FIVE(5); + public enum StringEnum { + ONE, TWO, FIVE; + } - private int value; + public enum NumberEnum { + ONE(1), TWO(2), FIVE(5); - public int value() { - return value; - } + private int value; - NumberEnum(int value) { - this.value = value; - } + public int value() { + return value; + } - } - - private StringEnum stringEnum; - - private NumberEnum numberEnum; - - private String id; - - private String name; + NumberEnum(int value) { + this.value = value; + } - public StringEnum getStringEnum() { - return stringEnum; - } + } - public void setStringEnum(StringEnum stringEnum) { - this.stringEnum = stringEnum; - } + private StringEnum stringEnum; - public NumberEnum getNumberEnum() { - return numberEnum; - } + private NumberEnum numberEnum; - public void setNumberEnum(NumberEnum numberEnum) { - this.numberEnum = numberEnum; - } + private String id; - public String getId() { - return id; - } + private String name; - public void setId(String id) { - this.id = id; - } + public StringEnum getStringEnum() { + return stringEnum; + } - public String getName() { - return name; - } + public void setStringEnum(StringEnum stringEnum) { + this.stringEnum = stringEnum; + } + + public NumberEnum getNumberEnum() { + return numberEnum; + } + + public void setNumberEnum(NumberEnum numberEnum) { + this.numberEnum = numberEnum; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } - public void setName(String name) { - this.name = name; - } - } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/Trade.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/Trade.java index c7a620c8c..e8ef3a79a 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/Trade.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/Trade.java @@ -17,46 +17,45 @@ package org.springframework.data.document.mongodb; public class Trade { - private String ticker; + private String ticker; - private long quantity; + private long quantity; - private double price; + private double price; - private String orderType; + private String orderType; - public String getOrderType() { - return orderType; - } + public String getOrderType() { + return orderType; + } - public void setOrderType(String orderType) { - this.orderType = orderType; - } + public void setOrderType(String orderType) { + this.orderType = orderType; + } - public double getPrice() { - return price; - } + public double getPrice() { + return price; + } - public void setPrice(double price) { - this.price = price; - } + public void setPrice(double price) { + this.price = price; + } - public long getQuantity() { - return quantity; - } + public long getQuantity() { + return quantity; + } - public void setQuantity(long quantity) { - this.quantity = quantity; - } + public void setQuantity(long quantity) { + this.quantity = quantity; + } + + public String getTicker() { + return ticker; + } + + public void setTicker(String ticker) { + this.ticker = ticker; + } - public String getTicker() { - return ticker; - } - public void setTicker(String ticker) { - this.ticker = ticker; - } - - - } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/TradeBatch.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/TradeBatch.java index 979141200..2cb443bab 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/TradeBatch.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/TradeBatch.java @@ -3,36 +3,36 @@ package org.springframework.data.document.mongodb; import java.util.List; public class TradeBatch { - - private String batchId; - - private Trade[] trades; - - private List tradeList; - - public String getBatchId() { - return batchId; - } + private String batchId; - public void setBatchId(String batchId) { - this.batchId = batchId; - } + private Trade[] trades; - public Trade[] getTrades() { - return trades; - } + private List tradeList; - public void setTrades(Trade[] trades) { - this.trades = trades; - } - public List getTradeList() { - return tradeList; - } + public String getBatchId() { + return batchId; + } - public void setTradeList(List tradeList) { - this.tradeList = tradeList; - } + public void setBatchId(String batchId) { + this.batchId = batchId; + } + + public Trade[] getTrades() { + return trades; + } + + public void setTrades(Trade[] trades) { + this.trades = trades; + } + + public List getTradeList() { + return tradeList; + } + + public void setTradeList(List tradeList) { + this.tradeList = tradeList; + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/User.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/User.java index 47bfb2c96..23d5b1c74 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/User.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/User.java @@ -17,58 +17,58 @@ package org.springframework.data.document.mongodb; public class User { - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result - + ((accountName == null) ? 0 : accountName.hashCode()); - result = prime * result - + ((userName == null) ? 0 : userName.hashCode()); - return result; - } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((accountName == null) ? 0 : accountName.hashCode()); + result = prime * result + + ((userName == null) ? 0 : userName.hashCode()); + return result; + } - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - User other = (User) obj; - if (accountName == null) { - if (other.accountName != null) - return false; - } else if (!accountName.equals(other.accountName)) - return false; - if (userName == null) { - if (other.userName != null) - return false; - } else if (!userName.equals(other.userName)) - return false; - return true; - } + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + User other = (User) obj; + if (accountName == null) { + if (other.accountName != null) + return false; + } else if (!accountName.equals(other.accountName)) + return false; + if (userName == null) { + if (other.userName != null) + return false; + } else if (!userName.equals(other.userName)) + return false; + return true; + } - private String accountName; + private String accountName; - private String userName; + private String userName; - public String getAccountName() { - return accountName; - } + public String getAccountName() { + return accountName; + } - public void setAccountName(String accountName) { - this.accountName = accountName; - } + public void setAccountName(String accountName) { + this.accountName = accountName; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } - public String getUserName() { - return userName; - } - public void setUserName(String userName) { - this.userName = userName; - } - - } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/analytics/MvcAnalyticsTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/analytics/MvcAnalyticsTests.java index b2863a503..31ee8f24d 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/analytics/MvcAnalyticsTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/analytics/MvcAnalyticsTests.java @@ -4,6 +4,7 @@ import java.util.Calendar; import java.util.Date; import java.util.List; +import com.mongodb.*; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -14,223 +15,215 @@ import org.springframework.data.document.mongodb.MongoReader; import org.springframework.data.document.mongodb.MongoTemplate; import org.springframework.data.document.mongodb.query.BasicQuery; -import com.mongodb.BasicDBList; -import com.mongodb.BasicDBObject; -import com.mongodb.DBCollection; -import com.mongodb.DBObject; -import com.mongodb.Mongo; -import com.mongodb.QueryBuilder; -import com.mongodb.WriteResult; - public class MvcAnalyticsTests { - private MongoTemplate mongoTemplate; + private MongoTemplate mongoTemplate; - @Before - public void setUp() throws Exception { - Mongo m = new Mongo(); - mongoTemplate = new MongoTemplate(m, "mvc", "mvc"); - mongoTemplate.afterPropertiesSet(); - - - } - - @Test - public void clean() { - mongoTemplate.dropCollection("mvc"); - mongoTemplate.createCollection("mvc"); - mongoTemplate.dropCollection("counters"); - mongoTemplate.createCollection("counters"); - } + @Before + public void setUp() throws Exception { + Mongo m = new Mongo(); + mongoTemplate = new MongoTemplate(m, "mvc", "mvc"); + mongoTemplate.afterPropertiesSet(); - @Test - public void loadMvcEventData() { - mongoTemplate.dropCollection("mvc"); - mongoTemplate.createCollection("mvc"); - // datasize, favoriteRestId - createAndStoreMvcEvent(5, 1); - createAndStoreMvcEvent(6, 2); - createAndStoreMvcEvent(3, 3); - createAndStoreMvcEvent(8, 4); + } - List mvcEvents = mongoTemplate.getCollection("mvc", - MvcEvent.class); - Assert.assertEquals(22, mvcEvents.size()); - - mongoTemplate.getCollection("mvc", MvcEvent.class, - new MongoReader() { - public S read(Class clazz, DBObject dbo) { - return null; - } - }); + @Test + public void clean() { + mongoTemplate.dropCollection("mvc"); + mongoTemplate.createCollection("mvc"); + mongoTemplate.dropCollection("counters"); + mongoTemplate.createCollection("counters"); + } - } - - @Test - public void loadCounterData() { - for (int i = 0; i < 10; i++) { - storeCounterData("SignUpController", "createForm"); - storeCounterData("SignUpController", "create"); - storeCounterData("SignUpController", "show"); - storeCounterData("RestaurantController", "addFavoriteRestaurant"); - } - for (int i = 0; i< 5;i++) { - storeCounterData("RestaurantController", "list"); - storeCounterData("SignUpController", "show"); - } - - - } - - @Test - public void queryCounterData() { - DBObject query = QueryBuilder.start("name").is("SignUpController").get(); - for (DBObject dbo : mongoTemplate.getCollection("counters").find(query)) { - System.out.println(dbo); - } - List counters = mongoTemplate.find("counters", new BasicQuery("{ 'name' : 'SignUpController'} "), ControllerCounter.class); - for (ControllerCounter controllerCounter : counters) { - System.out.println(controllerCounter); - } - } - - /* - * - * var start = new Date(2010,9,1); var end = new Date(2010,11,1); - * db.mvc.group( { cond: {"action": "addFavoriteRestaurant", "date": {$gte: - * start, $lt: end}} , key: {"parameters.p1": true} , initial: {count: 0} , - * reduce: function(doc, out){ out.count++; } } ); - */ + @Test + public void loadMvcEventData() { - @Test - public void listAllMvcEvents() { - List mvcEvents = mongoTemplate.getCollection("mvc", - MvcEvent.class); - for (MvcEvent mvcEvent : mvcEvents) { - System.out.println(mvcEvent.getDate()); - } - } + mongoTemplate.dropCollection("mvc"); + mongoTemplate.createCollection("mvc"); + // datasize, favoriteRestId + createAndStoreMvcEvent(5, 1); + createAndStoreMvcEvent(6, 2); + createAndStoreMvcEvent(3, 3); + createAndStoreMvcEvent(8, 4); - @Test - public void groupQuery() { - // This circumvents exception translation - DBCollection collection = mongoTemplate.getDb().getCollection( - "mvc"); + List mvcEvents = mongoTemplate.getCollection("mvc", + MvcEvent.class); + Assert.assertEquals(22, mvcEvents.size()); - // QueryBuilder qb = new QueryBuilder(); - // qb.start("date").greaterThan(object) - Calendar startDate = Calendar.getInstance(); - startDate.clear(); - startDate.set(Calendar.YEAR, 2010); - startDate.set(Calendar.MONTH, 5); - Calendar endDate = Calendar.getInstance(); - endDate.clear(); - endDate.set(Calendar.YEAR, 2010); - endDate.set(Calendar.MONTH, 12); + mongoTemplate.getCollection("mvc", MvcEvent.class, + new MongoReader() { + public S read(Class clazz, DBObject dbo) { + return null; + } + }); - /* - * QueryBuilder qb = new QueryBuilder(); Query q = - * qb.find("date").gte(startDate - * .getTime()).lt(endDate.getTime()).and("action" - * ).is("addFavoriteRestaurant").build(); DBObject cond2 = - * q.getQueryObject(); - */ - DBObject cond = QueryBuilder.start("date") - .greaterThanEquals(startDate.getTime()) - .lessThan(endDate.getTime()).and("action") - .is("addFavoriteRestaurant").get(); - DBObject key = new BasicDBObject("parameters.p1", true); - /* - * DBObject dateQ = new BasicDBObject(); dateQ.put("$gte", - * startDate.getTime()); dateQ.put("$lt", endDate.getTime()); DBObject - * cond = new BasicDBObject(); cond.put("action", - * "addFavoriteRestaurant"); cond.put("date", dateQ); - */ + } - DBObject intitial = new BasicDBObject("count", 0); - DBObject result = collection.group(key, cond, intitial, - "function(doc, out){ out.count++; }"); - if (result instanceof BasicDBList) { - BasicDBList dbList = (BasicDBList) result; - for (Object element : dbList) { - DBObject dbo = (DBObject) element; - System.out.println(dbo); - } - } - System.out.println(result); - } + @Test + public void loadCounterData() { + for (int i = 0; i < 10; i++) { + storeCounterData("SignUpController", "createForm"); + storeCounterData("SignUpController", "create"); + storeCounterData("SignUpController", "show"); + storeCounterData("RestaurantController", "addFavoriteRestaurant"); + } + for (int i = 0; i < 5; i++) { + storeCounterData("RestaurantController", "list"); + storeCounterData("SignUpController", "show"); + } - @Test - public void storeControllerCounterInfo() { - BasicDBObject query = new BasicDBObject("name", "controller1"); - - BasicDBObject changes = new BasicDBObject(); - changes.put("$set", new BasicDBObject("name", "controller1")); - changes.put("$inc", new BasicDBObject("count", 1)); - - //mongoTemplate.upsertAndModify(dbo("key","value"), inc("count",1)); - //dbo(set("name","controller"), inc("count", 1)); - - ///mongoTemplate.update(collection("counters") - - WriteResult r = mongoTemplate.getCollection("counters").update(query, changes, true,false); - //{ "err" : "Modifiers and non-modifiers cannot be mixed" , "code" : 10154 , "n" : 0 , "ok" : 1.0} - //{ "err" : null , "updatedExisting" : false , "upserted" : { "$oid" : "4cba814a5a4900000000495d"} , "n" : 1 , "ok" : 1.0} - //{ "err" : null , "updatedExisting" : true , "n" : 1 , "ok" : 1.0} - System.out.println(r); + } - // changes = new BasicDBObject("methods", new BasicDBObject("find", 1)); - // mongoTemplate.getCollection("counters").update(query, changes, true, - // false); - } + @Test + public void queryCounterData() { + DBObject query = QueryBuilder.start("name").is("SignUpController").get(); + for (DBObject dbo : mongoTemplate.getCollection("counters").find(query)) { + System.out.println(dbo); + } + List counters = mongoTemplate.find("counters", new BasicQuery("{ 'name' : 'SignUpController'} "), ControllerCounter.class); + for (ControllerCounter controllerCounter : counters) { + System.out.println(controllerCounter); + } + } - @Test - public void updateMethodCounter() { - DBObject query = new BasicDBObject("name", "controller1"); - DBObject changes = new BasicDBObject("$inc", new BasicDBObject("methods.find", 1)); - mongoTemplate.getDb().getCollection("counters").update(query, changes, true, false); - } - - - public void storeCounterData(String controllerName, String methodName) { - BasicDBObject query = new BasicDBObject("name", controllerName); - - BasicDBObject changes = new BasicDBObject(); - changes.put("$set", new BasicDBObject("name", controllerName)); - changes.put("$inc", new BasicDBObject("count", 1)); - - WriteResult r = mongoTemplate.getCollection("counters").update(query, changes, true,false); - System.out.println(r); - - changes = new BasicDBObject("$inc", new BasicDBObject("methods." + methodName, 1)); - r = mongoTemplate.getDb().getCollection("counters").update(query, changes, true, false); - System.out.println(r); - } + /* + * + * var start = new Date(2010,9,1); var end = new Date(2010,11,1); + * db.mvc.group( { cond: {"action": "addFavoriteRestaurant", "date": {$gte: + * start, $lt: end}} , key: {"parameters.p1": true} , initial: {count: 0} , + * reduce: function(doc, out){ out.count++; } } ); + */ - private void createAndStoreMvcEvent(int dataSize, int p1) { - for (int i = 0; i < dataSize; i++) { - MvcEvent event = generateEvent(p1); - mongoTemplate.save(event); - } - } + @Test + public void listAllMvcEvents() { + List mvcEvents = mongoTemplate.getCollection("mvc", + MvcEvent.class); + for (MvcEvent mvcEvent : mvcEvents) { + System.out.println(mvcEvent.getDate()); + } + } - private MvcEvent generateEvent(Integer p1) { - MvcEvent event = new MvcEvent(); + @Test + public void groupQuery() { + // This circumvents exception translation + DBCollection collection = mongoTemplate.getDb().getCollection( + "mvc"); - event.setController("RestaurantController"); - event.setAction("addFavoriteRestaurant"); - event.setDate(new Date()); - event.setRemoteUser("mpollack"); - event.setRequestAddress("127.0.0.1"); - event.setRequestUri("/myrestaurants-analytics/restaurants"); - Parameters params = new Parameters(); - params.setP1(p1.toString()); - params.setP2("2"); - event.setParameters(params); + // QueryBuilder qb = new QueryBuilder(); + // qb.start("date").greaterThan(object) + Calendar startDate = Calendar.getInstance(); + startDate.clear(); + startDate.set(Calendar.YEAR, 2010); + startDate.set(Calendar.MONTH, 5); + Calendar endDate = Calendar.getInstance(); + endDate.clear(); + endDate.set(Calendar.YEAR, 2010); + endDate.set(Calendar.MONTH, 12); - return event; - } + /* + * QueryBuilder qb = new QueryBuilder(); Query q = + * qb.find("date").gte(startDate + * .getTime()).lt(endDate.getTime()).and("action" + * ).is("addFavoriteRestaurant").build(); DBObject cond2 = + * q.getQueryObject(); + */ + DBObject cond = QueryBuilder.start("date") + .greaterThanEquals(startDate.getTime()) + .lessThan(endDate.getTime()).and("action") + .is("addFavoriteRestaurant").get(); + DBObject key = new BasicDBObject("parameters.p1", true); + /* + * DBObject dateQ = new BasicDBObject(); dateQ.put("$gte", + * startDate.getTime()); dateQ.put("$lt", endDate.getTime()); DBObject + * cond = new BasicDBObject(); cond.put("action", + * "addFavoriteRestaurant"); cond.put("date", dateQ); + */ + + DBObject intitial = new BasicDBObject("count", 0); + DBObject result = collection.group(key, cond, intitial, + "function(doc, out){ out.count++; }"); + if (result instanceof BasicDBList) { + BasicDBList dbList = (BasicDBList) result; + for (Object element : dbList) { + DBObject dbo = (DBObject) element; + System.out.println(dbo); + } + } + System.out.println(result); + } + + @Test + public void storeControllerCounterInfo() { + + BasicDBObject query = new BasicDBObject("name", "controller1"); + + BasicDBObject changes = new BasicDBObject(); + changes.put("$set", new BasicDBObject("name", "controller1")); + changes.put("$inc", new BasicDBObject("count", 1)); + + //mongoTemplate.upsertAndModify(dbo("key","value"), inc("count",1)); + //dbo(set("name","controller"), inc("count", 1)); + + ///mongoTemplate.update(collection("counters") + + WriteResult r = mongoTemplate.getCollection("counters").update(query, changes, true, false); + //{ "err" : "Modifiers and non-modifiers cannot be mixed" , "code" : 10154 , "n" : 0 , "ok" : 1.0} + //{ "err" : null , "updatedExisting" : false , "upserted" : { "$oid" : "4cba814a5a4900000000495d"} , "n" : 1 , "ok" : 1.0} + //{ "err" : null , "updatedExisting" : true , "n" : 1 , "ok" : 1.0} + System.out.println(r); + + // changes = new BasicDBObject("methods", new BasicDBObject("find", 1)); + // mongoTemplate.getCollection("counters").update(query, changes, true, + // false); + } + + @Test + public void updateMethodCounter() { + DBObject query = new BasicDBObject("name", "controller1"); + DBObject changes = new BasicDBObject("$inc", new BasicDBObject("methods.find", 1)); + mongoTemplate.getDb().getCollection("counters").update(query, changes, true, false); + } + + + public void storeCounterData(String controllerName, String methodName) { + BasicDBObject query = new BasicDBObject("name", controllerName); + + BasicDBObject changes = new BasicDBObject(); + changes.put("$set", new BasicDBObject("name", controllerName)); + changes.put("$inc", new BasicDBObject("count", 1)); + + WriteResult r = mongoTemplate.getCollection("counters").update(query, changes, true, false); + System.out.println(r); + + changes = new BasicDBObject("$inc", new BasicDBObject("methods." + methodName, 1)); + r = mongoTemplate.getDb().getCollection("counters").update(query, changes, true, false); + System.out.println(r); + } + + private void createAndStoreMvcEvent(int dataSize, int p1) { + for (int i = 0; i < dataSize; i++) { + MvcEvent event = generateEvent(p1); + mongoTemplate.save(event); + } + } + + private MvcEvent generateEvent(Integer p1) { + MvcEvent event = new MvcEvent(); + + event.setController("RestaurantController"); + event.setAction("addFavoriteRestaurant"); + event.setDate(new Date()); + event.setRemoteUser("mpollack"); + event.setRequestAddress("127.0.0.1"); + event.setRequestUri("/myrestaurants-analytics/restaurants"); + Parameters params = new Parameters(); + params.setP1(p1.toString()); + params.setP2("2"); + event.setParameters(params); + + return event; + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/config/MongoNamespaceTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/config/MongoNamespaceTests.java index 0e09c7e7e..aa642b41b 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/config/MongoNamespaceTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/config/MongoNamespaceTests.java @@ -16,9 +16,7 @@ package org.springframework.data.document.mongodb.config; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import java.lang.reflect.Field; @@ -34,47 +32,45 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @ContextConfiguration public class MongoNamespaceTests { - @Autowired - private ApplicationContext ctx; - - + @Autowired + private ApplicationContext ctx; - public void testMongoSingleton() throws Exception { - assertTrue(ctx.containsBean("mongo")); - MongoFactoryBean mfb = (MongoFactoryBean) ctx.getBean("&mongo"); - assertNull(readField("host", mfb)); - assertNull(readField("port", mfb)); - } - - @Test - public void testMongoSingletonWithAttributes() throws Exception { - assertTrue(ctx.containsBean("defaultMongo")); - MongoFactoryBean mfb = (MongoFactoryBean) ctx.getBean("&defaultMongo"); - String host = readField("host", mfb); - Integer port = readField("port", mfb); - assertEquals("localhost", host); - assertEquals(new Integer(27017), port); - } - - - - @SuppressWarnings({"unchecked"}) + + public void testMongoSingleton() throws Exception { + assertTrue(ctx.containsBean("mongo")); + MongoFactoryBean mfb = (MongoFactoryBean) ctx.getBean("&mongo"); + assertNull(readField("host", mfb)); + assertNull(readField("port", mfb)); + } + + @Test + public void testMongoSingletonWithAttributes() throws Exception { + assertTrue(ctx.containsBean("defaultMongo")); + MongoFactoryBean mfb = (MongoFactoryBean) ctx.getBean("&defaultMongo"); + String host = readField("host", mfb); + Integer port = readField("port", mfb); + assertEquals("localhost", host); + assertEquals(new Integer(27017), port); + } + + + @SuppressWarnings({"unchecked"}) public static T readField(String name, Object target) throws Exception { - Field field = null; - Class clazz = target.getClass(); - do { - try { - field = clazz.getDeclaredField(name); - } catch (Exception ex) { - } + Field field = null; + Class clazz = target.getClass(); + do { + try { + field = clazz.getDeclaredField(name); + } catch (Exception ex) { + } - clazz = clazz.getSuperclass(); - } while (field == null && !clazz.equals(Object.class)); + clazz = clazz.getSuperclass(); + } while (field == null && !clazz.equals(Object.class)); - if (field == null) - throw new IllegalArgumentException("Cannot find field '" + name + "' in the class hierarchy of " - + target.getClass()); - field.setAccessible(true); - return (T) field.get(target); - } + if (field == null) + throw new IllegalArgumentException("Cannot find field '" + name + "' in the class hierarchy of " + + target.getClass()); + field.setAccessible(true); + return (T) field.get(target); + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/GenericMappingTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/GenericMappingTests.java index a74a81e37..db1faac24 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/GenericMappingTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/GenericMappingTests.java @@ -1,8 +1,12 @@ package org.springframework.data.document.mongodb.mapping; -import static org.hamcrest.CoreMatchers.*; -import static org.junit.Assert.*; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import com.mongodb.BasicDBObject; +import com.mongodb.DBObject; import org.junit.Before; import org.junit.Test; import org.springframework.data.document.mongodb.convert.MappingMongoConverter; @@ -10,9 +14,6 @@ import org.springframework.data.document.mongodb.convert.MongoConverter; import org.springframework.data.mapping.BasicMappingContext; import org.springframework.data.mapping.model.MappingContext; -import com.mongodb.BasicDBObject; -import com.mongodb.DBObject; - /** * Unit tests for testing the mapping works with generic types. * @@ -29,47 +30,47 @@ public class GenericMappingTests { context.addPersistentEntity(StringWrapper.class); converter = new MappingMongoConverter(context); } - + @Test public void writesGenericTypeCorrectly() { - + StringWrapper wrapper = new StringWrapper(); wrapper.container = new Container(); wrapper.container.content = "Foo!"; - + context.addPersistentEntity(StringWrapper.class); - + DBObject dbObject = new BasicDBObject(); converter.write(wrapper, dbObject); - + Object container = dbObject.get("container"); assertThat(container, is(notNullValue())); assertTrue(container instanceof DBObject); - + Object content = ((DBObject) container).get("content"); assertTrue(content instanceof String); assertThat((String) content, is("Foo!")); } - + @Test public void readsGenericTypeCorrectly() { - + DBObject content = new BasicDBObject("content", "Foo!"); BasicDBObject container = new BasicDBObject("container", content); - + StringWrapper result = converter.read(StringWrapper.class, container); assertThat(result.container, is(notNullValue())); assertThat(result.container.content, is("Foo!")); } - + public class StringWrapper extends Wrapper { - + } - + public class Wrapper { Container container; } - + public class Container { T content; } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/MappingTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/MappingTests.java index f2d3489b6..65aefd909 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/MappingTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/MappingTests.java @@ -16,6 +16,15 @@ package org.springframework.data.document.mongodb.mapping; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import com.mongodb.BasicDBObject; import com.mongodb.DBObject; import org.junit.Test; @@ -29,16 +38,6 @@ import org.springframework.data.mapping.BasicMappingContext; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static org.hamcrest.CoreMatchers.*; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertEquals; - /** * @author Jon Brisbin */ @@ -109,7 +108,7 @@ public class MappingTests { assertNotNull(p.getId()); List result = template.find(new Query(Criteria.where("ssn").is(1234567)), PersonMapProperty.class); - //assertThat(result.size(), is(1)); + assertThat(result.size(), is(1)); assertThat(result.get(0).getAccounts().size(), is(2)); assertThat(result.get(0).getAccounts().get("checking").getBalance(), is(1000.0f)); } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/Person.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/Person.java index c40cafe5f..68a16c776 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/Person.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/Person.java @@ -16,6 +16,8 @@ package org.springframework.data.document.mongodb.mapping; +import java.util.List; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.annotation.Id; import org.springframework.data.annotation.PersistenceConstructor; @@ -25,8 +27,6 @@ import org.springframework.data.document.mongodb.index.CompoundIndex; import org.springframework.data.document.mongodb.index.CompoundIndexes; import org.springframework.data.document.mongodb.index.Indexed; -import java.util.List; - /** * @author Jon Brisbin */ diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/PersonMapProperty.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/PersonMapProperty.java index 417427727..4987ecdf1 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/PersonMapProperty.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/PersonMapProperty.java @@ -16,10 +16,10 @@ package org.springframework.data.document.mongodb.mapping; -import org.bson.types.ObjectId; - import java.util.Map; +import org.bson.types.ObjectId; + /** * @author Jon Brisbin */ diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/PersonSimpleList.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/PersonSimpleList.java index b29392f92..3bcb89b72 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/PersonSimpleList.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/PersonSimpleList.java @@ -36,5 +36,5 @@ public class PersonSimpleList extends BasePerson { public void setNicknames(List nicknames) { this.nicknames = nicknames; } - + } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/monitor/MongoMonitorIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/monitor/MongoMonitorIntegrationTests.java index e7d68fff3..63f59b77a 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/monitor/MongoMonitorIntegrationTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/monitor/MongoMonitorIntegrationTests.java @@ -15,10 +15,7 @@ */ package org.springframework.data.document.mongodb.monitor; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.junit.Before; -import org.junit.BeforeClass; +import com.mongodb.Mongo; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -27,34 +24,29 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.util.Assert; import org.springframework.util.StringUtils; -import com.mongodb.CommandResult; -import com.mongodb.DB; -import com.mongodb.Mongo; - /** - * * This test class assumes that you are already running the MongoDB server. - * + * * @author Mark Pollack */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration public class MongoMonitorIntegrationTests { - @Autowired - Mongo mongo; - - @Test - public void serverInfo() { - ServerInfo serverInfo = new ServerInfo(mongo); - String version = serverInfo.getVersion(); - Assert.isTrue(StringUtils.hasText("1.")); - } - - @Test - public void operationCounters() { - OperationCounters operationCounters = new OperationCounters(mongo); - operationCounters.getInsertCount(); - } + @Autowired + Mongo mongo; + + @Test + public void serverInfo() { + ServerInfo serverInfo = new ServerInfo(mongo); + String version = serverInfo.getVersion(); + Assert.isTrue(StringUtils.hasText("1.")); + } + + @Test + public void operationCounters() { + OperationCounters operationCounters = new OperationCounters(mongo); + operationCounters.getInsertCount(); + } } \ No newline at end of file diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/query/IndexTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/query/IndexTests.java index bb6d2694f..248ac462a 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/query/IndexTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/query/IndexTests.java @@ -21,39 +21,39 @@ import org.springframework.data.document.mongodb.query.Index.Duplicates; public class IndexTests { - @Test - public void testWithAscendingIndex() { - Index i = new Index().on("name", Order.ASCENDING); - Assert.assertEquals("{ \"name\" : 1}", i.getIndexObject().toString()); - } + @Test + public void testWithAscendingIndex() { + Index i = new Index().on("name", Order.ASCENDING); + Assert.assertEquals("{ \"name\" : 1}", i.getIndexObject().toString()); + } - @Test - public void testWithDescendingIndex() { - Index i = new Index().on("name", Order.DESCENDING); - Assert.assertEquals("{ \"name\" : -1}", i.getIndexObject().toString()); - } + @Test + public void testWithDescendingIndex() { + Index i = new Index().on("name", Order.DESCENDING); + Assert.assertEquals("{ \"name\" : -1}", i.getIndexObject().toString()); + } - @Test - public void testNamedMultiFieldUniqueIndex() { - Index i = new Index().on("name", Order.ASCENDING).on("age", Order.DESCENDING); - i.named("test").unique(); - Assert.assertEquals("{ \"age\" : -1 , \"name\" : 1}", i.getIndexObject().toString()); - Assert.assertEquals("{ \"name\" : \"test\" , \"unique\" : true}", i.getIndexOptions().toString()); - } + @Test + public void testNamedMultiFieldUniqueIndex() { + Index i = new Index().on("name", Order.ASCENDING).on("age", Order.DESCENDING); + i.named("test").unique(); + Assert.assertEquals("{ \"age\" : -1 , \"name\" : 1}", i.getIndexObject().toString()); + Assert.assertEquals("{ \"name\" : \"test\" , \"unique\" : true}", i.getIndexOptions().toString()); + } - @Test - public void testWithDropDuplicates() { - Index i = new Index().on("name", Order.ASCENDING); - i.unique(Duplicates.DROP); - Assert.assertEquals("{ \"name\" : 1}", i.getIndexObject().toString()); - Assert.assertEquals("{ \"unique\" : true , \"drop_dups\" : true}", i.getIndexOptions().toString()); - } + @Test + public void testWithDropDuplicates() { + Index i = new Index().on("name", Order.ASCENDING); + i.unique(Duplicates.DROP); + Assert.assertEquals("{ \"name\" : 1}", i.getIndexObject().toString()); + Assert.assertEquals("{ \"unique\" : true , \"drop_dups\" : true}", i.getIndexOptions().toString()); + } - @Test - public void testGeospatialIndex() { - GeospatialIndex i = new GeospatialIndex("location").withMin(0); - Assert.assertEquals("{ \"location\" : \"2d\"}", i.getIndexObject().toString()); - Assert.assertEquals("{ \"min\" : 0}", i.getIndexOptions().toString()); - } + @Test + public void testGeospatialIndex() { + GeospatialIndex i = new GeospatialIndex("location").withMin(0); + Assert.assertEquals("{ \"location\" : \"2d\"}", i.getIndexObject().toString()); + Assert.assertEquals("{ \"min\" : 0}", i.getIndexOptions().toString()); + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/query/QueryTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/query/QueryTests.java index c4f33d568..df6de21a4 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/query/QueryTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/query/QueryTests.java @@ -19,61 +19,59 @@ import static org.springframework.data.document.mongodb.query.Criteria.where; import org.junit.Assert; import org.junit.Test; -import org.springframework.data.document.mongodb.query.BasicQuery; -import org.springframework.data.document.mongodb.query.Query; public class QueryTests { - @Test - public void testSimpleQuery() { - Query q = new Query(where("name").is("Thomas")).and(where("age").lt(80)); - String expected = "{ \"name\" : \"Thomas\" , \"age\" : { \"$lt\" : 80}}"; - Assert.assertEquals(expected, q.getQueryObject().toString()); - } + @Test + public void testSimpleQuery() { + Query q = new Query(where("name").is("Thomas")).and(where("age").lt(80)); + String expected = "{ \"name\" : \"Thomas\" , \"age\" : { \"$lt\" : 80}}"; + Assert.assertEquals(expected, q.getQueryObject().toString()); + } - @Test - public void testQueryWithNot() { - Query q = new Query(where("name").is("Thomas")).and(where("age").not().mod(10, 0)); - String expected = "{ \"name\" : \"Thomas\" , \"age\" : { \"$not\" : { \"$mod\" : [ 10 , 0]}}}"; - Assert.assertEquals(expected, q.getQueryObject().toString()); - } + @Test + public void testQueryWithNot() { + Query q = new Query(where("name").is("Thomas")).and(where("age").not().mod(10, 0)); + String expected = "{ \"name\" : \"Thomas\" , \"age\" : { \"$not\" : { \"$mod\" : [ 10 , 0]}}}"; + Assert.assertEquals(expected, q.getQueryObject().toString()); + } - @Test - public void testOrQuery() { - Query q = new OrQuery( - new Query(where("name").is("Sven")).and(where("age").lt(50)), - new Query(where("age").lt(50)), - new BasicQuery("{'name' : 'Thomas'}") - ); - String expected = "{ \"$or\" : [ { \"name\" : \"Sven\" , \"age\" : { \"$lt\" : 50}} , { \"age\" : { \"$lt\" : 50}} , { \"name\" : \"Thomas\"}]}"; - Assert.assertEquals(expected, q.getQueryObject().toString()); - } + @Test + public void testOrQuery() { + Query q = new OrQuery( + new Query(where("name").is("Sven")).and(where("age").lt(50)), + new Query(where("age").lt(50)), + new BasicQuery("{'name' : 'Thomas'}") + ); + String expected = "{ \"$or\" : [ { \"name\" : \"Sven\" , \"age\" : { \"$lt\" : 50}} , { \"age\" : { \"$lt\" : 50}} , { \"name\" : \"Thomas\"}]}"; + Assert.assertEquals(expected, q.getQueryObject().toString()); + } - @Test - public void testQueryWithLimit() { - Query q = new Query(where("name").gte("M").lte("T")).and(where("age").not().gt(22)); - q.limit(50); - String expected = "{ \"name\" : { \"$gte\" : \"M\" , \"$lte\" : \"T\"} , \"age\" : { \"$not\" : { \"$gt\" : 22}}}"; - Assert.assertEquals(expected, q.getQueryObject().toString()); - Assert.assertEquals(50, q.getLimit()); - } + @Test + public void testQueryWithLimit() { + Query q = new Query(where("name").gte("M").lte("T")).and(where("age").not().gt(22)); + q.limit(50); + String expected = "{ \"name\" : { \"$gte\" : \"M\" , \"$lte\" : \"T\"} , \"age\" : { \"$not\" : { \"$gt\" : 22}}}"; + Assert.assertEquals(expected, q.getQueryObject().toString()); + Assert.assertEquals(50, q.getLimit()); + } - @Test - public void testQueryWithFieldsAndSlice() { - Query q = new Query(where("name").gte("M").lte("T")).and(where("age").not().gt(22)); - q.fields().exclude("address").include("name").slice("orders", 10); + @Test + public void testQueryWithFieldsAndSlice() { + Query q = new Query(where("name").gte("M").lte("T")).and(where("age").not().gt(22)); + q.fields().exclude("address").include("name").slice("orders", 10); - String expected = "{ \"name\" : { \"$gte\" : \"M\" , \"$lte\" : \"T\"} , \"age\" : { \"$not\" : { \"$gt\" : 22}}}"; - Assert.assertEquals(expected, q.getQueryObject().toString()); - String expectedFields = "{ \"address\" : 0 , \"name\" : 1 , \"orders\" : { \"$slice\" : 10}}"; - Assert.assertEquals(expectedFields, q.getFieldsObject().toString()); - } + String expected = "{ \"name\" : { \"$gte\" : \"M\" , \"$lte\" : \"T\"} , \"age\" : { \"$not\" : { \"$gt\" : 22}}}"; + Assert.assertEquals(expected, q.getQueryObject().toString()); + String expectedFields = "{ \"address\" : 0 , \"name\" : 1 , \"orders\" : { \"$slice\" : 10}}"; + Assert.assertEquals(expectedFields, q.getFieldsObject().toString()); + } - @Test - public void testBasicQuery() { - Query q = new BasicQuery("{ \"name\" : \"Thomas\"}").and(where("age").lt(80)); - String expected = "{ \"name\" : \"Thomas\" , \"age\" : { \"$lt\" : 80}}"; - Assert.assertEquals(expected, q.getQueryObject().toString()); - } + @Test + public void testBasicQuery() { + Query q = new BasicQuery("{ \"name\" : \"Thomas\"}").and(where("age").lt(80)); + String expected = "{ \"name\" : \"Thomas\" , \"age\" : { \"$lt\" : 80}}"; + Assert.assertEquals(expected, q.getQueryObject().toString()); + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/query/SortTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/query/SortTests.java index e3b2d762b..eb257cb39 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/query/SortTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/query/SortTests.java @@ -17,21 +17,19 @@ package org.springframework.data.document.mongodb.query; import org.junit.Assert; import org.junit.Test; -import org.springframework.data.document.mongodb.query.Sort; -import org.springframework.data.document.mongodb.query.Order; public class SortTests { - @Test - public void testWithSortAscending() { - Sort s = new Sort().on("name", Order.ASCENDING); - Assert.assertEquals("{ \"name\" : 1}", s.getSortObject().toString()); - } + @Test + public void testWithSortAscending() { + Sort s = new Sort().on("name", Order.ASCENDING); + Assert.assertEquals("{ \"name\" : 1}", s.getSortObject().toString()); + } - @Test - public void testWithSortDescending() { - Sort s = new Sort().on("name", Order.DESCENDING); - Assert.assertEquals("{ \"name\" : -1}", s.getSortObject().toString()); - } + @Test + public void testWithSortDescending() { + Sort s = new Sort().on("name", Order.DESCENDING); + Assert.assertEquals("{ \"name\" : -1}", s.getSortObject().toString()); + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/query/UpdateTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/query/UpdateTests.java index c1454453b..5b3f60391 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/query/UpdateTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/query/UpdateTests.java @@ -20,118 +20,117 @@ import java.util.Map; import org.junit.Assert; import org.junit.Test; -import org.springframework.data.document.mongodb.query.Update; public class UpdateTests { - @Test - public void testSet() { - Update u = new Update() - .set("directory", "/Users/Test/Desktop"); - Assert.assertEquals("{ \"$set\" : { \"directory\" : \"/Users/Test/Desktop\"}}", u.getUpdateObject().toString()); - } + @Test + public void testSet() { + Update u = new Update() + .set("directory", "/Users/Test/Desktop"); + Assert.assertEquals("{ \"$set\" : { \"directory\" : \"/Users/Test/Desktop\"}}", u.getUpdateObject().toString()); + } - @Test - public void testInc() { - Update u = new Update() - .inc("size", 1); - Assert.assertEquals("{ \"$inc\" : { \"size\" : 1}}", u.getUpdateObject().toString()); - } + @Test + public void testInc() { + Update u = new Update() + .inc("size", 1); + Assert.assertEquals("{ \"$inc\" : { \"size\" : 1}}", u.getUpdateObject().toString()); + } - @Test - public void testIncAndSet() { - Update u = new Update() - .inc("size", 1) - .set("directory", "/Users/Test/Desktop"); - Assert.assertEquals("{ \"$inc\" : { \"size\" : 1} , \"$set\" : { \"directory\" : \"/Users/Test/Desktop\"}}", - u.getUpdateObject().toString()); - } + @Test + public void testIncAndSet() { + Update u = new Update() + .inc("size", 1) + .set("directory", "/Users/Test/Desktop"); + Assert.assertEquals("{ \"$inc\" : { \"size\" : 1} , \"$set\" : { \"directory\" : \"/Users/Test/Desktop\"}}", + u.getUpdateObject().toString()); + } - @Test - public void testUnset() { - Update u = new Update() - .unset("directory"); - Assert.assertEquals("{ \"$unset\" : { \"directory\" : 1}}", u.getUpdateObject().toString()); - } + @Test + public void testUnset() { + Update u = new Update() + .unset("directory"); + Assert.assertEquals("{ \"$unset\" : { \"directory\" : 1}}", u.getUpdateObject().toString()); + } - @Test - public void testPush() { - Map m = new HashMap(); - m.put("name", "Sven"); - Update u = new Update() - .push("authors", m); - Assert.assertEquals("{ \"$push\" : { \"authors\" : { \"name\" : \"Sven\"}}}", u.getUpdateObject().toString()); - } + @Test + public void testPush() { + Map m = new HashMap(); + m.put("name", "Sven"); + Update u = new Update() + .push("authors", m); + Assert.assertEquals("{ \"$push\" : { \"authors\" : { \"name\" : \"Sven\"}}}", u.getUpdateObject().toString()); + } - @Test - public void testPushAll() { - Map m1 = new HashMap(); - m1.put("name", "Sven"); - Map m2 = new HashMap(); - m2.put("name", "Maria"); - Update u = new Update() - .pushAll("authors", new Object[] {m1, m2}); - Assert.assertEquals("{ \"$pushAll\" : { \"authors\" : [ { \"name\" : \"Sven\"} , { \"name\" : \"Maria\"}]}}", u.getUpdateObject().toString()); - } + @Test + public void testPushAll() { + Map m1 = new HashMap(); + m1.put("name", "Sven"); + Map m2 = new HashMap(); + m2.put("name", "Maria"); + Update u = new Update() + .pushAll("authors", new Object[]{m1, m2}); + Assert.assertEquals("{ \"$pushAll\" : { \"authors\" : [ { \"name\" : \"Sven\"} , { \"name\" : \"Maria\"}]}}", u.getUpdateObject().toString()); + } - @Test - public void testAddToSet() { - Map m = new HashMap(); - m.put("name", "Sven"); - Update u = new Update() - .addToSet("authors", m); - Assert.assertEquals("{ \"$addToSet\" : { \"authors\" : { \"name\" : \"Sven\"}}}", u.getUpdateObject().toString()); - } + @Test + public void testAddToSet() { + Map m = new HashMap(); + m.put("name", "Sven"); + Update u = new Update() + .addToSet("authors", m); + Assert.assertEquals("{ \"$addToSet\" : { \"authors\" : { \"name\" : \"Sven\"}}}", u.getUpdateObject().toString()); + } - @Test - public void testPop() { - Update u = new Update() - .pop("authors", Update.Position.FIRST); - Assert.assertEquals("{ \"$pop\" : { \"authors\" : -1}}", u.getUpdateObject().toString()); - u = new Update() - .pop("authors", Update.Position.LAST); - Assert.assertEquals("{ \"$pop\" : { \"authors\" : 1}}", u.getUpdateObject().toString()); - } + @Test + public void testPop() { + Update u = new Update() + .pop("authors", Update.Position.FIRST); + Assert.assertEquals("{ \"$pop\" : { \"authors\" : -1}}", u.getUpdateObject().toString()); + u = new Update() + .pop("authors", Update.Position.LAST); + Assert.assertEquals("{ \"$pop\" : { \"authors\" : 1}}", u.getUpdateObject().toString()); + } - @Test - public void testPull() { - Map m = new HashMap(); - m.put("name", "Sven"); - Update u = new Update() - .pull("authors", m); - Assert.assertEquals("{ \"$pull\" : { \"authors\" : { \"name\" : \"Sven\"}}}", u.getUpdateObject().toString()); - } + @Test + public void testPull() { + Map m = new HashMap(); + m.put("name", "Sven"); + Update u = new Update() + .pull("authors", m); + Assert.assertEquals("{ \"$pull\" : { \"authors\" : { \"name\" : \"Sven\"}}}", u.getUpdateObject().toString()); + } - @Test - public void testPullAll() { - Map m1 = new HashMap(); - m1.put("name", "Sven"); - Map m2 = new HashMap(); - m2.put("name", "Maria"); - Update u = new Update() - .pullAll("authors", new Object[] {m1, m2}); - Assert.assertEquals("{ \"$pullAll\" : { \"authors\" : [ { \"name\" : \"Sven\"} , { \"name\" : \"Maria\"}]}}", u.getUpdateObject().toString()); - } + @Test + public void testPullAll() { + Map m1 = new HashMap(); + m1.put("name", "Sven"); + Map m2 = new HashMap(); + m2.put("name", "Maria"); + Update u = new Update() + .pullAll("authors", new Object[]{m1, m2}); + Assert.assertEquals("{ \"$pullAll\" : { \"authors\" : [ { \"name\" : \"Sven\"} , { \"name\" : \"Maria\"}]}}", u.getUpdateObject().toString()); + } - @Test - public void testRename() { - Update u = new Update() - .rename("directory", "folder"); - Assert.assertEquals("{ \"$rename\" : { \"directory\" : \"folder\"}}", u.getUpdateObject().toString()); - } + @Test + public void testRename() { + Update u = new Update() + .rename("directory", "folder"); + Assert.assertEquals("{ \"$rename\" : { \"directory\" : \"folder\"}}", u.getUpdateObject().toString()); + } - @Test - public void testBasicUpdateInc() { - Update u = new Update() - .inc("size", 1); - Assert.assertEquals("{ \"$inc\" : { \"size\" : 1}}", u.getUpdateObject().toString()); - } + @Test + public void testBasicUpdateInc() { + Update u = new Update() + .inc("size", 1); + Assert.assertEquals("{ \"$inc\" : { \"size\" : 1}}", u.getUpdateObject().toString()); + } - @Test - public void testBasicUpdateIncAndSet() { - Update u = new BasicUpdate("{ \"$inc\" : { \"size\" : 1}}") - .set("directory", "/Users/Test/Desktop"); - Assert.assertEquals("{ \"$inc\" : { \"size\" : 1} , \"$set\" : { \"directory\" : \"/Users/Test/Desktop\"}}", - u.getUpdateObject().toString()); - } + @Test + public void testBasicUpdateIncAndSet() { + Update u = new BasicUpdate("{ \"$inc\" : { \"size\" : 1}}") + .set("directory", "/Users/Test/Desktop"); + Assert.assertEquals("{ \"$inc\" : { \"size\" : 1} , \"$set\" : { \"directory\" : \"/Users/Test/Desktop\"}}", + u.getUpdateObject().toString()); + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java index b04b2ebd3..d7e9e12e3 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java @@ -1,8 +1,8 @@ package org.springframework.data.document.mongodb.repository; -import static java.util.Arrays.*; +import static java.util.Arrays.asList; import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; +import static org.junit.Assert.assertThat; import java.util.Arrays; import java.util.HashSet; @@ -20,179 +20,179 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * Base class for tests for {@link PersonRepository}. - * + * * @author Oliver Gierke */ @RunWith(SpringJUnit4ClassRunner.class) public abstract class AbstractPersonRepositoryIntegrationTests { - @Autowired - protected PersonRepository repository; - Person dave, carter, boyd, stefan, leroi; + @Autowired + protected PersonRepository repository; + Person dave, carter, boyd, stefan, leroi; - @Before - public void setUp() { + @Before + public void setUp() { - repository.deleteAll(); + repository.deleteAll(); - dave = new Person("Dave", "Matthews", 42); - carter = new Person("Carter", "Beauford", 49); - boyd = new Person("Boyd", "Tinsley", 45); - stefan = new Person("Stefan", "Lessard", 34); - leroi = new Person("Leroi", "Moore", 41); + dave = new Person("Dave", "Matthews", 42); + carter = new Person("Carter", "Beauford", 49); + boyd = new Person("Boyd", "Tinsley", 45); + stefan = new Person("Stefan", "Lessard", 34); + leroi = new Person("Leroi", "Moore", 41); - repository.save(Arrays.asList(dave, carter, boyd, stefan, leroi)); - } + repository.save(Arrays.asList(dave, carter, boyd, stefan, leroi)); + } - @Test - public void existsWorksCorrectly() { - assertThat(repository.exists(dave.getId()), is(true)); - assertThat(repository.exists(carter.getId()), is(true)); - assertThat(repository.exists(boyd.getId()), is(true)); - assertThat(repository.exists(stefan.getId()), is(true)); - assertThat(repository.exists(leroi.getId()), is(true)); - assertThat(repository.exists(new ObjectId().toString()), is(false)); - } + @Test + public void existsWorksCorrectly() { + assertThat(repository.exists(dave.getId()), is(true)); + assertThat(repository.exists(carter.getId()), is(true)); + assertThat(repository.exists(boyd.getId()), is(true)); + assertThat(repository.exists(stefan.getId()), is(true)); + assertThat(repository.exists(leroi.getId()), is(true)); + assertThat(repository.exists(new ObjectId().toString()), is(false)); + } - @Test - public void findsPersonById() throws Exception { + @Test + public void findsPersonById() throws Exception { - assertThat(repository.findOne(dave.getId()), is(dave)); - } + assertThat(repository.findOne(dave.getId()), is(dave)); + } - @Test - public void findsAllMusicians() throws Exception { - List result = repository.findAll(); - assertThat(result, hasItems(dave, carter, boyd, stefan, leroi)); - assertThat(result.size(), is(5)); - } - - @Test - public void deletesPersonCorrectly() throws Exception { - - repository.delete(dave); - - List result = repository.findAll(); - - assertThat(result.size(), is(4)); - assertThat(result, not(hasItem(dave))); - } + @Test + public void findsAllMusicians() throws Exception { + List result = repository.findAll(); + assertThat(result, hasItems(dave, carter, boyd, stefan, leroi)); + assertThat(result.size(), is(5)); + } - @Test - public void findsPersonsByLastname() throws Exception { + @Test + public void deletesPersonCorrectly() throws Exception { - List result = repository.findByLastname("Beauford"); - assertThat(result.size(), is(1)); - assertThat(result, hasItem(carter)); - } - - @Test - public void findsPersonsByFirstname() { - - List result = repository.findByThePersonsFirstname("Leroi"); - assertThat(result.size(), is(1)); - assertThat(result, hasItem(leroi)); - } + repository.delete(dave); - @Test - public void findsPersonsByFirstnameLike() throws Exception { + List result = repository.findAll(); - List result = repository.findByFirstnameLike("Bo*"); - assertThat(result.size(), is(1)); - assertThat(result, hasItem(boyd)); - } + assertThat(result.size(), is(4)); + assertThat(result, not(hasItem(dave))); + } - @Test - public void findsPagedPersons() throws Exception { + @Test + public void findsPersonsByLastname() throws Exception { - Page result = repository.findAll(new PageRequest(1, 2, Direction.ASC, "lastname")); - assertThat(result.isFirstPage(), is(false)); - assertThat(result.isLastPage(), is(false)); - assertThat(result, hasItems(dave, leroi)); - } + List result = repository.findByLastname("Beauford"); + assertThat(result.size(), is(1)); + assertThat(result, hasItem(carter)); + } - @Test - public void executesPagedFinderCorrectly() throws Exception { + @Test + public void findsPersonsByFirstname() { - Page page = repository.findByLastnameLike("*a*", new PageRequest(0, 2, Direction.ASC, "lastname")); - assertThat(page.isFirstPage(), is(true)); - assertThat(page.isLastPage(), is(false)); - assertThat(page.getNumberOfElements(), is(2)); - assertThat(page, hasItems(carter, stefan)); - } + List result = repository.findByThePersonsFirstname("Leroi"); + assertThat(result.size(), is(1)); + assertThat(result, hasItem(leroi)); + } - @Test - public void findsPersonInAgeRangeCorrectly() throws Exception { + @Test + public void findsPersonsByFirstnameLike() throws Exception { - List result = repository.findByAgeBetween(40, 45); - assertThat(result.size(), is(2)); - assertThat(result, hasItems(dave, leroi)); - } + List result = repository.findByFirstnameLike("Bo*"); + assertThat(result.size(), is(1)); + assertThat(result, hasItem(boyd)); + } - @Test - public void findsPersonByShippingAddressesCorrectly() throws Exception { + @Test + public void findsPagedPersons() throws Exception { - Address address = new Address("Foo Street 1", "C0123", "Bar"); - dave.setShippingAddresses(new HashSet
                      (asList(address))); + Page result = repository.findAll(new PageRequest(1, 2, Direction.ASC, "lastname")); + assertThat(result.isFirstPage(), is(false)); + assertThat(result.isLastPage(), is(false)); + assertThat(result, hasItems(dave, leroi)); + } - repository.save(dave); - assertThat(repository.findByShippingAddresses(address), is(dave)); - } + @Test + public void executesPagedFinderCorrectly() throws Exception { - @Test - public void findsPersonByAddressCorrectly() throws Exception { + Page page = repository.findByLastnameLike("*a*", new PageRequest(0, 2, Direction.ASC, "lastname")); + assertThat(page.isFirstPage(), is(true)); + assertThat(page.isLastPage(), is(false)); + assertThat(page.getNumberOfElements(), is(2)); + assertThat(page, hasItems(carter, stefan)); + } - Address address = new Address("Foo Street 1", "C0123", "Bar"); - dave.setAddress(address); - repository.save(dave); + @Test + public void findsPersonInAgeRangeCorrectly() throws Exception { - List result = repository.findByAddress(address); - assertThat(result.size(), is(1)); - assertThat(result, hasItem(dave)); - } + List result = repository.findByAgeBetween(40, 45); + assertThat(result.size(), is(2)); + assertThat(result, hasItems(dave, leroi)); + } - @Test - public void findsPeopleByZipCode() throws Exception { + @Test + public void findsPersonByShippingAddressesCorrectly() throws Exception { - Address address = new Address("Foo Street 1", "C0123", "Bar"); - dave.setAddress(address); - repository.save(dave); + Address address = new Address("Foo Street 1", "C0123", "Bar"); + dave.setShippingAddresses(new HashSet
                      (asList(address))); - List result = repository.findByAddressZipCode(address.getZipCode()); - assertThat(result.size(), is(1)); - assertThat(result, hasItem(dave)); - } - - - @Test - public void findsPeopleByFirstnameInVarargs() { - - List result = repository.findByFirstnameIn("Dave", "Carter"); - assertThat(result.size(), is(2)); - assertThat(result, hasItems(dave, carter)); - } - - @Test - public void findsPeopleByFirstnameNotInCollection() { - - List result = repository.findByFirstnameNotIn(Arrays.asList("Boyd", "Carter")); - assertThat(result.size(), is(3)); - assertThat(result, hasItems(dave, leroi, stefan)); - } - - @Test - public void findsPeopleByLastnameLikeAndAgeIn() throws Exception { - - List result = repository.findByLastnameLikeAndAgeBetween("*e*", 44, 50); - assertThat(result.size(), is(2)); - assertThat(result, hasItems(carter, boyd)); - } - - @Test - public void findsPeopleWithAndAndOr() throws Exception { - - List result = repository.findByAgeOrLastnameLikeAndFirstnameLike(45, "*ss*", "*a*"); - assertThat(result.size(), is(2)); - assertThat(result, hasItems(boyd, stefan)); - } + repository.save(dave); + assertThat(repository.findByShippingAddresses(address), is(dave)); + } + + @Test + public void findsPersonByAddressCorrectly() throws Exception { + + Address address = new Address("Foo Street 1", "C0123", "Bar"); + dave.setAddress(address); + repository.save(dave); + + List result = repository.findByAddress(address); + assertThat(result.size(), is(1)); + assertThat(result, hasItem(dave)); + } + + @Test + public void findsPeopleByZipCode() throws Exception { + + Address address = new Address("Foo Street 1", "C0123", "Bar"); + dave.setAddress(address); + repository.save(dave); + + List result = repository.findByAddressZipCode(address.getZipCode()); + assertThat(result.size(), is(1)); + assertThat(result, hasItem(dave)); + } + + + @Test + public void findsPeopleByFirstnameInVarargs() { + + List result = repository.findByFirstnameIn("Dave", "Carter"); + assertThat(result.size(), is(2)); + assertThat(result, hasItems(dave, carter)); + } + + @Test + public void findsPeopleByFirstnameNotInCollection() { + + List result = repository.findByFirstnameNotIn(Arrays.asList("Boyd", "Carter")); + assertThat(result.size(), is(3)); + assertThat(result, hasItems(dave, leroi, stefan)); + } + + @Test + public void findsPeopleByLastnameLikeAndAgeIn() throws Exception { + + List result = repository.findByLastnameLikeAndAgeBetween("*e*", 44, 50); + assertThat(result.size(), is(2)); + assertThat(result, hasItems(carter, boyd)); + } + + @Test + public void findsPeopleWithAndAndOr() throws Exception { + + List result = repository.findByAgeOrLastnameLikeAndFirstnameLike(45, "*ss*", "*a*"); + assertThat(result.size(), is(2)); + assertThat(result, hasItems(boyd, stefan)); + } } \ No newline at end of file diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/Address.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/Address.java index f8a2ac67f..3fea59f84 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/Address.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/Address.java @@ -16,69 +16,68 @@ package org.springframework.data.document.mongodb.repository; /** - * * @author Oliver Gierke */ public class Address { - private String street; - private String zipCode; - private String city; + private String street; + private String zipCode; + private String city; - protected Address() { - - } - - /** - * @param string - * @param string2 - * @param string3 - */ - public Address(String street, String zipcode, String city) { - this.street = street; - this.zipCode = zipcode; - this.city = city; - } + protected Address() { - /** - * @return the street - */ - public String getStreet() { - return street; - } + } - /** - * @param street the street to set - */ - public void setStreet(String street) { - this.street = street; - } + /** + * @param string + * @param string2 + * @param string3 + */ + public Address(String street, String zipcode, String city) { + this.street = street; + this.zipCode = zipcode; + this.city = city; + } - /** - * @return the zipCode - */ - public String getZipCode() { - return zipCode; - } + /** + * @return the street + */ + public String getStreet() { + return street; + } - /** - * @param zipCode the zipCode to set - */ - public void setZipCode(String zipCode) { - this.zipCode = zipCode; - } + /** + * @param street the street to set + */ + public void setStreet(String street) { + this.street = street; + } - /** - * @return the city - */ - public String getCity() { - return city; - } + /** + * @return the zipCode + */ + public String getZipCode() { + return zipCode; + } - /** - * @param city the city to set - */ - public void setCity(String city) { - this.city = city; - } + /** + * @param zipCode the zipCode to set + */ + public void setZipCode(String zipCode) { + this.zipCode = zipCode; + } + + /** + * @return the city + */ + public String getCity() { + return city; + } + + /** + * @param city the city to set + */ + public void setCity(String city) { + this.city = city; + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/MongoEntityMetadataUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/MongoEntityMetadataUnitTests.java index 9dc06d195..aaec1262b 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/MongoEntityMetadataUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/MongoEntityMetadataUnitTests.java @@ -15,45 +15,45 @@ */ package org.springframework.data.document.mongodb.repository; -import static org.hamcrest.CoreMatchers.*; -import static org.junit.Assert.*; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; import org.junit.Test; /** * Unit test for {@link MongoEntityInformation}. - * + * * @author Oliver Gierke */ public class MongoEntityMetadataUnitTests { - @Test - public void findsIdField() throws Exception { + @Test + public void findsIdField() throws Exception { - MongoEntityInformation isNewAware = - new MongoEntityInformation(Person.class); + MongoEntityInformation isNewAware = + new MongoEntityInformation(Person.class); - Person person = new Person(); - assertThat(isNewAware.isNew(person), is(true)); - person.id = 1L; - assertThat(isNewAware.isNew(person), is(false)); - } + Person person = new Person(); + assertThat(isNewAware.isNew(person), is(true)); + person.id = 1L; + assertThat(isNewAware.isNew(person), is(false)); + } - @Test(expected = IllegalArgumentException.class) - public void rejectsClassIfNoIdField() throws Exception { + @Test(expected = IllegalArgumentException.class) + public void rejectsClassIfNoIdField() throws Exception { - new MongoEntityInformation(InvalidPerson.class); - } + new MongoEntityInformation(InvalidPerson.class); + } - class Person { + class Person { - Long id; - } + Long id; + } - class InvalidPerson { + class InvalidPerson { - Long foo; - } + Long foo; + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/MongoQueryCreatorUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/MongoQueryCreatorUnitTests.java index 9aeafec75..01cd00de9 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/MongoQueryCreatorUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/MongoQueryCreatorUnitTests.java @@ -15,7 +15,7 @@ */ package org.springframework.data.document.mongodb.repository; -import static org.springframework.data.document.mongodb.repository.StubParameterAccessor.*; +import static org.springframework.data.document.mongodb.repository.StubParameterAccessor.getAccessor; import java.lang.reflect.Method; import java.util.List; @@ -25,59 +25,59 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; -import org.springframework.data.document.mongodb.convert.MongoConverter; import org.springframework.data.document.mongodb.Person; +import org.springframework.data.document.mongodb.convert.MongoConverter; import org.springframework.data.repository.query.parser.PartTree; /** * Unit test for {@link MongoQueryCreator}. - * + * * @author Oliver Gierke */ @RunWith(MockitoJUnitRunner.class) public class MongoQueryCreatorUnitTests { - Method findByFirstname; - Method findByFirstnameAndFriend; + Method findByFirstname; + Method findByFirstnameAndFriend; - @Mock - MongoConverter converter; + @Mock + MongoConverter converter; - @Before - public void setUp() throws SecurityException, NoSuchMethodException { + @Before + public void setUp() throws SecurityException, NoSuchMethodException { - findByFirstname = - Sample.class.getMethod("findByFirstname", String.class); - findByFirstnameAndFriend = - Sample.class.getMethod("findByFirstnameAndFriend", - String.class, Person.class); + findByFirstname = + Sample.class.getMethod("findByFirstname", String.class); + findByFirstnameAndFriend = + Sample.class.getMethod("findByFirstnameAndFriend", + String.class, Person.class); - } + } - @Test - public void createsQueryCorrectly() throws Exception { + @Test + public void createsQueryCorrectly() throws Exception { - PartTree tree = new PartTree("findByFirstName", Person.class); + PartTree tree = new PartTree("findByFirstName", Person.class); - MongoQueryCreator creator = - new MongoQueryCreator(tree, getAccessor(converter, "Oliver")); + MongoQueryCreator creator = + new MongoQueryCreator(tree, getAccessor(converter, "Oliver")); - creator.createQuery(); + creator.createQuery(); - creator = - new MongoQueryCreator(new PartTree("findByFirstNameAndFriend", - Person.class), getAccessor(converter, "Oliver", new Person())); - creator.createQuery(); - } + creator = + new MongoQueryCreator(new PartTree("findByFirstNameAndFriend", + Person.class), getAccessor(converter, "Oliver", new Person())); + creator.createQuery(); + } - interface Sample { + interface Sample { - List findByFirstname(String firstname); + List findByFirstname(String firstname); - List findByFirstnameAndFriend(String firstname, Person friend); - } + List findByFirstnameAndFriend(String firstname, Person friend); + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/MongoRepositoryFactoryUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/MongoRepositoryFactoryUnitTests.java index c24861014..1fae42c2c 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/MongoRepositoryFactoryUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/MongoRepositoryFactoryUnitTests.java @@ -24,22 +24,22 @@ import org.springframework.data.document.mongodb.repository.MongoRepositoryFacto /** * Unit test for {@link MongoRepositoryFactory}. - * + * * @author Oliver Gierke */ @RunWith(MockitoJUnitRunner.class) public class MongoRepositoryFactoryUnitTests { - - @Mock - MongoTemplate template; - @Test(expected = IllegalArgumentException.class) - public void rejectsInvalidIdType() throws Exception { - MongoRepositoryFactory factory = new MongoRepositoryFactory(template); - factory.getRepository(SampleRepository.class); - } - - private interface SampleRepository extends MongoRepository { - - } + @Mock + MongoTemplate template; + + @Test(expected = IllegalArgumentException.class) + public void rejectsInvalidIdType() throws Exception { + MongoRepositoryFactory factory = new MongoRepositoryFactory(template); + factory.getRepository(SampleRepository.class); + } + + private interface SampleRepository extends MongoRepository { + + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/Person.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/Person.java index b0872dd3e..89d5f0be2 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/Person.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/Person.java @@ -22,182 +22,182 @@ import org.bson.types.ObjectId; /** * Sample domain class. - * + * * @author Oliver Gierke */ public class Person { - private String id; - private String firstname; - private String lastname; - private Integer age; - - private Address address; - private Set
                      shippingAddresses; + private String id; + private String firstname; + private String lastname; + private Integer age; + + private Address address; + private Set
                      shippingAddresses; - public Person() { + public Person() { - this(null, null); + this(null, null); + } + + + public Person(String firstname, String lastname) { + + this(firstname, lastname, null); + } + + + public Person(String firstname, String lastname, Integer age) { + + this.id = ObjectId.get().toString(); + this.firstname = firstname; + this.lastname = lastname; + this.age = age; + } + + + /** + * @param id the id to set + */ + public void setId(String id) { + + this.id = id; + } + + + /** + * @return the id + */ + public String getId() { + + return id; + } + + + /** + * @return the firstname + */ + public String getFirstname() { + + return firstname; + } + + + /** + * @param firstname the firstname to set + */ + public void setFirstname(String firstname) { + + this.firstname = firstname; + } + + + /** + * @return the lastname + */ + public String getLastname() { + + return lastname; + } + + + /** + * @param lastname the lastname to set + */ + public void setLastname(String lastname) { + + this.lastname = lastname; + } + + + /** + * @return the age + */ + public Integer getAge() { + + return age; + } + + + /** + * @param age the age to set + */ + public void setAge(Integer age) { + + this.age = age; + } + + + /** + * @return the address + */ + public Address getAddress() { + return address; + } + + + /** + * @param address the address to set + */ + public void setAddress(Address address) { + this.address = address; + } + + /** + * @return the addresses + */ + public Set
                      getShippingAddresses() { + return shippingAddresses; + } + + + /** + * @param addresses the addresses to set + */ + public void setShippingAddresses(Set
                      addresses) { + this.shippingAddresses = addresses; + } + + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + + if (this == obj) { + return true; } - - public Person(String firstname, String lastname) { - - this(firstname, lastname, null); + if (obj == null || !getClass().equals(obj.getClass())) { + return false; } + Person that = (Person) obj; - public Person(String firstname, String lastname, Integer age) { - - this.id = ObjectId.get().toString(); - this.firstname = firstname; - this.lastname = lastname; - this.age = age; - } + return this.id.equals(that.id); + } - /** - * @param id the id to set - */ - public void setId(String id) { + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { - this.id = id; - } + return id.hashCode(); + } - - /** - * @return the id - */ - public String getId() { - - return id; - } - - - /** - * @return the firstname - */ - public String getFirstname() { - - return firstname; - } - - - /** - * @param firstname the firstname to set - */ - public void setFirstname(String firstname) { - - this.firstname = firstname; - } - - - /** - * @return the lastname - */ - public String getLastname() { - - return lastname; - } - - - /** - * @param lastname the lastname to set - */ - public void setLastname(String lastname) { - - this.lastname = lastname; - } - - - /** - * @return the age - */ - public Integer getAge() { - - return age; - } - - - /** - * @param age the age to set - */ - public void setAge(Integer age) { - - this.age = age; - } - - - /** - * @return the address - */ - public Address getAddress() { - return address; - } - - - /** - * @param address the address to set - */ - public void setAddress(Address address) { - this.address = address; - } - - /** - * @return the addresses - */ - public Set
                      getShippingAddresses() { - return shippingAddresses; - } - - - /** - * @param addresses the addresses to set - */ - public void setShippingAddresses(Set
                      addresses) { - this.shippingAddresses = addresses; - } - - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object obj) { - - if (this == obj) { - return true; - } - - if (obj == null || !getClass().equals(obj.getClass())) { - return false; - } - - Person that = (Person) obj; - - return this.id.equals(that.id); - } - - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - - return id.hashCode(); - } - - /* (non-Javadoc) - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return String.format("%s %s", firstname, lastname); - } + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return String.format("%s %s", firstname, lastname); + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/PersonRepository.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/PersonRepository.java index 232d40af7..a66ff1064 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/PersonRepository.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/PersonRepository.java @@ -24,97 +24,97 @@ import org.springframework.data.domain.Pageable; /** * Sample repository managing {@link Person} entities. - * + * * @author Oliver Gierke */ public interface PersonRepository extends MongoRepository { - /** - * Returns all {@link Person}s with the given lastname. - * - * @param lastname - * @return - */ - List findByLastname(String lastname); - - /** - * Returns the {@link Person}s with the given firstname. Uses {@link Query} annotation to define the query to be - * executed. - * - * @param firstname - * @return - */ - @Query("{ 'firstname' : ?0 }") - List findByThePersonsFirstname(String firstname); + /** + * Returns all {@link Person}s with the given lastname. + * + * @param lastname + * @return + */ + List findByLastname(String lastname); + + /** + * Returns the {@link Person}s with the given firstname. Uses {@link Query} annotation to define the query to be + * executed. + * + * @param firstname + * @return + */ + @Query("{ 'firstname' : ?0 }") + List findByThePersonsFirstname(String firstname); - /** - * Returns all {@link Person}s with a firstname matching the given one - * (*-wildcard supported). - * - * @param firstname - * @return - */ - List findByFirstnameLike(String firstname); + /** + * Returns all {@link Person}s with a firstname matching the given one + * (*-wildcard supported). + * + * @param firstname + * @return + */ + List findByFirstnameLike(String firstname); - /** - * Returns a page of {@link Person}s with a lastname mathing the given one - * (*-wildcards supported). - * - * @param lastname - * @param pageable - * @return - */ - Page findByLastnameLike(String lastname, Pageable pageable); + /** + * Returns a page of {@link Person}s with a lastname mathing the given one + * (*-wildcards supported). + * + * @param lastname + * @param pageable + * @return + */ + Page findByLastnameLike(String lastname, Pageable pageable); - /** - * Returns all {@link Person}s with a firstname contained in the given varargs. - * - * @param firstnames - * @return - */ - List findByFirstnameIn(String... firstnames); + /** + * Returns all {@link Person}s with a firstname contained in the given varargs. + * + * @param firstnames + * @return + */ + List findByFirstnameIn(String... firstnames); - /** - * Returns all {@link Person}s with a firstname not contained in the given collection. - * - * @param firstnames - * @return - */ - List findByFirstnameNotIn(Collection firstnames); + /** + * Returns all {@link Person}s with a firstname not contained in the given collection. + * + * @param firstnames + * @return + */ + List findByFirstnameNotIn(Collection firstnames); - /** - * Returns all {@link Person}s with an age between the two given values. - * - * @param from - * @param to - * @return - */ - List findByAgeBetween(int from, int to); - - - /** - * Returns the {@link Person} with the given {@link Address} as shipping address. - * - * @param address - * @return - */ - Person findByShippingAddresses(Address address); - - - /** - * Returns all {@link Person}s with the given {@link Address}. - * - * @param address - * @return - */ - List findByAddress(Address address); - - - List findByAddressZipCode(String zipCode); - - List findByLastnameLikeAndAgeBetween(String lastname, int from, int to); - - List findByAgeOrLastnameLikeAndFirstnameLike(int age, String lastname, String firstname); + /** + * Returns all {@link Person}s with an age between the two given values. + * + * @param from + * @param to + * @return + */ + List findByAgeBetween(int from, int to); + + + /** + * Returns the {@link Person} with the given {@link Address} as shipping address. + * + * @param address + * @return + */ + Person findByShippingAddresses(Address address); + + + /** + * Returns all {@link Person}s with the given {@link Address}. + * + * @param address + * @return + */ + List findByAddress(Address address); + + + List findByAddressZipCode(String zipCode); + + List findByLastnameLikeAndAgeBetween(String lastname, int from, int to); + + List findByAgeOrLastnameLikeAndFirstnameLike(int age, String lastname, String firstname); } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/PersonRepositoryIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/PersonRepositoryIntegrationTests.java index 5a1c718bc..1c7461171 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/PersonRepositoryIntegrationTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/PersonRepositoryIntegrationTests.java @@ -20,10 +20,10 @@ import org.springframework.test.context.ContextConfiguration; /** * Integration test for {@link PersonRepository}. - * + * * @author Oliver Gierke */ @ContextConfiguration public class PersonRepositoryIntegrationTests extends - AbstractPersonRepositoryIntegrationTests { + AbstractPersonRepositoryIntegrationTests { } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/StringBasedMongoQueryUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/StringBasedMongoQueryUnitTests.java index b103088e7..0a5386247 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/StringBasedMongoQueryUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/StringBasedMongoQueryUnitTests.java @@ -15,9 +15,9 @@ */ package org.springframework.data.document.mongodb.repository; -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.when; import java.lang.reflect.Method; @@ -26,45 +26,45 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; -import org.springframework.data.document.mongodb.convert.MongoConverter; import org.springframework.data.document.mongodb.MongoTemplate; +import org.springframework.data.document.mongodb.convert.MongoConverter; import org.springframework.data.document.mongodb.convert.SimpleMongoConverter; import org.springframework.data.document.mongodb.query.BasicQuery; /** * Unit tests for {@link StringBasedMongoQuery}. - * + * * @author Oliver Gierke */ @RunWith(MockitoJUnitRunner.class) public class StringBasedMongoQueryUnitTests { - @Mock - MongoTemplate template; - MongoConverter converter = new SimpleMongoConverter(); + @Mock + MongoTemplate template; + MongoConverter converter = new SimpleMongoConverter(); - @Before - public void setUp() { - when(template.getConverter()).thenReturn(converter); - } + @Before + public void setUp() { + when(template.getConverter()).thenReturn(converter); + } - @Test - public void testname() throws Exception { + @Test + public void testname() throws Exception { - Method method = SampleRepository.class.getMethod("findByLastname", String.class); - MongoQueryMethod queryMethod = new MongoQueryMethod(method, Person.class); - StringBasedMongoQuery mongoQuery = new StringBasedMongoQuery(queryMethod, template); - ConvertingParameterAccessor accesor = StubParameterAccessor.getAccessor(converter, "Matthews"); - - org.springframework.data.document.mongodb.query.Query query = mongoQuery.createQuery(accesor); - org.springframework.data.document.mongodb.query.Query reference = new BasicQuery("{'lastname' : 'Matthews'}"); - - assertThat(query.getQueryObject(), is(reference.getQueryObject())); - } + Method method = SampleRepository.class.getMethod("findByLastname", String.class); + MongoQueryMethod queryMethod = new MongoQueryMethod(method, Person.class); + StringBasedMongoQuery mongoQuery = new StringBasedMongoQuery(queryMethod, template); + ConvertingParameterAccessor accesor = StubParameterAccessor.getAccessor(converter, "Matthews"); - private interface SampleRepository { + org.springframework.data.document.mongodb.query.Query query = mongoQuery.createQuery(accesor); + org.springframework.data.document.mongodb.query.Query reference = new BasicQuery("{'lastname' : 'Matthews'}"); - @Query("{ 'lastname' : ?0 }") - Person findByLastname(String lastname); - } + assertThat(query.getQueryObject(), is(reference.getQueryObject())); + } + + private interface SampleRepository { + + @Query("{ 'lastname' : ?0 }") + Person findByLastname(String lastname); + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/StubParameterAccessor.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/StubParameterAccessor.java index 1eedfc13c..19dd6017f 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/StubParameterAccessor.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/StubParameterAccessor.java @@ -30,57 +30,57 @@ import org.springframework.data.repository.query.ParameterAccessor; */ class StubParameterAccessor implements ParameterAccessor { - private final Object[] values; + private final Object[] values; - /** - * Creates a new {@link ConvertingParameterAccessor} backed by a {@link StubParameterAccessor} simply returning the - * given parameters converted but unfiltered. - * - * @param converter - * @param parameters - * @return - */ - public static ConvertingParameterAccessor getAccessor(MongoWriter converter, Object... parameters) { + /** + * Creates a new {@link ConvertingParameterAccessor} backed by a {@link StubParameterAccessor} simply returning the + * given parameters converted but unfiltered. + * + * @param converter + * @param parameters + * @return + */ + public static ConvertingParameterAccessor getAccessor(MongoWriter converter, Object... parameters) { - return new ConvertingParameterAccessor(converter, new StubParameterAccessor(parameters)); - } - + return new ConvertingParameterAccessor(converter, new StubParameterAccessor(parameters)); + } - public StubParameterAccessor(Object... values) { - this.values = values; - } - /* - * (non-Javadoc) - * - * @see org.springframework.data.repository.query.ParameterAccessor#getPageable() - */ - public Pageable getPageable() { - return null; - } - - /* (non-Javadoc) - * @see org.springframework.data.repository.query.ParameterAccessor#getBindableParameter(int) - */ - public Object getBindableValue(int index) { - return values[index]; - } + public StubParameterAccessor(Object... values) { + this.values = values; + } - /* - * (non-Javadoc) - * - * @see org.springframework.data.repository.query.ParameterAccessor#getSort() - */ - public Sort getSort() { - return null; - } + /* + * (non-Javadoc) + * + * @see org.springframework.data.repository.query.ParameterAccessor#getPageable() + */ + public Pageable getPageable() { + return null; + } - /* - * (non-Javadoc) - * - * @see java.lang.Iterable#iterator() - */ - public Iterator iterator() { - return Arrays.asList(values).iterator(); - } + /* (non-Javadoc) + * @see org.springframework.data.repository.query.ParameterAccessor#getBindableParameter(int) + */ + public Object getBindableValue(int index) { + return values[index]; + } + + /* + * (non-Javadoc) + * + * @see org.springframework.data.repository.query.ParameterAccessor#getSort() + */ + public Sort getSort() { + return null; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Iterable#iterator() + */ + public Iterator iterator() { + return Arrays.asList(values).iterator(); + } } \ No newline at end of file diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/config/MongoNamespaceIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/config/MongoNamespaceIntegrationTests.java index 0cca67cef..9dd7cebc2 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/config/MongoNamespaceIntegrationTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/config/MongoNamespaceIntegrationTests.java @@ -7,11 +7,11 @@ import org.springframework.test.context.ContextConfiguration; /** * Test class using the namespace configuration to set up the repository * instance. - * + * * @author Oliver Gierke */ @ContextConfiguration public class MongoNamespaceIntegrationTests extends - AbstractPersonRepositoryIntegrationTests { + AbstractPersonRepositoryIntegrationTests { } diff --git a/spring-data-mongodb/src/test/resources/org/springframework/data/document/mongodb/MongoBeanPropertyDocumentMapper-context.xml b/spring-data-mongodb/src/test/resources/org/springframework/data/document/mongodb/MongoBeanPropertyDocumentMapper-context.xml index 4717a9b6b..4f0883a6f 100644 --- a/spring-data-mongodb/src/test/resources/org/springframework/data/document/mongodb/MongoBeanPropertyDocumentMapper-context.xml +++ b/spring-data-mongodb/src/test/resources/org/springframework/data/document/mongodb/MongoBeanPropertyDocumentMapper-context.xml @@ -1,8 +1,8 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> - + diff --git a/spring-data-mongodb/src/test/resources/org/springframework/data/document/mongodb/config/MongoNamespaceTests-context.xml b/spring-data-mongodb/src/test/resources/org/springframework/data/document/mongodb/config/MongoNamespaceTests-context.xml index 18ab46a9d..31c3f3a91 100644 --- a/spring-data-mongodb/src/test/resources/org/springframework/data/document/mongodb/config/MongoNamespaceTests-context.xml +++ b/spring-data-mongodb/src/test/resources/org/springframework/data/document/mongodb/config/MongoNamespaceTests-context.xml @@ -1,17 +1,16 @@ - - - - - - + + + + + - diff --git a/spring-data-mongodb/src/test/resources/org/springframework/data/document/mongodb/monitor/MongoMonitorIntegrationTests-context.xml b/spring-data-mongodb/src/test/resources/org/springframework/data/document/mongodb/monitor/MongoMonitorIntegrationTests-context.xml index 22dd36542..a50be8d64 100644 --- a/spring-data-mongodb/src/test/resources/org/springframework/data/document/mongodb/monitor/MongoMonitorIntegrationTests-context.xml +++ b/spring-data-mongodb/src/test/resources/org/springframework/data/document/mongodb/monitor/MongoMonitorIntegrationTests-context.xml @@ -1,14 +1,14 @@ + xmlns:mongo="http://www.springframework.org/schema/data/mongo" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> - - - - - + + + + + diff --git a/spring-data-mongodb/src/test/resources/org/springframework/data/document/mongodb/repository/PersonRepositoryIntegrationTests-context.xml b/spring-data-mongodb/src/test/resources/org/springframework/data/document/mongodb/repository/PersonRepositoryIntegrationTests-context.xml index 12550d0de..e153ee3f2 100644 --- a/spring-data-mongodb/src/test/resources/org/springframework/data/document/mongodb/repository/PersonRepositoryIntegrationTests-context.xml +++ b/spring-data-mongodb/src/test/resources/org/springframework/data/document/mongodb/repository/PersonRepositoryIntegrationTests-context.xml @@ -1,13 +1,13 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> - - - - - - + + + + + + diff --git a/spring-data-mongodb/src/test/resources/org/springframework/data/document/mongodb/repository/config/MongoNamespaceIntegrationTests-context.xml b/spring-data-mongodb/src/test/resources/org/springframework/data/document/mongodb/repository/config/MongoNamespaceIntegrationTests-context.xml index 5e4048ebf..fc0d95432 100644 --- a/spring-data-mongodb/src/test/resources/org/springframework/data/document/mongodb/repository/config/MongoNamespaceIntegrationTests-context.xml +++ b/spring-data-mongodb/src/test/resources/org/springframework/data/document/mongodb/repository/config/MongoNamespaceIntegrationTests-context.xml @@ -1,16 +1,16 @@ - - - - - + + + + + diff --git a/spring-data-mongodb/src/test/resources/server-jmx.xml b/spring-data-mongodb/src/test/resources/server-jmx.xml index 2441dab55..406a0a1a0 100644 --- a/spring-data-mongodb/src/test/resources/server-jmx.xml +++ b/spring-data-mongodb/src/test/resources/server-jmx.xml @@ -1,25 +1,24 @@ - - + - + + + + + + - - - - - \ No newline at end of file diff --git a/src/ant/upload-dist.xml b/src/ant/upload-dist.xml index 32f828ff2..fbdaad3dc 100644 --- a/src/ant/upload-dist.xml +++ b/src/ant/upload-dist.xml @@ -1,48 +1,48 @@ - + ant -f src/ant/upload-dist.xml \ + -Ddist.id=spring-data-document \ + -Ddist.name='Spring Data Document' \ + -Ddist.key=DATADOC \ + -Ddist.releaseType=milestone \ + -Ddist.accessKey= \ + -Ddist.secretKey= \ + -Ddist.bucketName=dist.springframework.org \ + -Ddist.fileName=spring-data-document-1.0.0.M1.zip \ + -Ddist.filePath=../../spring-data-document-1.0.0.M1.zip \ + -Ddist.version=1.0.0.M1 \ + upload-dist + --> - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/src/assembly/distribution.xml b/src/assembly/distribution.xml index e953d7a53..f139a413d 100644 --- a/src/assembly/distribution.xml +++ b/src/assembly/distribution.xml @@ -1,71 +1,71 @@ - - distribution - - zip - - true - - - - src/main/resources - - readme.txt - license.txt - notice.txt - changelog.txt - - - dos - - - - target/site/reference - docs/reference - - - - target/site/apidocs - docs/javadoc - - - - - - - org.springframework.data:spring-data-document-core - org.springframework.data:spring-data-mongodb - org.springframework.data:spring-data-couchdb - - - dist - false - false - - - - - - org.springframework.data:spring-data-document-core - - org.springframework.data:spring-data-mongodb - - - sources - src - false - false - - - + + distribution + + zip + + true + + + + src/main/resources + + readme.txt + license.txt + notice.txt + changelog.txt + + + dos + + + + target/site/reference + docs/reference + + + + target/site/apidocs + docs/javadoc + + + + + + + org.springframework.data:spring-data-document-core + org.springframework.data:spring-data-mongodb + org.springframework.data:spring-data-couchdb + + + dist + false + false + + + + + + org.springframework.data:spring-data-document-core + + org.springframework.data:spring-data-mongodb + + + sources + src + false + false + + + diff --git a/src/docbkx/index.xml b/src/docbkx/index.xml index 0503dc7b4..d6b54a47c 100644 --- a/src/docbkx/index.xml +++ b/src/docbkx/index.xml @@ -1,6 +1,6 @@ + "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> Spring Datastore Document - Reference Documentation @@ -23,36 +23,37 @@ Gierke - Costin - Leau + Costin + Leau Copies of this document may be made for your own use and for - distribution to others, provided that you do not charge any fee for such - copies and further provided that each copy contains this Copyright - Notice, whether distributed in print or electronically. + distribution to others, provided that you do not charge any fee for such + copies and further provided that each copy contains this Copyright + Notice, whether distributed in print or electronically. + - + - + Introduction - + - + Reference Documentation - + diff --git a/src/docbkx/introduction/getting-started.xml b/src/docbkx/introduction/getting-started.xml index 2017f7d21..d95579c0c 100644 --- a/src/docbkx/introduction/getting-started.xml +++ b/src/docbkx/introduction/getting-started.xml @@ -1,72 +1,89 @@ + "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> Getting Started Learning a new framework is not always straight forward. In this - section, we (the Spring Data team) tried to provide, what we think is, an - easy to follow guide for starting with Spring Data Document module. Of - course, feel free to create your own learning 'path' as you see fit and, if - possible, please report back any improvements to the documentation that can - help others. + section, we (the Spring Data team) tried to provide, what we think is, an + easy to follow guide for starting with Spring Data Document module. Of + course, feel free to create your own learning 'path' as you see fit and, if + possible, please report back any improvements to the documentation that can + help others. +
                      First Steps - As explained in , Spring - Data Document (DATADOC) provides integration between Spring framework and - document oriented data stores. Thus, it is important to become acquainted - with both of these frameworks (storages or environments depending on how - you want to name them). Throughout the DATADOC documentation, each section - provides links to resources relevant however, it is best to become - familiar with these topics beforehand. + As explained in, Spring + Data Document (DATADOC) provides integration between Spring framework and + document oriented data stores. Thus, it is important to become acquainted + with both of these frameworks (storages or environments depending on how + you want to name them). Throughout the DATADOC documentation, each section + provides links to resources relevant however, it is best to become + familiar with these topics beforehand. +
                      Knowing Spring - Spring Data uses heavily Spring framework's core - functionality, such as the IoC - container, resource - abstract or AOP - infrastructure. While it is not important to know the Spring APIs, - understanding the concepts behind them is. At a minimum, the idea behind - IoC should be familiar. These being said, the more knowledge one has - about the Spring, the faster she will pick up Spring Data Document. - Besides the very comprehensive (and sometimes disarming) documentation - that explains in detail the Spring Framework, there are a lot of - articles, blog entries and books on the matter - take a look at the - Spring framework home page for - more information. In general, this should be the starting point for - developers wanting to try Spring Data Document. + Spring Data uses heavily Spring framework's + core + + functionality, such as the + IoC + + container, + resource + + abstract or + AOP + + infrastructure. While it is not important to know the Spring APIs, + understanding the concepts behind them is. At a minimum, the idea behind + IoC should be familiar. These being said, the more knowledge one has + about the Spring, the faster she will pick up Spring Data Document. + Besides the very comprehensive (and sometimes disarming) documentation + that explains in detail the Spring Framework, there are a lot of + articles, blog entries and books on the matter - take a look at the + Spring framework + home page + + for + more information. In general, this should be the starting point for + developers wanting to try Spring Data Document. +
                      Knowing NoSQL and Document stores NoSQL stores have taken the storage world by storm. It is a vast - domain with a plethora of solutions, terms and patterns (to make things - worth even the term itself has multiple meanings). - While some of the principles are common, it is crucial that the user is - familiar to some degree with the stores supported by DATADOC. The best - way to get acquainted to this solutions is to read their documentation - and follow their examples - it usually doesn't take more then 5-10 - minutes to go through them and if you are coming from an RDMBS-only - background many times these exercises can be an eye opener. + domain with a plethora of solutions, terms and patterns (to make things + worth even the term itself has multiplemeanings). + While some of the principles are common, it is crucial that the user is + familiar to some degree with the stores supported by DATADOC. The best + way to get acquainted to this solutions is to read their documentation + and follow their examples - it usually doesn't take more then 5-10 + minutes to go through them and if you are coming from an RDMBS-only + background many times these exercises can be an eye opener. +
                      Trying Out The Samples The DATADOC project is very young but there are some samples - available in the GitHub repository: https://github.com/SpringSource/spring-data-document-examples. + available in the GitHub repository: + https://github.com/SpringSource/spring-data-document-examples. +
                      @@ -74,25 +91,31 @@ Need Help? If you encounter issues or you are just looking for an advice, feel - free to use one of the links below: + free to use one of the links below: +
                      Community Forum - The Spring Data forum - is a message board for all Spring Data (not just Document) users to - share information and help each other. Note that registration is needed - only for posting. + The Spring Data + forum + + is a message board for all Spring Data (not just Document) users to + share information and help each other. Note that registration is needed + only + for posting. +
                      Professional Support Professional, from-the-source support, with guaranteed response - time, is available from SpringSource, the company - behind Spring Data and Spring. + time, is available fromSpringSource, the company + behind Spring Data and Spring. +
                      @@ -100,24 +123,32 @@ Following Development For information on the Spring Data source code repository, nightly - builds and snapshot artifacts please see the Spring Data home page. + builds and snapshot artifacts please see the Spring Data homepage. + You can help make Spring Data best serve the needs of the Spring - community by interacting with developers through the Spring Community - forums. + community by interacting with developers through the Spring Community + forums. + If you encounter a bug or want to suggest an improvement, please - create a ticket on the Spring Data issue tracker. + create a ticket on the Spring Data issuetracker. + To stay up to date with the latest news and announcements in the - Spring eco system, subscribe to the Spring Community Portal. + Spring eco system, subscribe to the Spring CommunityPortal. + - Lastly, you can follow the SpringSource Data blog or - the project team on Twitter (SpringData) + Lastly, you can follow the SpringSource Data + blog + + or + the project team on Twitter (SpringData) +
                      diff --git a/src/docbkx/introduction/introduction.xml b/src/docbkx/introduction/introduction.xml index fd60d7787..3897413a6 100644 --- a/src/docbkx/introduction/introduction.xml +++ b/src/docbkx/introduction/introduction.xml @@ -1,17 +1,20 @@ + "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> - - This document is the reference guide for Spring Data - Document Support. - It explains Document module concepts and semantics and the syntax for various - stores namespaces. - - For an introduction to document stores or Spring, or Spring Data examples, please refer to - - this documentation refers only to Spring Data Document Support and - assumes the user is familiar with the document stores and Spring concepts. + + This document is the reference guide for Spring Data - Document Support. + It explains Document module concepts and semantics and the syntax for various + stores namespaces. + + + For an introduction to document stores or Spring, or Spring Data examples, please refer to + + - this documentation refers only to Spring Data Document Support and + assumes the user is familiar with the document stores and Spring concepts. + + + - - \ No newline at end of file diff --git a/src/docbkx/introduction/requirements.xml b/src/docbkx/introduction/requirements.xml index 9fa620544..526164c98 100644 --- a/src/docbkx/introduction/requirements.xml +++ b/src/docbkx/introduction/requirements.xml @@ -1,11 +1,17 @@ - - Requirements + + Requirements - Spring Data Document 1.x binaries requires JDK level 6.0 and above, - and Spring Framework - 3.0.x and above. - - In terms of document stores, MongoDB preferably version 1.6.5 - or later or CouchDB 1.0.1 or later are required. - - \ No newline at end of file + Spring Data Document 1.x binaries requires JDK level 6.0 and above, + and + Spring Framework + 3.0.x and above. + + + In terms of document stores, + MongoDB + preferably version 1.6.5 + or later or + CouchDB + 1.0.1 or later are required. + + \ No newline at end of file diff --git a/src/docbkx/introduction/why-sd-doc.xml b/src/docbkx/introduction/why-sd-doc.xml index fccb6380c..e76b769f5 100644 --- a/src/docbkx/introduction/why-sd-doc.xml +++ b/src/docbkx/introduction/why-sd-doc.xml @@ -1,21 +1,25 @@ + "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> - Why Spring Data - Document? + Why Spring Data - Document? - The Spring Framework is the leading full-stack Java/JEE + The Spring Framework is the leading full-stack Java/JEE application framework. It provides a lightweight container and a non-invasive programming model enabled by the use of dependency - injection, AOP, and portable service abstractions. - - NoSQL + injection, AOP, and portable service abstractions. + + + + NoSQL storages provide an alternative to classical RDBMS for horizontal scalability and speed. In terms of implementation, Document stores represent one of the - most popular types of stores in the NoSQL space. + most popular types of stores in the NoSQL space. + - The Spring Data Document (or DATADOC) framework makes it easy to + The Spring Data Document (or DATADOC) framework makes it easy to write Spring applications that use a Document store by eliminating the redundant tasks and boiler place code required for interacting with the store through - Spring's excellent infrastructure support. + Spring's excellent infrastructure support. + \ No newline at end of file diff --git a/src/docbkx/preface.xml b/src/docbkx/preface.xml index 89010a73e..71a52ff83 100644 --- a/src/docbkx/preface.xml +++ b/src/docbkx/preface.xml @@ -1,12 +1,13 @@ + "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> Preface The Spring Datastore Document project applies core Spring concepts to - the development of solutions using a document style data store. We provide a - "template" as a high-level abstraction for storing and querying documents. - You will notice similarities to the JDBC support in the Spring - Framework. + the development of solutions using a document style data store. We provide a + "template" as a high-level abstraction for storing and querying documents. + You will notice similarities to the JDBC support in the Spring + Framework. + diff --git a/src/docbkx/reference/couchdb.xml b/src/docbkx/reference/couchdb.xml index e54af4303..ca71fd671 100644 --- a/src/docbkx/reference/couchdb.xml +++ b/src/docbkx/reference/couchdb.xml @@ -1,11 +1,12 @@ + "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> CouchDB support - One of the document stores supported by DATADOC is CouchDB. + One of the document stores supported by DATADOC isCouchDB. +
                      CouchDB Requirements @@ -25,10 +26,14 @@ Roadmap ahead The Spring Data Document projects CouchDB support is in its early - stages. We are interested in feedback, knowing what your use cases are, - what are the common patters you encounter so that the CouchDB module - better serves your needs. Do contact us using the channels mentioned above, we are - interested in hearing from you! + stages. We are interested in feedback, knowing what your use cases are, + what are the common patters you encounter so that the CouchDB module + better serves your needs. Do contact us using the channels + mentioned + + above, we are + interested in hearing from you! +
                      diff --git a/src/docbkx/reference/introduction.xml b/src/docbkx/reference/introduction.xml index c1d1abb71..583e09d0b 100644 --- a/src/docbkx/reference/introduction.xml +++ b/src/docbkx/reference/introduction.xml @@ -1,13 +1,20 @@ - - Document Structure + + Document Structure - This part of the reference documentation explains the core functionality - offered by Spring Data Document. + This part of the reference documentation explains the core functionality + offered by Spring Data Document. + - introduces the MongoDB module feature set. + + + introduces the MongoDB module feature set. + - introduces the repository support for MongoDB. + + + introduces the repository support for MongoDB. + - + - \ No newline at end of file + \ No newline at end of file diff --git a/src/docbkx/reference/jmx.xml b/src/docbkx/reference/jmx.xml index c8592e642..098058255 100644 --- a/src/docbkx/reference/jmx.xml +++ b/src/docbkx/reference/jmx.xml @@ -1,64 +1,70 @@ + "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> JMX support The JMX support for MongoDB exposes the results of executing the - 'serverStatus' command on the admin database for a single MongoDB server - instance. It also exposes an administrative MBean, MongoAdmin which will let - you perform administrative operations such as drop or create a database. The - JMX features build upon the JMX feature set available in the Spring - Framework. See here - for more details. + 'serverStatus' command on the admin database for a single MongoDB server + instance. It also exposes an administrative MBean, MongoAdmin which will let + you perform administrative operations such as drop or create a database. The + JMX features build upon the JMX feature set available in the Spring + Framework. See + here + + for more details. +
                      MongoDB JMX Configuration Spring's Mongo namespace enables you to easily enable JMX - functionality + functionality + XML schmea to configure MongoDB <?xml version="1.0" encoding="UTF-8"?> -<beans xmlns="http://www.springframework.org/schema/beans" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns:context="http://www.springframework.org/schema/context" - xmlns:mongo="http://www.springframework.org/schema/data/mongo" - xsi:schemaLocation= -"http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd -http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd -http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> + <beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:context="http://www.springframework.org/schema/context" + xmlns:mongo="http://www.springframework.org/schema/data/mongo" + xsi:schemaLocation= + "http://www.springframework.org/schema/context + http://www.springframework.org/schema/context/spring-context-3.0.xsd + http://www.springframework.org/schema/data/mongo + http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> -<beans> + <beans> - <!-- Default bean name is 'mongo' --> - <mongo:mongo host="localhost" port="27017"/> + <!-- Default bean name is 'mongo' --> + <mongo:mongo host="localhost" port="27017"/> - <!-- by default look for a Mongo object named 'mongo' --> - <mongo:jmx/> + <!-- by default look for a Mongo object named 'mongo' --> + <mongo:jmx/> - <context:mbean-export/> - - <!-- To translate any MongoExceptions thrown in @Repository annotated classes --> - <context:annotation-config/> + <context:mbean-export/> - <bean id="registry" class="org.springframework.remoting.rmi.RmiRegistryFactoryBean" - p:port="1099" /> - - <!-- Expose JMX over RMI --> - <bean id="serverConnector" class="org.springframework.jmx.support.ConnectorServerFactoryBean" - depends-on="registry" - p:objectName="connector:name=rmi" - p:serviceUrl="service:jmx:rmi://localhost/jndi/rmi://localhost:1099/myconnector" /> + <!-- To translate any MongoExceptions thrown in @Repository annotated classes --> + <context:annotation-config/> -</beans> - + <bean id="registry" class="org.springframework.remoting.rmi.RmiRegistryFactoryBean" + p:port="1099" /> + + <!-- Expose JMX over RMI --> + <bean id="serverConnector" class="org.springframework.jmx.support.ConnectorServerFactoryBean" + depends-on="registry" + p:objectName="connector:name=rmi" + p:serviceUrl="service:jmx:rmi://localhost/jndi/rmi://localhost:1099/myconnector" /> + + </beans> + - This will expose several MBeans + This will expose several MBeans @@ -102,7 +108,7 @@ http://www.springframework.org/schema/beans http://www.springframework.org/schem - +
                      diff --git a/src/docbkx/reference/mongo-repositories.xml b/src/docbkx/reference/mongo-repositories.xml index 6e00ef290..0a8de97c8 100644 --- a/src/docbkx/reference/mongo-repositories.xml +++ b/src/docbkx/reference/mongo-repositories.xml @@ -4,153 +4,189 @@ This chapter will point out the specialties for repository support - for MongoDB. This builds on the core repository support explained in . So make sure you've got a sound understanding - of the basic concepts explained there. + for MongoDB. This builds on the core repository support explained in. So make sure you've got a sound understanding + of the basic concepts explained there. + To access domain entities stored in a MongoDB you can leverage our - sophisticated repository support that eases implementing those quite - significantly. To do so, simply create an interface for your - repository: + sophisticated repository support that eases implementing those quite + significantly. To do so, simply create an interface for your + repository: + Sample Person entity public class Person { - private ObjectId id; - private String firstname; - private String lastname; + private ObjectId id; + private String firstname; + private String lastname; - // … getters and setters omitted -} + // … getters and setters omitted + } + We have a quite simple domain object here. Note that it has a property - named id of type ObjectId. The default - serialization mechanism used in MongoTemplate (which - is backing the repository support) regards properties named id as document - id. Currently we support String, - ObjectId and BigInteger as - id-types. + named + id + of typeObjectId. The default + serialization mechanism used in + MongoTemplate + (which + is backing the repository support) regards properties named id as document + id. Currently we supportString, + ObjectId + and + BigInteger + as + id-types. + Basic repository interface to persist Person entities public interface PersonRepository extends MongoRepository<Person, Long> { -} + } + The central MongoDB CRUD repository interface is - MongoRepository. Right now this interface - simply serves typing purposes but we will add additional methods to it - later. In your Spring configuration simply add + MongoRepository. Right now this interface + simply serves typing purposes but we will add additional methods to it + later. In your Spring configuration simply add + General mongo repository Spring configuration <?xml version="1.0" encoding="UTF-8"?> -<beans xmlns="http://www.springframework.org/schema/beans" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns:mongo="http://www.springframework.org/schema/data/mongo" - xmlns:context="http://www.springframework.org/schema/context" - xsi:schemaLocation="http://www.springframework.org/schema/beans - http://www.springframework.org/schema/beans/spring-beans-3.0.xsd - http://www.springframework.org/schema/data/mongo - http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd - http://www.springframework.org/schema/context - http://www.springframework.org/schema/context/spring-context-3.0.xsd"> + <beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:mongo="http://www.springframework.org/schema/data/mongo" + xmlns:context="http://www.springframework.org/schema/context" + xsi:schemaLocation="http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans-3.0.xsd + http://www.springframework.org/schema/data/mongo + http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd + http://www.springframework.org/schema/context + http://www.springframework.org/schema/context/spring-context-3.0.xsd"> - <mongo:repositories base-package="com.acme.*.repositories" - mongo-template-ref="myMongoTemplate" /> + <mongo:repositories base-package="com.acme.*.repositories" + mongo-template-ref="myMongoTemplate" /> - … + … -</beans> + </beans> This namespace element will cause the base packages to be scanned for - interfaces extending MongoRepository and - create Spring beans for each of them found. By default the repositories will - get a MongoTemplate Spring bean wired that is called - mongoTemplate, so you only need to configure - mongo-template-ref explicitly if you deviate from this - convention. + interfaces extending + MongoRepository + and + create Spring beans for each of them found. By default the repositories will + get a + MongoTemplate + Spring bean wired that is called + mongoTemplate, so you only need to configure + mongo-template-ref + explicitly if you deviate from this + convention. + - MongoRepository extends - PagingAndSortingRepository which you can read - about in . In general it provides - you with CRUD operations as well as methods for paginated and sorted access - to the entities. Working with the repository instance is just a matter of - dependency injecting it into a client. So accessing the second page of - Persons at a page size of 10 would simply look - something like this: + + MongoRepository + extends + PagingAndSortingRepository + which you can read + about in. In general it provides + you with CRUD operations as well as methods for paginated and sorted access + to the entities. Working with the repository instance is just a matter of + dependency injecting it into a client. So accessing the second page of + Persons at a page size of 10 would simply look + something like this: + Paging access to Person entities @RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration -class PersonRepositoryTests { + @ContextConfiguration + class PersonRepositoryTests { - @Autowired PersonRepository repository; + @Autowired PersonRepository repository; - @Test - public void readsFirstPageCorrectly() { + @Test + public void readsFirstPageCorrectly() { - Page<Person> persons = repository.findAll(new PageRequest(0, 10)); - assertThat(persons.isFirstPage(), is(true)); - } -} + Page<Person> persons = repository.findAll(new PageRequest(0, 10)); + assertThat(persons.isFirstPage(), is(true)); + } + } + The sample creates an application context with Spring's unit test - support which will perform annotation based dependency injection into test - cases. Inside the test method we simply use the repository to query the - datastore. We hand the repository a PageRequest - instance that requests the first page of persons at a page size of - 10. + support which will perform annotation based dependency injection into test + cases. Inside the test method we simply use the repository to query the + datastore. We hand the repository a + PageRequest + instance that requests the first page of persons at a page size of + 10. +
                      Query methods Most of the data access operations you usually trigger on a - repository result a query being executed against the Mongo databases. - Defining such a query is just a matter of declaring a method on the - repository interface + repository result a query being executed against the Mongo databases. + Defining such a query is just a matter of declaring a method on the + repository interface + PersonRepository with query methods public interface PersonRepository extends MongoRepository<Person, Long> { - List<Person> findByLastname(String lastname); + List<Person> findByLastname(String lastname); - Page<Person> findByFirstname(String firstname, Pageable pageable); -} + Page<Person> findByFirstname(String firstname, Pageable pageable); + } + The first method shows a query for all people with the given - lastname. The query will be derived parsing the method name for - constraints which can be concatenated with And and - Or. Thus the method name will result in a query - expression of {"lastname" : lastname}. The second example - shows how pagination is applied to a query. Just equip your method - signature with a Pageable parameter and let - the method return a Page instance and we - will automatically page the query accordingly. + lastname. The query will be derived parsing the method name for + constraints which can be concatenated with + And + and + Or. Thus the method name will result in a query + expression of{"lastname" : lastname}. The second example + shows how pagination is applied to a query. Just equip your method + signature with a + Pageable + parameter and let + the method return a + Page + instance and we + will automatically page the query accordingly. + - + +
                      Supported keywords for query methods - + - + - + @@ -164,79 +200,133 @@ class PersonRepositoryTests { - GreaterThan + + GreaterThan + - findByAgeGreaterThan(int - age) + + findByAgeGreaterThan(int + age) + + - {"age" : {"$gt" : age}} + + {"age" : {"$gt" : age}} + - LessThan + + LessThan + - findByAgeLessThan(int - age) + + findByAgeLessThan(int + age) + + - {"age" : {"$lt" : age}} + + {"age" : {"$lt" : age}} + - Between + + Between + - findByAgeBetween(int from, int - to) + + findByAgeBetween(int from, int + to) + + - {"age" : {"$gt" : from, "$lt" : to}} + + {"age" : {"$gt" : from, "$lt" : to}} + IsNotNull, - NotNull + NotNull + - findByFirstnameNotNull() + + findByFirstnameNotNull() + - {"age" : {"$ne" : null}} + + {"age" : {"$ne" : null}} + IsNull, - Null + Null + - findByFirstnameNull() + + findByFirstnameNull() + - {"age" : null} + + {"age" : null} + - Like + + Like + - findByFirstnameLike(String - name) + + findByFirstnameLike(String + name) + + - {"age" : age} (age as - regex) + + {"age" : age} + ( + age + as + regex) + (No keyword) - findByFirstname(String - name) + + findByFirstname(String + name) + + - {"age" : name} + + {"age" : name} + - Not + + Not + - findByFirstnameNot(String - name) + + findByFirstnameNot(String + name) + + - {"age" : {"$ne" : name}} + + {"age" : {"$ne" : name}} + -
                      + +
                      \ No newline at end of file diff --git a/src/docbkx/reference/mongodb.xml b/src/docbkx/reference/mongodb.xml index 7fd37fee2..bbda93dd5 100644 --- a/src/docbkx/reference/mongodb.xml +++ b/src/docbkx/reference/mongodb.xml @@ -1,22 +1,28 @@ + "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> MongoDB support - One of the document stores supported by DATADOC is MongoDB. To quote the project home - page: MongoDB (from "humongous") is a scalable, high-performance, - open source, document-oriented database. Spring Data Document - provides easy configuration and access to MongoDB from a Spring application. - Offers both low-level and high-level abstraction for interacting with the - store, freeing the user from infrastructural concerns. + One of the document stores supported by DATADOC isMongoDB. To quote the project home + page: + MongoDB (from "humongous") is a scalable, high-performance, + open source, document-oriented database. + + Spring Data Document + provides easy configuration and access to MongoDB from a Spring application. + Offers both low-level and high-level abstraction for interacting with the + store, freeing the user from infrastructural concerns. + +
                      MongoDB Requirements DATADOC requires MongoDB 1.4 while the latest production release - (1.6.5 as of this writing) is recommended. + (1.6.5 as of this writing) is recommended. +
                      @@ -26,161 +32,197 @@ - + Configuration Factory - - for configuring and handling communication with MongoDB via its Java driver + - for configuring and handling communication with MongoDB via its Java driver - + Template implementation - - As with many of Spring's template classes, MongoTemplate simplifies the use of accessing the database for common use-cases and infrastructure concerns such as exception translation. Features include integrated object mapping between documents and domain classes and fluent DSLs for query and update operations. The chapter + - As with many of Spring's template classes, MongoTemplate simplifies the use of accessing the database for + common use-cases and infrastructure concerns such as exception translation. Features include integrated object + mapping between documents and domain classes and fluent DSLs for query and update operations. The chapter - + - provides additional details. + provides additional details. - + Support Classes - - that offer reusable components such as mapping support and exception translation. + - that offer reusable components such as mapping support and exception translation. For most tasks, the higher-level abstractions and support services - are the best choice. Note that at any point, one can move between layers - - for example, it's very easy to get a hold of the low level connection - (org.mongo.DB) to communicate directly with MongoDB. + are the best choice. Note that at any point, one can move between layers - + for example, it's very easy to get a hold of the low level connection + (org.mongo.DB) to communicate directly with MongoDB. +
                      Connecting to MongoDB One of the first tasks when using MongoDB and Spring is to create a - com.mongodb.Mongo object using the IoC container. - There are two main ways to do this, either using Java based bean metadata - or XML based bean metadata. These are discussed in the following - sections. + com.mongodb.Mongo + object using the IoC container. + There are two main ways to do this, either using Java based bean metadata + or XML based bean metadata. These are discussed in the following + sections. + For those not familiar with how to configure the Spring - container using Java based bean metadata instead of XML based metadata - see the high level introduction in the reference docs here as well as the detailed documentation here. - + container using Java based bean metadata instead of XML based metadata + see the high level introduction in the reference docs + here + + as well as the detailed documentation + here. + + +
                      Using Java based metadata An example of using Java based bean metadata to register an - instance of a com.mongodb.Mongo is shown - below + instance of a + com.mongodb.Mongo + is shown + below + Registering a com.mongodb.Mongo object using Java based bean - metadata + metadata + @Configuration -public class AppConfig { + public class AppConfig { - /* - * Factory bean that creates the com.mongodb.Mongo instance - */ - public @Bean Mongo mongo() throws UnknownHostException, MongoException { - return new Mongo("localhost"); - } + /* + * Factory bean that creates the com.mongodb.Mongo instance + */ + public @Bean Mongo mongo() throws UnknownHostException, MongoException { + return new Mongo("localhost"); + } -} - - + } + + + This approach allows you to use the standard com.mongodb.Mongo API - that you may already be used to using but also pollutes the code with - the UnknownHostException checked exception. + that you may already be used to using but also pollutes the code with + the UnknownHostException checked exception. + However, you may also register an instance of - com.mongodb.Mongo instance with the container - using Spring's MongoFactoryBean. As - compared to instantiating a com.mongodb.Mongo - instance directly, the FactoryBean approach has the added advantage of - also acting as an ExceptionTranslator that can be used to translate any - Mongo exceptions to exceptions in the - SpringDataAccessException. This is part of Spring's - DAO support features. The exception translation feature works - hand in hand with Spring's @Repository - annotation. To enable exception translation on data access components - annotated with @Repository register a - PersistenceExceptionTranslationPostProcessor - (JavaDoc) - with the container. + com.mongodb.Mongo + instance with the container + using Spring'sMongoFactoryBean. As + compared to instantiating a + com.mongodb.Mongo + instance directly, the FactoryBean approach has the added advantage of + also acting as an ExceptionTranslator that can be used to translate any + Mongo exceptions to exceptions in the + SpringDataAccessException. This is part ofSpring's + DAO support features. The exception translation feature works + hand in hand with Spring's + @Repository + annotation. To enable exception translation on data access components + annotated with + @Repository + register a + PersistenceExceptionTranslationPostProcessor + ( + JavaDoc) + with the container. + While enabling exception translation can be done using Java - based bean metadata it is often done declaratively in XML using - Spring's context namespace - <context::annotation-config/>.to enable - annotation - configuration features. - + based bean metadata it is often done declaratively in XML using + Spring's context namespace + <context::annotation-config/>.to enable + + annotation + configuration features. + + + An example of a Java based bean metadata that supports exception - translation on @Repository annotated classes is - shown below: + translation on + @Repository + annotated classes is + shown below: + Registering a com.mongodb.Mongo object using Spring's - MongoFactoryBean and enabling Spring's exception translation - support + MongoFactoryBean and enabling Spring's exception translation + support + @Configuration -public class AppConfig { + public class AppConfig { - /* - * Factory bean that creates the com.mongodb.Mongo instance - */ - public @Bean MongoFactoryBean mongo() { - MongoFactoryBean mongo = new MongoFactoryBean(); - mongo.setHost("localhost"); - return mongo; - } + /* + * Factory bean that creates the com.mongodb.Mongo instance + */ + public @Bean MongoFactoryBean mongo() { + MongoFactoryBean mongo = new MongoFactoryBean(); + mongo.setHost("localhost"); + return mongo; + } - /* - * Use this post processor to translate any MongoExceptions thrown in @Repository - * annotated classes - */ - public @Bean PersistenceExceptionTranslationPostProcessor - persistenceExceptionTranslationPostProcessor() { - return new PersistenceExceptionTranslationPostProcessor(); - } + /* + * Use this post processor to translate any MongoExceptions thrown in @Repository + * annotated classes + */ + public @Bean PersistenceExceptionTranslationPostProcessor + persistenceExceptionTranslationPostProcessor() { + return new PersistenceExceptionTranslationPostProcessor(); + } -} - + } + if you prefer to use the standard MongoDB API to create a - com.mongodb.Mongo instance and have exception translation enabled on - your @Repository instances, simply inherit from - MongoExceptionTranslationConfig as shown - below. + com.mongodb.Mongo instance and have exception translation enabled on + your + @Repository + instances, simply inherit from + MongoExceptionTranslationConfig + as shown + below. + Registering a com.mongodb.Mongo object and enabling Spring's - exception translation support + exception translation support + @Configuration -public class AppConfig extends MongoExceptionTranslationConfig { - - public @Bean Mongo mongo() throws UnknownHostException, MongoException { - return new Mongo("localhost"); - } -} - + public class AppConfig extends MongoExceptionTranslationConfig { + + public @Bean Mongo mongo() throws UnknownHostException, MongoException { + return new Mongo("localhost"); + } + } +
                      @@ -188,218 +230,272 @@ public class AppConfig extends MongoExceptionTranslationConfig { Using XML based metadata While you can use Spring's traditional <beans/> XML - namespace to register an instance of - com.mongodb.Mongo with the container, the XML can - be quite verbose, does not easily support the configuration of public - instance variables used with the driver's MongoOptions class, and - constructor arguments/names are not the most effective means to - distinguish between configuration of replica sets and replica pairs. o - address these issues a XML namespace is available to simplify the - configuration of a com.mongodb.Mongo instance in XML. + namespace to register an instance of + com.mongodb.Mongo + with the container, the XML can + be quite verbose, does not easily support the configuration of public + instance variables used with the driver's MongoOptions class, and + constructor arguments/names are not the most effective means to + distinguish between configuration of replica sets and replica pairs. o + address these issues a XML namespace is available to simplify the + configuration of a com.mongodb.Mongo instance in XML. + To use the Mongo namespace elements you will need to reference the - Mongo schema: + Mongo schema: + XML schema to configure MongoDB <?xml version="1.0" encoding="UTF-8"?> -<beans xmlns="http://www.springframework.org/schema/beans" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns:context="http://www.springframework.org/schema/context" - xmlns:mongo="http://www.springframework.org/schema/data/mongo" - xsi:schemaLocation= - "http://www.springframework.org/schema/context - http://www.springframework.org/schema/context/spring-context-3.0.xsd - http://www.springframework.org/schema/data/mongo - http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd - http://www.springframework.org/schema/beans - http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> + <beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:context="http://www.springframework.org/schema/context" + xmlns:mongo="http://www.springframework.org/schema/data/mongo" + xsi:schemaLocation= + "http://www.springframework.org/schema/context + http://www.springframework.org/schema/context/spring-context-3.0.xsd + http://www.springframework.org/schema/data/mongo + http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd + http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> -<beans> - - <!-- Default bean name is 'mongo' --> - <mongo:mongo host="localhost" port="27017"/> - - <!-- To translate any MongoExceptions thrown in @Repository annotated classes --> - <context:annotation-config/> + <beans> -</beans> - + <!-- Default bean name is 'mongo' --> + <mongo:mongo host="localhost" port="27017"/> + + <!-- To translate any MongoExceptions thrown in @Repository annotated classes --> + <context:annotation-config/> + + </beans> + A more advanced configuration with MongoOptions is shown - below + below + XML schema to configure MongoOptinos in MongoDB <beans> - - <mongo:mongo host="localhost" port="27017"> - <mongo:options connectionsPerHost="10" - threadsAllowedToBlockForConnectionMultiplier="5" - maxWaitTime="12000" - connectTimeout="0" - socketTimeout="0" - autoConnectRetry="0"/> - </mongo:mongo/> - -</beans> - + + <mongo:mongo host="localhost" port="27017"> + <mongo:options connectionsPerHost="10" + threadsAllowedToBlockForConnectionMultiplier="5" + maxWaitTime="12000" + connectTimeout="0" + socketTimeout="0" + autoConnectRetry="0"/> + </mongo:mongo/> + + </beans> + - A configuration using replica sets is shown below: + A configuration using replica sets is shown below: + XML schema to configure replica sets in MongoDB <beans> - - <mongo:mongo> - <! replica set TBD -- should be available for release 1.0.0.M2 --> - <mongo:mongo> - -</beans> - - + + <mongo:mongo> + <! replica set TBD -- should be available for release 1.0.0.M2 --> + <mongo:mongo> + + </beans> + + +
                      Working with objects using the - <classname>MongoTemplate</classname> + MongoTemplate + - Most users are likely to use MongoTemplate - and its corresponding package - org.springframework.data.document.mongodb - the - template is in fact the central class of the MongoDB module due to its - rich feature set. The template offers convenience methods and automatic - mapping between MongoDB JSON documents and your domain classes. Out of the - box, MongoTemplate uses a Java-based default - converter but you can also write your own converter classes to be used for - reading and storing domain objects. + Most users are likely to use + MongoTemplate + and its corresponding package + org.springframework.data.document.mongodb + - the + template is in fact the central class of the MongoDB module due to its + rich feature set. The template offers convenience methods and automatic + mapping between MongoDB JSON documents and your domain classes. Out of the + box, + MongoTemplate + uses a Java-based default + converter but you can also write your own converter classes to be used for + reading and storing domain objects. + - Once configured, MongoTemplate is - thread-safe and can be reused across multiple instances. + Once configured, + MongoTemplate + is + thread-safe and can be reused across multiple instances. + Let's look at a couple of examples for how to work with the - MongoTemplate in the context of the Spring - container. + MongoTemplate + in the context of the Spring + container. +
                      Instantiating MongoTemplate In Java based configuration using the driver's com.mongodb.Mongo - object + object + Registering a com.mongodb.Mongo object and enabling Spring's - exception translation support + exception translation support + @Configuration -public class AppConfig extends MongoExceptionTranslationConfig { - - public @Bean Mongo mongo() throws UnknownHostException, MongoException { - return new Mongo("localhost"); - } + public class AppConfig extends MongoExceptionTranslationConfig { - public @Bean MongoTemplate mongoTemplate() throws UnknownHostException, MongoException { - return new MongoTemplate(mongo(), "test", "HelloMongo"); - } -} - + public @Bean Mongo mongo() throws UnknownHostException, MongoException { + return new Mongo("localhost"); + } + + public @Bean MongoTemplate mongoTemplate() throws UnknownHostException, MongoException { + return new MongoTemplate(mongo(), "test", "HelloMongo"); + } + } + Alternatively using MongoFactoryBean, which avoid dealing with the - checked UnknownHostException + checked UnknownHostException + Registering a com.mongodb.Mongo object and enabling Spring's - exception translation support + exception translation support + @Configuration -public class AppConfig { + public class AppConfig { - /* - * The method argument is the container managed Mongo instance created by the mongo() method - */ - public @Bean MongoTemplate mongoTemplate(Mongo mongo) { - MongoTemplate mongoTemplate = new MongoTemplate(mongo, "test", "HelloMongo"); - return mongoTemplate; - } - - /* - * Factory bean that creates the Mongo instance - */ - public @Bean MongoFactoryBean mongo() { - MongoFactoryBean mongo = new MongoFactoryBean(); - mongo.setHost("localhost"); - return mongo; - } - - /* - * Use this post processor to translate any MongoExceptions thrown in @Repository - * annotated classes - */ - public @Bean PersistenceExceptionTranslationPostProcessor + /* + * The method argument is the container managed Mongo instance created by the mongo() method + */ + public @Bean MongoTemplate mongoTemplate(Mongo mongo) { + MongoTemplate mongoTemplate = new MongoTemplate(mongo, "test", "HelloMongo"); + return mongoTemplate; + } + + /* + * Factory bean that creates the Mongo instance + */ + public @Bean MongoFactoryBean mongo() { + MongoFactoryBean mongo = new MongoFactoryBean(); + mongo.setHost("localhost"); + return mongo; + } + + /* + * Use this post processor to translate any MongoExceptions thrown in @Repository + * annotated classes + */ + public @Bean PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor() { - return new PersistenceExceptionTranslationPostProcessor(); - } + return new PersistenceExceptionTranslationPostProcessor(); + } -} - + } + There are several overloaded constructors of MongoTemplate. - These are + These are + - MongoTemplate(Mongo mongo, String - databaseName) - takes the default database name to - operate against + + MongoTemplate + + (Mongo mongo, String + databaseName) + + - takes the default database name to + operate against + - MongoTemplate(Mongo mongo, String - databaseName, String defaultCollectionName) - adds the - default collection name to operate against. + + MongoTemplate + + (Mongo mongo, String + databaseName, String defaultCollectionName) + + - adds the + default collection name to operate against. + - MongoTemplate(Mongo mongo, String - databaseName, String defaultCollectionName, MongoConverter - mongoConverter) - override with a provided - MongoConverter. Default is SimpleMongoConverter + + MongoTemplate + + (Mongo mongo, String + databaseName, String defaultCollectionName, MongoConverter + mongoConverter) + + - override with a provided + MongoConverter. Default is SimpleMongoConverter + - MongoTemplate(Mongo mongo, String - databaseName, String defaultCollectionName, MongoConverter - mongoConverter, WriteConcern writeConcern, WriteResultChecking - writeResultChecking) - Specify a default WriteConcern - and also WriteResultChecking policy + + MongoTemplate + + (Mongo mongo, String + databaseName, String defaultCollectionName, MongoConverter + mongoConverter, WriteConcern writeConcern, WriteResultChecking + writeResultChecking) + + - Specify a default WriteConcern + and also WriteResultChecking policy + - MongoTemplate(Mongo mongo, String - databaseName, String defaultCollectionName, WriteConcern - writeConcern, WriteResultChecking writeResultChecking)- - Specify a default WriteConcern and also WriteResultChecking - policy + + MongoTemplate + + (Mongo mongo, String + databaseName, String defaultCollectionName, WriteConcern + writeConcern, WriteResultChecking writeResultChecking)- + Specify a default WriteConcern and also WriteResultChecking + policy + - MongoTemplate(Mongo mongo, String - databaseName, WriteConcern writeConcern, WriteResultChecking - writeResultChecking)- Specify a default WriteConcern and - also WriteResultChecking policy + + MongoTemplate + + (Mongo mongo, String + databaseName, WriteConcern writeConcern, WriteResultChecking + writeResultChecking)- Specify a default WriteConcern and + also WriteResultChecking policy + @@ -410,12 +506,13 @@ public class AppConfig { WriteResultChecking Policy When in development it is very handy to either log or throw an - exception if the WriteResult returned from any MongoDB operation - contains an error. It is quite common to forget to do this during - development and then end up with an application that looks like it ran - successfully but the database was not modified according to your - expectations. Setting the WriteResultChecking is an enum with the - following values, NONE, LOG, EXCEPTION. + exception if the WriteResult returned from any MongoDB operation + contains an error. It is quite common to forget to do this during + development and then end up with an application that looks like it ran + successfully but the database was not modified according to your + expectations. Setting the WriteResultChecking is an enum with the + following values, NONE, LOG, EXCEPTION. + The default is to use a WriteResultChecking of NONE.
                      @@ -424,67 +521,122 @@ public class AppConfig {
                      Overview of MongoTemplate Methods - The public methods for MongoTemplate are - defined by the interface MongoOperations. - They can be grouped into the following categories: + The public methods for + MongoTemplate + are + defined by the interfaceMongoOperations. + They can be grouped into the following categories: +
                      Methods for working with a Collection - + + - Set<String> getCollectionNames() A - set of collection names. + + Set<String> + getCollectionNames + + () + A + set of collection names. + - boolean collectionExists(String - collectionName) Check to see if a collection with a - given name exists. + + boolean + collectionExists + + (String + collectionName) + + Check to see if a collection with a + given name exists. + - DBCollection createCollection(String - collectionName) Create an uncapped collection with the - provided name. + + DBCollection + createCollection + + (String + collectionName) + + Create an uncapped collection with the + provided name. + - DBCollection createCollection(String - collectionName, CollectionOptions collectionOptions) - Create a collect with the provided name and options. + + DBCollection + createCollection + + (String + collectionName, CollectionOptions collectionOptions) + + Create a collect with the provided name and options. + - void dropCollection(String - collectionName) Drop the collection with the given - name. + + void + dropCollection + + (String + collectionName) + + Drop the collection with the given + name. + - DBCollection getCollection(String - collectionName) Get a collection by name, creating it - if it doesn't exist. + + DBCollection + getCollection + + (String + collectionName) + + Get a collection by name, creating it + if it doesn't exist. + - DBCollection getDefaultCollection() - The default collection used by this template. + + DBCollection + getDefaultCollection + + () + The default collection used by this template. + - String getDefaultCollectionName() - The default collection name used by this template. + + String + getDefaultCollectionName + + () + The default collection name used by this template. + - + +
                      @@ -492,51 +644,95 @@ public class AppConfig {
                      Methods for executing commands - + + - CommandResult executeCommand(DBObject - command) Execute a MongoDB command. + + CommandResult + executeCommand + + (DBObject + command) + + Execute a MongoDB command. + - CommandResult executeCommand(String - jsonCommand) Execute the a MongoDB command expressed - as a JSON string. + + CommandResult + executeCommand + + (String + jsonCommand) + + Execute the a MongoDB command expressed + as a JSON string. + - <T> T execute(CollectionCallback<T> - action) Executes the given CollectionCallback on the - default collection. + + <T> T + execute + + (CollectionCallback<T> + action) + + Executes the given CollectionCallback on the + default collection. + - <T> T execute(String collectionName, - CollectionCallback<T> action) Executes the given - CollectionCallback on the collection of the given name.update - using the $addToSet update modifier + + <T> T + execute + + (String collectionName, + CollectionCallback<T> action) + + Executes the given + CollectionCallback on the collection of the given name.update + using the $addToSet update modifier + - <T> T execute(DbCallback<T> - action) Executes a DbCallback translating any - exceptions as necessary. + + <T> T + execute + + (DbCallback<T> + action) + + Executes a DbCallback translating any + exceptions as necessary. + - <T> T executeInSession(DbCallback<T> - action) Executes the given DbCallback within the same - connection to the database so as to ensure consistency in a - write heavy environment where you may read the data that you - wrote. + + <T> T + executeInSession + + (DbCallback<T> + action) + + Executes the given DbCallback within the same + connection to the database so as to ensure consistency in a + write heavy environment where you may read the data that you + wrote. + - + +
                      @@ -544,22 +740,37 @@ public class AppConfig {
                      Methods for creating an Index - + + - void ensureIndex(IndexDefinition - indexDefintion) Ensure that an index for the provided - IndexDefinition exists for the default collection. + + void + ensureIndex + + (IndexDefinition + indexDefintion) + + Ensure that an index for the provided + IndexDefinition exists for the default collection. + - void ensureIndex(String - collectionName, IndexDefinition indexSpecification) - Ensure that an index for the provided IndexDefinition - exists. + + void + ensureIndex + + (String + collectionName, IndexDefinition indexSpecification) + + Ensure that an index for the provided IndexDefinition + exists. + - + +
                      @@ -567,69 +778,127 @@ public class AppConfig {
                      Methods for inserting documents - + + - void insert(Object - objectToSave) Insert the object into the default - collection. + + void + insert + + (Object + objectToSave) + + Insert the object into the default + collection. + - void insert(String collectionName, - Object objectToSave) Insert the object into the - specified collection. + + void + insert + + (String collectionName, + Object objectToSave) + + Insert the object into the + specified collection. + - void insertList(List<? extends - Object> listToSave) Insert a list of objects into - the default collection in a single batch write to the - database. + + void + insertList + + (List<? extends + Object> listToSave) + + Insert a list of objects into + the default collection in a single batch write to the + database. + - void insertList(String - collectionName, List<? extends Object> - listToSave) Insert a list of objects into the - specified collection in a single batch write to the - database. + + void + insertList + + (String + collectionName, List<? extends Object> + listToSave) + + Insert a list of objects into the + specified collection in a single batch write to the + database. + - <T> void insert(T objectToSave, - MongoWriter<T> writer) Insert the object into - the default collection. + + <T> void + insert + + (T objectToSave, + MongoWriter<T> writer) + + Insert the object into + the default collection. + - <T> void insert(String collectionName, T - objectToSave, MongoWriter<T> writer) Insert the - object into the specified collection. + + <T> void + insert + + (String collectionName, T + objectToSave, MongoWriter<T> writer) + + Insert the + object into the specified collection. + - <T> void insertList(List<? extends - T> listToSave, MongoWriter<T> writer) Insert - a list of objects into the default collection using the provided - MongoWriter instance + + <T> void + insertList + + (List<? extends + T> listToSave, MongoWriter<T> writer) + + Insert + a list of objects into the default collection using the provided + MongoWriter instance + - <T> void insertList(String - collectionName, List<? extends T> listToSave, - MongoWriter<T> writer) Insert a list of objects - into the specified collection using the provided MongoWriter - instance + + <T> void + insertList + + (String + collectionName, List<? extends T> listToSave, + MongoWriter<T> writer) + + Insert a list of objects + into the specified collection using the provided MongoWriter + instance + - + +
                      @@ -637,105 +906,191 @@ public class AppConfig {
                      Methods for querying for documents - + + - <T> List<T> getCollection(Class<T> - targetClass) Query for a list of objects of type T - from the default collection. + + <T> List<T> + getCollection + + (Class<T> + targetClass) + + Query for a list of objects of type T + from the default collection. + - <T> List<T> getCollection(String - collectionName, Class<T> targetClass) Query for - a list of objects of type T from the specified - collection. + + <T> List<T> + getCollection + + (String + collectionName, Class<T> targetClass) + + Query for + a list of objects of type T from the specified + collection. + - <T> List<T> getCollection(String - collectionName, Class<T> targetClass, MongoReader<T> - reader) Query for a list of objects of type T from the - specified collection, mapping the DBObject using the provided - MongoReader. + + <T> List<T> + getCollection + + (String + collectionName, Class<T> targetClass, MongoReader<T> + reader) + + Query for a list of objects of type T from the + specified collection, mapping the DBObject using the provided + MongoReader. + - <T> T findOne(Query query, - Class<T> targetClass) Map the results of an - ad-hoc query on the default MongoDB collection to a single - instance of an object of the specified type. + + <T> T + findOne + + (Query query, + Class<T> targetClass) + + Map the results of an + ad-hoc query on the default MongoDB collection to a single + instance of an object of the specified type. + - <T> T findOne(Query query, - Class<T> targetClass, MongoReader<T> - reader) Map the results of an ad-hoc query on the - default MongoDB collection to a single instance of an object of - the specified type. + + <T> T + findOne + + (Query query, + Class<T> targetClass, MongoReader<T> + reader) + + Map the results of an ad-hoc query on the + default MongoDB collection to a single instance of an object of + the specified type. + - <T> T findOne(String collectionName, - Query query, Class<T> targetClass) Map the - results of an ad-hoc query on the specified collection to a - single instance of an object of the specified type. + + <T> T + findOne + + (String collectionName, + Query query, Class<T> targetClass) + + Map the + results of an ad-hoc query on the specified collection to a + single instance of an object of the specified type. + - <T> T findOne(String collectionName, - Query query, Class<T> targetClass, MongoReader<T> - reader) Map the results of an ad-hoc query on the - specified collection to a single instance of an object of the - specified type. + + <T> T + findOne + + (String collectionName, + Query query, Class<T> targetClass, MongoReader<T> + reader) + + Map the results of an ad-hoc query on the + specified collection to a single instance of an object of the + specified type. + - <T> List<T> find(Query query, Class<T> - targetClass) Map the results of an ad-hoc query on the - default MongoDB collection to a List of the specified - type. + + <T> List<T> + find + + (Query query, Class<T> + targetClass) + + Map the results of an ad-hoc query on the + default MongoDB collection to a List of the specified + type. + - <T> List<T> find(Query query, Class<T> - targetClass, MongoReader<T> reader) Map the - results of an ad-hoc query on the default MongoDB collection to - a List of the specified type. + + <T> List<T> + find + + (Query query, Class<T> + targetClass, MongoReader<T> reader) + + Map the + results of an ad-hoc query on the default MongoDB collection to + a List of the specified type. + - <T> List<T> find(String collectionName, - Query query, Class<T> targetClass) Map the - results of an ad-hoc query on the specified collection to a List - of the specified type. + + <T> List<T> + find + + (String collectionName, + Query query, Class<T> targetClass) + + Map the + results of an ad-hoc query on the specified collection to a List + of the specified type. + - <T> List<T> find(String collectionName, - Query query, Class<T> targetClass, CursorPreparer - preparer) Map the results of an ad-hoc query on the - specified collection to a List of the specified type. + + <T> List<T> + find + + (String collectionName, + Query query, Class<T> targetClass, CursorPreparer + preparer) + + Map the results of an ad-hoc query on the + specified collection to a List of the specified type. + - <T> List<T> find(String collectionName, - Query query, Class<T> targetClass, MongoReader<T> - reader) Map the results of an ad-hoc query on the - specified collection to a List of the specified type. + + <T> List<T> + find + + (String collectionName, + Query query, Class<T> targetClass, MongoReader<T> + reader) + + Map the results of an ad-hoc query on the + specified collection to a List of the specified type. + - + +
                      @@ -743,36 +1098,66 @@ public class AppConfig {
                      Methods for saving documents - + + - void save(Object - objectToSave) Save the object to the default - collection. + + void + save + + (Object + objectToSave) + + Save the object to the default + collection. + - void save(String collectionName, - Object objectToSave) Save the object to the specified - collection. + + void + save + + (String collectionName, + Object objectToSave) + + Save the object to the specified + collection. + - <T> void save(T objectToSave, - MongoWriter<T> writer) Save the object into the - default collection using the provided writer. + + <T> void + save + + (T objectToSave, + MongoWriter<T> writer) + + Save the object into the + default collection using the provided writer. + - <T> void save(String collectionName, T - objectToSave, MongoWriter<T> writer) Save the - object into the specified collection using the provided - writer. + + <T> void + save + + (String collectionName, T + objectToSave, MongoWriter<T> writer) + + Save the + object into the specified collection using the provided + writer. + - + +
                      @@ -780,22 +1165,36 @@ public class AppConfig {
                      Methods for removing documents - + + - void remove(Query query) - Remove all documents from the default collection that match the - provided query document criteria. + + void + remove + + (Query query) + Remove all documents from the default collection that match the + provided query document criteria. + - void remove(String collectionName, - Query query) Remove all documents from the specified - collection that match the provided query document - criteria. + + void + remove + + (String collectionName, + Query query) + + Remove all documents from the specified + collection that match the provided query document + criteria. + - + +
                      @@ -803,41 +1202,71 @@ public class AppConfig {
                      Methods for executing updates for documents - + + - WriteResult updateFirst(Query query, Update - update) Updates the first object that is found in the - default collection that matches the query document with the - provided updated document. + + WriteResult + updateFirst + + (Query query, Update + update) + + Updates the first object that is found in the + default collection that matches the query document with the + provided updated document. + - WriteResult updateFirst(String - collectionName, Query query, Update update) Updates - the first object that is found in the specified collection that - matches the query document criteria with the provided updated - document. + + WriteResult + updateFirst + + (String + collectionName, Query query, Update update) + + Updates + the first object that is found in the specified collection that + matches the query document criteria with the provided updated + document. + - WriteResult updateMulti(Query query, Update - update) Updates all objects that are found in the - default collection that matches the query document criteria with - the provided updated document. + + WriteResult + updateMulti + + (Query query, Update + update) + + Updates all objects that are found in the + default collection that matches the query document criteria with + the provided updated document. + - WriteResult updateMulti(String - collectionName, Query query, Update update) Updates - all objects that are found in the specified collection that - matches the query document criteria with the provided updated - document. + + WriteResult + updateMulti + + (String + collectionName, Query query, Update update) + + Updates + all objects that are found in the specified collection that + matches the query document criteria with the provided updated + document. + - + +
                      @@ -847,19 +1276,20 @@ public class AppConfig { Working with collections It's time to look at some code examples showing how to use the - MongoTemplate. First we look at creating our - first collection. + MongoTemplate. First we look at creating our + first collection. + Working with collections using the MongoTemplate - DBCollection collection = null; - if (!mongoTemplate.getCollectionNames().contains("MyNewCollection")) { - collection = mongoTemplate.createCollection("MyNewCollection"); - } + DBCollection collection = null; + if (!mongoTemplate.getCollectionNames().contains("MyNewCollection")) { + collection = mongoTemplate.createCollection("MyNewCollection"); + } - mongoTemplate.dropCollection("MyNewCollection"); - + mongoTemplate.dropCollection("MyNewCollection"); +
                      @@ -867,40 +1297,45 @@ public class AppConfig { Creating an index We can create an index on a collection to improve query - performance. + performance. + Creating an index using the MongoTemplate - mongoTemplate.ensureIndex("MyCollection", new Index().on("name", Order.ASCENDING)); - + mongoTemplate.ensureIndex("MyCollection", new Index().on("name", + Order.ASCENDING)); +
                      Saving and retrieving objects as documents in a - collection + collection + Once we have created the collection and maybe an index we can - start using the collection to store our domain objects as documents. - Note that we are using a static import for - org.springframework.data.document.mongodb.query.Criteria.where - to make the query more readable. + start using the collection to store our domain objects as documents. + Note that we are using a static import for + org.springframework.data.document.mongodb.query.Criteria.where + to make the query more readable. + Inserting and retrieving documents using the - MongoTemplate + MongoTemplate + import static org.springframework.data.document.mongodb.query.Criteria.where; -... + ... - Person p = new Person("Bob", 33); - mongoTemplate.insert("MyCollection", p); - - Person qp = mongoTemplate.findOne("MyCollection", - new Query(where("id").is(p.getId())), Person.class); - + Person p = new Person("Bob", 33); + mongoTemplate.insert("MyCollection", p); + + Person qp = mongoTemplate.findOne("MyCollection", + new Query(where("id").is(p.getId())), Person.class); +
                      @@ -908,42 +1343,53 @@ public class AppConfig { Querying documents in a collection We saw how to retrieve a single document. We can also query for a - collection of documents to be returned as domain objects in a list. - Assuming that we have a number of Person objects with name and age - stored as documents in a collection and that each person has an embedded - account document with a balance. We can now run a query using the - following code. + collection of documents to be returned as domain objects in a list. + Assuming that we have a number of Person objects with name and age + stored as documents in a collection and that each person has an embedded + account document with a balance. We can now run a query using the + following code. + Querying for documents using the MongoTemplate import static org.springframework.data.document.mongodb.query.Criteria.where; -... + ... - List<Person> result = mongoTemplate.find( - new Query(where("age").lt(50)).and(where("accounts.balance").gt(1000.00d)), - Person.class); - + List<Person> result = mongoTemplate.find( + new Query(where("age").lt(50)).and(where("accounts.balance").gt(1000.00d)), + Person.class); + - All find methods take a Query object as a - parameter. This object defines the criteria and options used to perform - the query. The criteria is specified using a - Criteria object that has a static factory method - named where used to instantiate a new - Criteria object. We recommend using a static - import for - org.springframework.data.document.mongodb.query.Criteria.where - to make the query more readable. + All find methods take a + Query + object as a + parameter. This object defines the criteria and options used to perform + the query. The criteria is specified using a + Criteria + object that has a static factory method + named + where + used to instantiate a new + Criteria + object. We recommend using a static + import for + org.springframework.data.document.mongodb.query.Criteria.where + to make the query more readable. + This query should return a list of Person objects that meet the - specified criteria. The Criteria class has the following methods that - correspond to the operators provided in MongoDB. + specified criteria. The Criteria class has the following methods that + correspond to the operators provided in MongoDB. + As you can see most methods return the - Criteria object to provide a fluent style for the - API. + Criteria + object to provide a fluent style for the + API. +
                      Methods for the Criteria class @@ -951,109 +1397,210 @@ public class AppConfig { - Criteria all(Object o) Creates - a criterion using the $all operator + + Criteria + all + + (Object o)Creates + a criterion using the + $all + operator + - Criteria exists(boolean b) - Creates a criterion using the - $exists operator + + Criteria + exists + + (boolean b) + Creates a criterion using the + $exists + operator + - Criteria gt(Object o) Creates a - criterion using the $gt operator + + Criteria + gt + + (Object o)Creates a + criterion using the + $gt + operator + - Criteria gte(Object o) Creates - a criterion using the $gte operator + + Criteria + gte + + (Object o)Creates + a criterion using the + $gte + operator + - Criteria in(Object... o) - Creates a criterion using the $in - operator + + Criteria + in + + (Object... o) + Creates a criterion using the + $in + operator + - Criteria is(Object o) Creates a - criterion using the $is operator + + Criteria + is + + (Object o)Creates a + criterion using the + $is + operator + - Criteria lt(Object o) Creates a - criterion using the $lt operator + + Criteria + lt + + (Object o)Creates a + criterion using the + $lt + operator + - Criteria lte(Object o) Creates - a criterion using the $lte operator + + Criteria + lte + + (Object o)Creates + a criterion using the + $lte + operator + - Criteriamod(Number value, Number - remainder) Creates a criterion using the - $mod operator + + Criteria + mod + + (Number value, Number + remainder)Creates a criterion using the + $mod + operator + - Criteria nin(Object... o) - Creates a criterion using the $nin - operator + + Criteria + nin + + (Object... o) + Creates a criterion using the + $nin + operator + - Criteria not() Creates a - criterion using the $not meta operator which - affects the clause directly following + + Criteria + not + + ()Creates a + criterion using the + $not + meta operator which + affects the clause directly following + - Criteria regex(String re) - Creates a criterion using a - $regex + + Criteria + regex + + (String re) + Creates a criterion using a + $regex + - Criteria size(int s) Creates a - criterion using the $size operator + + Criteria + size + + (int s)Creates a + criterion using the + $size + operator + - Criteria type(int t) Creates a - criterion using the $type operator + + Criteria + type + + (int t)Creates a + criterion using the + $type + operator + - void or(List<Query> queries) - Creates an or query using the $or - operator for all of the provided queries + + void + or + + (List<Query> queries) + Creates an or query using the + $or + operator for all of the provided queries + - +
                      - The Query class has some additional methods - used to provide options for the query. + The + Query + class has some additional methods + used to provide options for the query. +
                      Methods for the Query class @@ -1061,37 +1608,66 @@ public class AppConfig { - Query and(Criteria criteria) - used to add additional criteria to the query + + Query + and + + (Criteria criteria) + used to add additional criteria to the query + - Field fields() used to - define fields to be included in the query results + + Field + fields + + () + used to + define fields to be included in the query results + - Query limit(int limit) used - to limit the size of the returned results to the provided limit - (used for paging) + + Query + limit + + (int limit) + used + to limit the size of the returned results to the provided limit + (used for paging) + - Query skip(int skip) used to - skip the provided number of documents in the results (used for - paging) + + Query + skip + + (int skip) + used to + skip the provided number of documents in the results (used for + paging) + - Sort sort() used to provide - sort definition for the results + + Sort + sort + + () + used to provide + sort definition for the results + - + @@ -1102,108 +1678,203 @@ public class AppConfig { Updating documents in a collection For updates we can elect to update the first document found using - updateFirst or we can update all documents that were - found to match the query using updateMulti. Here is - an example of an update of all SAVINGS accounts where we are adding a - one time $50.00 bonus to the balance using the $inc - operator. + updateFirst + or we can update all documents that were + found to match the query usingupdateMulti. Here is + an example of an update of all SAVINGS accounts where we are adding a + one time $50.00 bonus to the balance using the + $inc + operator. + Updating documents using the MongoTemplate import static org.springframework.data.document.mongodb.query.Criteria.where; -... + ... - WriteResult wr = mongoTemplate.updateMulti( - new Query(where("accounts.accountType").is(Account.Type.SAVINGS)), - new Update().inc("accounts.$.balance", 50.00)); - + WriteResult wr = mongoTemplate.updateMulti( + new Query(where("accounts.accountType").is(Account.Type.SAVINGS)), + new Update().inc("accounts.$.balance", 50.00)); + - In addition to the Query discussed above we - provide the update definition using an Update - object. The Update class has methods that match - the update modifiers available for MongoDB. + In addition to the + Query + discussed above we + provide the update definition using an + Update + object. The + Update + class has methods that match + the update modifiers available for MongoDB. + As you can see most methods return the - Update object to provide a fluent style for the - API. + Update + object to provide a fluent style for the + API. +
                      Methods for the Update class - + + - Update addToSet(String key, Object - value) Update using the $addToSet - update modifier + + Update + addToSet + + (String key, Object + value) + + Update using the + $addToSet + update modifier + - Update inc(String key, Number - inc) Update using the $inc update - modifier + + Update + inc + + (String key, Number + inc) + + Update using the + $inc + update + modifier + - Update pop(String key, Update.Position - pos) Update using the $pop update - modifier + + Update + pop + + (String key, Update.Position + pos) + + Update using the + $pop + update + modifier + - Update pull(String key, Object - value) Update using the $pull - update modifier + + Update + pull + + (String key, Object + value) + + Update using the + $pull + update modifier + - Update pullAll(String key, Object[] - values) Update using the $pullAll - update modifier + + Update + pullAll + + (String key, Object[] + values) + + Update using the + $pullAll + update modifier + - Update push(String key, Object - value) Update using the $push - update modifier + + Update + push + + (String key, Object + value) + + Update using the + $push + update modifier + - Update pushAll(String key, Object[] - values) Update using the $pushAll - update modifier + + Update + pushAll + + (String key, Object[] + values) + + Update using the + $pushAll + update modifier + - Update rename(String oldName, String - newName) Update using the $rename - update modifier + + Update + rename + + (String oldName, String + newName) + + Update using the + $rename + update modifier + - Update set(String key, Object - value) Update using the $set update - modifier + + Update + set + + (String key, Object + value) + + Update using the + $set + update + modifier + - Update unset(String key) - Update using the $unset update - modifier + + Update + unset + + (String key) + Update using the + $unset + update + modifier + - + +
                      @@ -1214,10 +1885,14 @@ public class AppConfig { Road map ahead The Spring Data Document projects MongoDB support is in its early - stages. We are interested in feedback, knowing what your use cases are, - what are the common patters you encounter so that the MongoDB module - better serves your needs. Do contact us using the channels mentioned above, we are - interested in hearing from you! + stages. We are interested in feedback, knowing what your use cases are, + what are the common patters you encounter so that the MongoDB module + better serves your needs. Do contact us using the channels + mentioned + + above, we are + interested in hearing from you! +
                      diff --git a/src/docbkx/resources/css/highlight.css b/src/docbkx/resources/css/highlight.css index ffefef72d..6e99e890f 100644 --- a/src/docbkx/resources/css/highlight.css +++ b/src/docbkx/resources/css/highlight.css @@ -5,7 +5,7 @@ .hl-keyword { color: #7F0055; - font-weight: bold; + font-weight: bold; } .hl-comment { diff --git a/src/docbkx/resources/css/html.css b/src/docbkx/resources/css/html.css index 10936f337..0e93e06d7 100644 --- a/src/docbkx/resources/css/html.css +++ b/src/docbkx/resources/css/html.css @@ -1,11 +1,11 @@ body { - text-align: justify; - margin-right: 2em; - margin-left: 2em; + text-align: justify; + margin-right: 2em; + margin-left: 2em; } a, - a[accesskey^ +a[accesskey^ = "h" @@ -29,72 +29,69 @@ a[accesskey^ "p" ] { -font-family: Verdana, Arial, helvetica, sans-serif + font-family: Verdana, Arial, helvetica, sans-serif ; -font-size: - -12 -px + font-size: 12px ; -color: #003399 + color: #003399 ; } a:active { - color: #003399; + color: #003399; } a:visited { - color: #888888; + color: #888888; } p { - font-family: Verdana, Arial, sans-serif; + font-family: Verdana, Arial, sans-serif; } dt { - font-family: Verdana, Arial, sans-serif; - font-size: 12px; + font-family: Verdana, Arial, sans-serif; + font-size: 12px; } p, dl, dt, dd, blockquote { - color: #000000; - margin-bottom: 3px; - margin-top: 3px; - padding-top: 0px; + color: #000000; + margin-bottom: 3px; + margin-top: 3px; + padding-top: 0px; } ol, ul, p { - margin-top: 6px; - margin-bottom: 6px; + margin-top: 6px; + margin-bottom: 6px; } p, blockquote { - font-size: 90%; + font-size: 90%; } p.releaseinfo { - font-size: 100%; - font-weight: bold; - font-family: Verdana, Arial, helvetica, sans-serif; - padding-top: 10px; + font-size: 100%; + font-weight: bold; + font-family: Verdana, Arial, helvetica, sans-serif; + padding-top: 10px; } p.pubdate { - font-size: 120%; - font-weight: bold; - font-family: Verdana, Arial, helvetica, sans-serif; + font-size: 120%; + font-weight: bold; + font-family: Verdana, Arial, helvetica, sans-serif; } td { - font-size: 80%; + font-size: 80%; } td, th, span { - color: #000000; + color: #000000; } td[width^ @@ -103,16 +100,13 @@ td[width^ "40%" ] { -font-family: Verdana, Arial, helvetica, sans-serif + font-family: Verdana, Arial, helvetica, sans-serif ; -font-size: - -12 -px + font-size: 12px ; -color: #003399 + color: #003399 ; } @@ -128,60 +122,60 @@ tbody tr th[colspan^ "3" ] { -font-family: Verdana, Arial, helvetica, sans-serif + font-family: Verdana, Arial, helvetica, sans-serif ; } blockquote { - margin-right: 0px; + margin-right: 0px; } h1, h2, h3, h4, h6, H6 { - color: #000000; - font-weight: 500; - margin-top: 0px; - padding-top: 14px; - font-family: Verdana, Arial, helvetica, sans-serif; - margin-bottom: 0px; + color: #000000; + font-weight: 500; + margin-top: 0px; + padding-top: 14px; + font-family: Verdana, Arial, helvetica, sans-serif; + margin-bottom: 0px; } h2.title { - font-weight: 800; - margin-bottom: 8px; + font-weight: 800; + margin-bottom: 8px; } h2.subtitle { - font-weight: 800; - margin-bottom: 20px; + font-weight: 800; + margin-bottom: 20px; } .firstname, .surname { - font-size: 12px; - font-family: Verdana, Arial, helvetica, sans-serif; + font-size: 12px; + font-family: Verdana, Arial, helvetica, sans-serif; } table { - border-collapse: collapse; - border-spacing: 0; - border: 1px black; - empty-cells: hide; - margin: 10px 0px 30px 50px; - width: 90%; + border-collapse: collapse; + border-spacing: 0; + border: 1px black; + empty-cells: hide; + margin: 10px 0px 30px 50px; + width: 90%; } div.table { - margin: 30px 0px 30px 0px; - border: 1px dashed gray; - padding: 10px; + margin: 30px 0px 30px 0px; + border: 1px dashed gray; + padding: 10px; } div .table-contents table { - border: 1px solid black; + border: 1px solid black; } div.table > p.title { - padding-left: 10px; + padding-left: 10px; } table[summary^ @@ -190,32 +184,21 @@ table[summary^ "Navigation footer" ] { -border-collapse: collapse + border-collapse: collapse ; -border-spacing: - -0 + border-spacing: 0 ; -border: - -1 -px black + border: 1px black ; -empty-cells: hide + empty-cells: hide ; -margin: - -0 -px + margin: 0px ; -width: - -100 -% + width: 100% ; } @@ -237,185 +220,164 @@ table[summary^ "Tip" ] { -border-collapse: collapse + border-collapse: collapse ; -border-spacing: - -0 + border-spacing: 0 ; -border: - -1 -px black + border: 1px black ; -empty-cells: hide + empty-cells: hide ; -margin: - -10 -px - -0 -px - -10 -px - -- -20 -px + margin: 10px 0px 10px -20px ; -width: - -100 -% + width: 100% ; } td { - padding: 4pt; - font-family: Verdana, Arial, helvetica, sans-serif; + padding: 4pt; + font-family: Verdana, Arial, helvetica, sans-serif; } div.warning TD { - text-align: justify; + text-align: justify; } h1 { - font-size: 150%; + font-size: 150%; } h2 { - font-size: 110%; + font-size: 110%; } h3 { - font-size: 100%; - font-weight: bold; + font-size: 100%; + font-weight: bold; } h4 { - font-size: 90%; - font-weight: bold; + font-size: 90%; + font-weight: bold; } h5 { - font-size: 90%; - font-style: italic; + font-size: 90%; + font-style: italic; } h6 { - font-size: 100%; - font-style: italic; + font-size: 100%; + font-style: italic; } tt { - font-size: 110%; - font-family: "Courier New", Courier, monospace; - color: #000000; + font-size: 110%; + font-family: "Courier New", Courier, monospace; + color: #000000; } .navheader, .navfooter { - border: none; + border: none; } div.navfooter table { - border: dashed gray; - border-width: 1px 1px 1px 1px; - background-color: #cde48d; + border: dashed gray; + border-width: 1px 1px 1px 1px; + background-color: #cde48d; } pre { - font-size: 110%; - padding: 5px; - border-style: solid; - border-width: 1px; - border-color: #CCCCCC; - background-color: #f3f5e9; + font-size: 110%; + padding: 5px; + border-style: solid; + border-width: 1px; + border-color: #CCCCCC; + background-color: #f3f5e9; } ul, ol, li { - list-style: disc; + list-style: disc; } hr { - width: 100%; - height: 1px; - background-color: #CCCCCC; - border-width: 0px; - padding: 0px; + width: 100%; + height: 1px; + background-color: #CCCCCC; + border-width: 0px; + padding: 0px; } .variablelist { - padding-top: 10px; - padding-bottom: 10px; - margin: 0; + padding-top: 10px; + padding-bottom: 10px; + margin: 0; } .term { - font-weight: bold; + font-weight: bold; } .mediaobject { - padding-top: 30px; - padding-bottom: 30px; + padding-top: 30px; + padding-bottom: 30px; } .legalnotice { - font-family: Verdana, Arial, helvetica, sans-serif; - font-size: 12px; - font-style: italic; + font-family: Verdana, Arial, helvetica, sans-serif; + font-size: 12px; + font-style: italic; } .sidebar { - float: right; - margin: 10px 0px 10px 30px; - padding: 10px 20px 20px 20px; - width: 33%; - border: 1px solid black; - background-color: #F4F4F4; - font-size: 14px; + float: right; + margin: 10px 0px 10px 30px; + padding: 10px 20px 20px 20px; + width: 33%; + border: 1px solid black; + background-color: #F4F4F4; + font-size: 14px; } .property { - font-family: "Courier New", Courier, monospace; + font-family: "Courier New", Courier, monospace; } a code { - font-family: Verdana, Arial, monospace; - font-size: 12px; + font-family: Verdana, Arial, monospace; + font-size: 12px; } td code { - font-size: 110%; + font-size: 110%; } div.note * td, - div.tip * td, - div.warning * td, - div.calloutlist * td { - text-align: justify; - font-size: 100%; +div.tip * td, +div.warning * td, +div.calloutlist * td { + text-align: justify; + font-size: 100%; } .programlisting .interfacename, - .programlisting .literal, - .programlisting .classname { - font-size: 95%; +.programlisting .literal, +.programlisting .classname { + font-size: 95%; } .title .interfacename, - .title .literal, - .title .classname { - font-size: 130%; +.title .literal, +.title .classname { + font-size: 130%; } /* everything in a is displayed in a coloured, comment-like font */ .programlisting * .lineannotation, - .programlisting * .lineannotation * { - color: green; +.programlisting * .lineannotation * { + color: green; } diff --git a/src/docbkx/resources/css/stylesheet.css b/src/docbkx/resources/css/stylesheet.css index 77569070a..830548ada 100644 --- a/src/docbkx/resources/css/stylesheet.css +++ b/src/docbkx/resources/css/stylesheet.css @@ -1,99 +1,99 @@ @IMPORT url("highlight.css"); html { - padding: 0pt; - margin: 0pt; + padding: 0pt; + margin: 0pt; } body { - margin-left: 10%; - margin-right: 10%; - font-family: Arial, Sans-serif; + margin-left: 10%; + margin-right: 10%; + font-family: Arial, Sans-serif; } div { - margin: 0pt; + margin: 0pt; } p { - text-align: justify; + text-align: justify; } hr { - border: 1px solid gray; - background: gray; + border: 1px solid gray; + background: gray; } -h1,h2,h3,h4 { - color: #234623; - font-family: Arial, Sans-serif; +h1, h2, h3, h4 { + color: #234623; + font-family: Arial, Sans-serif; } pre { - line-height: 1.0; - color: black; + line-height: 1.0; + color: black; } pre.programlisting { - font-size: 10pt; - padding: 7pt 3pt; - border: 1pt solid black; - background: #eeeeee; - clear: both; + font-size: 10pt; + padding: 7pt 3pt; + border: 1pt solid black; + background: #eeeeee; + clear: both; } div.table { - margin: 1em; - padding: 0.5em; - text-align: center; + margin: 1em; + padding: 0.5em; + text-align: center; } div.table table { - display: table; - width: 100%; + display: table; + width: 100%; } div.table td { - padding-left: 7px; + padding-left: 7px; padding-right: 7px; } .sidebar { - float: right; - margin: 10px 0 10px 30px; - padding: 10px 20px 20px 20px; - width: 33%; - border: 1px solid black; - background-color: #F4F4F4; - font-size: 14px; + float: right; + margin: 10px 0 10px 30px; + padding: 10px 20px 20px 20px; + width: 33%; + border: 1px solid black; + background-color: #F4F4F4; + font-size: 14px; } .mediaobject { - padding-top: 30px; - padding-bottom: 30px; + padding-top: 30px; + padding-bottom: 30px; } .legalnotice { - font-family: Verdana, Arial, helvetica, sans-serif; - font-size: 12px; - font-style: italic; + font-family: Verdana, Arial, helvetica, sans-serif; + font-size: 12px; + font-style: italic; } p.releaseinfo { - font-size: 100%; - font-weight: bold; - font-family: Verdana, Arial, helvetica, sans-serif; - padding-top: 10px; + font-size: 100%; + font-weight: bold; + font-family: Verdana, Arial, helvetica, sans-serif; + padding-top: 10px; } p.pubdate { - font-size: 120%; - font-weight: bold; - font-family: Verdana, Arial, helvetica, sans-serif; + font-size: 120%; + font-weight: bold; + font-family: Verdana, Arial, helvetica, sans-serif; } span.productname { - font-size: 200%; - font-weight: bold; - font-family: Verdana, Arial, helvetica, sans-serif; + font-size: 200%; + font-weight: bold; + font-family: Verdana, Arial, helvetica, sans-serif; } diff --git a/src/docbkx/resources/xsl/fopdf.xsl b/src/docbkx/resources/xsl/fopdf.xsl index d18fda5ab..c19aabf42 100644 --- a/src/docbkx/resources/xsl/fopdf.xsl +++ b/src/docbkx/resources/xsl/fopdf.xsl @@ -13,406 +13,406 @@ version="1.0"> - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Copyright © 2010 - - - , - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Copyright © 2010 + + + , + + + + + + + + + + + + + + + - - - - - - - + + + + + + + - + - - - - - - -5em - -5em - + + + + + + -5em + -5em + - - - - - - - - - Spring Datastore Document ( - - ) - - + + + + + + + + + Spring Datastore Document ( + + ) + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + - + + + + + + + + + + + + + + - + - - 1 - 0 - 1 - - 1 + + 1 + 0 + 1 + + 1 - + - - - book toc - + + + book toc + - - 2 + + 2 - - + + - + - - - 0 - 0 - 0 + + + 0 + 0 + 0 - - 5mm - 10mm - 10mm + + 5mm + 10mm + 10mm - 15mm - 10mm - 0mm + 15mm + 10mm + 0mm - 18mm - 18mm + 18mm + 18mm - - 0pc + + 0pc - + - - justify - false + + justify + false - - 11 - 8 + + 11 + 8 - - 1.4 + + 1.4 - - - - - - 0.8em - + + + + + + 0.8em + - + - - 17.4cm + + 17.4cm - - - 4pt - 4pt - 4pt - 4pt - + + + 4pt + 4pt + 4pt + 4pt + - - 0.1pt - 0.1pt + + 0.1pt + 0.1pt - + - - 1 - - + + 1 + + - + - - - left - bold - - - pt - - + + + left + bold + + + pt + + - - - - - - - - + + + + + + + + - - - 0.8em - 0.8em - 0.8em - - - pt - - 0.1em - 0.1em - 0.1em - - - 0.6em - 0.6em - 0.6em - - - pt - - 0.1em - 0.1em - 0.1em - - - 0.4em - 0.4em - 0.4em - - - pt - - 0.1em - 0.1em - 0.1em - + + + 0.8em + 0.8em + 0.8em + + + pt + + 0.1em + 0.1em + 0.1em + + + 0.6em + 0.6em + 0.6em + + + pt + + 0.1em + 0.1em + 0.1em + + + 0.4em + 0.4em + 0.4em + + + pt + + 0.1em + 0.1em + 0.1em + - - - bold - - - pt - - false - 0.4em - 0.6em - 0.8em - + + + bold + + + pt + + false + 0.4em + 0.6em + 0.8em + - + - - - - - pt - - + + + + + pt + + - - 1em - 1em - 1em - #444444 - solid - 0.1pt - 0.5em - 0.5em - 0.5em - 0.5em - 0.5em - 0.5em - + + 1em + 1em + 1em + #444444 + solid + 0.1pt + 0.5em + 0.5em + 0.5em + 0.5em + 0.5em + 0.5em + - - 1 - - #F0F0F0 - + + 1 + + #F0F0F0 + - + - - 0 - 1 + + 0 + 1 - - 90 + + 90 - + - - '1' - + + '1' + - + - - - figure after - example before - equation before - table before - procedure before - + + + figure after + example before + equation before + table before + procedure before + - - 1 + + 1 - - - 0.8em - 0.8em - 0.8em - 0.1em - 0.1em - 0.1em - + + + 0.8em + 0.8em + 0.8em + 0.1em + 0.1em + 0.1em + - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/src/docbkx/resources/xsl/html.xsl b/src/docbkx/resources/xsl/html.xsl index aa7930bab..a323b71e3 100644 --- a/src/docbkx/resources/xsl/html.xsl +++ b/src/docbkx/resources/xsl/html.xsl @@ -7,85 +7,85 @@ xmlns:fo="http://www.w3.org/1999/XSL/Format" version="1.0"> - + - + - html.css + html.css - - 1 - 0 - 1 - 0 + + 1 + 0 + 1 + 0 - + - - - book toc - + + + book toc + - - 3 + + 3 - + - - 1 - - + + 1 + + - + - - 0 + + 0 - - 90 + + 90 - + - - 0 + + 0 - - - - figure after - example before - equation before - table before - procedure before - - - - , - - - - - - - - -
                      -

                      Authors

                      -

                      - -

                      -
                      + + + + figure after + example before + equation before + table before + procedure before + + + + , + + + + + + + + +
                      +

                      Authors

                      +

                      + +

                      +
                      diff --git a/src/docbkx/resources/xsl/html/html_chunk.xsl b/src/docbkx/resources/xsl/html/html_chunk.xsl index 81e6ab235..86d27fc5e 100644 --- a/src/docbkx/resources/xsl/html/html_chunk.xsl +++ b/src/docbkx/resources/xsl/html/html_chunk.xsl @@ -20,117 +20,134 @@ --> + xmlns:xslthl="http://xslthl.sf.net" + exclude-result-prefixes="xslthl" + version='1.0'> - '5' - + '5' + - - 1 - 0 - 1 + + 1 + 0 + 1 - - - images/ - .gif - - 120 - images/callouts/ - .gif + + + images/ + .gif + + 120 + images/callouts/ + .gif - - css/stylesheet.css - text/css - book toc,title + + css/stylesheet.css + text/css + book toc,title - text-align: left + text-align: left - - - - + + + + - - + + - - 3 + + 3 - - - - - - - - - - + + + + + + + + + + - - + + - - - + + + + + - - - + + + + + - - - + + + + + - - - + + + + + - - - + + + + + - - - + + + + + - - - - - - - + + + + + - - - Begin Google Analytics code - - - End Google Analytics code - + + + + + - - - Begin LoopFuse code - - - End LoopFuse code - + + + Begin Google Analytics code + + + End Google Analytics code + + + + + Begin LoopFuse code + + + End LoopFuse code + \ No newline at end of file diff --git a/src/docbkx/resources/xsl/html/titlepage.xml b/src/docbkx/resources/xsl/html/titlepage.xml index 09539c068..bdd737f11 100644 --- a/src/docbkx/resources/xsl/html/titlepage.xml +++ b/src/docbkx/resources/xsl/html/titlepage.xml @@ -23,39 +23,39 @@ xmlns:param="http://nwalsh.com/docbook/xsl/template/1.0/param" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> - + - - - - - <subtitle/> - <!-- <corpauthor/> - <authorgroup/> - <author/> - <mediaobject/> --> - <othercredit/> - <releaseinfo/> - <copyright/> - <legalnotice/> - <pubdate/> - <revision/> - <revhistory/> - <abstract/> - </t:titlepage-content> + <t:titlepage t:element="book" t:wrapper="div" class="titlepage"> + <t:titlepage-content t:side="recto"> + <productname/> + <title/> + <subtitle/> + <!-- <corpauthor/> + <authorgroup/> + <author/> + <mediaobject/> --> + <othercredit/> + <releaseinfo/> + <copyright/> + <legalnotice/> + <pubdate/> + <revision/> + <revhistory/> + <abstract/> + </t:titlepage-content> - <t:titlepage-content t:side="verso"> - </t:titlepage-content> + <t:titlepage-content t:side="verso"> + </t:titlepage-content> - <t:titlepage-separator> - <hr/> - </t:titlepage-separator> + <t:titlepage-separator> + <hr/> + </t:titlepage-separator> - <t:titlepage-before t:side="recto"> - </t:titlepage-before> + <t:titlepage-before t:side="recto"> + </t:titlepage-before> - <t:titlepage-before t:side="verso"> - </t:titlepage-before> -</t:titlepage> + <t:titlepage-before t:side="verso"> + </t:titlepage-before> + </t:titlepage> </t:templates> diff --git a/src/docbkx/resources/xsl/html_chunk.xsl b/src/docbkx/resources/xsl/html_chunk.xsl index 59016d819..858db67cf 100644 --- a/src/docbkx/resources/xsl/html_chunk.xsl +++ b/src/docbkx/resources/xsl/html_chunk.xsl @@ -6,203 +6,203 @@ xmlns:fo="http://www.w3.org/1999/XSL/Format" version="1.0"> - <xsl:import href="urn:docbkx:stylesheet"/> - <!--################################################### - HTML Settings - ################################################### --> - <xsl:param name="chunk.section.depth">'5'</xsl:param> - <xsl:param name="use.id.as.filename">'1'</xsl:param> - <!-- These extensions are required for table printing and other stuff --> - <xsl:param name="use.extensions">1</xsl:param> - <xsl:param name="tablecolumns.extension">0</xsl:param> - <xsl:param name="callout.extensions">1</xsl:param> - <xsl:param name="graphicsize.extension">0</xsl:param> - <!--################################################### - Table Of Contents - ################################################### --> - <!-- Generate the TOCs for named components only --> - <xsl:param name="generate.toc"> - book toc - </xsl:param> - <!-- Show only Sections up to level 3 in the TOCs --> - <xsl:param name="toc.section.depth">3</xsl:param> - <!--################################################### - Labels - ################################################### --> - <!-- Label Chapters and Sections (numbering) --> - <xsl:param name="chapter.autolabel">1</xsl:param> - <xsl:param name="section.autolabel" select="1"/> - <xsl:param name="section.label.includes.component.label" select="1"/> - <!--################################################### - Callouts - ################################################### --> - <!-- Place callout marks at this column in annotated areas --> - <xsl:param name="callout.graphics">1</xsl:param> - <xsl:param name="callout.defaultcolumn">90</xsl:param> - <!--################################################### - Misc - ################################################### --> - <!-- Placement of titles --> - <xsl:param name="formal.title.placement"> - figure after - example before - equation before - table before - procedure before - </xsl:param> - <xsl:template match="author" mode="titlepage.mode"> - <xsl:if test="name(preceding-sibling::*[1]) = 'author'"> - <xsl:text>, </xsl:text> - </xsl:if> - <span class="{name(.)}"> - <xsl:call-template name="person.name"/> - <xsl:apply-templates mode="titlepage.mode" select="./contrib"/> - <xsl:apply-templates mode="titlepage.mode" select="./affiliation"/> - </span> - </xsl:template> - <xsl:template match="authorgroup" mode="titlepage.mode"> - <div class="{name(.)}"> - <h2>Authors</h2> - <p/> - <xsl:apply-templates mode="titlepage.mode"/> - </div> - </xsl:template> - <!--################################################### - Headers and Footers - ################################################### --> - <!-- let's have a Spring and SpringSource banner across the top of each page --> - <xsl:template name="user.header.navigation"> - <div style="background-color:white;border:none;height:73px;border:1px solid black;"> - <a style="border:none;" href="http://static.springframework.org/spring-ws/site/" - title="The Spring Framework - Spring Web Services"> - <img style="border:none;" src="images/xdev-spring_logo.jpg"/> - </a> - <a style="border:none;" href="http://www.springsource.com/" title="SpringSource"> - <img style="border:none;position:absolute;padding-top:5px;right:42px;" src="images/s2_box_logo.png"/> - </a> - </div> - </xsl:template> - <!-- no other header navigation (prev, next, etc.) --> - <xsl:template name="header.navigation"/> - <xsl:param name="navig.showtitles">1</xsl:param> - <!-- let's have a 'Sponsored by SpringSource' strapline (or somesuch) across the bottom of each page --> - <xsl:template name="footer.navigation"> - <xsl:param name="prev" select="/foo"/> - <xsl:param name="next" select="/foo"/> - <xsl:param name="nav.context"/> - <xsl:variable name="home" select="/*[1]"/> - <xsl:variable name="up" select="parent::*"/> - <xsl:variable name="row1" select="count($prev) > 0 + <xsl:import href="urn:docbkx:stylesheet"/> + <!--################################################### + HTML Settings + ################################################### --> + <xsl:param name="chunk.section.depth">'5'</xsl:param> + <xsl:param name="use.id.as.filename">'1'</xsl:param> + <!-- These extensions are required for table printing and other stuff --> + <xsl:param name="use.extensions">1</xsl:param> + <xsl:param name="tablecolumns.extension">0</xsl:param> + <xsl:param name="callout.extensions">1</xsl:param> + <xsl:param name="graphicsize.extension">0</xsl:param> + <!--################################################### + Table Of Contents + ################################################### --> + <!-- Generate the TOCs for named components only --> + <xsl:param name="generate.toc"> + book toc + </xsl:param> + <!-- Show only Sections up to level 3 in the TOCs --> + <xsl:param name="toc.section.depth">3</xsl:param> + <!--################################################### + Labels + ################################################### --> + <!-- Label Chapters and Sections (numbering) --> + <xsl:param name="chapter.autolabel">1</xsl:param> + <xsl:param name="section.autolabel" select="1"/> + <xsl:param name="section.label.includes.component.label" select="1"/> + <!--################################################### + Callouts + ################################################### --> + <!-- Place callout marks at this column in annotated areas --> + <xsl:param name="callout.graphics">1</xsl:param> + <xsl:param name="callout.defaultcolumn">90</xsl:param> + <!--################################################### + Misc + ################################################### --> + <!-- Placement of titles --> + <xsl:param name="formal.title.placement"> + figure after + example before + equation before + table before + procedure before + </xsl:param> + <xsl:template match="author" mode="titlepage.mode"> + <xsl:if test="name(preceding-sibling::*[1]) = 'author'"> + <xsl:text>, </xsl:text> + </xsl:if> + <span class="{name(.)}"> + <xsl:call-template name="person.name"/> + <xsl:apply-templates mode="titlepage.mode" select="./contrib"/> + <xsl:apply-templates mode="titlepage.mode" select="./affiliation"/> + </span> + </xsl:template> + <xsl:template match="authorgroup" mode="titlepage.mode"> + <div class="{name(.)}"> + <h2>Authors</h2> + <p/> + <xsl:apply-templates mode="titlepage.mode"/> + </div> + </xsl:template> + <!--################################################### + Headers and Footers + ################################################### --> + <!-- let's have a Spring and SpringSource banner across the top of each page --> + <xsl:template name="user.header.navigation"> + <div style="background-color:white;border:none;height:73px;border:1px solid black;"> + <a style="border:none;" href="http://static.springframework.org/spring-ws/site/" + title="The Spring Framework - Spring Web Services"> + <img style="border:none;" src="images/xdev-spring_logo.jpg"/> + </a> + <a style="border:none;" href="http://www.springsource.com/" title="SpringSource"> + <img style="border:none;position:absolute;padding-top:5px;right:42px;" src="images/s2_box_logo.png"/> + </a> + </div> + </xsl:template> + <!-- no other header navigation (prev, next, etc.) --> + <xsl:template name="header.navigation"/> + <xsl:param name="navig.showtitles">1</xsl:param> + <!-- let's have a 'Sponsored by SpringSource' strapline (or somesuch) across the bottom of each page --> + <xsl:template name="footer.navigation"> + <xsl:param name="prev" select="/foo"/> + <xsl:param name="next" select="/foo"/> + <xsl:param name="nav.context"/> + <xsl:variable name="home" select="/*[1]"/> + <xsl:variable name="up" select="parent::*"/> + <xsl:variable name="row1" select="count($prev) > 0 or count($up) > 0 or count($next) > 0"/> - <xsl:variable name="row2" select="($prev and $navig.showtitles != 0) + <xsl:variable name="row2" select="($prev and $navig.showtitles != 0) or (generate-id($home) != generate-id(.) or $nav.context = 'toc') or ($chunk.tocs.and.lots != 0 and $nav.context != 'toc') or ($next and $navig.showtitles != 0)"/> - <xsl:if test="$suppress.navigation = '0' and $suppress.footer.navigation = '0'"> - <div class="navfooter"> - <xsl:if test="$footer.rule != 0"> - <hr/> - </xsl:if> - <xsl:if test="$row1 or $row2"> - <table width="100%" summary="Navigation footer"> - <xsl:if test="$row1"> - <tr> - <td width="40%" align="left"> - <xsl:if test="count($prev)>0"> - <a accesskey="p"> - <xsl:attribute name="href"> - <xsl:call-template name="href.target"> - <xsl:with-param name="object" select="$prev"/> - </xsl:call-template> - </xsl:attribute> - <xsl:call-template name="navig.content"> - <xsl:with-param name="direction" select="'prev'"/> - </xsl:call-template> - </a> - </xsl:if> - <xsl:text> </xsl:text> - </td> - - <td width="20%" align="center"> - <xsl:choose> - <xsl:when test="$home != . or $nav.context = 'toc'"> - <a accesskey="h"> - <xsl:attribute name="href"> - <xsl:call-template name="href.target"> - <xsl:with-param name="object" select="$home"/> - </xsl:call-template> - </xsl:attribute> - <xsl:call-template name="navig.content"> - <xsl:with-param name="direction" select="'home'"/> - </xsl:call-template> - </a> - <xsl:if test="$chunk.tocs.and.lots != 0 and $nav.context != 'toc'"> - <xsl:text> | </xsl:text> - </xsl:if> - </xsl:when> - <xsl:otherwise> </xsl:otherwise> - </xsl:choose> - <xsl:if test="$chunk.tocs.and.lots != 0 and $nav.context != 'toc'"> - <a accesskey="t"> - <xsl:attribute name="href"> - <xsl:apply-templates select="/*[1]" mode="recursive-chunk-filename"> - <xsl:with-param name="recursive" select="true()"/> - </xsl:apply-templates> - <xsl:text>-toc</xsl:text> - <xsl:value-of select="$html.ext"/> - </xsl:attribute> - <xsl:call-template name="gentext"> - <xsl:with-param name="key" select="'nav-toc'"/> - </xsl:call-template> - </a> - </xsl:if> - </td> - <td width="40%" align="right"> - <xsl:text> </xsl:text> - <xsl:if test="count($next)>0"> - <a accesskey="n"> - <xsl:attribute name="href"> - <xsl:call-template name="href.target"> - <xsl:with-param name="object" select="$next"/> - </xsl:call-template> - </xsl:attribute> - <xsl:call-template name="navig.content"> - <xsl:with-param name="direction" select="'next'"/> - </xsl:call-template> - </a> - </xsl:if> - </td> - </tr> - </xsl:if> - <xsl:if test="$row2"> - <tr> - <td width="40%" align="left" valign="top"> - <xsl:if test="$navig.showtitles != 0"> - <xsl:apply-templates select="$prev" mode="object.title.markup"/> - </xsl:if> - <xsl:text> </xsl:text> - </td> - <td width="20%" align="center"> - <span style="color:white;font-size:90%;"> - <a href="http://www.springsource.com/" - title="SpringSource">Sponsored by SpringSource - </a> - </span> - </td> - <td width="40%" align="right" valign="top"> - <xsl:text> </xsl:text> - <xsl:if test="$navig.showtitles != 0"> - <xsl:apply-templates select="$next" mode="object.title.markup"/> - </xsl:if> - </td> - </tr> - </xsl:if> - </table> - </xsl:if> - </div> + <xsl:if test="$suppress.navigation = '0' and $suppress.footer.navigation = '0'"> + <div class="navfooter"> + <xsl:if test="$footer.rule != 0"> + <hr/> </xsl:if> - </xsl:template> + <xsl:if test="$row1 or $row2"> + <table width="100%" summary="Navigation footer"> + <xsl:if test="$row1"> + <tr> + <td width="40%" align="left"> + <xsl:if test="count($prev)>0"> + <a accesskey="p"> + <xsl:attribute name="href"> + <xsl:call-template name="href.target"> + <xsl:with-param name="object" select="$prev"/> + </xsl:call-template> + </xsl:attribute> + <xsl:call-template name="navig.content"> + <xsl:with-param name="direction" select="'prev'"/> + </xsl:call-template> + </a> + </xsl:if> + <xsl:text> </xsl:text> + </td> + + <td width="20%" align="center"> + <xsl:choose> + <xsl:when test="$home != . or $nav.context = 'toc'"> + <a accesskey="h"> + <xsl:attribute name="href"> + <xsl:call-template name="href.target"> + <xsl:with-param name="object" select="$home"/> + </xsl:call-template> + </xsl:attribute> + <xsl:call-template name="navig.content"> + <xsl:with-param name="direction" select="'home'"/> + </xsl:call-template> + </a> + <xsl:if test="$chunk.tocs.and.lots != 0 and $nav.context != 'toc'"> + <xsl:text> | </xsl:text> + </xsl:if> + </xsl:when> + <xsl:otherwise> </xsl:otherwise> + </xsl:choose> + <xsl:if test="$chunk.tocs.and.lots != 0 and $nav.context != 'toc'"> + <a accesskey="t"> + <xsl:attribute name="href"> + <xsl:apply-templates select="/*[1]" mode="recursive-chunk-filename"> + <xsl:with-param name="recursive" select="true()"/> + </xsl:apply-templates> + <xsl:text>-toc</xsl:text> + <xsl:value-of select="$html.ext"/> + </xsl:attribute> + <xsl:call-template name="gentext"> + <xsl:with-param name="key" select="'nav-toc'"/> + </xsl:call-template> + </a> + </xsl:if> + </td> + <td width="40%" align="right"> + <xsl:text> </xsl:text> + <xsl:if test="count($next)>0"> + <a accesskey="n"> + <xsl:attribute name="href"> + <xsl:call-template name="href.target"> + <xsl:with-param name="object" select="$next"/> + </xsl:call-template> + </xsl:attribute> + <xsl:call-template name="navig.content"> + <xsl:with-param name="direction" select="'next'"/> + </xsl:call-template> + </a> + </xsl:if> + </td> + </tr> + </xsl:if> + <xsl:if test="$row2"> + <tr> + <td width="40%" align="left" valign="top"> + <xsl:if test="$navig.showtitles != 0"> + <xsl:apply-templates select="$prev" mode="object.title.markup"/> + </xsl:if> + <xsl:text> </xsl:text> + </td> + <td width="20%" align="center"> + <span style="color:white;font-size:90%;"> + <a href="http://www.springsource.com/" + title="SpringSource">Sponsored by SpringSource + </a> + </span> + </td> + <td width="40%" align="right" valign="top"> + <xsl:text> </xsl:text> + <xsl:if test="$navig.showtitles != 0"> + <xsl:apply-templates select="$next" mode="object.title.markup"/> + </xsl:if> + </td> + </tr> + </xsl:if> + </table> + </xsl:if> + </div> + </xsl:if> + </xsl:template> </xsl:stylesheet> diff --git a/src/docbkx/resources/xsl/pdf/fopdf.xsl b/src/docbkx/resources/xsl/pdf/fopdf.xsl index 2905ee3c2..34c5781eb 100644 --- a/src/docbkx/resources/xsl/pdf/fopdf.xsl +++ b/src/docbkx/resources/xsl/pdf/fopdf.xsl @@ -20,499 +20,515 @@ --> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" - xmlns:fo="http://www.w3.org/1999/XSL/Format" - xmlns:xslthl="http://xslthl.sf.net" - exclude-result-prefixes="xslthl" - version='1.0'> - -<!-- Use nice graphics for admonitions --> - <xsl:param name="admon.graphics">'1'</xsl:param> - <xsl:param name="admon.graphics.path">@file.prefix@@dbf.xsl@/images/</xsl:param> - <xsl:param name="draft.watermark.image" select="'@file.prefix@@dbf.xsl@/images/draft.png'"/> - <xsl:param name="paper.type" select="'@paper.type@'"/> - - <xsl:param name="page.margin.top" select="'1cm'"/> - <xsl:param name="region.before.extent" select="'1cm'"/> - <xsl:param name="body.margin.top" select="'1.5cm'"/> - - <xsl:param name="body.margin.bottom" select="'1.5cm'"/> - <xsl:param name="region.after.extent" select="'1cm'"/> - <xsl:param name="page.margin.bottom" select="'1cm'"/> - <xsl:param name="title.margin.left" select="'0cm'"/> - -<!--################################################### - Header - ################################################### --> - -<!-- More space in the center header for long text --> - <xsl:attribute-set name="header.content.properties"> - <xsl:attribute name="font-family"> - <xsl:value-of select="$body.font.family"/> - </xsl:attribute> - <xsl:attribute name="margin-left">-5em</xsl:attribute> - <xsl:attribute name="margin-right">-5em</xsl:attribute> - </xsl:attribute-set> - -<!--################################################### - Table of Contents - ################################################### --> - - <xsl:param name="generate.toc"> - book toc,title - </xsl:param> - -<!--################################################### - Custom Header - ################################################### --> - - <xsl:template name="header.content"> - <xsl:param name="pageclass" select="''"/> - <xsl:param name="sequence" select="''"/> - <xsl:param name="position" select="''"/> - <xsl:param name="gentext-key" select="''"/> - - <xsl:variable name="Version"> - <xsl:choose> - <xsl:when test="//productname"> - <xsl:value-of select="//productname"/><xsl:text> </xsl:text> - </xsl:when> - <xsl:otherwise> - <xsl:text>please define productname in your docbook file!</xsl:text> - </xsl:otherwise> - </xsl:choose> - </xsl:variable> - - <xsl:choose> - <xsl:when test="$sequence='blank'"> - <xsl:choose> - <xsl:when test="$position='center'"> - <xsl:value-of select="$Version"/> - </xsl:when> - - <xsl:otherwise> - <!-- nop --> - </xsl:otherwise> - </xsl:choose> - </xsl:when> - - <xsl:when test="$pageclass='titlepage'"> - <!-- nop: other titlepage sequences have no header --> - </xsl:when> - - <xsl:when test="$position='center'"> - <xsl:value-of select="$Version"/> - </xsl:when> - - <xsl:otherwise> - <!-- nop --> - </xsl:otherwise> - </xsl:choose> - </xsl:template> - -<!--################################################### - Custom Footer - ################################################### --> - - <xsl:template name="footer.content"> - <xsl:param name="pageclass" select="''"/> - <xsl:param name="sequence" select="''"/> - <xsl:param name="position" select="''"/> - <xsl:param name="gentext-key" select="''"/> - - <xsl:variable name="Version"> - <xsl:choose> - <xsl:when test="//releaseinfo"> - <xsl:value-of select="//releaseinfo"/> - </xsl:when> - <xsl:otherwise> - <!-- nop --> - </xsl:otherwise> - </xsl:choose> - </xsl:variable> - - <xsl:variable name="Title"> - <xsl:value-of select="//title"/> - </xsl:variable> - - <xsl:choose> - <xsl:when test="$sequence='blank'"> - <xsl:choose> - <xsl:when test="$double.sided != 0 and $position = 'left'"> - <xsl:value-of select="$Version"/> - </xsl:when> - - <xsl:when test="$double.sided = 0 and $position = 'center'"> - <!-- nop --> - </xsl:when> - - <xsl:otherwise> - <fo:page-number/> - </xsl:otherwise> - </xsl:choose> - </xsl:when> - - <xsl:when test="$pageclass='titlepage'"> - <!-- nop: other titlepage sequences have no footer --> - </xsl:when> - - <xsl:when test="$double.sided != 0 and $sequence = 'even' and $position='left'"> - <fo:page-number/> - </xsl:when> - - <xsl:when test="$double.sided != 0 and $sequence = 'odd' and $position='right'"> - <fo:page-number/> - </xsl:when> - - <xsl:when test="$double.sided = 0 and $position='right'"> - <fo:page-number/> - </xsl:when> - - <xsl:when test="$double.sided != 0 and $sequence = 'odd' and $position='left'"> - <xsl:value-of select="$Version"/> - </xsl:when> - - <xsl:when test="$double.sided != 0 and $sequence = 'even' and $position='right'"> - <xsl:value-of select="$Version"/> - </xsl:when> - - <xsl:when test="$double.sided = 0 and $position='left'"> - <xsl:value-of select="$Version"/> - </xsl:when> - - <xsl:when test="$position='center'"> - <xsl:value-of select="$Title"/> - </xsl:when> - - <xsl:otherwise> - <!-- nop --> - </xsl:otherwise> - </xsl:choose> - </xsl:template> - - <xsl:template match="processing-instruction('hard-pagebreak')"> - <fo:block break-before='page'/> - </xsl:template> - -<!--################################################### - Extensions - ################################################### --> - -<!-- These extensions are required for table printing and other stuff --> - <xsl:param name="use.extensions">1</xsl:param> - <xsl:param name="tablecolumns.extension">0</xsl:param> - <xsl:param name="callout.extensions">1</xsl:param> - <xsl:param name="fop.extensions">1</xsl:param> - -<!--################################################### - Paper & Page Size - ################################################### --> - -<!-- Paper type, no headers on blank pages, no double sided printing --> - <xsl:param name="double.sided">0</xsl:param> - <xsl:param name="headers.on.blank.pages">0</xsl:param> - <xsl:param name="footers.on.blank.pages">0</xsl:param> - -<!--################################################### - Fonts & Styles - ################################################### --> - - <xsl:param name="hyphenate">false</xsl:param> - -<!-- Default Font size --> - <xsl:param name="body.font.master">11</xsl:param> - <xsl:param name="body.font.small">8</xsl:param> - -<!-- Line height in body text --> - <xsl:param name="line-height">1.4</xsl:param> - -<!-- Chapter title size --> - <xsl:attribute-set name="chapter.titlepage.recto.style"> - <xsl:attribute name="text-align">left</xsl:attribute> - <xsl:attribute name="font-weight">bold</xsl:attribute> - <xsl:attribute name="font-size"> - <xsl:value-of select="$body.font.master * 1.8"/> - <xsl:text>pt</xsl:text> - </xsl:attribute> - </xsl:attribute-set> - -<!-- Why is the font-size for chapters hardcoded in the XSL FO templates? - Let's remove it, so this sucker can use our attribute-set only... --> - <xsl:template match="title" mode="chapter.titlepage.recto.auto.mode"> - <fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" - xsl:use-attribute-sets="chapter.titlepage.recto.style"> - <xsl:call-template name="component.title"> - <xsl:with-param name="node" select="ancestor-or-self::chapter[1]"/> - </xsl:call-template> - </fo:block> - </xsl:template> - -<!-- Sections 1, 2 and 3 titles have a small bump factor and padding --> - <xsl:attribute-set name="section.title.level1.properties"> - <xsl:attribute name="space-before.optimum">0.8em</xsl:attribute> - <xsl:attribute name="space-before.minimum">0.8em</xsl:attribute> - <xsl:attribute name="space-before.maximum">0.8em</xsl:attribute> - <xsl:attribute name="font-size"> - <xsl:value-of select="$body.font.master * 1.5"/> - <xsl:text>pt</xsl:text> - </xsl:attribute> - <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute> - </xsl:attribute-set> - <xsl:attribute-set name="section.title.level2.properties"> - <xsl:attribute name="space-before.optimum">0.6em</xsl:attribute> - <xsl:attribute name="space-before.minimum">0.6em</xsl:attribute> - <xsl:attribute name="space-before.maximum">0.6em</xsl:attribute> - <xsl:attribute name="font-size"> - <xsl:value-of select="$body.font.master * 1.25"/> - <xsl:text>pt</xsl:text> - </xsl:attribute> - <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute> - </xsl:attribute-set> - <xsl:attribute-set name="section.title.level3.properties"> - <xsl:attribute name="space-before.optimum">0.4em</xsl:attribute> - <xsl:attribute name="space-before.minimum">0.4em</xsl:attribute> - <xsl:attribute name="space-before.maximum">0.4em</xsl:attribute> - <xsl:attribute name="font-size"> - <xsl:value-of select="$body.font.master * 1.0"/> - <xsl:text>pt</xsl:text> - </xsl:attribute> - <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute> - </xsl:attribute-set> - <xsl:attribute-set name="section.title.level4.properties"> - <xsl:attribute name="space-before.optimum">0.3em</xsl:attribute> - <xsl:attribute name="space-before.minimum">0.3em</xsl:attribute> - <xsl:attribute name="space-before.maximum">0.3em</xsl:attribute> - <xsl:attribute name="font-size"> - <xsl:value-of select="$body.font.master * 0.9"/> - <xsl:text>pt</xsl:text> - </xsl:attribute> - <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute> - </xsl:attribute-set> - -<!-- Use code syntax highlighting --> - <xsl:param name="highlight.source" select="1"/> - <xsl:param name="highlight.default.language" select="xml" /> - - <xsl:template match='xslthl:keyword'> - <fo:inline font-weight="bold" color="#7F0055"><xsl:apply-templates/></fo:inline> - </xsl:template> - - <xsl:template match='xslthl:comment'> - <fo:inline font-style="italic" color="#3F5F5F"><xsl:apply-templates/></fo:inline> - </xsl:template> - - <xsl:template match='xslthl:oneline-comment'> - <fo:inline font-style="italic" color="#3F5F5F"><xsl:apply-templates/></fo:inline> - </xsl:template> - - <xsl:template match='xslthl:multiline-comment'> - <fo:inline font-style="italic" color="#3F5FBF"><xsl:apply-templates/></fo:inline> - </xsl:template> - - <xsl:template match='xslthl:tag'> - <fo:inline color="#3F7F7F"><xsl:apply-templates/></fo:inline> - </xsl:template> - - <xsl:template match='xslthl:attribute'> - <fo:inline color="#7F007F"><xsl:apply-templates/></fo:inline> - </xsl:template> - - <xsl:template match='xslthl:value'> - <fo:inline color="#2A00FF"><xsl:apply-templates/></fo:inline> - </xsl:template> - - <xsl:template match='xslthl:string'> - <fo:inline color="#2A00FF"><xsl:apply-templates/></fo:inline> - </xsl:template> - -<!--################################################### - Tables - ################################################### --> - - <!-- Some padding inside tables --> - <xsl:attribute-set name="table.cell.padding"> - <xsl:attribute name="padding-left">4pt</xsl:attribute> - <xsl:attribute name="padding-right">4pt</xsl:attribute> - <xsl:attribute name="padding-top">4pt</xsl:attribute> - <xsl:attribute name="padding-bottom">4pt</xsl:attribute> - </xsl:attribute-set> - -<!-- Only hairlines as frame and cell borders in tables --> - <xsl:param name="table.frame.border.thickness">0.1pt</xsl:param> - <xsl:param name="table.cell.border.thickness">0.1pt</xsl:param> - -<!--################################################### - Labels - ################################################### --> - -<!-- Label Chapters and Sections (numbering) --> - <xsl:param name="chapter.autolabel" select="1"/> - <xsl:param name="section.autolabel" select="1"/> - <xsl:param name="section.autolabel.max.depth" select="1"/> - - <xsl:param name="section.label.includes.component.label" select="1"/> - <xsl:param name="table.footnote.number.format" select="'1'"/> - -<!--################################################### - Programlistings - ################################################### --> - -<!-- Verbatim text formatting (programlistings) --> - <xsl:attribute-set name="monospace.verbatim.properties"> - <xsl:attribute name="font-size"> - <xsl:value-of select="$body.font.small * 1.0"/> - <xsl:text>pt</xsl:text> - </xsl:attribute> - </xsl:attribute-set> - - <xsl:attribute-set name="verbatim.properties"> - <xsl:attribute name="space-before.minimum">1em</xsl:attribute> - <xsl:attribute name="space-before.optimum">1em</xsl:attribute> - <xsl:attribute name="space-before.maximum">1em</xsl:attribute> - <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute> - - <xsl:attribute name="border-color">#444444</xsl:attribute> - <xsl:attribute name="border-style">solid</xsl:attribute> - <xsl:attribute name="border-width">0.1pt</xsl:attribute> - <xsl:attribute name="padding-top">0.5em</xsl:attribute> - <xsl:attribute name="padding-left">0.5em</xsl:attribute> - <xsl:attribute name="padding-right">0.5em</xsl:attribute> - <xsl:attribute name="padding-bottom">0.5em</xsl:attribute> - <xsl:attribute name="margin-left">0.5em</xsl:attribute> - <xsl:attribute name="margin-right">0.5em</xsl:attribute> - </xsl:attribute-set> - - <!-- Shade (background) programlistings --> - <xsl:param name="shade.verbatim">1</xsl:param> - <xsl:attribute-set name="shade.verbatim.style"> - <xsl:attribute name="background-color">#F0F0F0</xsl:attribute> - </xsl:attribute-set> - - <xsl:attribute-set name="list.block.spacing"> - <xsl:attribute name="space-before.optimum">0.1em</xsl:attribute> - <xsl:attribute name="space-before.minimum">0.1em</xsl:attribute> - <xsl:attribute name="space-before.maximum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute> - </xsl:attribute-set> - - <xsl:attribute-set name="example.properties"> - <xsl:attribute name="space-before.minimum">0.5em</xsl:attribute> - <xsl:attribute name="space-before.optimum">0.5em</xsl:attribute> - <xsl:attribute name="space-before.maximum">0.5em</xsl:attribute> - <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute> - <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute> - <xsl:attribute name="keep-together.within-column">always</xsl:attribute> - </xsl:attribute-set> - -<!--################################################### - Title information for Figures, Examples etc. - ################################################### --> - - <xsl:attribute-set name="formal.title.properties" use-attribute-sets="normal.para.spacing"> - <xsl:attribute name="font-weight">normal</xsl:attribute> - <xsl:attribute name="font-style">italic</xsl:attribute> - <xsl:attribute name="font-size"> - <xsl:value-of select="$body.font.master"/> - <xsl:text>pt</xsl:text> - </xsl:attribute> - <xsl:attribute name="hyphenate">false</xsl:attribute> - <xsl:attribute name="space-before.minimum">0.1em</xsl:attribute> - <xsl:attribute name="space-before.optimum">0.1em</xsl:attribute> - <xsl:attribute name="space-before.maximum">0.1em</xsl:attribute> - </xsl:attribute-set> - -<!--################################################### - Callouts - ################################################### --> - -<!-- don't use images for callouts --> - <xsl:param name="callout.graphics">0</xsl:param> - <xsl:param name="callout.unicode">1</xsl:param> - -<!-- Place callout marks at this column in annotated areas --> - <xsl:param name="callout.defaultcolumn">90</xsl:param> - -<!--################################################### - Misc - ################################################### --> - -<!-- Placement of titles --> - <xsl:param name="formal.title.placement"> - figure after - example after - equation before - table before - procedure before - </xsl:param> - -<!-- Format Variable Lists as Blocks (prevents horizontal overflow) --> - <xsl:param name="variablelist.as.blocks">1</xsl:param> - - <xsl:param name="body.start.indent">0pt</xsl:param> - -<!-- Show only Sections up to level 3 in the TOCs --> - <xsl:param name="toc.section.depth">3</xsl:param> - -<!-- Remove "Chapter" from the Chapter titles... --> - <xsl:param name="local.l10n.xml" select="document('')"/> - <l:i18n xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0"> - <l:l10n language="en"> - <l:context name="title-numbered"> - <l:template name="chapter" text="%n. %t"/> - <l:template name="section" text="%n %t"/> - </l:context> - <l:context name="title"> - <l:template name="example" text="Example %n %t"/> - </l:context> - </l:l10n> - </l:i18n> - -<!--################################################### - colored and hyphenated links - ################################################### --> - - <xsl:template match="ulink"> - <fo:basic-link external-destination="{@url}" - xsl:use-attribute-sets="xref.properties" - text-decoration="underline" - color="blue"> - <xsl:choose> - <xsl:when test="count(child::node())=0"> - <xsl:value-of select="@url"/> - </xsl:when> - <xsl:otherwise> - <xsl:apply-templates/> - </xsl:otherwise> - </xsl:choose> - </fo:basic-link> - </xsl:template> - - <xsl:template match="link"> - <fo:basic-link internal-destination="{@linkend}" - xsl:use-attribute-sets="xref.properties" - text-decoration="underline" - color="blue"> - <xsl:choose> - <xsl:when test="count(child::node())=0"> - <xsl:value-of select="@linkend"/> - </xsl:when> - <xsl:otherwise> - <xsl:apply-templates/> - </xsl:otherwise> - </xsl:choose> - </fo:basic-link> - </xsl:template> + xmlns:fo="http://www.w3.org/1999/XSL/Format" + xmlns:xslthl="http://xslthl.sf.net" + exclude-result-prefixes="xslthl" + version='1.0'> + + <!-- Use nice graphics for admonitions --> + <xsl:param name="admon.graphics">'1'</xsl:param> + <xsl:param name="admon.graphics.path">@file.prefix@@dbf.xsl@/images/</xsl:param> + <xsl:param name="draft.watermark.image" select="'@file.prefix@@dbf.xsl@/images/draft.png'"/> + <xsl:param name="paper.type" select="'@paper.type@'"/> + + <xsl:param name="page.margin.top" select="'1cm'"/> + <xsl:param name="region.before.extent" select="'1cm'"/> + <xsl:param name="body.margin.top" select="'1.5cm'"/> + + <xsl:param name="body.margin.bottom" select="'1.5cm'"/> + <xsl:param name="region.after.extent" select="'1cm'"/> + <xsl:param name="page.margin.bottom" select="'1cm'"/> + <xsl:param name="title.margin.left" select="'0cm'"/> + + <!--################################################### + Header + ################################################### --> + + <!-- More space in the center header for long text --> + <xsl:attribute-set name="header.content.properties"> + <xsl:attribute name="font-family"> + <xsl:value-of select="$body.font.family"/> + </xsl:attribute> + <xsl:attribute name="margin-left">-5em</xsl:attribute> + <xsl:attribute name="margin-right">-5em</xsl:attribute> + </xsl:attribute-set> + + <!--################################################### + Table of Contents + ################################################### --> + + <xsl:param name="generate.toc"> + book toc,title + </xsl:param> + + <!--################################################### + Custom Header + ################################################### --> + + <xsl:template name="header.content"> + <xsl:param name="pageclass" select="''"/> + <xsl:param name="sequence" select="''"/> + <xsl:param name="position" select="''"/> + <xsl:param name="gentext-key" select="''"/> + + <xsl:variable name="Version"> + <xsl:choose> + <xsl:when test="//productname"> + <xsl:value-of select="//productname"/><xsl:text> </xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text>please define productname in your docbook file!</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:choose> + <xsl:when test="$sequence='blank'"> + <xsl:choose> + <xsl:when test="$position='center'"> + <xsl:value-of select="$Version"/> + </xsl:when> + + <xsl:otherwise> + <!-- nop --> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + + <xsl:when test="$pageclass='titlepage'"> + <!-- nop: other titlepage sequences have no header --> + </xsl:when> + + <xsl:when test="$position='center'"> + <xsl:value-of select="$Version"/> + </xsl:when> + + <xsl:otherwise> + <!-- nop --> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!--################################################### + Custom Footer + ################################################### --> + + <xsl:template name="footer.content"> + <xsl:param name="pageclass" select="''"/> + <xsl:param name="sequence" select="''"/> + <xsl:param name="position" select="''"/> + <xsl:param name="gentext-key" select="''"/> + + <xsl:variable name="Version"> + <xsl:choose> + <xsl:when test="//releaseinfo"> + <xsl:value-of select="//releaseinfo"/> + </xsl:when> + <xsl:otherwise> + <!-- nop --> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:variable name="Title"> + <xsl:value-of select="//title"/> + </xsl:variable> + + <xsl:choose> + <xsl:when test="$sequence='blank'"> + <xsl:choose> + <xsl:when test="$double.sided != 0 and $position = 'left'"> + <xsl:value-of select="$Version"/> + </xsl:when> + + <xsl:when test="$double.sided = 0 and $position = 'center'"> + <!-- nop --> + </xsl:when> + + <xsl:otherwise> + <fo:page-number/> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + + <xsl:when test="$pageclass='titlepage'"> + <!-- nop: other titlepage sequences have no footer --> + </xsl:when> + + <xsl:when test="$double.sided != 0 and $sequence = 'even' and $position='left'"> + <fo:page-number/> + </xsl:when> + + <xsl:when test="$double.sided != 0 and $sequence = 'odd' and $position='right'"> + <fo:page-number/> + </xsl:when> + + <xsl:when test="$double.sided = 0 and $position='right'"> + <fo:page-number/> + </xsl:when> + + <xsl:when test="$double.sided != 0 and $sequence = 'odd' and $position='left'"> + <xsl:value-of select="$Version"/> + </xsl:when> + + <xsl:when test="$double.sided != 0 and $sequence = 'even' and $position='right'"> + <xsl:value-of select="$Version"/> + </xsl:when> + + <xsl:when test="$double.sided = 0 and $position='left'"> + <xsl:value-of select="$Version"/> + </xsl:when> + + <xsl:when test="$position='center'"> + <xsl:value-of select="$Title"/> + </xsl:when> + + <xsl:otherwise> + <!-- nop --> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <xsl:template match="processing-instruction('hard-pagebreak')"> + <fo:block break-before='page'/> + </xsl:template> + + <!--################################################### + Extensions + ################################################### --> + + <!-- These extensions are required for table printing and other stuff --> + <xsl:param name="use.extensions">1</xsl:param> + <xsl:param name="tablecolumns.extension">0</xsl:param> + <xsl:param name="callout.extensions">1</xsl:param> + <xsl:param name="fop.extensions">1</xsl:param> + + <!--################################################### + Paper & Page Size + ################################################### --> + + <!-- Paper type, no headers on blank pages, no double sided printing --> + <xsl:param name="double.sided">0</xsl:param> + <xsl:param name="headers.on.blank.pages">0</xsl:param> + <xsl:param name="footers.on.blank.pages">0</xsl:param> + + <!--################################################### + Fonts & Styles + ################################################### --> + + <xsl:param name="hyphenate">false</xsl:param> + + <!-- Default Font size --> + <xsl:param name="body.font.master">11</xsl:param> + <xsl:param name="body.font.small">8</xsl:param> + + <!-- Line height in body text --> + <xsl:param name="line-height">1.4</xsl:param> + + <!-- Chapter title size --> + <xsl:attribute-set name="chapter.titlepage.recto.style"> + <xsl:attribute name="text-align">left</xsl:attribute> + <xsl:attribute name="font-weight">bold</xsl:attribute> + <xsl:attribute name="font-size"> + <xsl:value-of select="$body.font.master * 1.8"/> + <xsl:text>pt</xsl:text> + </xsl:attribute> + </xsl:attribute-set> + + <!-- Why is the font-size for chapters hardcoded in the XSL FO templates? + Let's remove it, so this sucker can use our attribute-set only... --> + <xsl:template match="title" mode="chapter.titlepage.recto.auto.mode"> + <fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" + xsl:use-attribute-sets="chapter.titlepage.recto.style"> + <xsl:call-template name="component.title"> + <xsl:with-param name="node" select="ancestor-or-self::chapter[1]"/> + </xsl:call-template> + </fo:block> + </xsl:template> + + <!-- Sections 1, 2 and 3 titles have a small bump factor and padding --> + <xsl:attribute-set name="section.title.level1.properties"> + <xsl:attribute name="space-before.optimum">0.8em</xsl:attribute> + <xsl:attribute name="space-before.minimum">0.8em</xsl:attribute> + <xsl:attribute name="space-before.maximum">0.8em</xsl:attribute> + <xsl:attribute name="font-size"> + <xsl:value-of select="$body.font.master * 1.5"/> + <xsl:text>pt</xsl:text> + </xsl:attribute> + <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute> + <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute> + <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute> + </xsl:attribute-set> + <xsl:attribute-set name="section.title.level2.properties"> + <xsl:attribute name="space-before.optimum">0.6em</xsl:attribute> + <xsl:attribute name="space-before.minimum">0.6em</xsl:attribute> + <xsl:attribute name="space-before.maximum">0.6em</xsl:attribute> + <xsl:attribute name="font-size"> + <xsl:value-of select="$body.font.master * 1.25"/> + <xsl:text>pt</xsl:text> + </xsl:attribute> + <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute> + <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute> + <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute> + </xsl:attribute-set> + <xsl:attribute-set name="section.title.level3.properties"> + <xsl:attribute name="space-before.optimum">0.4em</xsl:attribute> + <xsl:attribute name="space-before.minimum">0.4em</xsl:attribute> + <xsl:attribute name="space-before.maximum">0.4em</xsl:attribute> + <xsl:attribute name="font-size"> + <xsl:value-of select="$body.font.master * 1.0"/> + <xsl:text>pt</xsl:text> + </xsl:attribute> + <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute> + <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute> + <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute> + </xsl:attribute-set> + <xsl:attribute-set name="section.title.level4.properties"> + <xsl:attribute name="space-before.optimum">0.3em</xsl:attribute> + <xsl:attribute name="space-before.minimum">0.3em</xsl:attribute> + <xsl:attribute name="space-before.maximum">0.3em</xsl:attribute> + <xsl:attribute name="font-size"> + <xsl:value-of select="$body.font.master * 0.9"/> + <xsl:text>pt</xsl:text> + </xsl:attribute> + <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute> + <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute> + <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute> + </xsl:attribute-set> + + <!-- Use code syntax highlighting --> + <xsl:param name="highlight.source" select="1"/> + <xsl:param name="highlight.default.language" select="xml"/> + + <xsl:template match='xslthl:keyword'> + <fo:inline font-weight="bold" color="#7F0055"> + <xsl:apply-templates/> + </fo:inline> + </xsl:template> + + <xsl:template match='xslthl:comment'> + <fo:inline font-style="italic" color="#3F5F5F"> + <xsl:apply-templates/> + </fo:inline> + </xsl:template> + + <xsl:template match='xslthl:oneline-comment'> + <fo:inline font-style="italic" color="#3F5F5F"> + <xsl:apply-templates/> + </fo:inline> + </xsl:template> + + <xsl:template match='xslthl:multiline-comment'> + <fo:inline font-style="italic" color="#3F5FBF"> + <xsl:apply-templates/> + </fo:inline> + </xsl:template> + + <xsl:template match='xslthl:tag'> + <fo:inline color="#3F7F7F"> + <xsl:apply-templates/> + </fo:inline> + </xsl:template> + + <xsl:template match='xslthl:attribute'> + <fo:inline color="#7F007F"> + <xsl:apply-templates/> + </fo:inline> + </xsl:template> + + <xsl:template match='xslthl:value'> + <fo:inline color="#2A00FF"> + <xsl:apply-templates/> + </fo:inline> + </xsl:template> + + <xsl:template match='xslthl:string'> + <fo:inline color="#2A00FF"> + <xsl:apply-templates/> + </fo:inline> + </xsl:template> + + <!--################################################### + Tables + ################################################### --> + + <!-- Some padding inside tables --> + <xsl:attribute-set name="table.cell.padding"> + <xsl:attribute name="padding-left">4pt</xsl:attribute> + <xsl:attribute name="padding-right">4pt</xsl:attribute> + <xsl:attribute name="padding-top">4pt</xsl:attribute> + <xsl:attribute name="padding-bottom">4pt</xsl:attribute> + </xsl:attribute-set> + + <!-- Only hairlines as frame and cell borders in tables --> + <xsl:param name="table.frame.border.thickness">0.1pt</xsl:param> + <xsl:param name="table.cell.border.thickness">0.1pt</xsl:param> + + <!--################################################### + Labels + ################################################### --> + + <!-- Label Chapters and Sections (numbering) --> + <xsl:param name="chapter.autolabel" select="1"/> + <xsl:param name="section.autolabel" select="1"/> + <xsl:param name="section.autolabel.max.depth" select="1"/> + + <xsl:param name="section.label.includes.component.label" select="1"/> + <xsl:param name="table.footnote.number.format" select="'1'"/> + + <!--################################################### + Programlistings + ################################################### --> + + <!-- Verbatim text formatting (programlistings) --> + <xsl:attribute-set name="monospace.verbatim.properties"> + <xsl:attribute name="font-size"> + <xsl:value-of select="$body.font.small * 1.0"/> + <xsl:text>pt</xsl:text> + </xsl:attribute> + </xsl:attribute-set> + + <xsl:attribute-set name="verbatim.properties"> + <xsl:attribute name="space-before.minimum">1em</xsl:attribute> + <xsl:attribute name="space-before.optimum">1em</xsl:attribute> + <xsl:attribute name="space-before.maximum">1em</xsl:attribute> + <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute> + <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute> + <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute> + + <xsl:attribute name="border-color">#444444</xsl:attribute> + <xsl:attribute name="border-style">solid</xsl:attribute> + <xsl:attribute name="border-width">0.1pt</xsl:attribute> + <xsl:attribute name="padding-top">0.5em</xsl:attribute> + <xsl:attribute name="padding-left">0.5em</xsl:attribute> + <xsl:attribute name="padding-right">0.5em</xsl:attribute> + <xsl:attribute name="padding-bottom">0.5em</xsl:attribute> + <xsl:attribute name="margin-left">0.5em</xsl:attribute> + <xsl:attribute name="margin-right">0.5em</xsl:attribute> + </xsl:attribute-set> + + <!-- Shade (background) programlistings --> + <xsl:param name="shade.verbatim">1</xsl:param> + <xsl:attribute-set name="shade.verbatim.style"> + <xsl:attribute name="background-color">#F0F0F0</xsl:attribute> + </xsl:attribute-set> + + <xsl:attribute-set name="list.block.spacing"> + <xsl:attribute name="space-before.optimum">0.1em</xsl:attribute> + <xsl:attribute name="space-before.minimum">0.1em</xsl:attribute> + <xsl:attribute name="space-before.maximum">0.1em</xsl:attribute> + <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute> + <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute> + <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute> + </xsl:attribute-set> + + <xsl:attribute-set name="example.properties"> + <xsl:attribute name="space-before.minimum">0.5em</xsl:attribute> + <xsl:attribute name="space-before.optimum">0.5em</xsl:attribute> + <xsl:attribute name="space-before.maximum">0.5em</xsl:attribute> + <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute> + <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute> + <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute> + <xsl:attribute name="keep-together.within-column">always</xsl:attribute> + </xsl:attribute-set> + + <!--################################################### + Title information for Figures, Examples etc. + ################################################### --> + + <xsl:attribute-set name="formal.title.properties" use-attribute-sets="normal.para.spacing"> + <xsl:attribute name="font-weight">normal</xsl:attribute> + <xsl:attribute name="font-style">italic</xsl:attribute> + <xsl:attribute name="font-size"> + <xsl:value-of select="$body.font.master"/> + <xsl:text>pt</xsl:text> + </xsl:attribute> + <xsl:attribute name="hyphenate">false</xsl:attribute> + <xsl:attribute name="space-before.minimum">0.1em</xsl:attribute> + <xsl:attribute name="space-before.optimum">0.1em</xsl:attribute> + <xsl:attribute name="space-before.maximum">0.1em</xsl:attribute> + </xsl:attribute-set> + + <!--################################################### + Callouts + ################################################### --> + + <!-- don't use images for callouts --> + <xsl:param name="callout.graphics">0</xsl:param> + <xsl:param name="callout.unicode">1</xsl:param> + + <!-- Place callout marks at this column in annotated areas --> + <xsl:param name="callout.defaultcolumn">90</xsl:param> + + <!--################################################### + Misc + ################################################### --> + + <!-- Placement of titles --> + <xsl:param name="formal.title.placement"> + figure after + example after + equation before + table before + procedure before + </xsl:param> + + <!-- Format Variable Lists as Blocks (prevents horizontal overflow) --> + <xsl:param name="variablelist.as.blocks">1</xsl:param> + + <xsl:param name="body.start.indent">0pt</xsl:param> + + <!-- Show only Sections up to level 3 in the TOCs --> + <xsl:param name="toc.section.depth">3</xsl:param> + + <!-- Remove "Chapter" from the Chapter titles... --> + <xsl:param name="local.l10n.xml" select="document('')"/> + <l:i18n xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0"> + <l:l10n language="en"> + <l:context name="title-numbered"> + <l:template name="chapter" text="%n. %t"/> + <l:template name="section" text="%n %t"/> + </l:context> + <l:context name="title"> + <l:template name="example" text="Example %n %t"/> + </l:context> + </l:l10n> + </l:i18n> + + <!--################################################### + colored and hyphenated links + ################################################### --> + + <xsl:template match="ulink"> + <fo:basic-link external-destination="{@url}" + xsl:use-attribute-sets="xref.properties" + text-decoration="underline" + color="blue"> + <xsl:choose> + <xsl:when test="count(child::node())=0"> + <xsl:value-of select="@url"/> + </xsl:when> + <xsl:otherwise> + <xsl:apply-templates/> + </xsl:otherwise> + </xsl:choose> + </fo:basic-link> + </xsl:template> + + <xsl:template match="link"> + <fo:basic-link internal-destination="{@linkend}" + xsl:use-attribute-sets="xref.properties" + text-decoration="underline" + color="blue"> + <xsl:choose> + <xsl:when test="count(child::node())=0"> + <xsl:value-of select="@linkend"/> + </xsl:when> + <xsl:otherwise> + <xsl:apply-templates/> + </xsl:otherwise> + </xsl:choose> + </fo:basic-link> + </xsl:template> </xsl:stylesheet> \ No newline at end of file diff --git a/src/docbkx/resources/xsl/pdf/titlepage.xml b/src/docbkx/resources/xsl/pdf/titlepage.xml index dc18e1e0d..faee284c6 100644 --- a/src/docbkx/resources/xsl/pdf/titlepage.xml +++ b/src/docbkx/resources/xsl/pdf/titlepage.xml @@ -20,19 +20,19 @@ --> <!DOCTYPE t:templates [ -<!ENTITY hsize0 "10pt"> -<!ENTITY hsize1 "12pt"> -<!ENTITY hsize2 "14.4pt"> -<!ENTITY hsize3 "17.28pt"> -<!ENTITY hsize4 "20.736pt"> -<!ENTITY hsize5 "24.8832pt"> -<!ENTITY hsize0space "7.5pt"> <!-- 0.75 * hsize0 --> -<!ENTITY hsize1space "9pt"> <!-- 0.75 * hsize1 --> -<!ENTITY hsize2space "10.8pt"> <!-- 0.75 * hsize2 --> -<!ENTITY hsize3space "12.96pt"> <!-- 0.75 * hsize3 --> -<!ENTITY hsize4space "15.552pt"> <!-- 0.75 * hsize4 --> -<!ENTITY hsize5space "18.6624pt"> <!-- 0.75 * hsize5 --> -]> + <!ENTITY hsize0 "10pt"> + <!ENTITY hsize1 "12pt"> + <!ENTITY hsize2 "14.4pt"> + <!ENTITY hsize3 "17.28pt"> + <!ENTITY hsize4 "20.736pt"> + <!ENTITY hsize5 "24.8832pt"> + <!ENTITY hsize0space "7.5pt"> <!-- 0.75 * hsize0 --> + <!ENTITY hsize1space "9pt"> <!-- 0.75 * hsize1 --> + <!ENTITY hsize2space "10.8pt"> <!-- 0.75 * hsize2 --> + <!ENTITY hsize3space "12.96pt"> <!-- 0.75 * hsize3 --> + <!ENTITY hsize4space "15.552pt"> <!-- 0.75 * hsize4 --> + <!ENTITY hsize5space "18.6624pt"> <!-- 0.75 * hsize5 --> + ]> <t:templates xmlns:t="http://nwalsh.com/docbook/xsl/template/1.0" xmlns:param="http://nwalsh.com/docbook/xsl/template/1.0/param" xmlns:fo="http://www.w3.org/1999/XSL/Format" @@ -41,18 +41,18 @@ <t:titlepage t:element="book" t:wrapper="fo:block"> <t:titlepage-content t:side="recto"> <title - t:named-template="division.title" - param:node="ancestor-or-self::book[1]" - text-align="center" - font-size="&hsize5;" - space-before="&hsize5space;" - font-weight="bold" - font-family="{$title.fontset}"/> + t:named-template="division.title" + param:node="ancestor-or-self::book[1]" + text-align="center" + font-size="&hsize5;" + space-before="&hsize5space;" + font-weight="bold" + font-family="{$title.fontset}"/> <subtitle - text-align="center" - font-size="&hsize4;" - space-before="&hsize4space;" - font-family="{$title.fontset}"/> + text-align="center" + font-size="&hsize4;" + space-before="&hsize4space;" + font-family="{$title.fontset}"/> <!-- <corpauthor space-before="0.5em" font-size="&hsize2;"/> @@ -61,41 +61,41 @@ <author space-before="0.5em" font-size="&hsize2;"/> --> - <mediaobject space-before="2em" space-after="2em"/> - <releaseinfo space-before="5em" font-size="&hsize2;"/> - <copyright space-before="1.5em" - font-weight="normal" - font-size="8"/> - <legalnotice space-before="5em" - font-weight="normal" - font-style="italic" - font-size="8"/> - <othercredit space-before="2em" - font-weight="normal" - font-size="8"/> - <pubdate space-before="0.5em"/> - <revision space-before="0.5em"/> - <revhistory space-before="0.5em"/> - <abstract space-before="0.5em" - text-align="start" - margin-left="0.5in" - margin-right="0.5in" - font-family="{$body.fontset}"/> - </t:titlepage-content> + <mediaobject space-before="2em" space-after="2em"/> + <releaseinfo space-before="5em" font-size="&hsize2;"/> + <copyright space-before="1.5em" + font-weight="normal" + font-size="8"/> + <legalnotice space-before="5em" + font-weight="normal" + font-style="italic" + font-size="8"/> + <othercredit space-before="2em" + font-weight="normal" + font-size="8"/> + <pubdate space-before="0.5em"/> + <revision space-before="0.5em"/> + <revhistory space-before="0.5em"/> + <abstract space-before="0.5em" + text-align="start" + margin-left="0.5in" + margin-right="0.5in" + font-family="{$body.fontset}"/> + </t:titlepage-content> - <t:titlepage-content t:side="verso"> - </t:titlepage-content> + <t:titlepage-content t:side="verso"> + </t:titlepage-content> - <t:titlepage-separator> - </t:titlepage-separator> + <t:titlepage-separator> + </t:titlepage-separator> - <t:titlepage-before t:side="recto"> - </t:titlepage-before> + <t:titlepage-before t:side="recto"> + </t:titlepage-before> - <t:titlepage-before t:side="verso"> - </t:titlepage-before> -</t:titlepage> + <t:titlepage-before t:side="verso"> + </t:titlepage-before> + </t:titlepage> -<!-- ==================================================================== --> + <!-- ==================================================================== --> </t:templates> diff --git a/src/main/javadoc/spring-javadoc.css b/src/main/javadoc/spring-javadoc.css index c438fafa5..79cb2cedb 100644 --- a/src/main/javadoc/spring-javadoc.css +++ b/src/main/javadoc/spring-javadoc.css @@ -6,173 +6,143 @@ * */ - - -.code -{ - border: 1px solid black; - background-color: #F4F4F4; - padding: 5px; +.code { + border: 1px solid black; + background-color: #F4F4F4; + padding: 5px; } -body -{ - font: 12px Verdana, Arial, Helvetica, "Bitstream Vera Sans", sans-serif; - background-color: #fff; - color: #333; +body { + font: 12px Verdana, Arial, Helvetica, "Bitstream Vera Sans", sans-serif; + background-color: #fff; + color: #333; } - /* Link colors */ -a -{ - color:#2c7b14; - text-decoration:none; +a { + color: #2c7b14; + text-decoration: none; } -a:hover -{ - text-decoration:underline; +a:hover { + text-decoration: underline; } /* Headings */ -h1 -{ - font-size:28px; - color:#007c00; +h1 { + font-size: 28px; + color: #007c00; } /* Table colors */ -table -{ - border:none; +table { + border: none; } -td -{ - border:none; - border-bottom:1px dotted #ddd; +td { + border: none; + border-bottom: 1px dotted #ddd; } -th -{ - border:none; +th { + border: none; } -.TableHeadingColor th -{ - background-color: #efffcb; - background-image: url(doc-files/th-background.png); - background-repeat: repeat-x; - color:#fff; - font-size:14px; - height:26px; +.TableHeadingColor th { + background-color: #efffcb; + background-image: url(doc-files/th-background.png); + background-repeat: repeat-x; + color: #fff; + font-size: 14px; + height: 26px; } -.TableSubHeadingColor -{ - background: #f7ffee; +.TableSubHeadingColor { + background: #f7ffee; -} -.TableRowColor -{ - background: #fff; } -.TableRowColor a -{ - border-bottom:none; - color:#2c7b14; - font-weight:normal; +.TableRowColor { + background: #fff; } -tr.TableRowColor:hover -{ - background:#eef2e1; +.TableRowColor a { + border-bottom: none; + color: #2c7b14; + font-weight: normal; +} + +tr.TableRowColor:hover { + background: #eef2e1; } - /* Font used in left-hand frame lists */ -.FrameTitleFont -{ - font-size: 120%; - font-weight:bold; +.FrameTitleFont { + font-size: 120%; + font-weight: bold; } -.FrameTitleFont a -{ - color: #333; +.FrameTitleFont a { + color: #333; } -.FrameHeadingFont -{ - font-weight: bold; - font-size:95%; +.FrameHeadingFont { + font-weight: bold; + font-size: 95%; } -.FrameItemFont -{ - line-height:130%; - font-size: 95%; +.FrameItemFont { + line-height: 130%; + font-size: 95%; } -.FrameItemFont a -{ - color:#333; +.FrameItemFont a { + color: #333; } -.FrameItemFont a:hover -{ - color:#249901; - border-bottom:none; - text-decoration:underline; +.FrameItemFont a:hover { + color: #249901; + border-bottom: none; + text-decoration: underline; } /* Navigation bar fonts and colors */ -.NavBarCell1 -{ - background-color:#fff; - border:none; -} - -.NavBarCell1Rev -{ - background-color:#e3faa5; - border:1px solid #9ad00c; - padding:0; - margin:0; -} - -.NavBarCell1 a -{ - color:#333; - text-decoration:none; +.NavBarCell1 { + background-color: #fff; + border: none; } -.NavBarFont1Rev -{ +.NavBarCell1Rev { + background-color: #e3faa5; + border: 1px solid #9ad00c; + padding: 0; + margin: 0; +} + +.NavBarCell1 a { + color: #333; + text-decoration: none; +} + +.NavBarFont1Rev { } -.NavBarCell2 -{ - border:none; +.NavBarCell2 { + border: none; } -.NavBarCell2 a -{ - color:#249901; - font-size:90%; +.NavBarCell2 a { + color: #249901; + font-size: 90%; } -.NavBarCell3 -{ - border:none; +.NavBarCell3 { + border: none; } /* Override sizes in font tags */ -font -{ - font: inherit !important; +font { + font: inherit !important; }