001package org.avaje.ebean.ignite.config;
002
003import com.avaje.ebean.cache.ServerCacheType;
004import org.apache.ignite.cache.eviction.lru.LruEvictionPolicy;
005import org.apache.ignite.configuration.CacheConfiguration;
006import org.apache.ignite.configuration.NearCacheConfiguration;
007import org.jetbrains.annotations.Nullable;
008import org.slf4j.Logger;
009import org.slf4j.LoggerFactory;
010
011import java.util.List;
012
013/**
014 * Determines the cache configuration that should be applied to any given L2 cache.
015 */
016public class ConfigManager {
017
018  private static final Logger logger = LoggerFactory.getLogger(ConfigManager.class);
019
020  private final L2Configuration configuration;
021
022  private final L2CacheConfig baseQuery;
023  private final L2CacheConfig baseBean;
024  private final L2CacheConfig baseKey;
025  private final L2CacheConfig baseManyIds;
026
027  /**
028   * Create given the configuration.
029   */
030  public ConfigManager(L2Configuration configuration) {
031
032    this.configuration = configuration;
033
034    L2CacheConfig base = defaultConfig(configuration.getBase());
035    this.baseQuery = add(base, configuration.getBaseQuery());
036    this.baseBean = add(base, configuration.getBaseBean());
037    this.baseKey = add(base, configuration.getBaseKey());
038    this.baseManyIds = add(base, configuration.getBaseManyIds());
039  }
040
041  /**
042   * Add the configurations together apply over the top of base.
043   */
044  private L2CacheConfig add(L2CacheConfig base, L2CacheConfig apply) {
045    return AddL2CacheConfig.add(base, apply);
046  }
047
048  /**
049   * Return the config with an empty default if required.
050   */
051  private L2CacheConfig defaultConfig(L2CacheConfig base) {
052    return (base != null) ? base : new L2CacheConfig();
053  }
054
055  /**
056   * Return the config pair for main and near cache given the type and key.
057   */
058  public ConfigPair getConfig(ServerCacheType type, String key) {
059
060    L2CacheConfig config = getBase(type);
061
062    L2Apply apply = configuration.getApply();
063    if (apply != null) {
064      List<L2CacheMatch> match = apply.getMatch();
065      for (L2CacheMatch l2CacheMatch : match) {
066        if (isMatch(type, key, l2CacheMatch)) {
067          logger.debug("match for type[{}] key[{}] to config [{}]", type, key, l2CacheMatch);
068          config = add(config, l2CacheMatch.getConfig());
069        }
070      }
071    }
072
073    return createPair(type, config);
074  }
075
076  private ConfigPair createPair(ServerCacheType type, L2CacheConfig config) {
077
078    CacheConfiguration main = new CacheConfiguration();
079    AddL2CacheConfig.apply(main, config);
080
081    NearCacheConfiguration near = getNearCacheConfig(type, config);
082
083    return new ConfigPair(main, near);
084  }
085
086  @Nullable
087  @SuppressWarnings("unchecked")
088  private NearCacheConfiguration getNearCacheConfig(ServerCacheType type, L2CacheConfig config) {
089
090    if (type.equals(ServerCacheType.QUERY) || config.getNearSize() == null) {
091      return null;
092
093    } else {
094      NearCacheConfiguration near = new NearCacheConfiguration();
095      near.setNearEvictionPolicy(new LruEvictionPolicy(config.getNearSize()));
096      return  near;
097    }
098  }
099
100  private boolean isMatch(ServerCacheType type, String key, L2CacheMatch l2CacheMatch) {
101
102    switch (type) {
103      case QUERY:
104        return isMatch(l2CacheMatch.isTypeQuery(), key, l2CacheMatch);
105      case BEAN:
106        return isMatch(l2CacheMatch.isTypeBean(), key, l2CacheMatch);
107      case NATURAL_KEY:
108        return isMatch(l2CacheMatch.isTypeKey(), key, l2CacheMatch);
109      case COLLECTION_IDS:
110        return isMatch(l2CacheMatch.isTypeManyId(), key, l2CacheMatch);
111      default :
112        throw new IllegalStateException("Unknown type "+type);
113    }
114  }
115
116  private boolean isMatch(Boolean typeMatch, String key, L2CacheMatch l2CacheMatch) {
117    return isTrue(typeMatch) && isMatch(key, l2CacheMatch.getMatchClasses());
118  }
119
120  private boolean isMatch(String key, String matchClasses) {
121    String[] matches = matchClasses.split("[,;]");
122    for (int i = 0; i < matches.length; i++) {
123      String matcher = matches[i].trim();
124      if (!matcher.contains(".")) {
125        matcher = "." + matcher;
126        key = key.toLowerCase();
127      }
128      if (key.contains(matcher)) {
129        return true;
130      }
131    }
132    return false;
133  }
134
135  private boolean isTrue(Boolean typeBean) {
136    return Boolean.TRUE.equals(typeBean);
137  }
138
139  /**
140   * Return the base configuration based on the cache type.
141   */
142  private L2CacheConfig getBase(ServerCacheType type) {
143    switch (type) {
144      case QUERY:
145        return baseQuery;
146      case BEAN:
147        return baseBean;
148      case NATURAL_KEY:
149        return baseKey;
150      case COLLECTION_IDS:
151        return baseManyIds;
152      default:
153        throw new IllegalStateException("Invalid type " + type);
154    }
155
156  }
157}