com.sastix.cms.server.services.cache.hazelcast.HazelcastCacheService.java Source code

Java tutorial

Introduction

Here is the source code for com.sastix.cms.server.services.cache.hazelcast.HazelcastCacheService.java

Source

/*
 * Copyright(c) 2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.sastix.cms.server.services.cache.hazelcast;

import com.hazelcast.core.IMap;
import com.hazelcast.core.IdGenerator;
import com.sastix.cms.common.Constants;
import com.sastix.cms.common.cache.CacheDTO;
import com.sastix.cms.common.cache.QueryCacheDTO;
import com.sastix.cms.common.cache.RemoveCacheDTO;
import com.sastix.cms.common.cache.exceptions.CacheValidationException;
import com.sastix.cms.common.cache.exceptions.DataNotFound;
import com.sastix.cms.server.services.cache.CacheFileUtilsService;
import com.sastix.cms.server.services.cache.CacheService;
import com.sastix.cms.server.services.cache.manager.DistributedCacheManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentMap;
import java.util.zip.CRC32;

@Profile("production")
@Service
public class HazelcastCacheService implements CacheService, BeanFactoryAware {
    /**
     * Static LOG.
     */
    private static final Logger LOG = LoggerFactory.getLogger(HazelcastCacheService.class);

    private static final String DEFAULT_HAZELCAST_MANAGER = "hazelcastDistributedCacheManager";

    private ConcurrentMap<String, CacheDTO> cache;
    DistributedCacheManager cm;

    @Value("${cms.cache.manager}")
    private String cacheManagerBean;

    private DistributedCacheManager cacheManager;

    @Autowired
    CacheFileUtilsService cacheFileUtilsService;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        try {
            this.cache = (ConcurrentMap<String, CacheDTO>) beanFactory.getBean(Constants.DEFAULT_CACHE_NAME);
            this.cacheManager = (DistributedCacheManager) beanFactory.getBean(cacheManagerBean);
        } catch (NoSuchBeanDefinitionException noSuchBeanDefinitionException) {
            /* Creating cache on the fly.
              Pay attention that 'default' map config key is going to be used in this case. */
            this.cacheManager = (DistributedCacheManager) beanFactory.getBean(DEFAULT_HAZELCAST_MANAGER);
            this.cm = cacheManager;
            this.cache = cacheManager.getCache(Constants.DEFAULT_CACHE_NAME);
        }
    }

    @Override
    public void cacheResource(CacheDTO cacheDTO) throws DataNotFound, CacheValidationException, IOException {
        LOG.info("HazelcastCacheService->cacheResource");
        nullValidationChecker(cacheDTO, CacheDTO.class);
        String cacheKey = cacheDTO.getCacheKey();
        String cacheRegion = cacheDTO.getCacheRegion();
        byte[] blob;
        String blobURI = cacheDTO.getCacheBlobURI();

        if (!StringUtils.isEmpty(blobURI) && !StringUtils.isEmpty(cacheDTO.getCacheBlobBinary())) {
            throw new CacheValidationException(
                    "Client should NOT be able to send both blob AND URI. Only one of them");
        }

        if (blobURI != null) {
            blob = cacheFileUtilsService.downloadResource(new URL(blobURI));
            cacheDTO.setCacheBlobBinary(blob);
        }

        if (cacheDTO.getCacheKey() == null) {
            throw new CacheValidationException("You cannot cache a resource with a null key");
        }

        // Put value into cache.
        if (!StringUtils.isEmpty(cacheRegion)) {
            cm.getCache(cacheRegion).put(cacheKey, cacheDTO);
        } else {
            this.cache.put(cacheKey, cacheDTO);
        }
    }

    @Override
    public CacheDTO getCachedResource(QueryCacheDTO queryCacheDTO) throws DataNotFound, CacheValidationException {
        LOG.info("HazelcastCacheService->getCachedResource ({})",
                queryCacheDTO != null ? queryCacheDTO.toString() : "null");
        nullValidationChecker(queryCacheDTO, QueryCacheDTO.class);
        String cacheKey = queryCacheDTO.getCacheKey();

        if (cacheKey == null) {
            throw new CacheValidationException("You cannot get a cache a resource with a null key");
        }

        String cacheRegion = queryCacheDTO.getCacheRegion();
        CacheDTO cacheDTO;
        if (!StringUtils.isEmpty(cacheRegion)) { // GET from cache region
            ConcurrentMap<String, CacheDTO> cMap = cm.getCache(cacheRegion);
            cacheDTO = cMap.get(cacheKey);
        } else {// GET from default cache
            cacheDTO = this.cache.get(cacheKey);
        }

        boolean hasExpired = cacheFileUtilsService.isExpiredCachedResource(cacheDTO);

        if (hasExpired) {
            // Delete from cache silently and return null
            RemoveCacheDTO removeCacheDTO = new RemoveCacheDTO();
            removeCacheDTO.setCacheKey(cacheKey);
            removeCacheDTO.setCacheRegion(cacheRegion);
            removeCachedResource(removeCacheDTO);
            cacheDTO = null;
        }

        if (cacheDTO == null) {
            throw new DataNotFound("A cached resource could not be found with the given key: " + cacheKey);
        }
        return cacheDTO;
    }

    @Override
    public void removeCachedResource(RemoveCacheDTO removeCacheDTO) throws DataNotFound, CacheValidationException {
        LOG.info("HazelcastCacheService->removeCachedResource");
        nullValidationChecker(removeCacheDTO, RemoveCacheDTO.class);
        String cacheKey = removeCacheDTO.getCacheKey();
        String cacheRegion = removeCacheDTO.getCacheRegion();

        if (cacheKey == null) {
            throw new CacheValidationException("You cannot remove a cached a resource with a null cache key");
        }

        if (!StringUtils.isEmpty(cacheRegion)) {
            ConcurrentMap<String, String> cMap = cm.getCache(cacheRegion);
            if (cMap.containsKey(cacheKey)) {
                cMap.remove(cacheKey);
            } else {
                throw new DataNotFound(
                        "Nothing to remove. There is no cached resource with the given key: " + cacheKey);
            }
        } else {
            if (this.cache.containsKey(cacheKey)) {
                this.cache.remove(cacheKey);
            } else {
                throw new DataNotFound(
                        "Nothing to remove. There is no cached resource with the given key: " + cacheKey);
            }
        }
    }

    @Override
    public void clearCache(RemoveCacheDTO removeCacheDTO) throws DataNotFound, CacheValidationException {
        LOG.info("HazelcastCacheService->CLEAR_CACHE_REGION");
        nullValidationChecker(removeCacheDTO, RemoveCacheDTO.class);
        String cacheRegion = removeCacheDTO != null ? removeCacheDTO.getCacheRegion() : null;

        if (!StringUtils.isEmpty(cacheRegion)) {//clear specific region
            ConcurrentMap<String, IMap> regionCacheMap = (ConcurrentMap<String, IMap>) cm.getCaches()
                    .get(cacheRegion);
            if (regionCacheMap == null) {
                throw new DataNotFound("The supplied region was not available  did not exist");
            } else {
                ConcurrentMap<String, CacheDTO> cMap = cm.getCache(cacheRegion);
                cMap.clear();
            }
        } else {
            throw new CacheValidationException(
                    "A cacheRegion was not provided. If you want to clear all caches use the clearCache() without passing any object.");
        }
    }

    @Override
    public void clearCache() {
        LOG.info("HazelcastCacheService->CLEAR_ALL_CACHE_REGIONS_AND_MAIN_CACHE");
        ConcurrentMap<String, IMap> caches = cm.getCaches();
        for (Map.Entry<String, IMap> entry : caches.entrySet()) {
            entry.getValue().clear();
        }
        this.cache.clear();
        cm.clearAllCaches();
    }

    @Override
    public void clearCacheExcept(List<String> cacheRegions) {
        LOG.info("HazelcastCacheService->CLEAR_ALL_CACHE_REGIONS_AND_MAIN_CACHE Except for specific values");
        ConcurrentMap<String, IMap> caches = cm.getCaches();
        for (Map.Entry<String, IMap> entry : caches.entrySet()) {
            String region = entry.getValue().getName();
            boolean exists = cacheRegions.stream().filter(s -> region.contains(s)).count() > 0;
            if (!exists) {
                entry.getValue().clear();
            }
        }
        this.cache.clear();
        cm.clearAllCachesExcept(cacheRegions);
    }

    @Override
    public String getUID(String region) {
        CRC32 CRC_32 = new CRC32();
        LOG.info("HazelcastCacheService->GET_UID");
        IdGenerator idGenerator = cm.getIdGenerator(region);
        final String uid = String.valueOf(idGenerator.newId()); //assures uniqueness during the life cycle of the cluster
        final String uuid = UUID.randomUUID().toString();
        String ret = new StringBuilder(uuid).append(region).append(uid).toString();
        CRC_32.reset();
        CRC_32.update(ret.getBytes());
        return Long.toHexString(CRC_32.getValue());
    }

    private void nullValidationChecker(Object obj, Class aClass) {
        if (obj == null) {
            throw new CacheValidationException(aClass + " object cannot be null!");
        }
    }
}