com.enterprisemath.dao.big.MongoBigEntityDao Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of em-dao Show documentation
Show all versions of em-dao Show documentation
Simple and powerful data access layer.
package com.enterprisemath.dao.big;
import com.enterprisemath.dao.filter.Criterium;
import com.enterprisemath.dao.filter.Direction;
import com.enterprisemath.dao.filter.Filter;
import com.enterprisemath.dao.filter.Operator;
import com.enterprisemath.dao.filter.Order;
import com.enterprisemath.utils.DomainUtils;
import com.enterprisemath.utils.ValidationUtils;
import com.mongodb.MongoClient;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.bson.BsonDocument;
import org.bson.BsonInt32;
import org.bson.Document;
import org.bson.conversions.Bson;
/**
* Big entity data access layer implemented with MongoDB.
*
* @author radek.hecl
*/
public class MongoBigEntityDao implements BigEntityDao {
/**
* Builder object.
*/
public static class Builder {
/**
* Client for the MongoDB.
*/
private MongoClient mongoClient;
/**
* Database name.
*/
private String databaseName;
/**
* Mapper from entity type to the collection.
*/
private TypeCollectionMapper typeCollectionMapper;
/**
* Sets client for MongoDB.
*
* @param mongoClient client
* @return this instance
*/
public Builder setMongoClient(MongoClient mongoClient) {
this.mongoClient = mongoClient;
return this;
}
/**
* Sets database name.
*
* @param databaseName database name
* @return this instance
*/
public Builder setDatabaseName(String databaseName) {
this.databaseName = databaseName;
return this;
}
/**
* Sets mapper from entity type to the collection.
*
* @param typeCollectionMapper mapper from entity type to the collection
* @return this instance
*/
public Builder setTypeCollectionMapper(TypeCollectionMapper typeCollectionMapper) {
this.typeCollectionMapper = typeCollectionMapper;
return this;
}
/**
* Builds the result object.
*
* @return created object
*/
public MongoBigEntityDao build() {
return new MongoBigEntityDao(this);
}
}
/**
* Client for the MongoDB.
*/
private MongoClient mongoClient;
/**
* Database name.
*/
private String databaseName;
/**
* Mapper from entity type to the collection.
*/
private TypeCollectionMapper typeCollectionMapper;
/**
* Creates new instance.
*
* @param builder builder object
*/
public MongoBigEntityDao(Builder builder) {
mongoClient = builder.mongoClient;
databaseName = builder.databaseName;
typeCollectionMapper = builder.typeCollectionMapper;
guardInvariants();
}
/**
* Guards this object to be consistent. Throws exception if this is not the case.
*/
private void guardInvariants() {
ValidationUtils.guardNotNull(mongoClient, "mongoClient cannot be null");
ValidationUtils.guardNotEmpty(databaseName, "databaseName cannot be empty");
ValidationUtils.guardNotNull(typeCollectionMapper, "typeCollectionMapper cannot be null");
}
@Override
public void insertBigEntity(String type, BigEntity entity, InsertOptions options) {
MongoCollection collection = getCollection(type);
Map vals = DomainUtils.softCopyMap(entity.getFields());
vals.put("_id", entity.getCode());
collection.insertOne(new Document(vals));
}
@Override
public void insertBigEntities(String type, List entities, InsertOptions options) {
for (BigEntity ent : entities) {
insertBigEntity(type, ent, options);
}
}
@Override
public BigEntityIterator selectBigEntities(String type, Filter filter, Set fields, SelectOptions options) {
MongoCollection collection = getCollection(type);
BsonDocument projection = new BsonDocument();
for (String field : fields) {
projection.append(field, new BsonInt32(1));
}
BsonDocument sort = new BsonDocument();
for (Order order : filter.getOrders()) {
String fld = order.getColumn();
if (fld.equals("code")) {
fld = "_id";
}
if (order.getDirection().equals(Direction.ASCENDANT)) {
sort.append(fld, new BsonInt32(1));
}
else if (order.getDirection().equals(Direction.DESCENDANT)) {
sort.append(fld, new BsonInt32(-1));
}
else {
throw new RuntimeException("unknown order direction: " + order);
}
}
FindIterable mongoIterable = collection.find(convertCriteria(filter.getCriteria())).
projection(projection).
sort(sort);
if (filter.getFrom() > 0) {
mongoIterable.skip((int) filter.getFrom());
}
if (filter.getLimit() != null) {
mongoIterable.limit(filter.getLimit());
}
return new EntIterator(mongoIterable.iterator(), fields);
}
@Override
public long countBigEntities(String type, List> criteria, CountOptions options) {
MongoCollection collection = getCollection(type);
return collection.count(convertCriteria(criteria));
}
@Override
public void updateBigEntity(String type, String code, BigEntityUpdate update, UpdateOptions options) {
if (update.getUpdateFields().isEmpty() && update.getDropFields().isEmpty()) {
return;
}
MongoCollection collection = getCollection(type);
List> crit = Arrays.asList(Criterium.createEqual("code", code));
Document mdbupdate = new Document();
if (!update.getUpdateFields().isEmpty()) {
Document setUpdate = new Document();
for (String fld : update.getUpdateFields().keySet()) {
setUpdate.append(fld, update.getUpdateFields().get(fld));
}
mdbupdate.append("$set", setUpdate);
}
if (!update.getDropFields().isEmpty()) {
Document unsetUpdate = new Document();
for (String fld : update.getDropFields()) {
unsetUpdate.append(fld, 1);
}
mdbupdate.append("$unset", unsetUpdate);
}
collection.updateOne(convertCriteria(crit), mdbupdate);
}
@Override
public void deleteBigEntity(String type, String code, DeleteOptions options) {
MongoCollection collection = getCollection(type);
List> crit = Arrays.asList(Criterium.createEqual("code", code));
collection.deleteOne(convertCriteria(crit));
}
/**
* Converts criteria to BSON object.
*
* @param criteria criteria
* @return BSON criteria object
*/
private Bson convertCriteria(List> criteria) {
if (criteria.isEmpty()) {
return new BsonDocument();
}
List andCrits = new ArrayList();
for (Criterium crit : criteria) {
String fld = crit.getColumn();
if (fld.equals("code")) {
fld = "_id";
}
if (crit.getOperator().equals(Operator.EQUAL)) {
andCrits.add(Filters.eq(fld, crit.getValue()));
}
else if (crit.getOperator().equals(Operator.NOT_EQUAL)) {
andCrits.add(Filters.ne(fld, crit.getValue()));
}
else if (crit.getOperator().equals(Operator.IN)) {
andCrits.add(Filters.in(fld, (Iterable) crit.getValue()));
}
else if (crit.getOperator().equals(Operator.GREATER)) {
andCrits.add(Filters.gt(fld, crit.getValue()));
}
else if (crit.getOperator().equals(Operator.GREATER_OR_EQUAL)) {
andCrits.add(Filters.gte(fld, crit.getValue()));
}
else if (crit.getOperator().equals(Operator.LESS)) {
andCrits.add(Filters.lt(fld, crit.getValue()));
}
else if (crit.getOperator().equals(Operator.LESS_OR_EQUAL)) {
andCrits.add(Filters.lte(fld, crit.getValue()));
}
else if (crit.getOperator().equals(Operator.LIKE)) {
String val = (String) crit.getValue();
val = val.replaceAll("%", ".*");
andCrits.add(Filters.regex(fld, val));
}
else {
throw new RuntimeException("unsupported operator: " + crit);
}
}
return Filters.and(andCrits);
}
/**
* Returns collection for a given type.
*
* @param type type
* @return collection
*/
private MongoCollection getCollection(String type) {
String collectionName = typeCollectionMapper.getCollectionName(type);
MongoDatabase database = mongoClient.getDatabase(databaseName);
MongoCollection collection = database.getCollection(collectionName);
return collection;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
/**
* Implementation of iterator for entities.
*/
private static class EntIterator implements BigEntityIterator {
/**
* Cursor to records
*/
private MongoCursor cursor;
/**
* Fields to pull.
*/
private Set fields;
/**
* Lock object.
*/
private final Object lock = new Object();
/**
* Creates new instance.
*
* @param cursor cursor to records
* @param fields fields to pull
*/
public EntIterator(MongoCursor cursor, Set fields) {
this.cursor = cursor;
this.fields = DomainUtils.softCopySet(fields);
guardInvariants();
}
/**
* Guards this object to be consistent. Throws exception if this is not the case.
*/
private void guardInvariants() {
ValidationUtils.guardNotNull(cursor, "cursor cannot be null");
}
@Override
public boolean isNextAvailable() {
synchronized (lock) {
return cursor.hasNext();
}
}
@Override
public BigEntity getNext() throws NoSuchElementException {
synchronized (lock) {
Document document = cursor.tryNext();
if (document == null) {
throw new NoSuchElementException("iterator is consumed");
}
BigEntity.Builder res = new BigEntity.Builder();
res.setCode(document.getString("_id"));
for (String fld : fields) {
res.addField(fld, document.get(fld));
}
return res.build();
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy