All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.enterprisemath.dao.big.MongoBigEntityDao Maven / Gradle / Ivy

There is a newer version: 4.3.2
Show newest version
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