diff --git a/src/main/java/org/springframework/datastore/document/AbstractDocumentStoreTemplate.java b/src/main/java/org/springframework/datastore/document/AbstractDocumentStoreTemplate.java index 010ada079..fddf117fd 100644 --- a/src/main/java/org/springframework/datastore/document/AbstractDocumentStoreTemplate.java +++ b/src/main/java/org/springframework/datastore/document/AbstractDocumentStoreTemplate.java @@ -19,12 +19,11 @@ package org.springframework.datastore.document; public abstract class AbstractDocumentStoreTemplate { - - public abstract DocumentStoreConnectionFactory getDocumentStoreConnectionFactory(); + public abstract C getConnection(); public T execute(DocumentStoreConnectionCallback action) { try { - return action.doInConnection(getDocumentStoreConnectionFactory().getConnection()); + return action.doInConnection(getConnection()); } catch (Exception e) { throw new UncategorizedDocumentStoreException("Failure executing using datastore connection", e); diff --git a/src/main/java/org/springframework/datastore/document/DocumentStoreConnectionFactory.java b/src/main/java/org/springframework/datastore/document/DocumentStoreConnectionFactory.java deleted file mode 100644 index fd90b5883..000000000 --- a/src/main/java/org/springframework/datastore/document/DocumentStoreConnectionFactory.java +++ /dev/null @@ -1,21 +0,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. - */ - -package org.springframework.datastore.document; - -public interface DocumentStoreConnectionFactory { - C getConnection(); -} diff --git a/src/main/java/org/springframework/datastore/document/couchdb/CouchDbConnectionFactory.java b/src/main/java/org/springframework/datastore/document/couchdb/CouchDbConnectionFactory.java deleted file mode 100644 index 89ee47019..000000000 --- a/src/main/java/org/springframework/datastore/document/couchdb/CouchDbConnectionFactory.java +++ /dev/null @@ -1,123 +0,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. - */ - -/* - * 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. - */ - -package org.springframework.datastore.document.couchdb; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.jcouchdb.db.Database; - -import org.springframework.beans.factory.InitializingBean; -import org.springframework.datastore.document.DocumentStoreConnectionFactory; - - -/** - * Convenient factory for configuring CouchDB. - * - * @author Thomas Risberg - * @since 1.0 - */ -public class CouchDbConnectionFactory implements DocumentStoreConnectionFactory, InitializingBean { - - /** - * Logger, available to subclasses. - */ - protected final Log logger = LogFactory.getLog(getClass()); - - private Database database; - private String host; - private String databaseName; - - public CouchDbConnectionFactory() { - super(); - } - - public CouchDbConnectionFactory(String host, String databaseName) { - super(); - this.host = host; - this.databaseName = databaseName; - } - - public CouchDbConnectionFactory(Database database) { - super(); - this.database = database; - } - - public void setDatabase(Database database) { - this.database = database; - } - - public void setDatabaseName(String databaseName) { - this.databaseName = databaseName; - } - - public void setHost(String host) { - this.host = host; - } - - public boolean isSingleton() { - return false; - } - - public void afterPropertiesSet() throws Exception { - // apply defaults - convenient when used to configure for tests - // in an application context - if (database == null) { - if (databaseName == null) { - logger.warn("Property databaseName not specified. Using default name 'test'"); - databaseName = "test"; - } - if (host == null) { - logger.warn("Property host not specified. Using default 'localhost'"); - database = new Database(host, databaseName); - } - database = new Database(host, databaseName); - } - else { - logger.info("Using provided database configuration"); - } - } - - public Database getConnection() { - synchronized (this){ - if (database == null) { - try { - afterPropertiesSet(); - } catch (Exception e) { - throw new CannotGetCouchDbConnectionException("Unable to connect to CouchDB", e); - } - } - } - return database; - } - -} diff --git a/src/main/java/org/springframework/datastore/document/mongodb/MongoDbConnectionFactory.java b/src/main/java/org/springframework/datastore/document/couchdb/CouchDbFactoryBean.java similarity index 51% rename from src/main/java/org/springframework/datastore/document/mongodb/MongoDbConnectionFactory.java rename to src/main/java/org/springframework/datastore/document/couchdb/CouchDbFactoryBean.java index 8c7650603..63d629794 100644 --- a/src/main/java/org/springframework/datastore/document/mongodb/MongoDbConnectionFactory.java +++ b/src/main/java/org/springframework/datastore/document/couchdb/CouchDbFactoryBean.java @@ -14,73 +14,63 @@ * limitations under the License. */ -/* - * 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. - */ +package org.springframework.datastore.document.couchdb; -package org.springframework.datastore.document.mongodb; +import org.jcouchdb.db.Database; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.support.PersistenceExceptionTranslator; +import org.springframework.util.Assert; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.datastore.document.DocumentStoreConnectionFactory; -import org.springframework.util.Assert; - -import com.mongodb.DB; -import com.mongodb.Mongo; - /** * Convenient factory for configuring MongoDB. * * @author Thomas Risberg * @since 1.0 */ -public class MongoDbConnectionFactory implements DocumentStoreConnectionFactory, InitializingBean { +public class CouchDbFactoryBean implements FactoryBean, InitializingBean, + PersistenceExceptionTranslator { /** * Logger, available to subclasses. */ protected final Log logger = LogFactory.getLog(getClass()); - private Mongo mongo; + private String host; + private Integer port; private String databaseName; - - public MongoDbConnectionFactory() { - super(); - } - public MongoDbConnectionFactory(String databaseName) { - super(); - this.databaseName = databaseName; - } - - public MongoDbConnectionFactory(Mongo mongo, String databaseName) { - super(); - this.mongo = mongo; - this.databaseName = databaseName; - } - - public void setMongo(Mongo mongo) { - this.mongo = mongo; - } - public void setDatabaseName(String databaseName) { this.databaseName = databaseName; } + public void setHost(String host) { + this.host = host; + } + + public void setPort(int port) { + this.port = port; + } + + public Database getObject() throws Exception { + Assert.hasText(host, "Host must not be empty"); + Assert.hasText(databaseName, "Database name must not be empty"); + if (port == null) { + return new Database(host, databaseName); + } + else { + return new Database(host, port, databaseName); + } + } + + public Class getObjectType() { + return Database.class; + } + public boolean isSingleton() { return false; } @@ -88,20 +78,19 @@ public class MongoDbConnectionFactory implements DocumentStoreConnectionFactory< public void afterPropertiesSet() throws Exception { // apply defaults - convenient when used to configure for tests // in an application context + if (host == null) { + logger.warn("Property host not specified. Using default 'localhost'"); + databaseName = "localhost"; + } if (databaseName == null) { logger.warn("Property databaseName not specified. Using default name 'test'"); databaseName = "test"; } - if (mongo == null) { - logger.warn("Property mongo not specified. Using default configuration"); - mongo = new Mongo(); - } } - public DB getConnection() { - Assert.notNull(mongo, "Mongo must not be null"); - Assert.hasText(databaseName, "Database name must not be empty"); - return mongo.getDB(databaseName); + public DataAccessException translateExceptionIfPossible(RuntimeException ex) { + logger.debug("Translating " + ex); + return CouchDbUtils.translateCouchExceptionIfPossible(ex); } } diff --git a/src/main/java/org/springframework/datastore/document/couchdb/CouchDbUtils.java b/src/main/java/org/springframework/datastore/document/couchdb/CouchDbUtils.java new file mode 100644 index 000000000..e79dbfcf0 --- /dev/null +++ b/src/main/java/org/springframework/datastore/document/couchdb/CouchDbUtils.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package org.springframework.datastore.document.couchdb; + +import org.jcouchdb.exception.CouchDBException; +import org.springframework.dao.DataAccessException; +import org.springframework.datastore.document.UncategorizedDocumentStoreException; + +/** + * Helper class featuring helper methods for internal MongoDb classes. + * + *

Mainly intended for internal use within the framework. + * + * @author Thomas Risberg + * @since 1.0 + */ +public class CouchDbUtils { + + /** + * 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) { + + // Check for well-known MongoException subclasses. + + // All other MongoExceptions + if (ex instanceof CouchDBException) { + 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; + } + +} diff --git a/src/main/java/org/springframework/datastore/document/couchdb/CouchTemplate.java b/src/main/java/org/springframework/datastore/document/couchdb/CouchTemplate.java index 2d03c7544..927a54c61 100644 --- a/src/main/java/org/springframework/datastore/document/couchdb/CouchTemplate.java +++ b/src/main/java/org/springframework/datastore/document/couchdb/CouchTemplate.java @@ -21,11 +21,10 @@ import org.jcouchdb.db.Database; import org.jcouchdb.document.BaseDocument; import org.springframework.datastore.document.AbstractDocumentStoreTemplate; import org.springframework.datastore.document.DocumentSource; -import org.springframework.datastore.document.DocumentStoreConnectionFactory; public class CouchTemplate extends AbstractDocumentStoreTemplate { - private DocumentStoreConnectionFactory connectionFactory; + private Database database; public CouchTemplate() { super(); @@ -33,22 +32,22 @@ import org.springframework.datastore.document.DocumentStoreConnectionFactory; public CouchTemplate(String host, String databaseName) { super(); - connectionFactory = new CouchDbConnectionFactory(host, databaseName); + database = new Database(host, databaseName); } - public CouchTemplate(CouchDbConnectionFactory mcf) { + public CouchTemplate(Database database) { super(); - connectionFactory = mcf; + this.database = database; } public void save(DocumentSource documentSource) { BaseDocument d = documentSource.getDocument(); - getDocumentStoreConnectionFactory().getConnection().createDocument(d); + getConnection().createDocument(d); } @Override - public DocumentStoreConnectionFactory getDocumentStoreConnectionFactory() { - return connectionFactory; + public Database getConnection() { + return database; } diff --git a/src/main/java/org/springframework/datastore/document/mongodb/MongoBeanPropertyDocumentSource.java b/src/main/java/org/springframework/datastore/document/mongodb/MongoBeanPropertyDocumentSource.java index 17d0f3580..12aed8076 100644 --- a/src/main/java/org/springframework/datastore/document/mongodb/MongoBeanPropertyDocumentSource.java +++ b/src/main/java/org/springframework/datastore/document/mongodb/MongoBeanPropertyDocumentSource.java @@ -27,13 +27,9 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanWrapper; import org.springframework.beans.NotReadablePropertyException; -import org.springframework.beans.NotWritablePropertyException; import org.springframework.beans.PropertyAccessorFactory; -import org.springframework.beans.TypeMismatchException; import org.springframework.dao.DataRetrievalFailureException; -import org.springframework.datastore.document.DocumentMapper; import org.springframework.datastore.document.DocumentSource; -import org.springframework.util.Assert; import com.mongodb.BasicDBObject; import com.mongodb.DBObject; @@ -67,6 +63,7 @@ public class MongoBeanPropertyDocumentSource implements DocumentSource } + @SuppressWarnings("rawtypes") public DBObject getDocument() { BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this.source); DBObject dbo = new BasicDBObject(); diff --git a/src/main/java/org/springframework/datastore/document/mongodb/MongoDbFactoryBean.java b/src/main/java/org/springframework/datastore/document/mongodb/MongoDbFactoryBean.java index 0bfa081ed..c990ede11 100644 --- a/src/main/java/org/springframework/datastore/document/mongodb/MongoDbFactoryBean.java +++ b/src/main/java/org/springframework/datastore/document/mongodb/MongoDbFactoryBean.java @@ -18,6 +18,9 @@ package org.springframework.datastore.document.mongodb; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.support.PersistenceExceptionTranslator; +import org.springframework.util.Assert; import com.mongodb.DB; import com.mongodb.Mongo; @@ -31,25 +34,39 @@ import org.apache.commons.logging.LogFactory; * @author Thomas Risberg * @since 1.0 */ -public class MongoDbFactoryBean implements FactoryBean, InitializingBean { +public class MongoDbFactoryBean implements FactoryBean, InitializingBean, + PersistenceExceptionTranslator { /** * Logger, available to subclasses. */ protected final Log logger = LogFactory.getLog(getClass()); - private MongoDbConnectionFactory mcf = new MongoDbConnectionFactory(); + private Mongo mongo; + private String host; + private Integer port; + private String databaseName; public void setMongo(Mongo mongo) { - this.mcf.setMongo(mongo); + this.mongo = mongo; } public void setDatabaseName(String databaseName) { - this.mcf.setDatabaseName(databaseName); + this.databaseName = databaseName; + } + + public void setHost(String host) { + this.host = host; + } + + public void setPort(int port) { + this.port = port; } public DB getObject() throws Exception { - return mcf.getConnection(); + Assert.notNull(mongo, "Mongo must not be null"); + Assert.hasText(databaseName, "Database name must not be empty"); + return mongo.getDB(databaseName); } public Class getObjectType() { @@ -61,7 +78,31 @@ public class MongoDbFactoryBean implements FactoryBean, InitializingBean { } public void afterPropertiesSet() throws Exception { - this.mcf.afterPropertiesSet(); + // apply defaults - convenient when used to configure for tests + // in an application context + if (databaseName == null) { + logger.warn("Property databaseName not specified. Using default name 'test'"); + databaseName = "test"; + } + if (mongo == null) { + logger.warn("Property mongo not specified. Using default configuration"); + if (host == null) { + mongo = new Mongo(); + } + else { + if (port == null) { + mongo = new Mongo(host); + } + else { + mongo = new Mongo(host, port); + } + } + } + } + + public DataAccessException translateExceptionIfPossible(RuntimeException ex) { + logger.debug("Translating " + ex); + return MongoDbUtils.translateMongoExceptionIfPossible(ex); } } diff --git a/src/main/java/org/springframework/datastore/document/mongodb/MongoDbUtils.java b/src/main/java/org/springframework/datastore/document/mongodb/MongoDbUtils.java new file mode 100644 index 000000000..cf40f887f --- /dev/null +++ b/src/main/java/org/springframework/datastore/document/mongodb/MongoDbUtils.java @@ -0,0 +1,58 @@ +/* + * 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. + */ + +package org.springframework.datastore.document.mongodb; + +import org.springframework.dao.DataAccessException; +import org.springframework.datastore.document.UncategorizedDocumentStoreException; + +import com.mongodb.MongoException; + +/** + * Helper class featuring helper methods for internal MongoDb classes. + * + *

Mainly intended for internal use within the framework. + * + * @author Thomas Risberg + * @since 1.0 + */ +public class MongoDbUtils { + + /** + * 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 translateMongoExceptionIfPossible(RuntimeException ex) { + + // Check for well-known MongoException subclasses. + + // All other MongoExceptions + 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; + } + +} diff --git a/src/main/java/org/springframework/datastore/document/mongodb/MongoTemplate.java b/src/main/java/org/springframework/datastore/document/mongodb/MongoTemplate.java index 1482d3ad3..7e379822a 100644 --- a/src/main/java/org/springframework/datastore/document/mongodb/MongoTemplate.java +++ b/src/main/java/org/springframework/datastore/document/mongodb/MongoTemplate.java @@ -25,42 +25,29 @@ import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.datastore.document.AbstractDocumentStoreTemplate; import org.springframework.datastore.document.DocumentMapper; import org.springframework.datastore.document.DocumentSource; -import org.springframework.datastore.document.DocumentStoreConnectionFactory; import com.mongodb.CommandResult; import com.mongodb.DB; import com.mongodb.DBCollection; import com.mongodb.DBObject; -import com.mongodb.Mongo; import com.mongodb.MongoException; import com.mongodb.WriteResult; public class MongoTemplate extends AbstractDocumentStoreTemplate { - private DocumentStoreConnectionFactory connectionFactory; + private DB db; - public MongoTemplate() { - super(); - } +// public MongoTemplate() { +// super(); +// } - public MongoTemplate(Mongo mongo, String databaseName) { + public MongoTemplate(DB db) { super(); - connectionFactory = new MongoDbConnectionFactory(mongo, databaseName); - } - - public MongoTemplate(MongoDbConnectionFactory mcf) { - super(); - connectionFactory = mcf; - } - - @Override - public DocumentStoreConnectionFactory getDocumentStoreConnectionFactory() { - return connectionFactory; + this.db = db; } public void execute(String command) { - DB db = getDocumentStoreConnectionFactory().getConnection(); - CommandResult cr = db.command(command); + CommandResult cr = getConnection().command(command); String err = cr.getErrorMessage(); if (err != null) { throw new InvalidDataAccessApiUsageException("Command execution of " + @@ -69,9 +56,7 @@ public class MongoTemplate extends AbstractDocumentStoreTemplate { } public void execute(DocumentSource command) { - CommandResult cr = getDocumentStoreConnectionFactory() - .getConnection() - .command(command.getDocument()); + CommandResult cr = getConnection().command(command.getDocument()); String err = cr.getErrorMessage(); if (err != null) { throw new InvalidDataAccessApiUsageException("Command execution of " + @@ -80,18 +65,15 @@ public class MongoTemplate extends AbstractDocumentStoreTemplate { } public void createCollection(String collectionName, DocumentSource documentSource) { - DB db = getDocumentStoreConnectionFactory().getConnection(); try { - db.createCollection(collectionName, documentSource.getDocument()); + getConnection().createCollection(collectionName, documentSource.getDocument()); } catch (MongoException e) { throw new InvalidDataAccessApiUsageException("Error creating collection " + collectionName + ": " + e.getMessage(), e); } } public void dropCollection(String collectionName) { - getDocumentStoreConnectionFactory() - .getConnection() - .getCollection(collectionName) + getConnection().getCollection(collectionName) .drop(); } @@ -102,10 +84,9 @@ public class MongoTemplate extends AbstractDocumentStoreTemplate { public void save(String collectionName, DocumentSource documentSource) { DBObject dbDoc = documentSource.getDocument(); - DB db = getDocumentStoreConnectionFactory().getConnection(); WriteResult wr = null; try { - wr = db.getCollection(collectionName).save(dbDoc); + wr = getConnection().getCollection(collectionName).save(dbDoc); } catch (MongoException e) { throw new DataRetrievalFailureException(wr.getLastError().getErrorMessage(), e); } @@ -118,12 +99,20 @@ public class MongoTemplate extends AbstractDocumentStoreTemplate { public List queryForCollection(String collectionName, DocumentMapper mapper) { List results = new ArrayList(); - DB db = getDocumentStoreConnectionFactory().getConnection(); - DBCollection collection = db.getCollection(collectionName); + DBCollection collection = getConnection().getCollection(collectionName); for (DBObject dbo : collection.find()) { results.add(mapper.mapDocument(dbo)); } return results; } + public RuntimeException translateIfNecessary(RuntimeException ex) { + return MongoDbUtils.translateMongoExceptionIfPossible(ex); + } + + @Override + public DB getConnection() { + return db; + } + }