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

com.enterprisemath.dao.big.MyBatisBigEntityDao 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.Filter;
import com.enterprisemath.utils.DomainUtils;
import com.enterprisemath.utils.ValidationUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
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.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

/**
 * Implementation of big entity dao through MyBatis.
 *
 * @author radek.hecl
 */
public class MyBatisBigEntityDao implements BigEntityDao {

    /**
     * Builder object.
     */
    public static class Builder {

        /**
         * Factory for sql sessions.
         */
        private SqlSessionFactory sqlSessionFactory;

        /**
         * Mapper from entity type to the collection.
         */
        private TypeCollectionMapper typeCollectionMapper;

        /**
         * Sets factory for sql sessions.
         *
         * @param sqlSessionFactory factory for sql sessions
         * @return this instance
         */
        public Builder setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
            this.sqlSessionFactory = sqlSessionFactory;
            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 MyBatisBigEntityDao build() {
            return new MyBatisBigEntityDao(this);
        }
    }

    /**
     * Factory for sql sessions.
     */
    private SqlSessionFactory sqlSessionFactory;

    /**
     * Mapper from entity type to the collection.
     */
    private TypeCollectionMapper typeCollectionMapper;

    /**
     * Creates new instance.
     *
     * @param builder builder object
     */
    public MyBatisBigEntityDao(Builder builder) {
        sqlSessionFactory = builder.sqlSessionFactory;
        typeCollectionMapper = builder.typeCollectionMapper;
        guardInvariants();
    }

    /**
     * Guards this object to be consistent. Throws exception if this is not the case.
     */
    private void guardInvariants() {
        ValidationUtils.guardNotNull(sqlSessionFactory, "sqlSessionFactory cannot be null");
        ValidationUtils.guardNotNull(typeCollectionMapper, "typeCollectionMapper cannot be null");
    }

    @Override
    public void insertBigEntity(String type, BigEntity entity, InsertOptions options) {
        String table = typeCollectionMapper.getCollectionName(type);
        List fields = new ArrayList();
        List values = new ArrayList();
        fields.add("code");
        values.add(entity.getCode());
        for (String fld : entity.getFields().keySet()) {
            fields.add(fld);
            values.add(entity.getFields().get(fld));
        }
        SqlSession session = sqlSessionFactory.openSession();
        try {
            MyBatisBigEntityMapper mapper = session.getMapper(MyBatisBigEntityMapper.class);
            mapper.insertBigEntity(table, fields, values);
        } finally {
            session.close();
        }
    }

    @Override
    public void insertBigEntities(String type, List entities, InsertOptions options) {
        if (entities.isEmpty()) {
            return;
        }
        String table = typeCollectionMapper.getCollectionName(type);
        List fields = new ArrayList();
        fields.add("code");
        for (String fld : entities.get(0).getFields().keySet()) {
            fields.add(fld);
        }
        List pureFields = fields.subList(1, fields.size());
        Set pureFieldsSet = DomainUtils.softCopySet(pureFields);

        List> rawData = new ArrayList>();
        SqlSession session = sqlSessionFactory.openSession();
        try {
            MyBatisBigEntityMapper mapper = session.getMapper(MyBatisBigEntityMapper.class);
            for (BigEntity ent : entities) {
                ValidationUtils.guardEquals(pureFieldsSet, ent.getFields().keySet(), "all entities must have same fields");
                List rawRow = new ArrayList();
                rawRow.add(ent.getCode());
                for (String field : pureFields) {
                    rawRow.add(ent.getFields().get(field));
                }
                rawData.add(rawRow);
                if (rawData.size() >= 100) {
                    mapper.insertBigEntities(table, fields, rawData);
                    rawData.clear();
                }
            }
            if (!rawData.isEmpty()) {
                mapper.insertBigEntities(table, fields, rawData);
                rawData.clear();
            }
        } finally {
            session.close();
        }
    }

    @Override
    public BigEntityIterator selectBigEntities(String type, Filter filter, Set fields, SelectOptions options) {
        String table = typeCollectionMapper.getCollectionName(type);
        SqlSession session = sqlSessionFactory.openSession();
        try {
            MyBatisBigEntityMapper mapper = session.getMapper(MyBatisBigEntityMapper.class);
            // fetch data
            Set queryFields = DomainUtils.softCopySet(fields);
            queryFields.add("code");
            List> recs = mapper.selectBigEntities(table, filter, queryFields);
            if (recs == null || recs.isEmpty()) {
                return new EntIterator(Collections.emptyList());
            }
            // map data
            List res = new ArrayList();
            for (Map rec : recs) {
                rec = convertKeysToLowerKeys(rec);
                BigEntity.Builder builder = new BigEntity.Builder().
                        setCode((String) rec.get("code"));
                for (String field : fields) {
                    Object obj = rec.get(field.toLowerCase());
                    if (obj != null && obj instanceof java.sql.Timestamp) {
                        obj = DomainUtils.copyDate((Date) obj);
                    }
                    builder.addField(field, obj);
                }
                res.add(builder.build());
            }
            return new EntIterator(res);
        } finally {
            session.close();
        }
    }

    @Override
    public long countBigEntities(String type, List> criteria, CountOptions options) {
        String table = typeCollectionMapper.getCollectionName(type);
        SqlSession session = sqlSessionFactory.openSession();
        try {
            MyBatisBigEntityMapper mapper = session.getMapper(MyBatisBigEntityMapper.class);
            return mapper.countBigEntities(table, criteria);
        } finally {
            session.close();
        }
    }

    @Override
    public void updateBigEntity(String type, String code, BigEntityUpdate update, UpdateOptions options) {
        String table = typeCollectionMapper.getCollectionName(type);
        SqlSession session = sqlSessionFactory.openSession();
        try {
            MyBatisBigEntityMapper mapper = session.getMapper(MyBatisBigEntityMapper.class);
            for (String key : update.getUpdateFields().keySet()) {
                mapper.updateBigEntityField(table, code, key, update.getUpdateFields().get(key));
            }
            for (String key : update.getDropFields()) {
                mapper.updateBigEntityField(table, code, key, null);
            }
        } finally {
            session.close();
        }
    }

    @Override
    public void deleteBigEntity(String type, String code, DeleteOptions options) {
        String table = typeCollectionMapper.getCollectionName(type);
        SqlSession session = sqlSessionFactory.openSession();
        try {
            MyBatisBigEntityMapper mapper = session.getMapper(MyBatisBigEntityMapper.class);
            mapper.deleteBigEntity(table, code);
        } finally {
            session.close();
        }
    }

    /**
     * Converts keys in the one map to the lower case.
     *
     * @param source source map
     * @return map with lower case keys
     */
    private Map convertKeysToLowerKeys(Map source) {
        Map res = new HashMap(source.size());
        for (String key : source.keySet()) {
            res.put(key.toLowerCase(), source.get(key));
        }
        return res;
    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this);
    }

    /**
     * Implementation of iterator for entities.
     */
    private static class EntIterator implements BigEntityIterator {

        /**
         * Entities.
         */
        private List entities;

        /**
         * Index.
         */
        private int index = 0;

        /**
         * Lock object.
         */
        private final Object lock = new Object();

        /**
         * Creates new instance.
         *
         * @param entities list of entities
         */
        public EntIterator(List entities) {
            this.entities = DomainUtils.softCopyList(entities);
            guardInvariants();
        }

        /**
         * Guards this object to be consistent. Throws exception if this is not the case.
         */
        private void guardInvariants() {
            ValidationUtils.guardNotNullCollection(entities, "entities cannot have null element");
        }

        @Override
        public boolean isNextAvailable() {
            synchronized (lock) {
                return index < entities.size();
            }
        }

        @Override
        public BigEntity getNext() throws NoSuchElementException {
            synchronized (lock) {
                if (index >= entities.size()) {
                    throw new NoSuchElementException("iterator is consumed");
                }
                BigEntity res = entities.get(index);
                index = index + 1;
                return res;
            }
        }

    }

}