Package com.skyline.common.cache

Source Code of com.skyline.common.cache.CacheMethodDefinition

package com.skyline.common.cache;

import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.springframework.util.StringUtils;

import com.skyline.common.bean.Page;
import com.skyline.common.cache.annotation.Cache;
import com.skyline.common.cache.annotation.CacheCategoryType;
import com.skyline.common.cache.annotation.CacheDelete;
import com.skyline.common.cache.annotation.Fk;
import com.skyline.common.cache.annotation.GenericTable;
import com.skyline.common.cache.annotation.Param;

public class CacheMethodDefinition {
  private final Method method;
  private final Object target;

  private String keyPattern;
  private CacheCategoryType categoryType;
  private long expire;
  private boolean isPagination;

  private final Map<Class<? extends Annotation>, Annotation[]> parameterAnnotations = new HashMap<Class<? extends Annotation>, Annotation[]>(
      8, 1.0f);
  private int parameterCount;

  private boolean isCacheDelete;
  private boolean isCachable;
  private boolean isReturnCollection;
  private boolean isReturnCachable;
  private boolean isGenericCache;

  private int pageParameterIndex = -1;
  private int fkAnnotationIndex = -1;
  private int genericTableIndex = -1;

  public CacheMethodDefinition(Object target, Method method) {
    this.method = method;
    this.target = target;

    Annotation[] annotations = method.getAnnotations();
    parseMethodAnnotation(annotations);
    if (!isCachable && !isCacheDelete) { // 如果非Cache需要的对象则不再做解析
      return;
    }

    Annotation[][] parameterAnnotations = method.getParameterAnnotations();
    parseParameterAnnotations(parameterAnnotations);

    Class<? extends Object> returnType = method.getReturnType();
    isReturnCollection = isTypeCollection(returnType);
    isReturnCachable = isTypeCachable(returnType);

    Class<?>[] parameterTypes = method.getParameterTypes();
    getPageIndex(parameterTypes);

    judgeCacheParams();

  }

  private void parseMethodAnnotation(Annotation[] annotations) {
    for (Annotation annotation : annotations) {
      Class<? extends Annotation> annotationType = annotation.annotationType();
      if (annotationType.equals(Cache.class)) {
        Cache cache = (Cache) annotation;
        isCachable = true;
        keyPattern = cache.keyPattern();
        expire = cache.expire();
        isPagination = cache.pagination();
        categoryType = cache.type();
        isGenericCache = isCategoryTypeGeneric(categoryType);
      }
      if (annotationType.equals(CacheDelete.class)) { // 如categoryType等可能重复的数据以删除为准
        isCacheDelete = true;
        CacheDelete cacheDelete = (CacheDelete) annotation;
        categoryType = cacheDelete.type();
        expire = cacheDelete.expire();
        isGenericCache = isCategoryTypeGeneric(categoryType);
      }
    }
  }

  private void parseParameterAnnotations(Annotation[][] annotations) {
    parameterCount = annotations.length;
    for (int index = 0; index < parameterCount; index++) {
      for (Annotation annotation : annotations[index]) {
        Class<? extends Annotation> annotationType = annotation.annotationType();
        Annotation[] annotationArray = parameterAnnotations.get(annotationType);
        if (annotationArray == null) {
          annotationArray = (Annotation[]) Array.newInstance(annotationType,
              parameterCount);
          parameterAnnotations.put(annotationType, annotationArray);
        }
        annotationArray[index] = annotation;
        if (annotationType.equals(Fk.class)) {
          fkAnnotationIndex = index;
        }
        if (annotationType.equals(GenericTable.class)) {
          genericTableIndex = index;
        }
      }
    }
  }

  private void judgeCacheParams() {
    if (isPagination && pageParameterIndex == -1) { // 如果解析结果参数中没有Page类型,则不支持分页
      isPagination = false;
    }
    if (isCacheDelete && fkAnnotationIndex == -1) { // 如果参数中没有@Fk注解,则不支持Cache更新
      isCacheDelete = false;
    }
    if (isGenericCache && genericTableIndex == -1) { // 如果为同一处理的缓存但却没有相应的@GenericTable注解,则不支持同一处理,且不缓存
      isGenericCache = false;
      isCachable = false;
    }
    if ((isCachable && isReturnCollection && fkAnnotationIndex == -1) // 如果返回为集合但是参数中没有@Fk注解,则不支持Cache
        || (isCachable && !isReturnCollection && !isReturnCachable)) { // 如果返回不为集合但是却没有实现Cachable接口,则不支持Cache
      isCachable = false;
    }
    if (isCachable && isCacheDelete) { // 不能同时支持两个,已删除为准
      isCachable = false;
    }
  }

  private void getPageIndex(Class<?>[] parameterTypes) {
    int length = parameterTypes.length;
    for (int index = 0; index < length; index++) {
      Class<?> parameterType = parameterTypes[index];
      if (parameterType.equals(Page.class)) {
        pageParameterIndex = index;
      }
    }
  }

  private boolean isTypeCollection(Class<? extends Object> type) {
    return (type != null && (type.isArray() || Collection.class.isAssignableFrom(type)));
  }

  private boolean isTypeCachable(Class<? extends Object> type) {
    return (type != null && Cachable.class.isAssignableFrom(type));
  }

  private boolean isCategoryTypeGeneric(CacheCategoryType type) {
    switch (type) {
    case COMMENT:
      return true;
    default:
      return false;
    }
  }

  private boolean isNeedCacheOpration() {
    return (isCachable || isCacheDelete);
  }

  public String buildCacheKey(Object[] arguments) {
    if (!isCachable) {
      return "";
    }
    String key = keyPattern;
    Param[] paramAnnotations = (Param[]) parameterAnnotations.get(Param.class);
    for (int index = 0; index < parameterCount; index++) {
      Param param = paramAnnotations[index];
      if (param == null) {
        continue;
      }
      String value = param.value();
      String replaceToken = new StringBuilder(":").append(value).toString();
      key = key.replace(replaceToken, arguments[index].toString());
    }
    StringBuilder actualKey = new StringBuilder();
    if (isGenericCache) {
      actualKey.append(arguments[genericTableIndex]).append(key);
    } else {
      actualKey.append(key);
    }
    if (isPagination) {
      Page page = (Page) arguments[pageParameterIndex];
      if (page == null) {// 由于每个分页需要一个key,支持分页但是没有传分页对象,则表示复用了分页,此时不分页,加上-nop以区分
        actualKey.append("-nop");
      } else {
        actualKey.append("-p").append(page.getCurpage());
      }
    }
    return actualKey.toString();
  }

  public String buildVersionKey(Object[] arguments, Cachable cachedObject) {
    if (!isNeedCacheOpration()) {
      return "";
    }
    StringBuilder builder = null;
    if (isGenericCache) {
      builder = new StringBuilder(arguments[genericTableIndex].toString());
    } else {
      builder = new StringBuilder(categoryType.toString());
    }

    String fk = (fkAnnotationIndex == -1) ? cachedObject.getFkId()
        : arguments[fkAnnotationIndex].toString();
    builder.append('-').append(fk).append("-v");
    return builder.toString();
  }

  public String buildCachePageKey(String key, Object[] arguments) {
    if (!isCachable) {
      return "";
    }
    Page page = (Page) arguments[pageParameterIndex];
    if (page == null) {
      return "";
    }
    if (!StringUtils.hasLength(key)) {
      key = buildCacheKey(arguments);
    }
    StringBuilder builder = new StringBuilder("page-");
    builder.append(key);
    return builder.toString();
  }

  public Method getMethod() {
    return method;
  }

  public Object getTarget() {
    return target;
  }

  public boolean isCacheDelete() {
    return isCacheDelete;
  }

  public boolean isCachable() {
    return isCachable;
  }

  public String getKeyPattern() {
    return keyPattern;
  }

  public long getExpire() {
    return expire;
  }

  public boolean isPagination() {
    return isPagination;
  }

  public Map<Class<? extends Annotation>, Annotation[]> getParameterAnnotations() {
    return parameterAnnotations;
  }

  public int getParameterCount() {
    return parameterCount;
  }

  public boolean isReturnCollection() {
    return isReturnCollection;
  }

  public int getPageParameterIndex() {
    return pageParameterIndex;
  }

  public int getFkAnnotationIndex() {
    return fkAnnotationIndex;
  }

  public CacheCategoryType getCategoryType() {
    return categoryType;
  }

  public int getGenericTableIndex() {
    return genericTableIndex;
  }
}
TOP

Related Classes of com.skyline.common.cache.CacheMethodDefinition

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.