/**
* Copyright (C) 2010 Michael Mosmann <michael@mosmann.de>
*
* 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 de.flapdoodle.mongoom.datastore;
import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bson.types.ObjectId;
import com.google.common.collect.Lists;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import de.flapdoodle.mongoom.IDatastore;
import de.flapdoodle.mongoom.IEntityQuery;
import de.flapdoodle.mongoom.datastore.index.IIndex;
import de.flapdoodle.mongoom.datastore.query.Query;
import de.flapdoodle.mongoom.exceptions.MappingException;
import de.flapdoodle.mongoom.exceptions.ObjectMapperException;
import de.flapdoodle.mongoom.logging.LogConfig;
import de.flapdoodle.mongoom.mapping.Const;
import de.flapdoodle.mongoom.mapping.IEntityTransformation;
import de.flapdoodle.mongoom.mapping.context.Transformations;
import de.flapdoodle.mongoom.mapping.index.IndexDef;
public class Datastore implements IDatastore {
private static final Logger _logger = LogConfig.getLogger(Datastore.class);
private final Mongo _mongo;
private final String _name;
private final DB _db;
private final Transformations _transformations;
public Datastore(Mongo mongo, String name, Transformations transformations) {
_mongo = mongo;
_name = name;
_transformations = transformations;
_db = _mongo.getDB(_name);
}
@Override
public void ensureCaps() {
Collection<IEntityTransformation<?>> entities = _transformations.transformations();
for (IEntityTransformation<?> entity : entities) {
_logger.info("Ensure Caps for " + entity.collection().name());
Caps.ensureCaps(_db, entity.collection());
}
}
@Override
public void ensureIndexes() {
Collection<IEntityTransformation<?>> entities = _transformations.transformations();
for (IEntityTransformation<?> entity : entities) {
_logger.info("Ensure Index for " + entity.collection().name());
IIndex index = entity.indexes();
if (index != null) {
for (IndexDef def : index.list()) {
Indexes.ensureIndex(_db, def, entity.collection().name());
}
}
}
}
@Override
public <T> void insert(T entity) {
store(Operation.Insert, entity);
}
@Override
public <T> void save(T entity) {
store(Operation.Save, entity);
}
@Override
public <T> void update(T entity) {
store(Operation.Update, entity);
}
private <T> void store(Operation operation, T entity) {
IEntityTransformation<T> converter = _transformations.transformation((Class<T>) entity.getClass());
DBCollection dbCollection = _db.getCollection(converter.collection().name());
Object idValue = converter.getId(entity);
Object versionValue = converter.getVersion(entity);
// if (idValue == null)
// throw new MappingException(entity.getClass(), "Key is NULL");
// DBObject convertedEntity = converter.convertTo(entity);
BasicDBObject key = new BasicDBObject();
key.put(Const.ID_FIELDNAME, idValue);
if (versionValue!=null) key.put(Const.VERSION_FIELDNAME, versionValue);
boolean reReadId = true;
boolean mustHaveObjectId = false;
boolean update = false;
switch (operation) {
case Delete:
mustHaveObjectId = true;
reReadId = false;
break;
case Save:
mustHaveObjectId = true;
break;
case Update:
reReadId = false;
update = true;
if (idValue == null)
throw new MappingException(entity.getClass(), "Can not update Entities with Id not set");
break;
}
try {
_db.requestStart();
if (mustHaveObjectId) {
if ((idValue != null) && (!(idValue instanceof ObjectId))) {
throw new MappingException(entity.getClass(), "Can not save Entities with custom Id");
}
}
converter.newVersion(entity);
DBObject convertedEntity = converter.asObject(entity);
switch (operation) {
case Insert:
_logger.fine("Insert: " + convertedEntity);
if (idValue != null) {
_logger.log(Level.WARNING, "Insert with Id set: " + idValue, new Exception());
}
dbCollection.insert(convertedEntity);
break;
case Update:
_logger.fine("Update: " + convertedEntity + " (Id: " + idValue + ")");
// BasicDBObject updateQuery=new BasicDBObject();
// updateQuery.put(Const.ID_FIELDNAME, idValue);
dbCollection.update(key, convertedEntity, false, false);
break;
case Save:
_logger.fine("Save: " + convertedEntity);
dbCollection.save(convertedEntity);
break;
case Delete:
_logger.fine("Delete: " + key);
dbCollection.remove(key);
break;
default:
throw new ObjectMapperException("Operation not supported: " + operation);
}
if (reReadId) {
Object savedIdValue = convertedEntity.get(Const.ID_FIELDNAME);
converter.setId(entity, savedIdValue);
}
Errors.checkError(_db, operation);
if (operation == Operation.Delete) {
converter.setId(entity, null);
}
} finally {
_db.requestDone();
}
}
public <T> void delete(T entity) {
store(Operation.Delete, entity);
};
@Override
public <T> List<T> find(Class<T> entityClass) {
IEntityTransformation<T> converter = _transformations.transformation(entityClass);
DBCollection dbCollection = _db.getCollection(converter.collection().name());
DBCursor dbcursor = dbCollection.find();
List<T> ret = Lists.newArrayList();
while (dbcursor.hasNext()) {
ret.add(converter.asEntity(dbcursor.next()));
}
return ret;
}
@Override
public <T> IEntityQuery<T> with(Class<T> entityClass) {
IEntityTransformation<T> converter = _transformations.transformation(entityClass);
DBCollection dbCollection = _db.getCollection(converter.collection().name());
return new Query<T>(converter, dbCollection);
}
}