/* * (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser General Public License * (LGPL) version 2.1 which accompanies this distribution, and is available at * http://www.gnu.org/licenses/lgpl-2.1.html * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * Contributors: * Maxime Hilaire */ package org.nuxeo.ecm.core.redis.contribs; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuxeo.ecm.core.cache.AbstractCache; import org.nuxeo.ecm.core.cache.CacheDescriptor; import org.nuxeo.ecm.core.redis.RedisAdmin; import org.nuxeo.ecm.core.redis.RedisCallable; import org.nuxeo.ecm.core.redis.RedisExecutor; import org.nuxeo.runtime.api.Framework; import redis.clients.jedis.Jedis; /** * Cache implementation on top of Redis * * @since 6.0 */ public class RedisCache extends AbstractCache { protected static final String UTF_8 = "UTF-8"; protected static final Log log = LogFactory.getLog(RedisCache.class); protected final RedisExecutor executor; protected final String namespace; public RedisCache(CacheDescriptor desc) { super(desc); executor = Framework.getService(RedisExecutor.class); namespace = Framework.getService(RedisAdmin.class).namespace("cache",name); } protected String formatKey(String key) { return namespace.concat(key); } protected Serializable deserializeValue(byte[] workBytes) throws IOException { if (workBytes == null) { return null; } InputStream bain = new ByteArrayInputStream(workBytes); ObjectInputStream in = new ObjectInputStream(bain); try { return (Serializable) in.readObject(); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } protected static byte[] bytes(String string) { try { return string.getBytes(UTF_8); } catch (IOException e) { // cannot happen for UTF-8 throw new RuntimeException(e); } } @Override public Serializable get(final String key) throws IOException { return executor.execute(new RedisCallable<Serializable>() { @Override public Serializable call(Jedis jedis) throws Exception { return deserializeValue(jedis.get(bytes(formatKey(key)))); } }); } protected byte[] serializeValue(Serializable value) throws IOException { ByteArrayOutputStream baout = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(baout); out.writeObject(value); out.flush(); out.close(); return baout.toByteArray(); } @Override public void invalidate(final String key) throws IOException { executor.execute(new RedisCallable<Void>() { @Override public Void call(Jedis jedis) throws Exception { jedis.del(new String[] { formatKey(key)}); return null; } }); } @Override public void invalidateAll() throws IOException { Framework.getService(RedisAdmin.class).clear(formatKey("*")); } @Override public void put(final String key, final Serializable value) throws IOException { executor.execute(new RedisCallable<Void>() { @Override public Void call(Jedis jedis) throws Exception { byte[] bkey = bytes(formatKey(key)); jedis.set(bkey, serializeValue(value)); // Redis set in second ttl but descriptor set as mn int ttlKey = ttl * 60; jedis.expire(bkey, ttlKey); return null; } }); } }