// ---------------------------------------------------------------------------
// jWebSocket - EventsPlugIn
// Copyright (c) 2010 Innotrade GmbH, jWebSocket.org
// ---------------------------------------------------------------------------
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at your
// option) any later version.
// This program 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.
// You should have received a copy of the GNU Lesser General Public License along
// with this program; if not, see <http://www.gnu.org/licenses/lgpl.html>.
// ---------------------------------------------------------------------------
package org.jwebsocket.storage.memcached;
import java.security.InvalidParameterException;
import java.util.Map.Entry;
import org.jwebsocket.api.IBasicStorage;
import java.util.Collection;
import java.util.Set;
import java.util.Map;
import javolution.util.FastMap;
import net.spy.memcached.MemcachedClient;
import javolution.util.FastSet;
import java.util.Arrays;
/**
*
* @author kyberneees
*/
public class MemcachedStorage<K extends Object, V extends Object> implements IBasicStorage<K, V> {
private MemcachedClient memcachedClient;
private String name;
private final static String KEYS_LOCATION = ".KEYS::1234567890";
private final static String KEY_SEPARATOR = "::-::";
private final static int NOT_EXPIRE = 0;
public MemcachedStorage(String name, MemcachedClient memcachedClient) {
this.name = name;
this.memcachedClient = memcachedClient;
}
public void initialize() throws Exception {
//Key index support
if (null == get(name + KEYS_LOCATION)) {
memcachedClient.set(name + KEYS_LOCATION, NOT_EXPIRE, "");
}
}
public void clear() {
for (Object key : keySet()) {
remove((K) key);
}
//Removing the index
memcachedClient.set(name + KEYS_LOCATION, NOT_EXPIRE, "");
}
public Set<K> keySet() {
String index = (String) get(name + KEYS_LOCATION);
if (index.length() == 0) {
return new FastSet<K>();
} else {
String[] keys = index.split(KEY_SEPARATOR);
FastSet set = new FastSet();
set.addAll(Arrays.asList(keys));
return set;
}
}
public Collection<V> values() {
return getAll(keySet()).values();
}
public boolean containsKey(Object key) {
return keySet().contains((K) key);
}
public boolean containsValue(Object value) {
return values().contains((V) value);
}
public Map<K, V> getAll(Collection<K> keys) {
FastMap<K, V> m = new FastMap<K, V>();
for (K key : keys) {
m.put(key, get(key));
}
return m;
}
public V get(Object key) {
V myObj = null;
myObj = (V) memcachedClient.get(key.toString());
return myObj;
}
public V remove(Object key) {
V myObj = (V) get(key);
memcachedClient.delete(key.toString());
//Key index update
String index = (String) get(name + KEYS_LOCATION);
index = index.replace(key.toString() + KEY_SEPARATOR, "");
memcachedClient.set(name + KEYS_LOCATION, NOT_EXPIRE, index);
return myObj;
}
public V put(K key, V value) {
memcachedClient.set(key.toString(), NOT_EXPIRE, value);
//Key index update
if (!keySet().contains(key)) {
String index = (String) get(name + KEYS_LOCATION);
index = index + key.toString() + KEY_SEPARATOR;
memcachedClient.set(name + KEYS_LOCATION, NOT_EXPIRE, index);
}
return value;
}
public boolean isEmpty() {
return keySet().isEmpty();
}
public void putAll(Map<? extends K, ? extends V> m) {
for (K key : m.keySet()) {
put(key, m.get(key));
}
}
public MemcachedClient getMemcachedClient() {
return memcachedClient;
}
public void setMemcachedClient(MemcachedClient memcachedClient) {
this.memcachedClient = memcachedClient;
}
public String getName() {
return name;
}
public void setName(String name) throws Exception {
if (name.length() == 0) {
throw new InvalidParameterException();
}
Map<K, V> all = getAll(keySet());
clear();
this.name = name;
initialize();
for (K key : all.keySet()) {
put(key, all.get(key));
}
}
public int size() {
return keySet().size();
}
public Set<Entry<K, V>> entrySet() {
return getAll(keySet()).entrySet();
}
public void shutdown() {
}
}