/*
* Copyright Terracotta, Inc.
*
* 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.ehcache.clustered.client.internal.service;
import org.ehcache.clustered.client.internal.store.ClusterTierClientEntity;
import org.ehcache.clustered.common.internal.exceptions.ClusterException;
import org.ehcache.clustered.common.internal.messages.EhcacheEntityResponse;
import org.ehcache.clustered.common.internal.messages.StateRepositoryMessageFactory;
import org.ehcache.clustered.common.internal.messages.StateRepositoryOpMessage;
import org.ehcache.spi.persistence.StateHolder;
import java.util.AbstractMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeoutException;
import static org.ehcache.clustered.client.internal.service.ValueCodecFactory.getCodecForClass;
public class ClusteredStateHolder<K, V> implements StateHolder<K, V> {
private final StateRepositoryMessageFactory messageFactory;
private final ClusterTierClientEntity entity;
private final Class<K> keyClass;
private final ValueCodec<K> keyCodec;
private final ValueCodec<V> valueCodec;
public ClusteredStateHolder(final String cacheId, final String mapId, final ClusterTierClientEntity entity, Class<K> keyClass, Class<V> valueClass) {
this.keyClass = keyClass;
this.keyCodec = getCodecForClass(keyClass);
this.valueCodec = getCodecForClass(valueClass);
this.messageFactory = new StateRepositoryMessageFactory(cacheId, mapId, entity.getClientId());
this.entity = entity;
}
@Override
@SuppressWarnings("unchecked")
public V get(final Object key) {
if (!keyClass.isAssignableFrom(key.getClass())) {
return null;
}
@SuppressWarnings("unchecked")
Object response = getResponse(messageFactory.getMessage(keyCodec.encode((K) key)), false);
return valueCodec.decode(response);
}
private Object getResponse(StateRepositoryOpMessage message, boolean track) {
try {
EhcacheEntityResponse response = entity.invokeStateRepositoryOperation(message, track);
return ((EhcacheEntityResponse.MapValue)response).getValue();
} catch (ClusterException ce) {
throw new ClusteredMapException(ce);
} catch (TimeoutException te) {
throw new ClusteredMapException(te);
}
}
@Override
@SuppressWarnings("unchecked")
public Set<Map.Entry<K, V>> entrySet() {
@SuppressWarnings("unchecked")
Set<Map.Entry<Object, Object>> response = (Set<Map.Entry<Object, Object>>) getResponse(messageFactory.entrySetMessage(), true);
Set<Map.Entry<K, V>> entries = new HashSet<Map.Entry<K, V>>();
for (Map.Entry<Object, Object> objectEntry : response) {
entries.add(new AbstractMap.SimpleEntry<K, V>(keyCodec.decode(objectEntry.getKey()),
valueCodec.decode(objectEntry.getValue())));
}
return entries;
}
@Override
@SuppressWarnings("unchecked")
public V putIfAbsent(final K key, final V value) {
Object response = getResponse(messageFactory.putIfAbsentMessage(keyCodec.encode(key), valueCodec.encode(value)), true);
return valueCodec.decode(response);
}
}