Browse Source

Merge branch 'master' of git.springsource.org:spring-data/datastore-document

pull/1/head
Costin Leau 15 years ago
parent
commit
28fb505dc2
  1. 71
      spring-datastore-mongodb/src/main/java/org/springframework/datastore/document/mongodb/DBHolder.java
  2. 110
      spring-datastore-mongodb/src/main/java/org/springframework/datastore/document/mongodb/MongoDbUtils.java
  3. 29
      spring-datastore-mongodb/src/main/java/org/springframework/datastore/document/mongodb/MongoFactoryBean.java
  4. 15
      spring-datastore-mongodb/src/main/java/org/springframework/datastore/document/mongodb/MongoSynchronization.java
  5. 35
      spring-datastore-mongodb/src/main/java/org/springframework/datastore/document/mongodb/MongoTemplate.java
  6. 3
      spring-datastore-mongodb/src/test/java/org/springframework/datastore/document/mongodb/analytics/MvcAnalyticsTests.java
  7. 1
      spring-datastore-mongodb/template.mf

71
spring-datastore-mongodb/src/main/java/org/springframework/datastore/document/mongodb/DBHolder.java

@ -0,0 +1,71 @@
package org.springframework.datastore.document.mongodb;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.transaction.support.ResourceHolderSupport;
import org.springframework.util.Assert;
import com.mongodb.DB;
public class DBHolder extends ResourceHolderSupport {
private static final Object DEFAULT_KEY = new Object();
private final Map<Object, DB> dbMap = new ConcurrentHashMap<Object, DB>();
public DBHolder(DB db) {
addDB(db);
}
public DBHolder(Object key, DB db) {
addDB(key, db);
}
public DB getDB() {
return getDB(DEFAULT_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 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 DB removeDB(Object key) {
return this.dbMap.remove(key);
}
public boolean containsDB(DB session) {
return this.dbMap.containsValue(session);
}
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));
}
}
}

110
spring-datastore-mongodb/src/main/java/org/springframework/datastore/document/mongodb/MongoDbUtils.java

@ -16,10 +16,20 @@
package org.springframework.datastore.document.mongodb; package org.springframework.datastore.document.mongodb;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.datastore.document.UncategorizedDocumentStoreException; import org.springframework.datastore.document.UncategorizedDocumentStoreException;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
import com.mongodb.DB;
import com.mongodb.Mongo;
import com.mongodb.MongoException; import com.mongodb.MongoException;
import com.mongodb.MongoException.DuplicateKey;
import com.mongodb.MongoException.Network;
/** /**
* Helper class featuring helper methods for internal MongoDb classes. * Helper class featuring helper methods for internal MongoDb classes.
@ -27,10 +37,14 @@ import com.mongodb.MongoException;
* <p>Mainly intended for internal use within the framework. * <p>Mainly intended for internal use within the framework.
* *
* @author Thomas Risberg * @author Thomas Risberg
* @author Graeme Rocher
*
* @since 1.0 * @since 1.0
*/ */
public class MongoDbUtils { public class MongoDbUtils {
static final Log logger = LogFactory.getLog(MongoDbUtils.class);
/** /**
* Convert the given runtime exception to an appropriate exception from the * Convert the given runtime exception to an appropriate exception from the
* <code>org.springframework.dao</code> hierarchy. * <code>org.springframework.dao</code> hierarchy.
@ -45,6 +59,12 @@ public class MongoDbUtils {
// Check for well-known MongoException subclasses. // Check for well-known MongoException subclasses.
// All other MongoExceptions // 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) { if (ex instanceof MongoException) {
return new UncategorizedDocumentStoreException(ex.getMessage(), ex); return new UncategorizedDocumentStoreException(ex.getMessage(), ex);
} }
@ -55,4 +75,94 @@ public class MongoDbUtils {
return null; return null;
} }
public static DB getDB(Mongo mongo, String databaseName) {
return doGetDB(mongo, databaseName, true);
}
public static DB doGetDB(Mongo mongo, String databaseName, boolean allowCreate) {
Assert.notNull(mongo, "No Mongo instance specified");
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;
}
}
logger.debug("Opening Mongo DB");
DB db = mongo.getDB(databaseName);
// 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(dbHolder, 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 <code>null</code>)
* @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 <code>null</code>)
*/
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);
}
}
}
} }

29
spring-datastore-mongodb/src/main/java/org/springframework/datastore/document/mongodb/MongoDbFactoryBean.java → spring-datastore-mongodb/src/main/java/org/springframework/datastore/document/mongodb/MongoFactoryBean.java

@ -24,6 +24,7 @@ import org.springframework.util.Assert;
import com.mongodb.DB; import com.mongodb.DB;
import com.mongodb.Mongo; import com.mongodb.Mongo;
import com.mongodb.MongoOptions;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@ -32,9 +33,11 @@ import org.apache.commons.logging.LogFactory;
* Convenient factory for configuring MongoDB. * Convenient factory for configuring MongoDB.
* *
* @author Thomas Risberg * @author Thomas Risberg
* @author Graeme Rocher
*
* @since 1.0 * @since 1.0
*/ */
public class MongoDbFactoryBean implements FactoryBean<DB>, InitializingBean, public class MongoFactoryBean implements FactoryBean<Mongo>, InitializingBean,
PersistenceExceptionTranslator { PersistenceExceptionTranslator {
/** /**
@ -43,14 +46,20 @@ public class MongoDbFactoryBean implements FactoryBean<DB>, InitializingBean,
protected final Log logger = LogFactory.getLog(getClass()); protected final Log logger = LogFactory.getLog(getClass());
private Mongo mongo; private Mongo mongo;
private MongoOptions mongoOptions;
private String host; private String host;
private Integer port; private Integer port;
private String databaseName; private String databaseName;
public void setMongo(Mongo mongo) { public void setMongo(Mongo mongo) {
this.mongo = mongo; this.mongo = mongo;
} }
public void setMongoOptions(MongoOptions mongoOptions) {
this.mongoOptions = mongoOptions;
}
public void setDatabaseName(String databaseName) { public void setDatabaseName(String databaseName) {
this.databaseName = databaseName; this.databaseName = databaseName;
} }
@ -63,14 +72,13 @@ public class MongoDbFactoryBean implements FactoryBean<DB>, InitializingBean,
this.port = port; this.port = port;
} }
public DB getObject() throws Exception { public Mongo getObject() throws Exception {
Assert.notNull(mongo, "Mongo must not be null"); Assert.notNull(mongo, "Mongo must not be null");
Assert.hasText(databaseName, "Database name must not be empty"); return mongo;
return mongo.getDB(databaseName);
} }
public Class<? extends DB> getObjectType() { public Class<? extends Mongo> getObjectType() {
return DB.class; return Mongo.class;
} }
public boolean isSingleton() { public boolean isSingleton() {
@ -80,17 +88,16 @@ public class MongoDbFactoryBean implements FactoryBean<DB>, InitializingBean,
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
// apply defaults - convenient when used to configure for tests // apply defaults - convenient when used to configure for tests
// in an application context // in an application context
if (databaseName == null) {
logger.warn("Property databaseName not specified. Using default name 'test'");
databaseName = "test";
}
if (mongo == null) { if (mongo == null) {
logger.warn("Property mongo not specified. Using default configuration"); logger.warn("Property mongo not specified. Using default configuration");
if (host == null) { if (host == null) {
mongo = new Mongo(); mongo = new Mongo();
} }
else { else {
if (port == null) { if(mongoOptions != null) {
mongo = new Mongo(host != null ? host : "localhost", mongoOptions);
}
else if (port == null) {
mongo = new Mongo(host); mongo = new Mongo(host);
} }
else { else {

15
spring-datastore-mongodb/src/main/java/org/springframework/datastore/document/mongodb/MongoSynchronization.java

@ -0,0 +1,15 @@
package org.springframework.datastore.document.mongodb;
import org.springframework.transaction.support.ResourceHolder;
import org.springframework.transaction.support.ResourceHolderSynchronization;
import org.springframework.transaction.support.TransactionSynchronization;
public class MongoSynchronization extends ResourceHolderSynchronization
implements TransactionSynchronization {
public MongoSynchronization(ResourceHolder resourceHolder,
Object resourceKey) {
super(resourceHolder, resourceKey);
}
}

35
spring-datastore-mongodb/src/main/java/org/springframework/datastore/document/mongodb/MongoTemplate.java

@ -31,6 +31,7 @@ import com.mongodb.CommandResult;
import com.mongodb.DB; import com.mongodb.DB;
import com.mongodb.DBCollection; import com.mongodb.DBCollection;
import com.mongodb.DBObject; import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.MongoException; import com.mongodb.MongoException;
import com.mongodb.WriteResult; import com.mongodb.WriteResult;
import com.mongodb.util.JSON; import com.mongodb.util.JSON;
@ -46,30 +47,37 @@ public class MongoTemplate extends AbstractDocumentStoreTemplate<DB> implements
//TODO expose configuration... //TODO expose configuration...
private CollectionOptions defaultCollectionOptions; private CollectionOptions defaultCollectionOptions;
private Mongo mongo;
public MongoTemplate(DB db) { private String databaseName;
super();
this.db = db;
public MongoTemplate(Mongo mongo, String databaseName) {
this(mongo, databaseName, null, null);
} }
public MongoTemplate(DB db, String defaultCollectionName) { public MongoTemplate(Mongo mongo, String databaseName, String defaultCollectionName) {
super(); this(mongo, databaseName, defaultCollectionName, null);
this.db = db;
this.defaultCollectionName = defaultCollectionName;
} }
public MongoTemplate(DB db, MongoConverter mongoConverter) { public MongoTemplate(Mongo mongo, String databaseName, MongoConverter mongoConverter) {
this(db); this(mongo, databaseName, null, mongoConverter);
this.mongoConverter = mongoConverter;
} }
public MongoTemplate(DB db, String defaultCollectionName, MongoConverter mongoConverter) { public MongoTemplate(Mongo mongo, String databaseName, String defaultCollectionName, MongoConverter mongoConverter) {
this(db);
this.mongoConverter = mongoConverter; this.mongoConverter = mongoConverter;
this.defaultCollectionName = defaultCollectionName; this.defaultCollectionName = defaultCollectionName;
this.mongo = mongo;
this.databaseName = databaseName;
} }
public void setDefaultCollectionName(String defaultCollectionName) {
this.defaultCollectionName = defaultCollectionName;
}
public void setDatabaseName(String databaseName) {
this.databaseName = databaseName;
}
public String getDefaultCollectionName() { public String getDefaultCollectionName() {
return defaultCollectionName; return defaultCollectionName;
@ -268,7 +276,7 @@ public class MongoTemplate extends AbstractDocumentStoreTemplate<DB> implements
@Override @Override
public DB getConnection() { public DB getConnection() {
return db; return MongoDbUtils.getDB(mongo, databaseName);
} }
@ -292,6 +300,7 @@ public class MongoTemplate extends AbstractDocumentStoreTemplate<DB> implements
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
if (this.getDefaultCollectionName() != null) { if (this.getDefaultCollectionName() != null) {
DB db = getConnection();
if (! db.collectionExists(getDefaultCollectionName())) { if (! db.collectionExists(getDefaultCollectionName())) {
db.createCollection(getDefaultCollectionName(), null); db.createCollection(getDefaultCollectionName(), null);
} }

3
spring-datastore-mongodb/src/test/java/org/springframework/datastore/document/mongodb/analytics/MvcAnalyticsTests.java

@ -34,8 +34,7 @@ public class MvcAnalyticsTests {
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
Mongo m = new Mongo(); Mongo m = new Mongo();
DB db = m.getDB("mvc"); mongoTemplate = new MongoTemplate(m, "mvc", "mvc");
mongoTemplate = new MongoTemplate(db, "mvc");
mongoTemplate.afterPropertiesSet(); mongoTemplate.afterPropertiesSet();

1
spring-datastore-mongodb/template.mf

@ -9,6 +9,7 @@ Import-Template:
org.springframework.core.*;version="[3.0.0, 4.0.0)", org.springframework.core.*;version="[3.0.0, 4.0.0)",
org.springframework.dao.*;version="[3.0.0, 4.0.0)", org.springframework.dao.*;version="[3.0.0, 4.0.0)",
org.springframework.util.*;version="[3.0.0, 4.0.0)", org.springframework.util.*;version="[3.0.0, 4.0.0)",
org.springframework.transaction.*;version="[3.0.0, 4.0.0)",
org.springframework.data.core.*;version="[1.0.0, 2.0.0)", org.springframework.data.core.*;version="[1.0.0, 2.0.0)",
org.springframework.datastore.core.*;version="[1.0.0, 2.0.0)", org.springframework.datastore.core.*;version="[1.0.0, 2.0.0)",
org.springframework.datastore.persistence.*;version="[1.0.0, 2.0.0)", org.springframework.datastore.persistence.*;version="[1.0.0, 2.0.0)",

Loading…
Cancel
Save