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

com.eurodyn.qlack2.fuse.caching.memcached.CacheServiceImpl Maven / Gradle / Ivy

/*
* Copyright 2014 EUROPEAN DYNAMICS SA 
*
* Licensed under the EUPL, Version 1.1 only (the "License").
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
* https://joinup.ec.europa.eu/software/page/eupl/licence-eupl
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the Licence is distributed on an "AS IS" basis,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Licence for the specific language governing permissions and
* limitations under the Licence.
*/
package com.eurodyn.qlack2.fuse.caching.memcached;

import java.io.IOException;
import java.text.MessageFormat;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.lang3.StringUtils;

import com.eurodyn.qlack2.fuse.caching.api.CacheService;
import com.google.common.base.Predicates;
import com.google.common.collect.Sets;

import net.spy.memcached.AddrUtil;
import net.spy.memcached.BinaryConnectionFactory;
import net.spy.memcached.MemcachedClient;
import net.spy.memcached.OperationTimeoutException;

public class CacheServiceImpl implements CacheService {
	public static final Logger LOGGER = Logger.getLogger(CacheServiceImpl.class.getName());
	private MemcachedClient cache;
	private int directPort;
	private String directIp;
	private String localIp;
	// Set to '0' for no expiration (however, note that your key can still be
	// evicted from the cache).
	private long defaultExpirationAfterMsec;
	private Boolean active;

	// As Memcached does not support enlisting of its keys, this is a workaround
	// to allow deleting keys by a regular expression. Note that for very large
	// caches this may not be the most effective usage pattern, however if you
	// *need* to use Memcached this is your only option.
	Set keys;

	public CacheServiceImpl() {
		super();
	}

	public CacheServiceImpl(int directPort, String directIp, String localIp, long defaultExpirationAfterMsec,
			Boolean active) {
		super();
		this.directPort = directPort;
		this.directIp = directIp;
		this.localIp = localIp;
		this.defaultExpirationAfterMsec = defaultExpirationAfterMsec;
		this.active = active;
		this.init();
	}

	public void setLocalIp(String localIp) {
		this.localIp = localIp;
	}

	public void setCache(MemcachedClient cache) {
		this.cache = cache;
	}

	public void setDirectPort(int directPort) {
		this.directPort = directPort;
	}

	public String getDirectIp() {
		return directIp;
	}

	public void setDirectIp(String directIp) {
		this.directIp = directIp;
	}

	public void setDefaultExpirationAfterMsec(long defaultExpirationAfterMsec) {
		this.defaultExpirationAfterMsec = defaultExpirationAfterMsec;
	}

	public MemcachedClient getCache() {
		return cache;
	}

	public int getDirectPort() {
		return directPort;
	}

	public String getLocalIp() {
		return localIp;
	}

	/**
	 * @return the active
	 */
	public Boolean getActive() {
		return active;
	}

	/**
	 * @param active
	 *            the active to set
	 */
	public void setActive(Boolean active) {
		this.active = active;
	}

	public void init() {
		try {
			if (active) {
				cache = new MemcachedClient(new BinaryConnectionFactory(), AddrUtil
						.getAddresses((StringUtils.isNotBlank(directIp) ? directIp : "localhost") + ":" + directPort));
				LOGGER.fine(MessageFormat.format("Using cache server {0}:{1}.", directIp, String.valueOf(directPort)));
				keys = Sets.newConcurrentHashSet();
			} else {
				LOGGER.fine("Cache deactiveted.");
			}

		} catch (IOException e) {
			LOGGER.log(Level.SEVERE, "Cache client could not be initialised.", e);
		}
	}

	public void destroy() {
		if (cache != null) {
			cache.shutdown();
			cache = null;
			keys.clear();
			keys = null;
		}
	}

	@Override
	public void set(String key, String value) {
		set(key, value, defaultExpirationAfterMsec);
	}

	@Override
	public void set(String key, String value, long expiresAfterMsec) {
		// Memcache expresses EPOCH in seconds, therefore we need
		// to convert the msec passed EPOCH.
		try {
			int expiresAtEpochSec = expiresAfterMsec != 0
					? (int) ((System.currentTimeMillis() + expiresAfterMsec) / 1000l) : 0;
			cache.set(key, expiresAtEpochSec, value);
			LOGGER.log(Level.FINEST, "Added to memcached key {0}, with " + "value {1}.",
					new String[] { key, value.toString() });
			keys.add(key);
		} catch (OperationTimeoutException | CancellationException e) {
			// In case something went wrong we simply discard the message,
			// since a cache may not necessarily be available.
			LOGGER.log(Level.FINEST, "Could not add the key to the cache.", e);
		}
	}

	@Override
	public void deleteByKeyName(String key) {
		try {
			cache.delete(key);
			keys.remove(key);
			LOGGER.log(Level.FINEST, "Deleted from memcached key {0}.", key);
		} catch (OperationTimeoutException | CancellationException e) {
			// In case something went wrong we simply discard the message,
			// since a cache may not necessarily be available.
			LOGGER.log(Level.FINEST, "Could not delete the key from the cache.", e);
		}
	}

	@Override
	public String get(String key) {
		String retVal = null;
		try {
			if (cache != null) {
				retVal = (String) cache.get(key);
			}
		} catch (OperationTimeoutException | CancellationException e) {
			// In case something went wrong we simply discard the message,
			// since a cache may not necessarily be available.
			LOGGER.log(Level.FINEST, "Could not get the key to the cache.", e);
		}

		return retVal;
	}

	@Override
	public void deleteByKeyPattern(String pattern) {
		Set filter = Sets.filter(keys, Predicates.containsPattern(pattern));
		for (String key : filter) {
			deleteByKeyName(key);
		}
	}

	@Override
	public void deleteByKeyPrefix(String prefix) { 
		deleteByKeyPattern(prefix + ".*");
	}
	
	@Override
	public Set getKeyNames() {
		return keys;
	}

	@Override
	public void clear() {
		cache.flush();
		keys.clear();
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy