use of org.infinispan.notifications.cachelistener.filter.CacheEventFilter in project infinispan by infinispan.
the class CacheNotifierImpl method registerClusterListeners.
private <C> CompletionStage<Void> registerClusterListeners(List<Address> members, UUID generatedId, Address ourAddress, CacheEventFilter<? super K, ? super V> filter, CacheEventConverter<? super K, ? super V, C> converter, Listener l, Object listener, DataConversion keyDataConversion, DataConversion valueDataConversion, boolean useStorageFormat) {
if (log.isTraceEnabled()) {
log.tracef("Replicating cluster listener to other nodes %s for cluster listener with id %s", members, generatedId);
}
ClusterListenerReplicateCallable<K, V> callable = new ClusterListenerReplicateCallable(cache.wired().getName(), generatedId, ourAddress, filter, converter, l.sync(), findListenerCallbacks(listener), keyDataConversion, valueDataConversion, useStorageFormat);
TriConsumer<Address, Void, Throwable> handleSuspect = (a, ignore, t) -> {
if (t != null && !(t instanceof SuspectException)) {
log.debugf(t, "Address: %s encountered an exception while adding cluster listener", a);
throw new CacheListenerException(t);
}
};
// Send to all nodes but ours
CompletionStage<Void> completionStage = clusterExecutor.filterTargets(a -> !ourAddress.equals(a)).submitConsumer(callable, handleSuspect);
// the listener - unfortunately if there are no nodes it throws a SuspectException, so we ignore that
return completionStage.thenCompose(v -> clusterExecutor.filterTargets(a -> !members.contains(a) && !a.equals(ourAddress)).submitConsumer(callable, handleSuspect).exceptionally(t -> {
// Ignore any suspect exception
if (!(t instanceof SuspectException)) {
throw new CacheListenerException(t);
}
return null;
}));
}
use of org.infinispan.notifications.cachelistener.filter.CacheEventFilter in project infinispan by infinispan.
the class CacheNotifierImpl method convertKey.
private K convertKey(CacheEntryListenerInvocation listenerInvocation, K key) {
if (key == null)
return null;
DataConversion keyDataConversion = listenerInvocation.getKeyDataConversion();
Wrapper wrp = keyDataConversion.getWrapper();
Object unwrappedKey = keyDataConversion.getEncoder().fromStorage(wrp.unwrap(key));
CacheEventFilter filter = listenerInvocation.getFilter();
CacheEventConverter converter = listenerInvocation.getConverter();
if (filter == null && converter == null) {
if (listenerInvocation.useStorageFormat()) {
return (K) unwrappedKey;
}
// If no filter is present, convert to the requested format directly
return (K) keyDataConversion.fromStorage(key);
}
MediaType convertFormat = filter == null ? converter.format() : filter.format();
if (listenerInvocation.useStorageFormat() || convertFormat == null) {
// Filter will be run on the storage format, return the unwrapped key
return (K) unwrappedKey;
}
// Filter has a specific format to run, convert to that format
return (K) encoderRegistry.convert(unwrappedKey, keyDataConversion.getStorageMediaType(), convertFormat);
}
use of org.infinispan.notifications.cachelistener.filter.CacheEventFilter in project infinispan by infinispan.
the class CacheNotifierImpl method addFilteredListenerInternal.
private <C> CompletionStage<Void> addFilteredListenerInternal(Object listener, DataConversion keyDataConversion, DataConversion valueDataConversion, CacheEventFilter<? super K, ? super V> filter, CacheEventConverter<? super K, ? super V, C> converter, Set<Class<? extends Annotation>> filterAnnotations, boolean useStorageFormat) {
final Listener l = testListenerClassValidity(listener.getClass());
final UUID generatedId = Util.threadLocalRandomUUID();
final CacheMode cacheMode = config.clustering().cacheMode();
FilterIndexingServiceProvider indexingProvider = null;
boolean foundMethods = false;
// We use identity for null as this means it was invoked by a non encoder cache
DataConversion keyConversion = keyDataConversion == null ? DataConversion.IDENTITY_KEY : keyDataConversion;
DataConversion valueConversion = valueDataConversion == null ? DataConversion.IDENTITY_VALUE : valueDataConversion;
if (filter instanceof IndexedFilter) {
indexingProvider = findIndexingServiceProvider((IndexedFilter) filter);
if (indexingProvider != null) {
DelegatingCacheInvocationBuilder builder = new DelegatingCacheInvocationBuilder(indexingProvider);
adjustCacheInvocationBuilder(builder, filter, converter, filterAnnotations, l, useStorageFormat, generatedId, keyConversion, valueConversion, null);
foundMethods = validateAndAddFilterListenerInvocations(listener, builder, filterAnnotations);
builder.registerListenerInvocations();
}
}
if (indexingProvider == null) {
CacheInvocationBuilder builder = new CacheInvocationBuilder();
adjustCacheInvocationBuilder(builder, filter, converter, filterAnnotations, l, useStorageFormat, generatedId, keyConversion, valueConversion, null);
foundMethods = validateAndAddFilterListenerInvocations(listener, builder, filterAnnotations);
}
CompletionStage<Void> stage = CompletableFutures.completedNull();
if (foundMethods && l.clustered()) {
if (l.observation() == Listener.Observation.PRE) {
throw CONTAINER.clusterListenerRegisteredWithOnlyPreEvents(listener.getClass());
} else if (cacheMode.isInvalidation()) {
throw new UnsupportedOperationException("Cluster listeners cannot be used with Invalidation Caches!");
} else if (clusterListenerOnPrimaryOnly()) {
clusterListenerIDs.put(listener, generatedId);
// This way we only retrieve members of the cache itself
Address ourAddress = rpcManager.getAddress();
List<Address> members = rpcManager.getMembers();
// If we are the only member don't even worry about sending listeners
if (members != null && members.size() > 1) {
stage = registerClusterListeners(members, generatedId, ourAddress, filter, converter, l, listener, keyDataConversion, valueDataConversion, useStorageFormat);
}
}
}
// If we have a segment listener handler, it means we have to do initial state
QueueingSegmentListener<K, V, ? extends Event<K, V>> handler = segmentHandler.remove(generatedId);
if (handler != null) {
if (log.isTraceEnabled()) {
log.tracef("Listener %s requests initial state for cache", generatedId);
}
Collection<IntermediateOperation<?, ?, ?, ?>> intermediateOperations = new ArrayList<>();
MediaType storage = valueConversion.getStorageMediaType();
MediaType keyReq = keyConversion.getRequestMediaType();
MediaType valueReq = valueConversion.getRequestMediaType();
AdvancedCache advancedCache = cache.running();
DataConversion chainedKeyDataConversion = advancedCache.getKeyDataConversion();
DataConversion chainedValueDataConversion = advancedCache.getValueDataConversion();
if (keyReq != null && valueReq != null) {
chainedKeyDataConversion = chainedKeyDataConversion.withRequestMediaType(keyReq);
chainedValueDataConversion = chainedValueDataConversion.withRequestMediaType(valueReq);
}
boolean hasFilter = false;
MediaType filterMediaType = null;
if (filter != null) {
hasFilter = true;
filterMediaType = useStorageFormat ? null : filter.format();
if (filterMediaType == null) {
// iterate in the storage format
chainedKeyDataConversion = chainedKeyDataConversion.withRequestMediaType(storage);
chainedValueDataConversion = chainedValueDataConversion.withRequestMediaType(storage);
} else {
// iterate in the filter format
chainedKeyDataConversion = chainedKeyDataConversion.withRequestMediaType(filterMediaType);
chainedValueDataConversion = chainedValueDataConversion.withRequestMediaType(filterMediaType);
}
}
if (converter != null) {
hasFilter = true;
filterMediaType = useStorageFormat ? null : converter.format();
if (filterMediaType == null) {
// iterate in the storage format
chainedKeyDataConversion = chainedKeyDataConversion.withRequestMediaType(storage);
chainedValueDataConversion = chainedValueDataConversion.withRequestMediaType(storage);
} else {
// iterate in the filter format
chainedKeyDataConversion = chainedKeyDataConversion.withRequestMediaType(filterMediaType);
chainedValueDataConversion = chainedValueDataConversion.withRequestMediaType(filterMediaType);
}
}
if (!Objects.equals(chainedKeyDataConversion, keyDataConversion) || !Objects.equals(chainedValueDataConversion, valueDataConversion)) {
componentRegistry.wireDependencies(chainedKeyDataConversion, false);
componentRegistry.wireDependencies(chainedValueDataConversion, false);
intermediateOperations.add(new MapOperation<>(EncoderEntryMapper.newCacheEntryMapper(chainedKeyDataConversion, chainedValueDataConversion, entryFactory)));
}
if (filter instanceof CacheEventFilterConverter && (filter == converter || converter == null)) {
intermediateOperations.add(new MapOperation<>(CacheFilters.converterToFunction(new CacheEventFilterConverterAsKeyValueFilterConverter<>((CacheEventFilterConverter<?, ?, ?>) filter))));
intermediateOperations.add(new FilterOperation<>(CacheFilters.notNullCacheEntryPredicate()));
} else {
if (filter != null) {
intermediateOperations.add(new FilterOperation<>(CacheFilters.predicate(new CacheEventFilterAsKeyValueFilter<>(filter))));
}
if (converter != null) {
intermediateOperations.add(new MapOperation<>(CacheFilters.function(new CacheEventConverterAsConverter<>(converter))));
}
}
boolean finalHasFilter = hasFilter;
MediaType finalFilterMediaType = filterMediaType;
Function<Object, Object> kc = k -> {
if (!finalHasFilter)
return k;
if (finalFilterMediaType == null || useStorageFormat || keyReq == null) {
return keyDataConversion.fromStorage(k);
}
return encoderRegistry.convert(k, finalFilterMediaType, keyDataConversion.getRequestMediaType());
};
Function<Object, Object> kv = v -> {
if (!finalHasFilter)
return v;
if (finalFilterMediaType == null || useStorageFormat || valueReq == null) {
return valueConversion.fromStorage(v);
}
return encoderRegistry.convert(v, finalFilterMediaType, valueConversion.getRequestMediaType());
};
stage = handlePublisher(stage, intermediateOperations, handler, generatedId, l, kc, kv);
}
return stage;
}
use of org.infinispan.notifications.cachelistener.filter.CacheEventFilter in project infinispan by infinispan.
the class BaseCacheNotifierImplInitialTransferTest method testFilterConverterUnusedDuringIteration.
private void testFilterConverterUnusedDuringIteration(final StateListener<String, String> listener) {
final List<CacheEntry<String, String>> initialValues = new ArrayList<CacheEntry<String, String>>(10);
for (int i = 0; i < 10; i++) {
String key = "key-" + i;
String value = "value-" + i;
initialValues.add(new ImmortalCacheEntry(key, value));
}
// Note we don't actually use the filter/converter to retrieve values since it is being mocked, thus we can assert
// the filter/converter are not used by us
when(mockPublisherManager.entryPublisher(any(), any(), any(), anyLong(), any(), anyInt(), any())).thenReturn(wrapCompletionPublisher(Flowable.fromIterable(initialValues)));
CacheEventFilter filter = mock(CacheEventFilter.class, withSettings().serializable());
CacheEventConverter converter = mock(CacheEventConverter.class, withSettings().serializable());
n.addListener(listener, filter, converter);
verifyEvents(isClustered(listener), listener, initialValues);
verify(filter, never()).accept(any(), any(), any(Metadata.class), any(), any(Metadata.class), any(EventType.class));
verify(converter, never()).convert(any(), any(), any(Metadata.class), any(), any(Metadata.class), any(EventType.class));
}
use of org.infinispan.notifications.cachelistener.filter.CacheEventFilter in project infinispan by infinispan.
the class BaseCacheNotifierImplInitialTransferTest method testMetadataAvailable.
public void testMetadataAvailable() {
final List<CacheEntry<String, String>> initialValues = new ArrayList<>(10);
for (int i = 0; i < 10; i++) {
String key = "key-" + i;
String value = "value-" + i;
initialValues.add(new TransientMortalCacheEntry(key, value, i, -1, System.currentTimeMillis()));
}
// Note we don't actually use the filter/converter to retrieve values since it is being mocked, thus we can assert
// the filter/converter are not used by us
when(mockPublisherManager.entryPublisher(any(), any(), any(), anyLong(), any(), anyInt(), any())).thenReturn(wrapCompletionPublisher(Flowable.fromIterable(initialValues)));
CacheEventFilter filter = mock(CacheEventFilter.class, withSettings().serializable());
CacheEventConverter converter = mock(CacheEventConverter.class, withSettings().serializable());
StateListener<String, String> listener = new StateListenerClustered();
n.addListener(listener, filter, converter);
verifyEvents(isClustered(listener), listener, initialValues);
for (CacheEntryEvent<String, String> event : listener.events) {
String key = event.getKey();
Metadata metadata = event.getMetadata();
assertNotNull(metadata);
assertEquals(metadata.lifespan(), -1);
assertEquals(metadata.maxIdle(), Long.parseLong(key.substring(4)));
}
}
Aggregations