com.hazelcast.client.cache.impl.AbstractClientCacheProxy Maven / Gradle / Ivy
/*
* Copyright (c) 2008-2015, Hazelcast, Inc. All Rights Reserved.
*
* 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.hazelcast.client.cache.impl;
import com.hazelcast.cache.CacheStatistics;
import com.hazelcast.cache.impl.ICacheInternal;
import com.hazelcast.cache.impl.nearcache.NearCache;
import com.hazelcast.client.impl.ClientMessageDecoder;
import com.hazelcast.client.impl.HazelcastClientInstanceImpl;
import com.hazelcast.client.impl.protocol.ClientMessage;
import com.hazelcast.client.impl.protocol.codec.CacheGetAllCodec;
import com.hazelcast.client.impl.protocol.codec.CacheGetCodec;
import com.hazelcast.client.impl.protocol.codec.CacheSizeCodec;
import com.hazelcast.client.spi.ClientContext;
import com.hazelcast.client.spi.impl.ClientInvocation;
import com.hazelcast.client.spi.impl.ClientInvocationFuture;
import com.hazelcast.client.util.ClientDelegatingFuture;
import com.hazelcast.config.CacheConfig;
import com.hazelcast.core.ExecutionCallback;
import com.hazelcast.core.ICompletableFuture;
import com.hazelcast.nio.serialization.Data;
import com.hazelcast.nio.serialization.SerializationService;
import com.hazelcast.util.ExceptionUtil;
import javax.cache.CacheException;
import javax.cache.CacheManager;
import javax.cache.expiry.ExpiryPolicy;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Future;
import static com.hazelcast.cache.impl.CacheProxyUtil.validateNotNull;
/**
* Hazelcast provides extension functionality to default spec interface {@link javax.cache.Cache}.
* {@link com.hazelcast.cache.ICache} is the designated interface.
* AbstractCacheProxyExtension provides implementation of various {@link com.hazelcast.cache.ICache} methods.
* Note: this partial implementation is used by client.
*
* @param the type of key
* @param the type of value
*/
abstract class AbstractClientCacheProxy
extends AbstractClientInternalCacheProxy
implements ICacheInternal {
private static ClientMessageDecoder cacheGetResponseDecoder = new ClientMessageDecoder() {
@Override
public T decodeClientMessage(ClientMessage clientMessage) {
return (T) CacheGetCodec.decodeResponse(clientMessage).response;
}
};
protected AbstractClientCacheProxy(CacheConfig cacheConfig, ClientContext clientContext,
HazelcastClientCacheManager cacheManager) {
super(cacheConfig, clientContext, cacheManager);
}
@Override
public String getName() {
return name;
}
@Override
public CacheManager getCacheManager() {
return cacheManager;
}
protected Object getFromNearCache(Data keyData, boolean async) {
Object cached = nearCache != null ? nearCache.get(keyData) : null;
if (cached != null && NearCache.NULL_OBJECT != cached) {
return !async ? cached : createCompletedFuture(cached);
}
return null;
}
protected Object getInternal(K key, ExpiryPolicy expiryPolicy, boolean async) {
final long start = System.nanoTime();
ensureOpen();
validateNotNull(key);
final Data keyData = toData(key);
Object cached = getFromNearCache(keyData, async);
if (cached != null) {
return cached;
}
final Data expiryPolicyData = toData(expiryPolicy);
ClientMessage request = CacheGetCodec.encodeRequest(nameWithPrefix, keyData, expiryPolicyData);
ClientInvocationFuture future;
try {
final int partitionId = clientContext.getPartitionService().getPartitionId(key);
final HazelcastClientInstanceImpl client = (HazelcastClientInstanceImpl) clientContext.getHazelcastInstance();
final ClientInvocation clientInvocation = new ClientInvocation(client, request, partitionId);
future = clientInvocation.invoke();
} catch (Exception e) {
throw ExceptionUtil.rethrow(e);
}
SerializationService serializationService = clientContext.getSerializationService();
ClientDelegatingFuture delegatingFuture =
new ClientDelegatingFuture(future, serializationService, cacheGetResponseDecoder);
if (async) {
if (nearCache != null) {
delegatingFuture.andThenInternal(new ExecutionCallback() {
public void onResponse(Data valueData) {
storeInNearCache(keyData, valueData, null);
if (statisticsEnabled) {
handleStatisticsOnGet(start, valueData);
}
}
public void onFailure(Throwable t) {
}
});
}
return delegatingFuture;
} else {
try {
Object value = toObject(delegatingFuture.get());
if (nearCache != null) {
storeInNearCache(keyData, (Data) delegatingFuture.getResponse(), (V) value);
}
if (statisticsEnabled) {
handleStatisticsOnGet(start, value);
}
return value;
} catch (Throwable e) {
throw ExceptionUtil.rethrowAllowedTypeFirst(e, CacheException.class);
}
}
}
protected void handleStatisticsOnGet(long start, Object response) {
if (response == null) {
statistics.increaseCacheMisses();
} else {
statistics.increaseCacheHits();
}
statistics.addGetTimeNanos(System.nanoTime() - start);
}
@Override
public ICompletableFuture getAsync(K key) {
return getAsync(key, null);
}
@Override
public ICompletableFuture getAsync(K key, ExpiryPolicy expiryPolicy) {
return (ICompletableFuture) getInternal(key, expiryPolicy, true);
}
@Override
public ICompletableFuture putAsync(K key, V value) {
return putAsync(key, value, null);
}
@Override
public ICompletableFuture putAsync(K key, V value, ExpiryPolicy expiryPolicy) {
return putAsyncInternal(key, value, expiryPolicy, false, true, true);
}
@Override
public ICompletableFuture putIfAbsentAsync(K key, V value) {
return putIfAbsentAsyncInternal(key, value, null, false, true);
}
@Override
public ICompletableFuture putIfAbsentAsync(K key, V value, ExpiryPolicy expiryPolicy) {
return putIfAbsentAsyncInternal(key, value, expiryPolicy, false, true);
}
@Override
public ICompletableFuture getAndPutAsync(K key, V value) {
return getAndPutAsync(key, value, null);
}
@Override
public ICompletableFuture getAndPutAsync(K key, V value, ExpiryPolicy expiryPolicy) {
return putAsyncInternal(key, value, expiryPolicy, true, false, true);
}
@Override
public ICompletableFuture removeAsync(K key) {
return removeAsyncInternal(key, null, false, false, true);
}
@Override
public ICompletableFuture removeAsync(K key, V oldValue) {
return removeAsyncInternal(key, oldValue, true, false, true);
}
@Override
public ICompletableFuture getAndRemoveAsync(K key) {
return getAndRemoveAsyncInternal(key, false, true);
}
@Override
public ICompletableFuture replaceAsync(K key, V value) {
return replaceAsyncInternal(key, null, value, null, false, false, true);
}
@Override
public ICompletableFuture replaceAsync(K key, V value, ExpiryPolicy expiryPolicy) {
return replaceAsyncInternal(key, null, value, expiryPolicy, false, false, true);
}
@Override
public ICompletableFuture replaceAsync(K key, V oldValue, V newValue) {
return replaceAsyncInternal(key, oldValue, newValue, null, true, false, true);
}
@Override
public ICompletableFuture replaceAsync(K key, V oldValue, V newValue, ExpiryPolicy expiryPolicy) {
return replaceAsyncInternal(key, oldValue, newValue, expiryPolicy, true, false, true);
}
@Override
public ICompletableFuture getAndReplaceAsync(K key, V value) {
return replaceAndGetAsyncInternal(key, null, value, null, false, false, true);
}
@Override
public ICompletableFuture getAndReplaceAsync(K key, V value, ExpiryPolicy expiryPolicy) {
return replaceAndGetAsyncInternal(key, null, value, expiryPolicy, false, false, true);
}
@Override
public V get(K key, ExpiryPolicy expiryPolicy) {
return (V) getInternal(key, expiryPolicy, false);
}
@Override
public Map getAll(Set keys, ExpiryPolicy expiryPolicy) {
final long start = System.nanoTime();
ensureOpen();
validateNotNull(keys);
if (keys.isEmpty()) {
return Collections.EMPTY_MAP;
}
final Set keySet = new HashSet(keys.size());
for (K key : keys) {
final Data k = toData(key);
keySet.add(k);
}
Map result = getAllFromNearCache(keySet);
if (keySet.isEmpty()) {
return result;
}
Data expiryPolicyData = toData(expiryPolicy);
ClientMessage request = CacheGetAllCodec.encodeRequest(nameWithPrefix, keySet, expiryPolicyData);
ClientMessage responseMessage = invoke(request);
Map mapEntrySet = CacheGetAllCodec.decodeResponse(responseMessage).map;
Set> entrySet = mapEntrySet.entrySet();
for (Map.Entry dataEntry : entrySet) {
Data keyData = dataEntry.getKey();
Data valueData = dataEntry.getValue();
K key = toObject(keyData);
V value = toObject(valueData);
result.put(key, value);
storeInNearCache(keyData, valueData, value);
}
if (statisticsEnabled) {
statistics.increaseCacheHits(entrySet.size());
statistics.addGetTimeNanos(System.nanoTime() - start);
}
return result;
}
private Map getAllFromNearCache(Set keySet) {
Map result = new HashMap();
if (nearCache != null) {
final Iterator iterator = keySet.iterator();
while (iterator.hasNext()) {
Data key = iterator.next();
Object cached = nearCache.get(key);
if (cached != null && !NearCache.NULL_OBJECT.equals(cached)) {
result.put((K) toObject(key), (V) cached);
iterator.remove();
}
}
}
return result;
}
@Override
public void put(K key, V value, ExpiryPolicy expiryPolicy) {
final long start = System.nanoTime();
final ICompletableFuture