Merge branch 'master' into 3.0.0
# Conflicts: # pom.xml # redisson-all/pom.xml # redisson-tomcat/pom.xml # redisson-tomcat/redisson-tomcat-6/pom.xml # redisson-tomcat/redisson-tomcat-7/pom.xml # redisson-tomcat/redisson-tomcat-8/pom.xml # redisson/pom.xmlpull/802/merge
commit
efbdcbc4d4
@ -1,179 +0,0 @@
|
||||
/**
|
||||
* Copyright 2016 Nikita Koksharov
|
||||
*
|
||||
* 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 org.redisson.connection.balancer;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.redisson.api.RFuture;
|
||||
import org.redisson.client.RedisConnection;
|
||||
import org.redisson.client.RedisConnectionException;
|
||||
import org.redisson.client.RedisPubSubConnection;
|
||||
import org.redisson.config.MasterSlaveServersConfig;
|
||||
import org.redisson.connection.ClientConnectionsEntry;
|
||||
import org.redisson.connection.ClientConnectionsEntry.FreezeReason;
|
||||
import org.redisson.connection.ConnectionManager;
|
||||
import org.redisson.connection.MasterSlaveEntry;
|
||||
import org.redisson.connection.pool.PubSubConnectionPool;
|
||||
import org.redisson.connection.pool.SlaveConnectionPool;
|
||||
import org.redisson.misc.RPromise;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.netty.util.concurrent.Future;
|
||||
import io.netty.util.concurrent.FutureListener;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
|
||||
public class LoadBalancerManagerImpl implements LoadBalancerManager {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private final ConnectionManager connectionManager;
|
||||
private final Map<InetSocketAddress, ClientConnectionsEntry> addr2Entry = PlatformDependent.newConcurrentHashMap();
|
||||
private final PubSubConnectionPool pubSubConnectionPool;
|
||||
private final SlaveConnectionPool slaveConnectionPool;
|
||||
|
||||
public LoadBalancerManagerImpl(MasterSlaveServersConfig config, ConnectionManager connectionManager, MasterSlaveEntry entry) {
|
||||
this.connectionManager = connectionManager;
|
||||
slaveConnectionPool = new SlaveConnectionPool(config, connectionManager, entry);
|
||||
pubSubConnectionPool = new PubSubConnectionPool(config, connectionManager, entry);
|
||||
}
|
||||
|
||||
public RFuture<Void> add(final ClientConnectionsEntry entry) {
|
||||
final RPromise<Void> result = connectionManager.newPromise();
|
||||
FutureListener<Void> listener = new FutureListener<Void>() {
|
||||
AtomicInteger counter = new AtomicInteger(2);
|
||||
@Override
|
||||
public void operationComplete(Future<Void> future) throws Exception {
|
||||
if (!future.isSuccess()) {
|
||||
result.tryFailure(future.cause());
|
||||
return;
|
||||
}
|
||||
if (counter.decrementAndGet() == 0) {
|
||||
addr2Entry.put(entry.getClient().getAddr(), entry);
|
||||
result.trySuccess(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
RFuture<Void> slaveFuture = slaveConnectionPool.add(entry);
|
||||
slaveFuture.addListener(listener);
|
||||
RFuture<Void> pubSubFuture = pubSubConnectionPool.add(entry);
|
||||
pubSubFuture.addListener(listener);
|
||||
return result;
|
||||
}
|
||||
|
||||
public int getAvailableClients() {
|
||||
int count = 0;
|
||||
for (ClientConnectionsEntry connectionEntry : addr2Entry.values()) {
|
||||
if (!connectionEntry.isFreezed()) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public boolean unfreeze(String host, int port, FreezeReason freezeReason) {
|
||||
InetSocketAddress addr = new InetSocketAddress(host, port);
|
||||
ClientConnectionsEntry entry = addr2Entry.get(addr);
|
||||
if (entry == null) {
|
||||
throw new IllegalStateException("Can't find " + addr + " in slaves!");
|
||||
}
|
||||
|
||||
synchronized (entry) {
|
||||
if (!entry.isFreezed()) {
|
||||
return false;
|
||||
}
|
||||
if ((freezeReason == FreezeReason.RECONNECT
|
||||
&& entry.getFreezeReason() == FreezeReason.RECONNECT)
|
||||
|| freezeReason != FreezeReason.RECONNECT) {
|
||||
entry.resetFailedAttempts();
|
||||
entry.setFreezed(false);
|
||||
entry.setFreezeReason(null);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public ClientConnectionsEntry freeze(String host, int port, FreezeReason freezeReason) {
|
||||
InetSocketAddress addr = new InetSocketAddress(host, port);
|
||||
ClientConnectionsEntry connectionEntry = addr2Entry.get(addr);
|
||||
return freeze(connectionEntry, freezeReason);
|
||||
}
|
||||
|
||||
public ClientConnectionsEntry freeze(ClientConnectionsEntry connectionEntry, FreezeReason freezeReason) {
|
||||
if (connectionEntry == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
synchronized (connectionEntry) {
|
||||
// only RECONNECT freeze reason could be replaced
|
||||
if (connectionEntry.getFreezeReason() == null
|
||||
|| connectionEntry.getFreezeReason() == FreezeReason.RECONNECT) {
|
||||
connectionEntry.setFreezed(true);
|
||||
connectionEntry.setFreezeReason(freezeReason);
|
||||
return connectionEntry;
|
||||
}
|
||||
if (connectionEntry.isFreezed()) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return connectionEntry;
|
||||
}
|
||||
|
||||
public RFuture<RedisPubSubConnection> nextPubSubConnection() {
|
||||
return pubSubConnectionPool.get();
|
||||
}
|
||||
|
||||
public RFuture<RedisConnection> getConnection(InetSocketAddress addr) {
|
||||
ClientConnectionsEntry entry = addr2Entry.get(addr);
|
||||
if (entry != null) {
|
||||
return slaveConnectionPool.get(entry);
|
||||
}
|
||||
RedisConnectionException exception = new RedisConnectionException("Can't find entry for " + addr);
|
||||
return connectionManager.newFailedFuture(exception);
|
||||
}
|
||||
|
||||
public RFuture<RedisConnection> nextConnection() {
|
||||
return slaveConnectionPool.get();
|
||||
}
|
||||
|
||||
public void returnPubSubConnection(RedisPubSubConnection connection) {
|
||||
ClientConnectionsEntry entry = addr2Entry.get(connection.getRedisClient().getAddr());
|
||||
pubSubConnectionPool.returnConnection(entry, connection);
|
||||
}
|
||||
|
||||
public void returnConnection(RedisConnection connection) {
|
||||
ClientConnectionsEntry entry = addr2Entry.get(connection.getRedisClient().getAddr());
|
||||
slaveConnectionPool.returnConnection(entry, connection);
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
for (ClientConnectionsEntry entry : addr2Entry.values()) {
|
||||
entry.getClient().shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdownAsync() {
|
||||
for (ClientConnectionsEntry entry : addr2Entry.values()) {
|
||||
connectionManager.shutdownAsync(entry.getClient());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,57 +0,0 @@
|
||||
/**
|
||||
* Copyright 2016 Nikita Koksharov
|
||||
*
|
||||
* 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 org.redisson.jcache;
|
||||
|
||||
import javax.cache.Cache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
* @param <K> key
|
||||
* @param <V> value
|
||||
*/
|
||||
public class JCacheEntry<K, V> implements Cache.Entry<K, V> {
|
||||
|
||||
private final K key;
|
||||
private final V value;
|
||||
|
||||
public JCacheEntry(K key, V value) {
|
||||
super();
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public K getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(Class<T> clazz) {
|
||||
if (clazz.isAssignableFrom(getClass())) {
|
||||
return clazz.cast(this);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
/**
|
||||
* Copyright 2016 Nikita Koksharov
|
||||
*
|
||||
* 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 org.redisson.jcache;
|
||||
|
||||
import javax.cache.Cache;
|
||||
import javax.cache.event.CacheEntryEvent;
|
||||
import javax.cache.event.EventType;
|
||||
|
||||
/**
|
||||
* Entry event element passed to EventListener of JCache object
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
* @param <K> key
|
||||
* @param <V> value
|
||||
*/
|
||||
public class JCacheEntryEvent<K, V> extends CacheEntryEvent<K, V> {
|
||||
|
||||
private static final long serialVersionUID = -4601376694286796662L;
|
||||
|
||||
private final Object key;
|
||||
private final Object value;
|
||||
|
||||
public JCacheEntryEvent(Cache<K, V> source, EventType eventType, Object key, Object value) {
|
||||
super(source, eventType);
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public K getKey() {
|
||||
return (K) key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V getValue() {
|
||||
return (V) value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(Class<T> clazz) {
|
||||
if (clazz.isAssignableFrom(getClass())) {
|
||||
return clazz.cast(this);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V getOldValue() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOldValueAvailable() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
/**
|
||||
* Copyright 2016 Nikita Koksharov
|
||||
*
|
||||
* 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 org.redisson.jcache;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.redisson.client.codec.Codec;
|
||||
import org.redisson.client.handler.State;
|
||||
import org.redisson.client.protocol.Decoder;
|
||||
import org.redisson.client.protocol.Encoder;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class JCacheEventCodec implements Codec {
|
||||
|
||||
private final Codec codec;
|
||||
private final Decoder<Object> decoder = new Decoder<Object>() {
|
||||
@Override
|
||||
public Object decode(ByteBuf buf, State state) throws IOException {
|
||||
List<Object> result = new ArrayList<Object>();
|
||||
int keyLen = buf.order(ByteOrder.LITTLE_ENDIAN).readInt();
|
||||
ByteBuf keyBuf = buf.readSlice(keyLen);
|
||||
Object key = codec.getMapKeyDecoder().decode(keyBuf, state);
|
||||
result.add(key);
|
||||
|
||||
int valueLen = buf.order(ByteOrder.LITTLE_ENDIAN).readInt();
|
||||
ByteBuf valueBuf = buf.readSlice(valueLen);
|
||||
Object value = codec.getMapValueDecoder().decode(valueBuf, state);
|
||||
result.add(value);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
public JCacheEventCodec(Codec codec) {
|
||||
super();
|
||||
this.codec = codec;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Decoder<Object> getMapValueDecoder() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Encoder getMapValueEncoder() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Decoder<Object> getMapKeyDecoder() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Encoder getMapKeyEncoder() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Decoder<Object> getValueDecoder() {
|
||||
return decoder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Encoder getValueEncoder() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
@ -1,364 +0,0 @@
|
||||
/**
|
||||
* Copyright 2016 Nikita Koksharov
|
||||
*
|
||||
* 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 org.redisson.jcache;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import javax.cache.Cache;
|
||||
import javax.cache.CacheException;
|
||||
import javax.cache.CacheManager;
|
||||
import javax.cache.configuration.CompleteConfiguration;
|
||||
import javax.cache.configuration.Configuration;
|
||||
import javax.cache.spi.CachingProvider;
|
||||
import javax.management.InstanceAlreadyExistsException;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.MBeanRegistrationException;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import org.redisson.Redisson;
|
||||
import org.redisson.jcache.bean.EmptyStatisticsMXBean;
|
||||
import org.redisson.jcache.bean.JCacheManagementMXBean;
|
||||
import org.redisson.jcache.bean.JCacheStatisticsMXBean;
|
||||
import org.redisson.jcache.configuration.JCacheConfiguration;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class JCacheManager implements CacheManager {
|
||||
|
||||
private static final EmptyStatisticsMXBean EMPTY_INSTANCE = new EmptyStatisticsMXBean();
|
||||
private static MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
|
||||
|
||||
private final ClassLoader classLoader;
|
||||
private final CachingProvider cacheProvider;
|
||||
private final Properties properties;
|
||||
private final URI uri;
|
||||
private final ConcurrentMap<String, JCache<?, ?>> caches = new ConcurrentHashMap<String, JCache<?, ?>>();
|
||||
private final ConcurrentMap<JCache<?, ?>, JCacheStatisticsMXBean> statBeans = new ConcurrentHashMap<JCache<?, ?>, JCacheStatisticsMXBean>();
|
||||
private final ConcurrentMap<JCache<?, ?>, JCacheManagementMXBean> managementBeans = new ConcurrentHashMap<JCache<?, ?>, JCacheManagementMXBean>();
|
||||
|
||||
private volatile boolean closed;
|
||||
|
||||
private final Redisson redisson;
|
||||
|
||||
public JCacheManager(Redisson redisson, ClassLoader classLoader, CachingProvider cacheProvider, Properties properties, URI uri) {
|
||||
super();
|
||||
this.classLoader = classLoader;
|
||||
this.cacheProvider = cacheProvider;
|
||||
this.properties = properties;
|
||||
this.uri = uri;
|
||||
this.redisson = redisson;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CachingProvider getCachingProvider() {
|
||||
return cacheProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getURI() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader getClassLoader() {
|
||||
return classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Properties getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
private void checkNotClosed() {
|
||||
if (closed) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K, V, C extends Configuration<K, V>> Cache<K, V> createCache(String cacheName, C configuration)
|
||||
throws IllegalArgumentException {
|
||||
checkNotClosed();
|
||||
if (cacheName == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
if (configuration == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
JCacheConfiguration<K, V> cfg = new JCacheConfiguration<K, V>(configuration);
|
||||
JCache<K, V> cache = new JCache<K, V>(this, redisson, cacheName, cfg);
|
||||
JCache<?, ?> oldCache = caches.putIfAbsent(cacheName, cache);
|
||||
if (oldCache != null) {
|
||||
throw new CacheException("Cache " + cacheName + " already exists");
|
||||
}
|
||||
if (cfg.isStatisticsEnabled()) {
|
||||
enableStatistics(cacheName, true);
|
||||
}
|
||||
if (cfg.isManagementEnabled()) {
|
||||
enableManagement(cacheName, true);
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K, V> Cache<K, V> getCache(String cacheName, Class<K> keyType, Class<V> valueType) {
|
||||
checkNotClosed();
|
||||
if (cacheName == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
if (keyType == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
if (valueType == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
JCache<?, ?> cache = caches.get(cacheName);
|
||||
if (cache == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!keyType.isAssignableFrom(cache.getConfiguration(CompleteConfiguration.class).getKeyType())) {
|
||||
throw new ClassCastException("Wrong type of key for " + cacheName);
|
||||
}
|
||||
if (!valueType.isAssignableFrom(cache.getConfiguration(CompleteConfiguration.class).getValueType())) {
|
||||
throw new ClassCastException("Wrong type of value for " + cacheName);
|
||||
}
|
||||
return (Cache<K, V>) cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K, V> Cache<K, V> getCache(String cacheName) {
|
||||
checkNotClosed();
|
||||
Cache<K, V> cache = (Cache<K, V>) getCache(cacheName, Object.class, Object.class);
|
||||
if (cache != null) {
|
||||
if (cache.getConfiguration(CompleteConfiguration.class).getKeyType() != Object.class) {
|
||||
throw new IllegalArgumentException("Wrong type of key for " + cacheName);
|
||||
}
|
||||
if (cache.getConfiguration(CompleteConfiguration.class).getValueType() != Object.class) {
|
||||
throw new IllegalArgumentException("Wrong type of value for " + cacheName);
|
||||
}
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<String> getCacheNames() {
|
||||
return Collections.unmodifiableSet(new HashSet<String>(caches.keySet()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyCache(String cacheName) {
|
||||
checkNotClosed();
|
||||
if (cacheName == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
JCache<?, ?> cache = caches.get(cacheName);
|
||||
if (cache != null) {
|
||||
cache.clear();
|
||||
cache.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void closeCache(JCache<?, ?> cache) {
|
||||
caches.remove(cache.getName());
|
||||
unregisterStatisticsBean(cache);
|
||||
unregisterManagementBean(cache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableManagement(String cacheName, boolean enabled) {
|
||||
checkNotClosed();
|
||||
if (cacheName == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
JCache<?, ?> cache = caches.get(cacheName);
|
||||
if (cache == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
JCacheManagementMXBean statBean = managementBeans.get(cache);
|
||||
if (statBean == null) {
|
||||
statBean = new JCacheManagementMXBean(cache);
|
||||
JCacheManagementMXBean oldBean = managementBeans.putIfAbsent(cache, statBean);
|
||||
if (oldBean != null) {
|
||||
statBean = oldBean;
|
||||
}
|
||||
}
|
||||
try {
|
||||
ObjectName name = new ObjectName(getName("Management", cache));
|
||||
if (mBeanServer.queryNames(name, null).isEmpty()) {
|
||||
mBeanServer.registerMBean(statBean, name);
|
||||
}
|
||||
} catch (MalformedObjectNameException e) {
|
||||
throw new CacheException(e);
|
||||
} catch (InstanceAlreadyExistsException e) {
|
||||
throw new CacheException(e);
|
||||
} catch (MBeanRegistrationException e) {
|
||||
throw new CacheException(e);
|
||||
} catch (NotCompliantMBeanException e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
} else {
|
||||
unregisterManagementBean(cache);
|
||||
}
|
||||
cache.getConfiguration(JCacheConfiguration.class).setManagementEnabled(enabled);
|
||||
}
|
||||
|
||||
private void unregisterManagementBean(JCache<?, ?> cache) {
|
||||
JCacheManagementMXBean statBean = managementBeans.remove(cache);
|
||||
if (statBean != null) {
|
||||
try {
|
||||
ObjectName name = new ObjectName(getName("Management", cache));
|
||||
for (ObjectName objectName : mBeanServer.queryNames(name, null)) {
|
||||
mBeanServer.unregisterMBean(objectName);
|
||||
}
|
||||
} catch (MalformedObjectNameException e) {
|
||||
throw new CacheException(e);
|
||||
} catch (MBeanRegistrationException e) {
|
||||
throw new CacheException(e);
|
||||
} catch (InstanceNotFoundException e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public JCacheStatisticsMXBean getStatBean(JCache<?, ?> cache) {
|
||||
JCacheStatisticsMXBean bean = statBeans.get(cache);
|
||||
if (bean != null) {
|
||||
return bean;
|
||||
}
|
||||
return EMPTY_INSTANCE;
|
||||
}
|
||||
|
||||
private String getName(String name, JCache<?, ?> cache) {
|
||||
return "javax.cache:type=Cache" + name + ",CacheManager="
|
||||
+ cache.getCacheManager().getURI().toString().replaceAll(",|:|=|\n", ".")
|
||||
+ ",Cache=" + cache.getName().replaceAll(",|:|=|\n", ".");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableStatistics(String cacheName, boolean enabled) {
|
||||
checkNotClosed();
|
||||
if (cacheName == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
JCache<?, ?> cache = caches.get(cacheName);
|
||||
if (cache == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
JCacheStatisticsMXBean statBean = statBeans.get(cache);
|
||||
if (statBean == null) {
|
||||
statBean = new JCacheStatisticsMXBean();
|
||||
JCacheStatisticsMXBean oldBean = statBeans.putIfAbsent(cache, statBean);
|
||||
if (oldBean != null) {
|
||||
statBean = oldBean;
|
||||
}
|
||||
}
|
||||
try {
|
||||
ObjectName name = new ObjectName(getName("Statistics", cache));
|
||||
if (!mBeanServer.isRegistered(name)) {
|
||||
mBeanServer.registerMBean(statBean, name);
|
||||
}
|
||||
} catch (MalformedObjectNameException e) {
|
||||
throw new CacheException(e);
|
||||
} catch (InstanceAlreadyExistsException e) {
|
||||
throw new CacheException(e);
|
||||
} catch (MBeanRegistrationException e) {
|
||||
throw new CacheException(e);
|
||||
} catch (NotCompliantMBeanException e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
} else {
|
||||
unregisterStatisticsBean(cache);
|
||||
}
|
||||
cache.getConfiguration(JCacheConfiguration.class).setStatisticsEnabled(enabled);
|
||||
}
|
||||
|
||||
private void unregisterStatisticsBean(JCache<?, ?> cache) {
|
||||
JCacheStatisticsMXBean statBean = statBeans.remove(cache);
|
||||
if (statBean != null) {
|
||||
try {
|
||||
ObjectName name = new ObjectName(getName("Statistics", cache));
|
||||
for (ObjectName objectName : mBeanServer.queryNames(name, null)) {
|
||||
mBeanServer.unregisterMBean(objectName);
|
||||
}
|
||||
} catch (MalformedObjectNameException e) {
|
||||
throw new CacheException(e);
|
||||
} catch (MBeanRegistrationException e) {
|
||||
throw new CacheException(e);
|
||||
} catch (InstanceNotFoundException e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (isClosed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (cacheProvider) {
|
||||
if (!isClosed()) {
|
||||
cacheProvider.close(uri, classLoader);
|
||||
for (Cache<?, ?> cache : caches.values()) {
|
||||
try {
|
||||
cache.close();
|
||||
} catch (Exception e) {
|
||||
// skip
|
||||
}
|
||||
}
|
||||
redisson.shutdown();
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return closed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(Class<T> clazz) {
|
||||
if (clazz.isAssignableFrom(getClass())) {
|
||||
return clazz.cast(this);
|
||||
}
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,165 +0,0 @@
|
||||
/**
|
||||
* Copyright 2016 Nikita Koksharov
|
||||
*
|
||||
* 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 org.redisson.jcache;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import javax.cache.CacheManager;
|
||||
import javax.cache.configuration.OptionalFeature;
|
||||
import javax.cache.spi.CachingProvider;
|
||||
|
||||
import org.redisson.Redisson;
|
||||
import org.redisson.config.Config;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class JCachingProvider implements CachingProvider {
|
||||
|
||||
private final ConcurrentMap<ClassLoader, ConcurrentMap<URI, CacheManager>> managers =
|
||||
new ConcurrentHashMap<ClassLoader, ConcurrentMap<URI, CacheManager>>();
|
||||
|
||||
private static URI DEFAULT_URI;
|
||||
|
||||
static {
|
||||
try {
|
||||
DEFAULT_URI = JCachingProvider.class.getResource("/redisson-jcache.json").toURI();
|
||||
} catch (Exception e) {
|
||||
// trying next format
|
||||
try {
|
||||
DEFAULT_URI = JCachingProvider.class.getResource("/redisson-jcache.yaml").toURI();
|
||||
} catch (Exception e1) {
|
||||
// skip
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CacheManager getCacheManager(URI uri, ClassLoader classLoader, Properties properties) {
|
||||
if (uri == null) {
|
||||
uri = getDefaultURI();
|
||||
}
|
||||
if (classLoader == null) {
|
||||
classLoader = getDefaultClassLoader();
|
||||
}
|
||||
|
||||
ConcurrentMap<URI, CacheManager> value = new ConcurrentHashMap<URI, CacheManager>();
|
||||
ConcurrentMap<URI, CacheManager> oldValue = managers.putIfAbsent(classLoader, value);
|
||||
if (oldValue != null) {
|
||||
value = oldValue;
|
||||
}
|
||||
|
||||
CacheManager manager = value.get(uri);
|
||||
if (manager != null) {
|
||||
return manager;
|
||||
}
|
||||
|
||||
Config config = null;
|
||||
try {
|
||||
config = Config.fromJSON(uri.toURL());
|
||||
} catch (IOException e) {
|
||||
try {
|
||||
config = Config.fromYAML(uri.toURL());
|
||||
} catch (IOException e2) {
|
||||
throw new IllegalArgumentException("Can't parse config " + uri, e2);
|
||||
}
|
||||
}
|
||||
|
||||
Redisson redisson = (Redisson) Redisson.create(config);
|
||||
manager = new JCacheManager(redisson, classLoader, this, properties, uri);
|
||||
CacheManager oldManager = value.putIfAbsent(uri, manager);
|
||||
if (oldManager != null) {
|
||||
redisson.shutdown();
|
||||
manager = oldManager;
|
||||
}
|
||||
return manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader getDefaultClassLoader() {
|
||||
return getClass().getClassLoader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getDefaultURI() {
|
||||
return DEFAULT_URI;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Properties getDefaultProperties() {
|
||||
return new Properties();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CacheManager getCacheManager(URI uri, ClassLoader classLoader) {
|
||||
return getCacheManager(uri, classLoader, getDefaultProperties());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CacheManager getCacheManager() {
|
||||
return getCacheManager(getDefaultURI(), getDefaultClassLoader());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
synchronized (managers) {
|
||||
for (ClassLoader classLoader : managers.keySet()) {
|
||||
close(classLoader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(ClassLoader classLoader) {
|
||||
Map<URI, CacheManager> uri2manager = managers.remove(classLoader);
|
||||
if (uri2manager != null) {
|
||||
for (CacheManager manager : uri2manager.values()) {
|
||||
manager.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(URI uri, ClassLoader classLoader) {
|
||||
Map<URI, CacheManager> uri2manager = managers.get(classLoader);
|
||||
if (uri2manager == null) {
|
||||
return;
|
||||
}
|
||||
CacheManager manager = uri2manager.remove(uri);
|
||||
if (manager == null) {
|
||||
return;
|
||||
}
|
||||
manager.close();
|
||||
if (uri2manager.isEmpty()) {
|
||||
managers.remove(classLoader, Collections.emptyMap());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupported(OptionalFeature optionalFeature) {
|
||||
// TODO implement support of store_by_reference
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
/**
|
||||
* Copyright 2016 Nikita Koksharov
|
||||
*
|
||||
* 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 org.redisson.jcache;
|
||||
|
||||
import javax.cache.processor.MutableEntry;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
* @param <K>
|
||||
* @param <V>
|
||||
*/
|
||||
public class JMutableEntry<K, V> implements MutableEntry<K, V> {
|
||||
|
||||
public enum Action {CREATED, READ, UPDATED, DELETED, LOADED, SKIPPED}
|
||||
|
||||
final JCache<K, V> jCache;
|
||||
final K key;
|
||||
boolean isReadThrough;
|
||||
|
||||
Action action = Action.SKIPPED;
|
||||
V value;
|
||||
|
||||
public JMutableEntry(JCache<K, V> jCache, V value, K key, boolean isReadThrough) {
|
||||
super();
|
||||
this.jCache = jCache;
|
||||
this.value = value;
|
||||
this.key = key;
|
||||
this.isReadThrough = isReadThrough;
|
||||
}
|
||||
|
||||
@Override
|
||||
public K getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V getValue() {
|
||||
if (action != Action.SKIPPED) {
|
||||
return value;
|
||||
}
|
||||
if (value != null) {
|
||||
action = Action.READ;
|
||||
} else if (isReadThrough) {
|
||||
value = jCache.load(key);
|
||||
if (value != null) {
|
||||
action = Action.LOADED;
|
||||
}
|
||||
isReadThrough = false;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(Class<T> clazz) {
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists() {
|
||||
return getValue() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
if (action == Action.CREATED) {
|
||||
action = Action.SKIPPED;
|
||||
} else {
|
||||
action = Action.DELETED;
|
||||
}
|
||||
value = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(V value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
if (action != Action.CREATED) {
|
||||
if (exists()) {
|
||||
action = Action.UPDATED;
|
||||
} else {
|
||||
action = Action.CREATED;
|
||||
}
|
||||
}
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Action getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
/**
|
||||
* Copyright 2016 Nikita Koksharov
|
||||
*
|
||||
* 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 org.redisson.jcache.bean;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class EmptyStatisticsMXBean extends JCacheStatisticsMXBean {
|
||||
|
||||
@Override
|
||||
public void addEvictions(long value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addGetTime(long value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addHits(long value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMisses(long value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPuts(long value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPutTime(long value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRemovals(long value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRemoveTime(long value) {
|
||||
}
|
||||
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
/**
|
||||
* Copyright 2016 Nikita Koksharov
|
||||
*
|
||||
* 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 org.redisson.jcache.bean;
|
||||
|
||||
import javax.cache.configuration.CompleteConfiguration;
|
||||
import javax.cache.management.CacheMXBean;
|
||||
|
||||
import org.redisson.jcache.JCache;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class JCacheManagementMXBean implements CacheMXBean {
|
||||
|
||||
private final JCache<?, ?> cache;
|
||||
|
||||
public JCacheManagementMXBean(JCache<?, ?> cache) {
|
||||
super();
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKeyType() {
|
||||
return cache.getConfiguration(CompleteConfiguration.class).getKeyType().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValueType() {
|
||||
return cache.getConfiguration(CompleteConfiguration.class).getValueType().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadThrough() {
|
||||
return cache.getConfiguration(CompleteConfiguration.class).isReadThrough();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWriteThrough() {
|
||||
return cache.getConfiguration(CompleteConfiguration.class).isWriteThrough();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStoreByValue() {
|
||||
return cache.getConfiguration(CompleteConfiguration.class).isStoreByValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStatisticsEnabled() {
|
||||
return cache.getConfiguration(CompleteConfiguration.class).isStatisticsEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isManagementEnabled() {
|
||||
return cache.getConfiguration(CompleteConfiguration.class).isManagementEnabled();
|
||||
}
|
||||
|
||||
}
|
@ -1,157 +0,0 @@
|
||||
/**
|
||||
* Copyright 2016 Nikita Koksharov
|
||||
*
|
||||
* 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 org.redisson.jcache.bean;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import javax.cache.management.CacheStatisticsMXBean;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class JCacheStatisticsMXBean implements CacheStatisticsMXBean {
|
||||
|
||||
private final AtomicLong removals = new AtomicLong();
|
||||
private final AtomicLong hits = new AtomicLong();
|
||||
private final AtomicLong puts = new AtomicLong();
|
||||
private final AtomicLong misses = new AtomicLong();
|
||||
private final AtomicLong evictions = new AtomicLong();
|
||||
|
||||
private final AtomicLong removeTime = new AtomicLong();
|
||||
private final AtomicLong getTime = new AtomicLong();
|
||||
private final AtomicLong putTime = new AtomicLong();
|
||||
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
removals.set(0);
|
||||
hits.set(0);
|
||||
puts.set(0);
|
||||
misses.set(0);
|
||||
evictions.set(0);
|
||||
|
||||
removeTime.set(0);
|
||||
getTime.set(0);
|
||||
putTime.set(0);
|
||||
}
|
||||
|
||||
public void addHits(long value) {
|
||||
hits.addAndGet(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCacheHits() {
|
||||
return hits.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getCacheHitPercentage() {
|
||||
long gets = getCacheGets();
|
||||
if (gets == 0) {
|
||||
return 0;
|
||||
}
|
||||
return (getCacheHits() * 100) / (float) gets;
|
||||
}
|
||||
|
||||
public void addMisses(long value) {
|
||||
misses.addAndGet(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCacheMisses() {
|
||||
return misses.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getCacheMissPercentage() {
|
||||
long gets = getCacheGets();
|
||||
if (gets == 0) {
|
||||
return 0;
|
||||
}
|
||||
return (getCacheMisses() * 100) / (float) gets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCacheGets() {
|
||||
return hits.get() + misses.get();
|
||||
}
|
||||
|
||||
public void addPuts(long value) {
|
||||
puts.addAndGet(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCachePuts() {
|
||||
return puts.get();
|
||||
}
|
||||
|
||||
public void addRemovals(long value) {
|
||||
removals.addAndGet(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCacheRemovals() {
|
||||
return removals.get();
|
||||
}
|
||||
|
||||
public void addEvictions(long value) {
|
||||
evictions.addAndGet(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCacheEvictions() {
|
||||
return evictions.get();
|
||||
}
|
||||
|
||||
private float get(long value, long timeInNanos) {
|
||||
if (value == 0 || timeInNanos == 0) {
|
||||
return 0;
|
||||
}
|
||||
long timeInMicrosec = TimeUnit.NANOSECONDS.toMicros(timeInNanos);
|
||||
return timeInMicrosec / value;
|
||||
}
|
||||
|
||||
public void addGetTime(long value) {
|
||||
getTime.addAndGet(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getAverageGetTime() {
|
||||
return get(getCacheGets(), getTime.get());
|
||||
}
|
||||
|
||||
public void addPutTime(long value) {
|
||||
putTime.addAndGet(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getAveragePutTime() {
|
||||
return get(getCachePuts(), putTime.get());
|
||||
}
|
||||
|
||||
public void addRemoveTime(long value) {
|
||||
removeTime.addAndGet(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getAverageRemoveTime() {
|
||||
return get(getCachePuts(), removeTime.get());
|
||||
}
|
||||
|
||||
}
|
@ -1,147 +0,0 @@
|
||||
/**
|
||||
* Copyright 2016 Nikita Koksharov
|
||||
*
|
||||
* 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 org.redisson.jcache.configuration;
|
||||
|
||||
import javax.cache.configuration.CacheEntryListenerConfiguration;
|
||||
import javax.cache.configuration.CompleteConfiguration;
|
||||
import javax.cache.configuration.Configuration;
|
||||
import javax.cache.configuration.Factory;
|
||||
import javax.cache.configuration.MutableConfiguration;
|
||||
import javax.cache.expiry.ExpiryPolicy;
|
||||
import javax.cache.integration.CacheLoader;
|
||||
import javax.cache.integration.CacheWriter;
|
||||
|
||||
/**
|
||||
* Configuration object for JCache {@link javax.cache.Cache}
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
* @param <K> key type
|
||||
* @param <V> value type
|
||||
*/
|
||||
public class JCacheConfiguration<K, V> implements CompleteConfiguration<K, V> {
|
||||
|
||||
private static final long serialVersionUID = -7861479608049089078L;
|
||||
|
||||
private final ExpiryPolicy expiryPolicy;
|
||||
private final MutableConfiguration<K, V> delegate;
|
||||
|
||||
public JCacheConfiguration(Configuration<K, V> configuration) {
|
||||
this(configuration, configuration.getKeyType(), configuration.getValueType());
|
||||
}
|
||||
|
||||
public JCacheConfiguration(Configuration<K, V> configuration, Class<K> keyType, Class<V> valueType) {
|
||||
if (configuration != null) {
|
||||
if (configuration instanceof CompleteConfiguration) {
|
||||
delegate = new MutableConfiguration<K, V>((CompleteConfiguration<K, V>)configuration);
|
||||
} else {
|
||||
delegate = new MutableConfiguration<K, V>();
|
||||
delegate.setStoreByValue(configuration.isStoreByValue());
|
||||
delegate.setTypes(configuration.getKeyType(), configuration.getValueType());
|
||||
}
|
||||
} else {
|
||||
delegate = new MutableConfiguration<K, V>();
|
||||
}
|
||||
|
||||
this.expiryPolicy = delegate.getExpiryPolicyFactory().create();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<K> getKeyType() {
|
||||
if (delegate.getKeyType() == null) {
|
||||
return (Class<K>) Object.class;
|
||||
}
|
||||
return delegate.getKeyType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<V> getValueType() {
|
||||
if (delegate.getValueType() == null) {
|
||||
return (Class<V>) Object.class;
|
||||
}
|
||||
return delegate.getValueType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStoreByValue() {
|
||||
return delegate.isStoreByValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadThrough() {
|
||||
return delegate.isReadThrough();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWriteThrough() {
|
||||
return delegate.isWriteThrough();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStatisticsEnabled() {
|
||||
return delegate.isStatisticsEnabled();
|
||||
}
|
||||
|
||||
public void setStatisticsEnabled(boolean enabled) {
|
||||
delegate.setStatisticsEnabled(enabled);
|
||||
}
|
||||
|
||||
public void setManagementEnabled(boolean enabled) {
|
||||
delegate.setManagementEnabled(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isManagementEnabled() {
|
||||
return delegate.isManagementEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<CacheEntryListenerConfiguration<K, V>> getCacheEntryListenerConfigurations() {
|
||||
return delegate.getCacheEntryListenerConfigurations();
|
||||
}
|
||||
|
||||
public void addCacheEntryListenerConfiguration(
|
||||
CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration) {
|
||||
delegate.addCacheEntryListenerConfiguration(cacheEntryListenerConfiguration);
|
||||
}
|
||||
|
||||
public void removeCacheEntryListenerConfiguration(
|
||||
CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration) {
|
||||
delegate.removeCacheEntryListenerConfiguration(cacheEntryListenerConfiguration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Factory<CacheLoader<K, V>> getCacheLoaderFactory() {
|
||||
return delegate.getCacheLoaderFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Factory<CacheWriter<? super K, ? super V>> getCacheWriterFactory() {
|
||||
return delegate.getCacheWriterFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Factory<ExpiryPolicy> getExpiryPolicyFactory() {
|
||||
return delegate.getExpiryPolicyFactory();
|
||||
}
|
||||
|
||||
public ExpiryPolicy getExpiryPolicy() {
|
||||
return expiryPolicy;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
/**
|
||||
* Copyright 2016 Nikita Koksharov
|
||||
*
|
||||
* 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 org.redisson.misc;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
public class URIBuilder {
|
||||
|
||||
public static URI create(String uri) {
|
||||
String[] parts = uri.split(":");
|
||||
if (parts.length-1 >= 3) {
|
||||
String port = parts[parts.length-1];
|
||||
String newPort = port.split("[^\\d]")[0];
|
||||
uri = "[" + uri.replace(":" + port, "") + "]:" + newPort;
|
||||
} else {
|
||||
String port = parts[parts.length-1];
|
||||
String newPort = port.split("[^\\d]")[0];
|
||||
uri = uri.replace(":" + port, "") + ":" + newPort;
|
||||
}
|
||||
|
||||
return URI.create("//" + uri);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Copyright 2016 Nikita Koksharov
|
||||
*
|
||||
* 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 org.redisson.misc;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLStreamHandler;
|
||||
import java.net.URLStreamHandlerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nikita Koksharov
|
||||
*
|
||||
*/
|
||||
public class URLBuilder {
|
||||
|
||||
private static volatile boolean init = false;
|
||||
|
||||
static {
|
||||
init();
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
if (init) {
|
||||
return;
|
||||
}
|
||||
init = true;
|
||||
URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory() {
|
||||
@Override
|
||||
public URLStreamHandler createURLStreamHandler(String protocol) {
|
||||
if ("redis".equals(protocol)) {
|
||||
return new URLStreamHandler() {
|
||||
@Override
|
||||
protected URLConnection openConnection(URL u) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
};
|
||||
|
||||
@Override
|
||||
protected boolean equals(URL u1, URL u2) {
|
||||
return u1.toString().equals(u2.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int hashCode(URL u) {
|
||||
return u.toString().hashCode();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static URL create(String url) {
|
||||
try {
|
||||
String[] parts = url.split(":");
|
||||
if (parts.length-1 >= 3) {
|
||||
String port = parts[parts.length-1];
|
||||
String newPort = port.split("[^\\d]")[0];
|
||||
String host = url.replace(":" + port, "");
|
||||
return new URL("redis://[" + host + "]:" + newPort);
|
||||
} else {
|
||||
String port = parts[parts.length-1];
|
||||
String newPort = port.split("[^\\d]")[0];
|
||||
String host = url.replace(":" + port, "");
|
||||
return new URL("redis://" + host + ":" + newPort);
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1 +0,0 @@
|
||||
org.redisson.jcache.JCachingProvider
|
@ -1,81 +0,0 @@
|
||||
package org.redisson.jcache;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.cache.Cache;
|
||||
import javax.cache.Caching;
|
||||
import javax.cache.configuration.FactoryBuilder;
|
||||
import javax.cache.configuration.MutableCacheEntryListenerConfiguration;
|
||||
import javax.cache.configuration.MutableConfiguration;
|
||||
import javax.cache.event.CacheEntryEvent;
|
||||
import javax.cache.event.CacheEntryExpiredListener;
|
||||
import javax.cache.event.CacheEntryListenerException;
|
||||
import javax.cache.expiry.CreatedExpiryPolicy;
|
||||
import javax.cache.expiry.Duration;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.redisson.BaseTest;
|
||||
|
||||
public class JCacheTest extends BaseTest {
|
||||
|
||||
@Test
|
||||
public void test() throws InterruptedException, IllegalArgumentException, URISyntaxException {
|
||||
MutableConfiguration<String, String> config = new MutableConfiguration<>();
|
||||
config.setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(new Duration(TimeUnit.SECONDS, 1)));
|
||||
config.setStoreByValue(true);
|
||||
|
||||
Cache<String, String> cache = Caching.getCachingProvider().getCacheManager(getClass().getResource("redisson-jcache.json").toURI(), null)
|
||||
.createCache("test", config);
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
String key = "123";
|
||||
ExpiredListener clientListener = new ExpiredListener(latch, key, "90");
|
||||
MutableCacheEntryListenerConfiguration<String, String> listenerConfiguration =
|
||||
new MutableCacheEntryListenerConfiguration<String, String>(FactoryBuilder.factoryOf(clientListener), null, true, true);
|
||||
cache.registerCacheEntryListener(listenerConfiguration);
|
||||
|
||||
cache.put(key, "90");
|
||||
Assert.assertNotNull(cache.get(key));
|
||||
|
||||
latch.await();
|
||||
|
||||
|
||||
Assert.assertNull(cache.get(key));
|
||||
}
|
||||
|
||||
public static class ExpiredListener implements CacheEntryExpiredListener<String, String>, Serializable {
|
||||
|
||||
private Object key;
|
||||
private Object value;
|
||||
private CountDownLatch latch;
|
||||
|
||||
public ExpiredListener(CountDownLatch latch, Object key, Object value) {
|
||||
super();
|
||||
this.latch = latch;
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void onExpired(Iterable<CacheEntryEvent<? extends String, ? extends String>> events)
|
||||
throws CacheEntryListenerException {
|
||||
CacheEntryEvent<? extends String, ? extends String> entry = events.iterator().next();
|
||||
|
||||
assertThat(entry.getKey()).isEqualTo(key);
|
||||
assertThat(entry.getValue()).isEqualTo(value);
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue