package org.infinispan.server.test.query; import static org.infinispan.query.dsl.Expression.param; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import org.infinispan.arquillian.core.InfinispanResource; import org.infinispan.arquillian.core.RemoteInfinispanServer; import org.infinispan.client.hotrod.Search; import org.infinispan.client.hotrod.annotation.ClientCacheEntryCreated; import org.infinispan.client.hotrod.annotation.ClientCacheEntryModified; import org.infinispan.client.hotrod.annotation.ClientCacheEntryRemoved; import org.infinispan.client.hotrod.annotation.ClientListener; import org.infinispan.client.hotrod.event.ClientCacheEntryCustomEvent; import org.infinispan.client.hotrod.event.ClientCacheEntryRemovedEvent; import org.infinispan.client.hotrod.event.ClientEvents; import org.infinispan.client.hotrod.filter.Filters; import org.infinispan.client.hotrod.marshall.ProtoStreamMarshaller; import org.infinispan.protostream.ProtobufUtil; import org.infinispan.protostream.SerializationContext; import org.infinispan.protostream.sampledomain.Address; import org.infinispan.protostream.sampledomain.User; import org.infinispan.query.dsl.Query; import org.infinispan.query.dsl.QueryFactory; import org.infinispan.query.remote.client.FilterResult; import org.infinispan.server.test.category.Queries; import org.infinispan.util.logging.Log; import org.infinispan.util.logging.LogFactory; import org.jboss.arquillian.junit.Arquillian; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; /** * Basic test for query DSL based remote event filters. * * @author anistor@redhat.com * @since 8.1 */ @Category(Queries.class) @RunWith(Arquillian.class) public class RemoteListenerWithDslFilterIT extends RemoteQueryBaseIT { @InfinispanResource("remote-query-1") protected RemoteInfinispanServer server; public RemoteListenerWithDslFilterIT() { super("clustered", "localtestcache"); } @Override protected RemoteInfinispanServer getServer() { return server; } @Test public void testEventFilter() throws Exception { User user1 = new User(); user1.setId(1); user1.setName("John"); user1.setSurname("Doe"); user1.setGender(User.Gender.MALE); user1.setAge(22); user1.setAccountIds(new HashSet<>(Arrays.asList(1, 2))); user1.setNotes("Lorem ipsum dolor sit amet"); Address address1 = new Address(); address1.setStreet("Main Street"); address1.setPostCode("X1234"); user1.setAddresses(Collections.singletonList(address1)); User user2 = new User(); user2.setId(2); user2.setName("Spider"); user2.setSurname("Man"); user2.setGender(User.Gender.MALE); user2.setAge(32); user2.setAccountIds(Collections.singleton(3)); Address address2 = new Address(); address2.setStreet("Old Street"); address2.setPostCode("Y12"); Address address3 = new Address(); address3.setStreet("Bond Street"); address3.setPostCode("ZZ"); user2.setAddresses(Arrays.asList(address2, address3)); User user3 = new User(); user3.setId(3); user3.setName("Spider"); user3.setSurname("Woman"); user3.setGender(User.Gender.FEMALE); user3.setAge(31); user3.setAccountIds(Collections.emptySet()); remoteCache.put(user1.getId(), user1); remoteCache.put(user2.getId(), user2); remoteCache.put(user3.getId(), user3); assertEquals(3, remoteCache.size()); SerializationContext serCtx = ProtoStreamMarshaller.getSerializationContext(remoteCache.getRemoteCacheManager()); QueryFactory qf = Search.getQueryFactory(remoteCache); Query query = qf.from(User.class) .having("age").lte(param("ageParam")) .select("age") .build() .setParameter("ageParam", 32); ClientEntryListener listener = new ClientEntryListener(serCtx); ClientEvents.addClientQueryListener(remoteCache, listener, query); expectElementsInQueue(listener.createEvents, 3); user3.setAge(40); remoteCache.put(user1.getId(), user1); remoteCache.put(user2.getId(), user2); remoteCache.put(user3.getId(), user3); assertEquals(3, remoteCache.size()); expectElementsInQueue(listener.modifyEvents, 2); remoteCache.removeClientListener(listener); } private void expectElementsInQueue(BlockingQueue<?> queue, int numElements) { for (int i = 0; i < numElements; i++) { try { Object e = queue.poll(5, TimeUnit.SECONDS); assertNotNull("Queue was empty!", e); } catch (InterruptedException e) { throw new AssertionError("Interrupted while waiting for condition", e); } } try { // no more elements expected here Object e = queue.poll(5, TimeUnit.SECONDS); assertNull("No more elements expected in queue!", e); } catch (InterruptedException e) { throw new AssertionError("Interrupted while waiting for condition", e); } } @ClientListener(filterFactoryName = Filters.QUERY_DSL_FILTER_FACTORY_NAME, converterFactoryName = Filters.QUERY_DSL_FILTER_FACTORY_NAME, useRawData = true, includeCurrentState = true) public static class ClientEntryListener { private final Log log = LogFactory.getLog(getClass()); public final BlockingQueue<FilterResult> createEvents = new LinkedBlockingQueue<>(); public final BlockingQueue<FilterResult> modifyEvents = new LinkedBlockingQueue<>(); private final SerializationContext serializationContext; public ClientEntryListener(SerializationContext serializationContext) { this.serializationContext = serializationContext; } @ClientCacheEntryCreated public void handleClientCacheEntryCreatedEvent(ClientCacheEntryCustomEvent event) throws IOException { FilterResult r = ProtobufUtil.fromWrappedByteArray(serializationContext, (byte[]) event.getEventData()); createEvents.add(r); log.debugf("handleClientCacheEntryCreatedEvent instance=%s projection=%s sortProjection=%s\n", r.getInstance(), r.getProjection() == null ? null : Arrays.asList(r.getProjection()), r.getSortProjection() == null ? null : Arrays.asList(r.getSortProjection())); } @ClientCacheEntryModified public void handleClientCacheEntryModifiedEvent(ClientCacheEntryCustomEvent event) throws IOException { FilterResult r = ProtobufUtil.fromWrappedByteArray(serializationContext, (byte[]) event.getEventData()); modifyEvents.add(r); log.debugf("handleClientCacheEntryModifiedEvent instance=%s projection=%s sortProjection=%s\n", r.getInstance(), r.getProjection() == null ? null : Arrays.asList(r.getProjection()), r.getSortProjection() == null ? null : Arrays.asList(r.getSortProjection())); } @ClientCacheEntryRemoved public void handleClientCacheEntryRemovedEvent(ClientCacheEntryRemovedEvent event) { log.debugf("handleClientCacheEntryRemovedEvent %s\n", event.getKey()); } } }