org.hoteia.qalingo.core.aop.cache.CacheManagementAspect.java Source code

Java tutorial

Introduction

Here is the source code for org.hoteia.qalingo.core.aop.cache.CacheManagementAspect.java

Source

/**
 * Most of the code in the Qalingo project is copyrighted Hoteia and licensed
 * under the Apache License Version 2.0 (release version 0.8.0)
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p/>
 * Copyright (c) Hoteia, 2012-2014
 * http://www.hoteia.com - http://twitter.com/hoteia - contact@hoteia.com
 */
package org.hoteia.qalingo.core.aop.cache;

import java.lang.reflect.Method;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.ehcache.Cache;
import org.hoteia.qalingo.core.annotation.CacheEntityInformation;
import org.hoteia.qalingo.core.annotation.CacheMethodInformation;
import org.hoteia.qalingo.core.annotation.CacheType;
import org.hoteia.qalingo.core.domain.AbstractEntity;
import org.hoteia.qalingo.core.domain.impl.DomainEntity;
import org.hoteia.qalingo.core.fetchplan.FetchPlan;
import org.hoteia.qalingo.core.pojo.AbstractPojo;
import org.hoteia.qalingo.core.web.cache.util.CacheService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component(value = "cacheManagementAspect")
public class CacheManagementAspect {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private CacheService cacheService;

    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        Object returnObject = null;
        try {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Class classReturnType = signature.getReturnType();
            Object[] args = joinPoint.getArgs();
            String cacheType = null;
            String cacheName = null;
            Cache cache = null;
            String key = null;

            logger.debug("Start Cache AOP. Call from : '" + joinPoint.getSignature().toShortString() + "'");

            // DEFINE THE CACHE TYPE
            try {
                CacheMethodInformation cacheMethodInformation = signature.getMethod()
                        .getAnnotation(CacheMethodInformation.class);
                cacheType = cacheMethodInformation.cacheType();
                logger.debug("CacheMethodInformation from annotation : cacheType= '" + cacheType + "'");
                cacheName = cacheMethodInformation.cacheName();
                logger.debug("CacheEntityInformation from annotation : cacheName= '" + cacheName + "'");

            } catch (Exception e) {
                // TODO: handle exception
            }
            if (DomainEntity.class.isAssignableFrom(classReturnType)) {
                cacheType = CacheType.CACHE_ENTITY;
                if (joinPoint.getSignature().toShortString().contains("ByCode")) {
                    // FIRST ARG IS A STRING FOR THE GET METHOD : SO THIS A GET BY CODE
                    cacheType = CacheType.CACHE_LINK_CODE_ID;
                }
            } else if (AbstractPojo.class.isAssignableFrom(classReturnType)) {
                cacheType = CacheType.CACHE_POJO;

            }
            logger.debug("Cache Type : '" + cacheType + "'");

            // TARGETED FETCH PLAN
            FetchPlan askedFetchPlan = null;
            FetchPlan loadedFetchPlan = null;
            for (Object arg : args) {
                if (arg instanceof Object[]) {
                    Object[] objects = (Object[]) arg;
                    for (Object object : objects) {
                        if (object instanceof FetchPlan) {
                            FetchPlan fetchPlan = (FetchPlan) object;
                            if (fetchPlan != null && !fetchPlan.getFetchModes().isEmpty()) {
                                askedFetchPlan = fetchPlan;
                                break;
                            }
                        }
                    }
                }
            }

            if (StringUtils.isNotEmpty(cacheType)) {
                try {
                    CacheEntityInformation cacheEntityInformation = (CacheEntityInformation) classReturnType
                            .getAnnotation(CacheEntityInformation.class);
                    cacheName = cacheEntityInformation.cacheName();
                    // CHECK THE NAME OF THE CACHE
                    if (cacheType.equals(CacheType.CACHE_LINK_CODE_ID)) {
                        cacheName += "_link_code_id";
                    }
                    logger.debug("CacheEntityInformation from annotation : cacheName= '" + cacheName + "'");

                } catch (Exception e) {
                    // TODO: handle exception
                }

                if (StringUtils.isNotEmpty(cacheName)) {
                    // LOAD THE CACHE
                    if (cacheType.equals(CacheType.CACHE_ENTITY)) {
                        String id = null;
                        if (args != null && args.length > 0) {
                            if (args[0] instanceof Long) {
                                id = ((Long) args[0]).toString();
                            }
                        }
                        key = cacheService.buildEntityKey(signature.getReturnType(), id);
                        if (id == null) {
                            // OVERRIDE THE KEY BY THE METHOD
                            key = signature.toShortString();
                        }
                        cache = cacheService.getCache(cacheName, String.class, AbstractEntity.class);

                    } else if (cacheType.equals(CacheType.CACHE_LINK_CODE_ID)) {
                        String code = null;
                        if (args != null && args.length > 0) {
                            if (args[0] instanceof String) {
                                code = ((String) args[0]).toString();
                            }
                        }
                        key = cacheService.buildCodeIdKey(signature, code);
                        if (code == null) {
                            // OVERRIDE THE KEY BY THE METHOD
                            key = signature.toShortString();
                        }
                        cache = cacheService.getCache(cacheName, String.class, Long.class);

                    } else if (cacheType.equals(CacheType.CACHE_POJO)) {
                        key = cacheService.buildCommonKey(signature, args);
                        cache = cacheService.getCache(cacheName, String.class, AbstractPojo.class);

                    } else if (cacheType.equals(CacheType.CACHE_STRING)) {
                        key = cacheService.buildCommonKey(signature, args);
                        cache = cacheService.getCache(cacheName, String.class, String.class);
                    }

                    // TEST IF THE VALUE IS IN CACHE
                    if (cache != null) {
                        logger.debug("Searching object in cache with : key= '" + key + "'");
                        if (cache.containsKey(key)) {
                            logger.debug("Object exist in cache with : key= '" + key + "'");
                            Object element = cache.get(key);
                            if (element != null) {
                                // WE TEST IF THE FETCH PLAN ARE EQUALS
                                returnObject = element;

                                if (cacheType.equals(CacheType.CACHE_ENTITY)) {
                                    returnObject = checkFetchPlan(returnObject, askedFetchPlan, loadedFetchPlan);

                                } else if (cacheType.equals(CacheType.CACHE_LINK_CODE_ID)) {
                                    String cacheNameEntity = cacheName.replace("_link_code_id", "");
                                    Long id = (Long) returnObject;
                                    returnObject = null;
                                    Cache cacheEntity = cacheService.getCache(cacheNameEntity, String.class,
                                            AbstractEntity.class);
                                    String keyEntity = cacheService.buildEntityKey(signature.getReturnType(),
                                            id.toString());
                                    if (cacheEntity.containsKey(keyEntity)) {
                                        Object entity = cacheEntity.get(keyEntity);
                                        returnObject = entity;
                                        returnObject = checkFetchPlan(returnObject, askedFetchPlan,
                                                loadedFetchPlan);
                                    }
                                }
                            }
                        } else {
                            logger.debug("Object doesn't exist in cache with : key= '" + key + "'");
                        }
                    }
                }
            }

            // NOTHING IN CACHE - CALL THE TARGET METHOD
            if (returnObject == null) {
                if (loadedFetchPlan != null) {
                    args = ArrayUtils.add(args, loadedFetchPlan);
                    returnObject = joinPoint.proceed(args);
                } else {
                    returnObject = joinPoint.proceed();
                }

                if (returnObject != null && cache != null) {
                    // PUT IN CACHE
                    if (cacheType.equals(CacheType.CACHE_ENTITY)) {
                        logger.debug("Put in cache '" + cacheName + "'. key : '" + key + "'. value: '"
                                + returnObject + "'");
                        cache.put(key, returnObject);

                        // PUT THE CODE/ID
                        String cacheNameCodeId = cacheName + "_link_code_id";
                        Cache cacheCodeId = cacheService.getCache(cacheNameCodeId, String.class, Long.class);
                        Long id = (Long) handleClassMethodGetValue(joinPoint, returnObject, classReturnType,
                                "getId");
                        String code = (String) handleClassMethodGetValue(joinPoint, returnObject, classReturnType,
                                "getCode");
                        String newKey = key = cacheService.buildCodeIdKey(signature, code);
                        logger.debug("Put in cache '" + cacheNameCodeId + "'. key : '" + newKey + "'. value: '" + id
                                + "'");
                        cacheCodeId.put(newKey, id);

                    } else if (cacheType.equals(CacheType.CACHE_LINK_CODE_ID)) {
                        Long id = (Long) handleClassMethodGetValue(joinPoint, returnObject, classReturnType,
                                "getId");
                        logger.debug("Put in cache '" + cacheName + "'. key : '" + key + "'. value: '" + id + "'");
                        cache.put(key, id);

                        // PUT THE ENTITY
                        String cacheNameEntity = cacheName.replace("_link_code_id", "");
                        Cache cacheEntity = cacheService.getCache(cacheNameEntity, String.class,
                                AbstractEntity.class);
                        String newKey = cacheService.buildEntityKey(signature.getReturnType(), id.toString());
                        logger.debug("Put in cache '" + cacheName + "'. key : '" + newKey + "'. value: '"
                                + returnObject + "'");
                        cacheEntity.put(newKey, returnObject);

                    } else if (cacheType.equals(CacheType.CACHE_POJO)) {
                        logger.debug("Put in cache '" + cacheName + "'. key : '" + key + "'. value: '"
                                + returnObject + "'");
                        cache.put(key, returnObject);

                    } else if (cacheType.equals(CacheType.CACHE_STRING)) {
                        logger.debug("Put in cache '" + cacheName + "'. key : '" + key + "'. value: '"
                                + returnObject + "'");
                        cache.put(key, returnObject);
                    }
                }
            }

        } catch (Exception e) {
            logger.error("Failed to load datas with Cache AOP! Call from : '"
                    + joinPoint.getSignature().toShortString() + "'", e);
        }

        logger.debug("End Cache AOP. Call from : '" + joinPoint.getSignature().toShortString() + "'");
        logger.debug("---------------------------------------------------------------------------------");

        return returnObject;
    }

    protected Object handleClassMethodGetValue(ProceedingJoinPoint joinPoint, Object returnObject,
            Class classReturnType, String methode) {
        try {
            Method[] methods = classReturnType.getMethods();
            for (Method methodIt : methods) {
                if (methodIt.getName().equals(methode)) {
                    return methodIt.invoke(returnObject);
                }
            }
        } catch (Exception e) {
            logger.debug("Exception code. Call from : '" + joinPoint.getSignature().toShortString() + "'", e);
        }
        return null;
    }

    protected Object checkFetchPlan(Object returnObject, FetchPlan askedFetchPlan, FetchPlan loadedFetchPlan) {
        if (returnObject instanceof DomainEntity) {
            AbstractEntity entity = (AbstractEntity) returnObject;
            if (entity.getFetchPlan() != null) {
                loadedFetchPlan = entity.getFetchPlan();
            }
        }

        if (askedFetchPlan != null) {
            if (loadedFetchPlan != null && !loadedFetchPlan.containAllTargetFetchPlans(askedFetchPlan)) {
                // ENTITY IS LOAD WITHOUT FETCHPLAN - WE RESET THE returnObject TO TRIGGER THE RELOAD WITH THE FETCHPLAN
                // WE WILL ADD LOADED FETCH PLAN AND ASKED FETCH PLAN TO THE INVOCATED METHOD
                returnObject = null;
            }
        }
        return returnObject;
    }

}