package org.infinispan.client.hotrod.impl.operations; import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.infinispan.client.hotrod.CacheTopologyInfo; import org.infinispan.client.hotrod.Flag; import org.infinispan.client.hotrod.RemoteCacheManager; import org.infinispan.client.hotrod.configuration.ClientIntelligence; import org.infinispan.client.hotrod.event.ClientListenerNotifier; import org.infinispan.client.hotrod.impl.iteration.KeyTracker; import org.infinispan.client.hotrod.impl.protocol.Codec; import org.infinispan.client.hotrod.impl.protocol.HotRodConstants; import org.infinispan.client.hotrod.impl.query.RemoteQuery; import org.infinispan.client.hotrod.impl.transport.Transport; import org.infinispan.client.hotrod.impl.transport.TransportFactory; import net.jcip.annotations.Immutable; /** * Factory for {@link org.infinispan.client.hotrod.impl.operations.HotRodOperation} objects. * * @author Mircea.Markus@jboss.com * @since 4.1 */ @Immutable public class OperationsFactory implements HotRodConstants { private final ThreadLocal<Integer> flagsMap = new ThreadLocal<>(); private final TransportFactory transportFactory; private final byte[] cacheNameBytes; private final AtomicInteger topologyId; private final boolean forceReturnValue; private final Codec codec; private final ClientListenerNotifier listenerNotifier; private final String cacheName; private final ExecutorService executorService; private final ClientIntelligence clientIntelligence; public OperationsFactory(TransportFactory transportFactory, String cacheName, boolean forceReturnValue, Codec codec, ClientListenerNotifier listenerNotifier, ExecutorService executorService, ClientIntelligence clientIntelligence) { this.transportFactory = transportFactory; this.executorService = executorService; this.cacheNameBytes = RemoteCacheManager.cacheNameBytes(cacheName); this.cacheName = cacheName; this.topologyId = transportFactory != null ? transportFactory.createTopologyId(cacheNameBytes) : new AtomicInteger(-1); this.forceReturnValue = forceReturnValue; this.codec = codec; this.listenerNotifier = listenerNotifier; this.clientIntelligence = clientIntelligence; } public ClientListenerNotifier getListenerNotifier() { return listenerNotifier; } public byte[] getCacheName() { return cacheNameBytes; } public <V> GetOperation<V> newGetKeyOperation(Object key, byte[] keyBytes) { return new GetOperation<>( codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags(), clientIntelligence); } public <K, V> GetAllParallelOperation<K, V> newGetAllOperation(Set<byte[]> keys) { return new GetAllParallelOperation<>(codec, transportFactory, keys, cacheNameBytes, topologyId, flags(), clientIntelligence, executorService); } public <V> RemoveOperation<V> newRemoveOperation(Object key, byte[] keyBytes) { return new RemoveOperation<>( codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags(), clientIntelligence); } public <V> RemoveIfUnmodifiedOperation<V> newRemoveIfUnmodifiedOperation(Object key, byte[] keyBytes, long version) { return new RemoveIfUnmodifiedOperation<>( codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags(), clientIntelligence, version); } public ReplaceIfUnmodifiedOperation newReplaceIfUnmodifiedOperation(Object key, byte[] keyBytes, byte[] value, long lifespan, TimeUnit lifespanTimeUnit, long maxIdle, TimeUnit maxIdleTimeUnit, long version) { return new ReplaceIfUnmodifiedOperation( codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags(lifespan, maxIdle), clientIntelligence, value, lifespan, lifespanTimeUnit, maxIdle, maxIdleTimeUnit, version); } public <V> GetWithVersionOperation<V> newGetWithVersionOperation(Object key, byte[] keyBytes) { return new GetWithVersionOperation<>( codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags(), clientIntelligence); } public <V> GetWithMetadataOperation<V> newGetWithMetadataOperation(Object key, byte[] keyBytes) { return new GetWithMetadataOperation<>( codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags(), clientIntelligence); } public StatsOperation newStatsOperation() { return new StatsOperation( codec, transportFactory, cacheNameBytes, topologyId, flags(), clientIntelligence); } public <V> PutOperation<V> newPutKeyValueOperation(Object key, byte[] keyBytes, byte[] value, long lifespan, TimeUnit lifespanTimeUnit, long maxIdle, TimeUnit maxIdleTimeUnit) { return new PutOperation<>( codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags(lifespan, maxIdle), clientIntelligence, value, lifespan, lifespanTimeUnit, maxIdle, maxIdleTimeUnit); } public PutAllParallelOperation newPutAllOperation(Map<byte[], byte[]> map, long lifespan, TimeUnit lifespanTimeUnit, long maxIdle, TimeUnit maxIdleTimeUnit) { return new PutAllParallelOperation( codec, transportFactory, map, cacheNameBytes, topologyId, flags(lifespan, maxIdle), clientIntelligence, lifespan, lifespanTimeUnit, maxIdle, maxIdleTimeUnit, executorService); } public <V> PutIfAbsentOperation<V> newPutIfAbsentOperation(Object key, byte[] keyBytes, byte[] value, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) { return new PutIfAbsentOperation<>( codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags(lifespan, maxIdleTime), clientIntelligence, value, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit); } public <V> ReplaceOperation<V> newReplaceOperation(Object key, byte[] keyBytes, byte[] values, long lifespan, TimeUnit lifespanTimeUnit, long maxIdle, TimeUnit maxIdleTimeUnit) { return new ReplaceOperation<>( codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags(lifespan, maxIdle), clientIntelligence, values, lifespan, lifespanTimeUnit, maxIdle, maxIdleTimeUnit); } public ContainsKeyOperation newContainsKeyOperation(Object key, byte[] keyBytes) { return new ContainsKeyOperation( codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags(), clientIntelligence); } public ClearOperation newClearOperation() { return new ClearOperation( codec, transportFactory, cacheNameBytes, topologyId, flags(), clientIntelligence); } public <K, V> BulkGetOperation<K, V> newBulkGetOperation(int size) { return new BulkGetOperation( codec, transportFactory, cacheNameBytes, topologyId, flags(), clientIntelligence, size); } public <K> BulkGetKeysOperation<K> newBulkGetKeysOperation(int scope) { return new BulkGetKeysOperation<>( codec, transportFactory, cacheNameBytes, topologyId, flags(), clientIntelligence, scope); } public AddClientListenerOperation newAddClientListenerOperation(Object listener) { return new AddClientListenerOperation(codec, transportFactory, cacheName, topologyId, flags(), clientIntelligence, listenerNotifier, listener, null, null); } public AddClientListenerOperation newAddClientListenerOperation( Object listener, byte[][] filterFactoryParams, byte[][] converterFactoryParams) { return new AddClientListenerOperation(codec, transportFactory, cacheName, topologyId, flags(), clientIntelligence, listenerNotifier, listener, filterFactoryParams, converterFactoryParams); } public RemoveClientListenerOperation newRemoveClientListenerOperation(Object listener) { return new RemoveClientListenerOperation(codec, transportFactory, cacheNameBytes, topologyId, flags(), clientIntelligence, listenerNotifier, listener); } /** * Construct a ping request directed to a particular node. * * @param transport represents the node to which the operation is directed * @return a ping operation for a particular node */ public PingOperation newPingOperation(Transport transport) { return new PingOperation(codec, topologyId, clientIntelligence, transport, cacheNameBytes); } /** * Construct a fault tolerant ping request. This operation should be capable * to deal with nodes being down, so it will find the first node successful * node to respond to the ping. * * @return a ping operation for the cluster */ public FaultTolerantPingOperation newFaultTolerantPingOperation() { return new FaultTolerantPingOperation( codec, transportFactory, cacheNameBytes, topologyId, flags(), clientIntelligence); } public QueryOperation newQueryOperation(RemoteQuery remoteQuery) { return new QueryOperation( codec, transportFactory, cacheNameBytes, topologyId, flags(), clientIntelligence, remoteQuery); } public SizeOperation newSizeOperation() { return new SizeOperation(codec, transportFactory, cacheNameBytes, topologyId, flags(), clientIntelligence); } public <T> ExecuteOperation<T> newExecuteOperation(String taskName, Map<String, byte[]> marshalledParams) { return new ExecuteOperation<>(codec, transportFactory, cacheNameBytes, topologyId, flags(), clientIntelligence, taskName, marshalledParams); } private int flags(long lifespan, long maxIdle) { int intFlags = flags(); if (lifespan == 0) { intFlags |= Flag.DEFAULT_LIFESPAN.getFlagInt(); } if (maxIdle == 0) { intFlags |= Flag.DEFAULT_MAXIDLE.getFlagInt(); } return intFlags; } public int flags() { Integer threadLocalFlags = this.flagsMap.get(); this.flagsMap.remove(); int intFlags = 0; if (threadLocalFlags != null) { intFlags |= threadLocalFlags.intValue(); } if (forceReturnValue) { intFlags |= Flag.FORCE_RETURN_VALUE.getFlagInt(); } return intFlags; } public void setFlags(Flag[] flags) { int intFlags = 0; for(Flag flag : flags) intFlags |= flag.getFlagInt(); this.flagsMap.set(intFlags); } public void setFlags(int intFlags) { this.flagsMap.set(intFlags); } public boolean hasFlag(Flag flag) { Integer threadLocalFlags = this.flagsMap.get(); return threadLocalFlags != null && (threadLocalFlags & flag.getFlagInt()) != 0; } public CacheTopologyInfo getCacheTopologyInfo() { return transportFactory.getCacheTopologyInfo(cacheNameBytes); } public IterationStartOperation newIterationStartOperation(String filterConverterFactory, byte[][] filterParameters, Set<Integer> segments, int batchSize, boolean metadata) { return new IterationStartOperation(codec, flags(), clientIntelligence, cacheNameBytes, topologyId, filterConverterFactory, filterParameters, segments, batchSize, transportFactory, metadata); } public IterationEndOperation newIterationEndOperation(String iterationId, Transport transport) { return new IterationEndOperation(codec, flags(), clientIntelligence, cacheNameBytes, topologyId, iterationId, transportFactory, transport); } public <K, V> IterationNextOperation newIterationNextOperation(String iterationId, Transport transport, KeyTracker segmentKeyTracker) { return new IterationNextOperation(codec, flags(), clientIntelligence, cacheNameBytes, topologyId, iterationId, transport, segmentKeyTracker); } public <K> GetStreamOperation newGetStreamOperation(K key, byte[] keyBytes, int offset) { return new GetStreamOperation(codec, transportFactory, key, keyBytes, offset, cacheNameBytes, topologyId, flags(), clientIntelligence); } public <K> PutStreamOperation newPutStreamOperation(K key, byte[] keyBytes, long version, long lifespan, TimeUnit lifespanUnit, long maxIdle, TimeUnit maxIdleUnit) { return new PutStreamOperation(codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags(), clientIntelligence, version, lifespan, lifespanUnit, maxIdle, maxIdleUnit); } public <K> PutStreamOperation newPutStreamOperation(K key, byte[] keyBytes, long lifespan, TimeUnit lifespanUnit, long maxIdle, TimeUnit maxIdleUnit) { return new PutStreamOperation(codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags(), clientIntelligence, PutStreamOperation.VERSION_PUT, lifespan, lifespanUnit, maxIdle, maxIdleUnit); } public <K> PutStreamOperation newPutIfAbsentStreamOperation(K key, byte[] keyBytes, long lifespan, TimeUnit lifespanUnit, long maxIdle, TimeUnit maxIdleUnit) { return new PutStreamOperation(codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags(), clientIntelligence, PutStreamOperation.VERSION_PUT_IF_ABSENT, lifespan, lifespanUnit, maxIdle, maxIdleUnit); } }