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

win.doyto.query.service.AbstractService Maven / Gradle / Ivy

// Generated by delombok at Sat Aug 10 11:56:00 CST 2019
package win.doyto.query.service;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.support.NoOpCache;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.*;
import win.doyto.query.cache.CacheWrapper;
import win.doyto.query.core.*;
import win.doyto.query.entity.EntityAspect;
import win.doyto.query.entity.Persistable;
import win.doyto.query.entity.UserIdProvider;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.LinkedList;
import java.util.List;

/**
 * AbstractService
 *
 * @author f0rb on 2019-05-28
 */
public abstract class AbstractService, I extends Serializable, Q extends PageQuery> implements CommonCrudService {
    protected DataAccess dataAccess;
    protected final Class entityClass;
    protected final CacheWrapper entityCacheWrapper = CacheWrapper.createInstance();
    protected final CacheWrapper> queryCacheWrapper = CacheWrapper.createInstance();
    @Autowired(required = false)
    private UserIdProvider userIdProvider;
    @Autowired(required = false)
    private CacheManager cacheManager;
    @Autowired(required = false)
    protected List> entityAspects = new LinkedList<>();
    protected TransactionOperations transactionOperations = NoneTransactionOperations.instance;

    @SuppressWarnings("unchecked")
    public AbstractService() {
        entityClass = (Class) getActualTypeArguments()[0];
        dataAccess = new MemoryDataAccess<>(entityClass);
    }

    protected final Type[] getActualTypeArguments() {
        Type genericSuperclass = getClass();
        do {
            genericSuperclass = ((Class) genericSuperclass).getGenericSuperclass();
        } while (!(genericSuperclass instanceof ParameterizedType));
        return ((ParameterizedType) genericSuperclass).getActualTypeArguments();
    }

    @Autowired
    @SuppressWarnings("unchecked")
    public void setJdbcOperations(JdbcOperations jdbcOperations) {
        dataAccess = new JdbcDataAccess<>(jdbcOperations, entityClass, (Class) getActualTypeArguments()[1], getRowMapper());
    }

    protected RowMapper getRowMapper() {
        return new BeanPropertyRowMapper<>(entityClass);
    }

    @Autowired(required = false)
    public void setTransactionManager(PlatformTransactionManager transactionManager) {
        transactionOperations = new TransactionTemplate(transactionManager);
    }

    @SuppressWarnings("squid:S4973")
    @Value("${doyto.query.caches:}")
    public void setCacheList(List cacheList) {
        if (cacheManager != null) {
            String cacheName = getCacheName();
            if (cacheList.contains(cacheName) || cacheName != entityClass.getSimpleName().intern()) {
                entityCacheWrapper.setCache(cacheManager.getCache(cacheName));
                queryCacheWrapper.setCache(cacheManager.getCache(getQueryCacheName()));
            }
        }
    }

    protected abstract String resolveCacheKey(E e);

    protected String getCacheName() {
        return entityClass.getSimpleName().intern();
    }

    private String getQueryCacheName() {
        return getCacheName() + ":query";
    }

    protected void clearCache() {
        entityCacheWrapper.clear();
        queryCacheWrapper.clear();
    }

    protected void evictCache(String key) {
        entityCacheWrapper.evict(key);
        queryCacheWrapper.clear();
    }

    protected boolean caching() {
        return !(entityCacheWrapper.getCache() instanceof NoOpCache);
    }

    @Override
    public List query(Q query) {
        String key = null;
        if (caching() && !TransactionSynchronizationManager.isActualTransactionActive()) {
            key = ToStringBuilder.reflectionToString(query, NonNullToStringStyle.NO_CLASS_NAME_NON_NULL_STYLE);
        }
        return queryCacheWrapper.execute(key, () -> dataAccess.query(query));
    }

    public long count(Q query) {
        return dataAccess.count(query);
    }

    public List queryIds(Q query) {
        return dataAccess.queryIds(query);
    }

    public  List queryColumns(Q query, Class clazz, String... columns) {
        return dataAccess.queryColumns(query, clazz, columns);
    }

    public void create(E e) {
        if (userIdProvider != null) {
            userIdProvider.setupUserId(e);
        }
        if (!entityAspects.isEmpty()) {
            transactionOperations.execute(s -> {
                dataAccess.create(e);
                entityAspects.forEach(entityAspect -> entityAspect.afterCreate(e));
                return null;
            });
        } else {
            dataAccess.create(e);
        }
        evictCache(resolveCacheKey(e));
    }

    public int update(E e) {
        return doUpdate(e, () -> dataAccess.update(e));
    }

    public int patch(E e) {
        return doUpdate(e, () -> dataAccess.patch(e));
    }

    private int doUpdate(E e, Invocable invocable) {
        if (userIdProvider != null) {
            userIdProvider.setupUserId(e);
        }
        E origin;
        if (e == null || (origin = dataAccess.get(e)) == null) {
            return 0;
        }
        if (!entityAspects.isEmpty()) {
            transactionOperations.execute(s -> {
                invocable.invoke();
                E current = dataAccess.get(e);
                entityAspects.forEach(entityAspect -> entityAspect.afterUpdate(origin, current));
                return null;
            });
        } else {
            invocable.invoke();
        }
        evictCache(resolveCacheKey(e));
        return 1;
    }

    public int batchInsert(Iterable entities, String... columns) {
        if (userIdProvider != null) {
            for (E e : entities) {
                userIdProvider.setupUserId(e);
            }
        }
        int insert = dataAccess.batchInsert(entities, columns);
        clearCache();
        return insert;
    }

    public int patch(E e, Q q) {
        if (userIdProvider != null) {
            userIdProvider.setupUserId(e);
        }
        int patch = dataAccess.patch(e, q);
        clearCache();
        return patch;
    }

    public int delete(Q query) {
        int delete = dataAccess.delete(query);
        clearCache();
        return delete;
    }


    private static class NoneTransactionOperations implements TransactionOperations {
        private static final TransactionOperations instance = new NoneTransactionOperations();
        private static final TransactionStatus TRANSACTION_STATUS = new SimpleTransactionStatus();

        @Override
        public  T execute(TransactionCallback transactionCallback) {
            return transactionCallback.doInTransaction(TRANSACTION_STATUS);
        }
    }

    @java.lang.SuppressWarnings("all")
    @lombok.Generated
    public void setCacheManager(final CacheManager cacheManager) {
        this.cacheManager = cacheManager;
    }
}