package org.infinispan.server.test.client.hotrod;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.infinispan.arquillian.core.InfinispanResource;
import org.infinispan.arquillian.core.RemoteInfinispanServer;
import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.client.hotrod.RemoteCacheManager;
import org.infinispan.client.hotrod.configuration.ConfigurationBuilder;
import org.infinispan.client.hotrod.exceptions.HotRodClientException;
import org.infinispan.client.hotrod.marshall.ProtoStreamMarshaller;
import org.infinispan.commons.marshall.Marshaller;
import org.infinispan.commons.util.CloseableIterator;
import org.infinispan.commons.util.Util;
import org.infinispan.filter.AbstractKeyValueFilterConverter;
import org.infinispan.filter.KeyValueFilterConverter;
import org.infinispan.filter.KeyValueFilterConverterFactory;
import org.infinispan.filter.NamedFactory;
import org.infinispan.filter.ParamKeyValueFilterConverterFactory;
import org.infinispan.metadata.Metadata;
import org.infinispan.protostream.FileDescriptorSource;
import org.infinispan.protostream.SerializationContext;
import org.infinispan.protostream.sampledomain.Address;
import org.infinispan.protostream.sampledomain.User;
import org.infinispan.protostream.sampledomain.marshallers.GenderMarshaller;
import org.infinispan.protostream.sampledomain.marshallers.UserMarshaller;
import org.infinispan.query.remote.client.BaseProtoStreamMarshaller;
import org.infinispan.server.test.category.HotRodSingleNode;
import org.infinispan.server.test.util.RemoteCacheManagerFactory;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.TargetsContainer;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
/**
* Tests for remote iteration using a custom filter with custom classes marshalled with a custom Protobuf based marshaller.
*
* @author gustavonalle
* @since 8.0
*/
@RunWith(Arquillian.class)
@Category(HotRodSingleNode.class)
public class HotRodCustomMarshallerIteratorIT {
private static final String TO_STRING_FILTER_CONVERTER_FACTORY_NAME = "to-string-filter-converter";
private static final String PARAM_FILTER_CONVERTER_FACTORY_NAME = "param-filter-converter";
private static final String CACHE_NAME = "default";
private static RemoteCacheManager remoteCacheManager;
private RemoteCache<Integer, User> remoteCache;
@InfinispanResource("container1")
RemoteInfinispanServer server1;
@Deployment(testable = false, name = "marshallerFilter")
@TargetsContainer("container1")
public static Archive<?> deploy() throws IOException {
return createFilterMarshallerArchive();
}
@Before
public void setup() throws IOException {
RemoteCacheManagerFactory remoteCacheManagerFactory = new RemoteCacheManagerFactory();
ConfigurationBuilder clientBuilder = new ConfigurationBuilder();
clientBuilder.addServer()
.host(server1.getHotrodEndpoint().getInetAddress().getHostName())
.port(server1.getHotrodEndpoint().getPort())
.marshaller(new CustomProtoStreamMarshaller());
remoteCacheManager = remoteCacheManagerFactory.createManager(clientBuilder);
remoteCache = remoteCacheManager.getCache(CACHE_NAME);
}
@AfterClass
public static void release() {
if (remoteCacheManager != null) {
remoteCacheManager.stop();
}
}
private static Archive<?> createFilterMarshallerArchive() throws IOException {
String protoFile = Util.read(HotRodCustomMarshallerIteratorIT.class.getResourceAsStream("/sample_bank_account/bank.proto"));
return ShrinkWrap.create(JavaArchive.class, "filter-marshaller.jar")
// Add custom marshaller classes
.addClasses(CustomProtoStreamMarshaller.class, ProtoStreamMarshaller.class, BaseProtoStreamMarshaller.class)
.addClasses(HotRodClientException.class, UserMarshaller.class, GenderMarshaller.class, User.class, Address.class)
// Add marshaller dependencies
.add(new StringAsset(protoFile), "/sample_bank_account/bank.proto")
.add(new StringAsset("Dependencies: org.infinispan.protostream"), "META-INF/MANIFEST.MF")
// Register marshaller
.addAsServiceProvider(Marshaller.class, CustomProtoStreamMarshaller.class)
// Add custom filterConverter classes
.addClasses(CustomFilterFactory.class, CustomFilterFactory.CustomFilter.class, ParamCustomFilterFactory.class,
ParamCustomFilterFactory.ParamCustomFilter.class)
// Register custom filterConverterFactories
.addAsServiceProviderAndClasses(KeyValueFilterConverterFactory.class, ParamCustomFilterFactory.class, CustomFilterFactory.class);
}
@Test
public void testIteration() {
remoteCache.clear();
for (int i = 0; i < 10; i++) {
User user = new User();
user.setId(i);
user.setName("name" + i);
user.setSurname("surname" + i);
remoteCache.put(i, user);
}
// Filter-less iteration
Map<Object, Object> entryMap = iteratorToMap(remoteCache.retrieveEntries(null, 10));
assertEquals(10, entryMap.size());
assertEquals(((User) entryMap.get(2)).getName(), "name2");
// Iteration with filter
entryMap = iteratorToMap(remoteCache.retrieveEntries(TO_STRING_FILTER_CONVERTER_FACTORY_NAME, 10));
assertEquals(10, entryMap.size());
assertTrue(((String) entryMap.get(2)).startsWith("User{"));
// Iteration with parametrised filter
entryMap = iteratorToMap(remoteCache.retrieveEntries(PARAM_FILTER_CONVERTER_FACTORY_NAME, new Object[]{3}, null, 10));
assertEquals(10, entryMap.size());
assertTrue(entryMap.get(2).equals("Use"));
}
private Map<Object, Object> iteratorToMap(CloseableIterator<Entry<Object, Object>> iterator) {
Map<Object, Object> entryMap = new HashMap<>();
try {
while (iterator.hasNext()) {
Entry<Object, Object> next = iterator.next();
entryMap.put(next.getKey(), next.getValue());
}
} finally {
assert iterator != null;
iterator.close();
}
return entryMap;
}
// Custom filter and marshaller
public static class CustomProtoStreamMarshaller extends ProtoStreamMarshaller {
public CustomProtoStreamMarshaller() throws IOException {
SerializationContext serCtx = getSerializationContext();
serCtx.registerProtoFiles(FileDescriptorSource.fromResources(CustomProtoStreamMarshaller.class.getClassLoader(), "/sample_bank_account/bank.proto"));
serCtx.registerMarshaller(new UserMarshaller());
serCtx.registerMarshaller(new GenderMarshaller());
}
}
@NamedFactory(name = TO_STRING_FILTER_CONVERTER_FACTORY_NAME)
public static class CustomFilterFactory implements KeyValueFilterConverterFactory<Integer, User, String> {
@Override
public KeyValueFilterConverter<Integer, User, String> getFilterConverter() {
return new CustomFilter();
}
public static class CustomFilter extends AbstractKeyValueFilterConverter<Integer, User, String> implements Serializable {
@Override
public String filterAndConvert(Integer key, User value, Metadata metadata) {
return value.toString();
}
}
}
@NamedFactory(name = PARAM_FILTER_CONVERTER_FACTORY_NAME)
public static class ParamCustomFilterFactory implements ParamKeyValueFilterConverterFactory<Integer, User, String> {
@Override
public KeyValueFilterConverter<Integer, User, String> getFilterConverter(Object[] params) {
return new ParamCustomFilter((Integer) params[0]);
}
public static class ParamCustomFilter extends AbstractKeyValueFilterConverter<Integer, User, String> implements Serializable {
private final int maxLength;
public ParamCustomFilter(int maxLength) {
this.maxLength = maxLength;
}
@Override
public String filterAndConvert(Integer key, User value, Metadata metadata) {
return value.toString().substring(0, maxLength);
}
}
}
}