Category Archives: Hazelcast

DIY Annotations

Since Java 5 there have been annotations in Java.  I wanted to make my own annotation just to see what it takes.  However, I found out that they were just interfaces.

There is the rub

Interfaces have no teeth behind them.  Some piece of code has to implement it.  I figured this is where the rubber hits the road and I really find a way to do this.

To start, I would need a purpose

I picked one recent hot topic, caching.  I didn’t want to implement JSR 109(JCache) but I didn’t want to do the typical “Hello World” either.  I picked implementing two annotations, one without any parameters and one with a parameter.  I also needed a caching provider.  Might as well bring a real caching library to the mix if I am going to do this.  It also follows my design philosophy to use products/libraries to reach  a goal instead of home spinning everything.  After careful consideration, I chose hazelcast to be my caching engine.  It is the fastest on the market and it is free.

More Decisions

After my purpose was chosen, I still needed to find out how to put teeth behind them.  After some digging around I found two methods:

Reflection

Almost every time I have used reflection, I have felt sorry for making such a clunky piece of code.  Plus, to do it the way I would like, I would have to create my own framework.  Sounds like a lot of work for two annotations.

Aspect Oriented Programming(AOP)

This was a perfect fit for what I wanted to do.  AOP deals in reducing boilerplate code into a single place.  This would be convenient and dovetails into caching because caching breaks down into the following steps:

  1. Check to see if this situation was done before.
  2. If so:
    1. retrieve the stored result
  3. if not:
    1. run the function
    2. store the result
  4. return the result

That maybe an oversimplification but in a nut shell it is true.  Like in all things, the devil is in the details.

Meanwhile, Back at the AOP Ranch

While I knew AOP was the place for me, I did not know much about it.  I found that Spring has an AOP library and that a well known library is AspectJ.  AspectJ is unfamiliar to me and needs a runtime engine to work.  I am much more familiar with Spring so I picked it.  As I dug into Spring’s AOP, I found that I had to delve into AspectJ’s annotations so I was stuck with AspectJ in some form or fashion anyway.

New Concepts, New Vocabulary

Writing aspects aren’t like writing objects.  They are objects but not really so, of course, a new set of terms are needed.  The ones I used are in the Spring AOP Documentation

I really needed to read the page a couple of times to grasp what is being said.  One is highly recommended to do the same or the rest of the post is going to sound like gibberish.

What Makes the Pointcut and How to Advise it

The pointcut design was easy since I was only interested in methods that had the annotation.  The advise it needed was the around advice because I needed to be able to circumvent calling the method if there was a matching call already done.

Finally the Code

Maven Pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.darylmathison</groupId>
    <artifactId>annotation-implementation</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <spring.version>4.2.4.RELEASE</spring.version>
    </properties>

    <description>
        This project is an example of how to implement an annotation via Spring AOP.
    </description>

    <scm>
        <url>https://github.com/darylmathison/annotation-implementation-example.git</url>
        <connection>scm:git:https://github.com/darylmathison/annotation-implementation-example.git</connection>
        <developerConnection>scm:git:git@github.com:darylmathison/annotation-implementation-example.git</developerConnection>
    </scm>

    <issueManagement>
        <system>GitHub</system>
        <url>https://github.com/darylmathison/annotation-implementation-example/issues</url>
    </issueManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.8</version>
        </dependency>

        <dependency>
            <groupId>com.hazelcast</groupId>
            <artifactId>hazelcast</artifactId>
            <version>3.6</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <reporting>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-project-info-reports-plugin</artifactId>
                <version>2.7</version>
                <reportSets>
                    <reportSet>
                        <reports>
                            <report>dependencies</report>
                            <report>index</report>
                            <report>project-team</report>
                            <report>issue-tracking</report>
                            <report>scm</report>
                        </reports>
                    </reportSet>
                </reportSets>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-report-plugin</artifactId>
                <version>2.18.1</version>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-javadoc-plugin</artifactId>
                <version>2.10.3</version>
                <reportSets>
                    <reportSet>
                        <reports>
                            <report>javadoc</report>
                            <report>test-javadoc</report>
                        </reports>
                    </reportSet>
                </reportSets>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jxr-plugin</artifactId>
                <version>2.5</version>
                <configuration>
                    <linkJavadoc>true</linkJavadoc>
                </configuration>
                <reportSets>
                    <reportSet>
                        <reports>
                            <report>jxr</report>
                            <report>test-jxr</report>
                        </reports>
                    </reportSet>
                </reportSets>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-changelog-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <type>range</type>
                    <range>90</range>
                </configuration>
            </plugin>
        </plugins>
    </reporting>
</project>

The Annotations

CacheMe

Cute name for a caching annotation, right?

package com.darylmathison.ai.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Created by Daryl on 2/19/2016.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface CacheMe {
}

CacheMeNow

package com.darylmathison.ai.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Created by Daryl on 2/19/2016.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface CacheMeNow {
    String key();
}

Spring Configuration

I decided to use Java based configuration instead of XML like I normally use for a change of pace. The EnableAspectJAutoProxy annotation is key to getting Spring AOP to start working. I was beside myself until I read this about this little jewel. Sometimes it is the easiest thing that burns a day.

AppConfig

package com.darylmathison.ai.config;

import com.darylmathison.ai.cache.CacheAspect;
import com.darylmathison.ai.service.FibonacciService;
import com.darylmathison.ai.service.FibonacciServiceImpl;
import com.hazelcast.config.Config;
import com.hazelcast.config.EvictionPolicy;
import com.hazelcast.config.MapConfig;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by Daryl on 2/20/2016.
 */
@Configuration
@ComponentScan(basePackages = "com.darylmathison.ai")
@EnableAspectJAutoProxy
public class AppConfig {

    @Bean
    public Map<String, Object> cache() {
        Config config = new Config();
        MapConfig mapConfig = new MapConfig();
        mapConfig.setEvictionPercentage(50);
        mapConfig.setEvictionPolicy(EvictionPolicy.LFU);
        mapConfig.setTimeToLiveSeconds(300);
        Map<String, MapConfig> mapConfigMap = new HashMap<>();
        mapConfigMap.put("cache", mapConfig);
        config.setMapConfigs(mapConfigMap);

        HazelcastInstance instance = Hazelcast.newHazelcastInstance(config);
        return instance.getMap("cache");
    }

    @Bean
    public FibonacciService fibonacci() {
        return new FibonacciServiceImpl();
    }

    @Bean
    public CacheAspect cacheAspect() {
        return new CacheAspect();
    }
}

Service Code

Classic Spring based design needs a service right? Because Spring uses proxies to implement their AOP, it is highly advised to define an interface for the annotated class to implement.

FibonacciService

package com.darylmathison.ai.service;

/**
 * Created by Daryl on 2/20/2016.
 */
public interface FibonacciService {

    long calculate(int rounds);

    long calculateWithKey(int rounds);
}

FibonacciServiceImpl

package com.darylmathison.ai.service;


import com.darylmathison.ai.annotation.CacheMe;
import com.darylmathison.ai.annotation.CacheMeNow;

/**
 * Created by Daryl on 2/20/2016.
 */
public class FibonacciServiceImpl implements FibonacciService {

    @Override
    @CacheMe
    public long calculate(int rounds) {
        return sharedCalculate(rounds);
    }

    @Override
    @CacheMeNow(key = "now")
    public long calculateWithKey(int rounds) {
        return sharedCalculate(rounds);
    }

    private static long sharedCalculate(int rounds) {
        long[] lastTwo = new long[] {1, 1};

        for(int i = 0; i < rounds; i++) {
            long last = lastTwo[1];
            lastTwo[1] = lastTwo[0] + lastTwo[1];
            lastTwo[0] = last;
        }

        return lastTwo[1];
    }
}

AOP Stuff

This is heart of the annotation implementation. Everything else is support to do the source that follows.

SystemArch

According to Spring documentation, centralizing the pointcut definitions are a good idea.

package com.darylmathison.ai.cache;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

/**
 * Created by Daryl on 2/20/2016.
 */
@Aspect
public class SystemArch {

    @Pointcut("@annotation(com.darylmathison.ai.annotation.CacheMe)")
    public void cacheMeCut() {

    }

    @Pointcut("@annotation(com.darylmathison.ai.annotation.CacheMeNow)")
    public void cacheMeNowCut() {

    }
}

CacheAspect

The Around annotations take the full method names of the pointcut class to define what to advise. The advice for the CacheMeNow annotation includes an extra condition so the annotation can be defined so the key parameter can be read. There is a design bug in CacheMeNow that is revealed in the test code.

package com.darylmathison.ai.cache;

import com.darylmathison.ai.annotation.CacheMeNow;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Map;

/**
 * Created by Daryl on 2/20/2016.
 */
@Aspect
public class CacheAspect {

    @Autowired
    private Map<String, Object> cache;

    @Around("com.darylmathison.ai.cache.SystemArch.cacheMeCut()")
    public Object simpleCache(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        StringBuffer keyBuffer = new StringBuffer();
        for(Object o: proceedingJoinPoint.getArgs()) {
            keyBuffer.append(o.hashCode());
        }
        String key = keyBuffer.toString();
        Object ret = cache.get(key);
        if(ret == null) {
            ret = proceedingJoinPoint.proceed();
            cache.put(key, ret);
        }
        return ret;
    }

    @Around("com.darylmathison.ai.cache.SystemArch.cacheMeNowCut() && @annotation(cacheMeNow)")
    public Object simpleCacheWithParam(ProceedingJoinPoint proceedingJoinPoint, CacheMeNow cacheMeNow) throws Throwable {
        Object ret = cache.get(cacheMeNow.key());
        if(ret == null) {
            ret = proceedingJoinPoint.proceed();
            cache.put(cacheMeNow.key(), ret);
        }
        return ret;
    }
}

Test Code

Driver code to show that the annotations do cause caching.

FibonacciTest

package com.darylmathison.ai.service;

import com.darylmathison.ai.config.AppConfig;
import org.junit.Assert;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
 * Created by Daryl on 2/20/2016.
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {AppConfig.class})
public class FibonacciTest {

    private static final int ROUNDS = 12;
    private static final long ANSWER = 377;

    @Autowired
    private FibonacciService fibonacci;

    @org.junit.Test
    public void testCalculate() throws Exception {
        long start = System.currentTimeMillis();
        Assert.assertEquals(ANSWER, fibonacci.calculate(ROUNDS));
        long middle = System.currentTimeMillis();
        Assert.assertEquals(ANSWER, fibonacci.calculate(ROUNDS));
        long end = System.currentTimeMillis();
        Assert.assertTrue((end - middle) < (middle - start));
    }

    @org.junit.Test
    public void testCalculateWithKey() throws Exception {
        Assert.assertEquals(ANSWER, fibonacci.calculateWithKey(ROUNDS));
        // This test should not pass
        Assert.assertEquals(ANSWER, fibonacci.calculateWithKey(13));
    }
}

Conclusion

Annotations do not have to be hard to implement. Using AOP programming, I was able to implement two annotations with little coding.  The code can be found here.

Advertisement

Beginner’s Guide to Hazelcast Part 7

This is a continuation of a series explaining how to use Hazelcast.  If one has not read the other six posts, please go to the Table Of Contents and read the other posts.

A Different Breed of Map

Hazelcast’s MultiMap breaks the normal mold of using java.util.Collection interfaces that have been used in former posts.  In fact, the concept of a MultiMap breaks the idea of a map altogether in my opinion.  While normal maps associate one key to one value, MultiMaps can map multiple values to the same key.  That is a really important concept, multiple values to the same key.  Values can be stored in two different collections, set or list.  These collections act like the collections of java.util.Collections library.

Is it Safe?

MultiMaps have a method to their madness.  In a normal map, multiple values per key can be stored but it has to be done manually.  That means getting a collection out of storage, doing any changes and then putting the collection back into storage.  This can be problematic for thread safety because the prior steps need to be done atomically or there is the possibility of stale or inconsistent data being read by other threads.  MultiMaps help with this problem by offering the following services:

  • One can add a value via a single put operation.
  • One can lock an entry by the key.  This is key (pun intended) because this means the developer does not have to keep track of a separate lock per entry.

Example

This example is a little different because I used Maven’s failsafe plugin as the main engine when running the examples.  Yes, I wrote two examples because I wanted to show two different ways of using a MultiMap.  One way is every thread getting their own playground, being assigned an unique key, or being assigned a shared playground or all of the threads sharing the same key.  This also is an example of how Hazelcast’s IdGenerator can be used as a method of creating thread safety in an application.

Pom File

Remember, this example code takes advantage of Apache’s Failsafe Maven plugin.  The failsafe plugin aids in automated integration tests by not killing the build at the first failure.  It is a fork of the surefire plugin.  I also have been experimenting with the reporting that is available with Maven.  Type “mvn site” at the command line and it will generate a website.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0>

    <groupId>com.darylmathison>
    <artifactId>hazelcast-multimap-example>
    <version>1.0-SNAPSHOT>
    <description>Examples of using Hazelcast Multimap>
    <developers>
        <developer>
            <name>Daryl Mathison>
            <id>dmathison>
            <roles>
                <role>developer>
            >
        >
    >

    <scm>
        <connection>scm:git:https://github.com/darylmathison/hazelcast-multimap-example.git>
        <url>https://github.com/darylmathison/hazelcast-multimap-example>
    >

    <properties>
        <maven.compiler.source>1.8>
        <maven.compiler.target>1.8>
        <project.build.sourceEncoding>UTF-8>
    >

    <dependencies>
        <dependency>
            <groupId>com.hazelcast>
            <artifactId>hazelcast>
            <version>3.4.2>
        >
        <dependency>
            <groupId>junit>
            <artifactId>junit>
            <version>4.12>
            <scope>test>
        >
    >

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins>
                <artifactId>maven-failsafe-plugin>
                <version>2.18.1>
                <executions>
                    <execution>
                        <goals>
                            <goal>integration-test>
                            <goal>verify>
                        >
                    >
                >
            >
        >
    >

    <reporting>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins>
                <artifactId>maven-project-info-reports-plugin>
                <version>2.7>
                <reportSets>
                    <reportSet>
                        <reports>
                            <report>dependencies>
                            <report>index>
                            <report>project-team>
                            <report>scm>
                        >
                    >
                >
            >
            <plugin>
                <groupId>org.apache.maven.plugins>
                <artifactId>maven-javadoc-plugin>
                <version>2.10.3>
                <reportSets>
                    <reportSet>
                        <reports>
                            <report>javadoc>
                            <report>test-javadoc>
                        >
                    >
                >
            >
            <plugin>
                <groupId>org.apache.maven.plugins>
                <artifactId>maven-surefire-report-plugin>
                <version>2.18.1>
            >
            <plugin>
                <groupId>org.apache.maven.plugins>
                <artifactId>maven-jxr-plugin>
                <version>2.5>
                <configuration>
                    <linkJavadoc>true>
                >
                <reportSets>
                    <reportSet>
                        <reports>
                            <report>jxr>
                            <report>test-jxr>
                        >
                    >
                >
            >
        >
    >
>

MultimapAccessThread

This is the base class for each of the access type threads.

package com.darylmathison.multimap;

import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.HazelcastInstanceAware;
import com.hazelcast.core.MultiMap;

import java.io.Serializable;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Abstract class to access MultiMap.
 */
public abstract class MultiMapAccessThread implements Serializable, Runnable, HazelcastInstanceAware {
    protected com.hazelcast.core.HazelcastInstance instance;
    protected MultiMap<Long, Long> map;
    protected String mapName;
    protected Lock l = new ReentrantLock();

    public void setHazelcastInstance(HazelcastInstance instance) {
        l.lock();
        try {
            this.instance = instance;
            if (mapName != null && !mapName.isEmpty()) {
                map = instance.getMultiMap(mapName);
            }
        } finally {
            l.unlock();
        }
    }

    public String getMapName() {
        return mapName;
    }

    public void setMapName(String mapName) {
        l.lock();
        try {
            this.mapName = mapName;
        } finally {
            l.unlock();
        }
    }
}

IdMultiMapAccessThread

package com.darylmathison.multimap;

/**
 * This thread accesses only one "slot" in a multimap.
 */
public class IdMultiMapAccessThread extends MultiMapAccessThread {
    private Long id;

    @Override
    public void run() {
        l.lock();
        boolean shouldRun = (map != null && id != null);
        l.unlock();
        if(shouldRun) {
            for (long i = 0; i < 10; i++) {
                map.put(id, i);
            }
        }
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}

GroupMultiMapAccessThread

package com.darylmathison.multimap;

/**
 * Thread designed to share the same "slot" on a MultiMap.
 */
public class GroupMultiMapAccessThread extends MultiMapAccessThread {

    private static final long MAX = 10;

    private Long groupId;

    /**
     * When an object implementing interface Runnable is used
     * to create a thread, starting the thread causes the object's
     * run method to be called in that separately executing
     * thread.
     * 
     * The general contract of the method run is that it may
     * take any action whatsoever.
     *
     * @see Thread#run()
     */
    @Override
    public void run() {
        l.lock();
        boolean shouldRun = (groupId != null && map != null);
        l.unlock();
        if(shouldRun) {
            map.lock(groupId);
            try {
                if (map.get(groupId).isEmpty()) {
                    System.out.println("adding to list");
                    for (long i = 0; i < MAX; i++) {
                        map.put(groupId, i);
                    }
                } else {
                    System.out.println("nothing to add");
                }
            } finally {
                map.unlock(groupId);
            }
        }
    }

    public void setGroupId(Long groupId) {
        l.lock();
        this.groupId = groupId;
        l.unlock();
    }
}

HazelcastInstanceResource

This rule starts up and shuts down the Hazelcast instance needed for running the threads.

package com.darylmathison.multimap.test.rule;

import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.IExecutorService;
import org.junit.rules.ExternalResource;

/**
 * Created by Daryl on 4/27/2015.
 */
public class HazelcastInstanceResource extends ExternalResource {
    public static final String SERVICE_NAME = "Charlotte";
    HazelcastInstance instance;
    IExecutorService service;

    @Override
    protected void before() throws Throwable {
        super.before();
        instance = Hazelcast.newHazelcastInstance();
        service = instance.getExecutorService(SERVICE_NAME);
    }

    @Override
    protected void after() {
        super.after();
        service.shutdown();
        instance.shutdown();
    }

    public HazelcastInstance getInstance() {
        return instance;
    }

    public IExecutorService getService() {
        return service;
    }
}

IdMultiMapAccessIT

Here is an example of using the IdGenerator to create new “playgrounds” or keys for the threads to place data.

package com.darylmathison.multimap;

import com.darylmathison.multimap.test.rule.HazelcastInstanceResource;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.IExecutorService;
import com.hazelcast.core.IdGenerator;
import org.junit.ClassRule;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * Integration test for IdMultiMapAccessThread
 */
public class IdMultiMapAccessThreadIT {

    public static final String MAP_NAME = "idAccessMap";
    public static final String GEN_NAME = "singleAccess";
    public static final int NUM_THREADS = 10;

    @ClassRule
    public static HazelcastInstanceResource hazelcastInstanceResource = new HazelcastInstanceResource();

    @Test
    public void testIdThreads() {
        List threads = generateThreads(hazelcastInstanceResource.getInstance());
        List<Future<?>> futures = new ArrayList<>(NUM_THREADS);
        IExecutorService spinner = hazelcastInstanceResource.getService();
        for(IdMultiMapAccessThread thread: threads) {
            futures.add(spinner.submit(thread));
        }

        for(Future<?> future: futures) {
            try {
                future.get();
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }
    }

    private List generateThreads(HazelcastInstance instance) {
        IdGenerator gen = instance.getIdGenerator(GEN_NAME);
        List threads = new ArrayList<>(NUM_THREADS);
        for(int i = 0; i < NUM_THREADS; i++) {
            IdMultiMapAccessThread thread = new IdMultiMapAccessThread();
            thread.setMapName(MAP_NAME);
            thread.setId(gen.newId());
            threads.add(thread);
        }

        return threads;
    }
}

GroupMultiMapAccessThreadIT

This is an example of using an IdGenerator to create a shared playground or slot.

package com.darylmathison.multimap;

import com.darylmathison.multimap.test.rule.HazelcastInstanceResource;
import com.hazelcast.core.IExecutorService;
import com.hazelcast.core.IdGenerator;
import org.junit.ClassRule;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * GroupMultiMapAccessThread Integration Test
 */
public class GroupMultiMapAccessThreadIT {
    public static final int NUM_THREADS = 10;
    public static final String GEN_NAME = "groupIdGenerator";
    public static final String MAP_NAME = "groupMap";

    @ClassRule
    public static HazelcastInstanceResource hazelcastInstanceResource = new HazelcastInstanceResource();

    @Test
    public void testGroupMultiMapAccessThread() {
        List threads = createThreads();
        IExecutorService service = hazelcastInstanceResource.getService();
        List<Future<?>> futures = new ArrayList<>(NUM_THREADS);
        for(GroupMultiMapAccessThread thread: threads) {
            futures.add(service.submit(thread));
        }

        for(Future<?> future: futures) {
            try {
                future.get();
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }
    }

    private List createThreads() {
        List ret = new ArrayList<>(NUM_THREADS);
        IdGenerator gen = hazelcastInstanceResource.getInstance().getIdGenerator(GEN_NAME);
        Long groupId = gen.newId();
        for(int i = 0; i < NUM_THREADS; i++) {
            GroupMultiMapAccessThread thread = new GroupMultiMapAccessThread();
            thread.setMapName(MAP_NAME);
            thread.setGroupId(groupId);
            ret.add(thread);
        }

        return ret;
    }
}

Conclusion

In this post, Hazelcast’s MultiMap was profiled. It was shown that MultiMaps can store multiple values for a given key. It was also shown how a thread can share the data in a MultiMap or can store data for itself using the IdGenerator as a possible key generator.  The code can be found in GitHub here.

References

http://www.hazelcast.com
http://www.hazelcast.org
https://github.com/hazelcast/hazelcast

Beginner’s Guide to Hazelcast Part 6

This is the sixth post in a series of posts about Hazelcast.  If one has not read the last five, please go to the table of contents post I have created to catch up.

Native Clients

After the last post I decided that I am going to go native.  Yep, I am going to demonstrate Hazelcast’s own Java client.  Java is not the only language native clients come in, C++ and C# flavors are available for the enterprise version.

Why Go Native?

It is a good question.  Native clients can keep one fixed into a product line without chance to escape.  Hazelcast rewards the one going native with the following:

  • The client is part of the cluster.  That means one can create places to stash data and listen for events going on in the cluster.  It also means that all of the tricks that have been discussed in my earlier posts can be used as a client.  This advantage cannot be underestimated.
  • The configuration file is similar.  This means that one doesn’t have to translate from the Hazelcast configuration file to client configuration file.  One can copy the file over and like magic it works.  The less translating one has to do, the less that gets lost.

The Any Client Rule of Thumb

Hazelcast clients are the easiest I have ever had the pleasure to set up and use.

Example

This simple example is a continuation of a theme started by the last post, caching expensive operations.

Pom File

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.darylmathison</groupId>
    <artifactId>HazelcastJavaClient</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <showDeprecation>true</showDeprecation>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.3.2</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>java</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <mainClass>com.darylmathison.hazelcastjavaclient.Main</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>com.hazelcast</groupId>
            <artifactId>hazelcast-client</artifactId>
            <version>3.3.2</version>
        </dependency>
    </dependencies>

</project>

Client

This client becomes part of the cluster creates a IMap named “fibmap”. The fibonacci result is stored in the map if it hasn’t been calculated before. If one runs the client once, the results are stored in fibmap. The second time the client is run, the cached values are displayed.

package com.darylmathison.hazelcastjavaclient;

import com.hazelcast.client.HazelcastClient;
import com.hazelcast.core.HazelcastInstance;
import java.util.Map;

/**
 *
 * @author Daryl
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        HazelcastInstance instance = HazelcastClient.newHazelcastClient();
        Map<Long, Long> cacheMap = instance.getMap("fibmap");
        
        for(long i = 1; i <= 10L; i++) {
            System.out.println("value is " + fibonacci(i, cacheMap));
        }
        instance.shutdown();
    }
    
    private static long fibonacci(long rounds, Map<Long, Long> cacheMap) {
        Long cached = cacheMap.get(rounds);
        if(cached != null) {
            System.out.print("cached ");
            return cached;
        }
        
        long[] lastTwo = new long[] {1, 1};
        
        for(int i = 0; i < rounds; i++) {
            long last = lastTwo[1];
            lastTwo[1] = lastTwo[0] + lastTwo[1];
            lastTwo[0] = last;
        }
        
        cacheMap.put(rounds, lastTwo[1]);
        return lastTwo[1];
     }

}

Conclusion

In this post I discussed reasons to use Hazelcast’s native Java client. I also showed a quick example of how to use one. The code can be found here.

Reference

When it comes to Beginner’s Guide to Hazelcast. I always am looking at www.hazelcast.com and www.hazelcast.org.

The Beginner’s Guide to Hazelcast Part 5

This is a continuation of a series of posts I have written about Hazelcast.  I highly suggest you read the other ones: Part 1, Part 2, Part 3 and Part 4.

Things That Makes One Go “Huh?”

This post will have no Hazelcast specific code in it.  Let me repeat that.  This post will have no Hazelcast specific code in it.  That is because the fine folks at Hazelcast produced a product that implements different standards.  This allows for a choice of clients.  One of those standards that Hazelcast implements is memcached.

What about JCache?

JCache (JSR 107) is just for Java.  Memcached protocol clients have been implemented across several languages so one is not nailed down to one language.  Implementing the memcached protocol was a smart move in my opinion because it makes Hazelcast more than a “Java thing.”

Why Use Hazelcast?

Excellent question!  If one can use any memcached server, why use Hazelcast.  Well, to tell you the truth, unless one is sharing a database between several servers, one may not even need caching!  If one does need a caching solution, here is why I would choose Hazelcast:

  1. Automatic, real time backups – I have not read of one Hazelcast datatype that is not backed up at least once.  Just stand up two instances, one off machine from the other, to get the full benefit.
  2. Security – If the servers that need to cache are across different networks, then the firewall rules can be easier with Hazelcast.  Lets say n servers are needing to cache data and n/2 of them are on the 192.168.1.x network and the other n/2 are on the 10.10.1.x network.  By setting one Hazelcast instance on either network, all n machines can be sharing a cache.  The Hazelcast instances can be configured to talk to just the instance on the other side.  That makes the firewall rule writer job easier because there only has to be a rule made for two servers rather than n machines  then the 192.168.1.x machines just talk to their Hazelcast node and the 10.10.1.x machines just talk to their Hazelcast node and let the Hazelcast instances do the rest of the work.

Example

I never like to show just a “ho hum” kind of example so I am going to show how a Java client can share data with a Python client.

Setup

I am using Java 1.7 and Python 3.4.  Unfortunately, neither language has memcached support out of the box so I went looking for already written clients.

Java

I found Spymemcached for Java.  I will be just skimming the surface of its abilities. It can be grabbed from Maven.  Here is the pom.xml file for the project:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 3     <modelVersion>4.0.0</modelVersion>
 4     <groupId>com.darylmathison</groupId>
 5     <artifactId>Memcache</artifactId>
 6     <version>1.0-SNAPSHOT</version>
 7     <packaging>jar</packaging>
 8     <properties>
 9         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
10         <maven.compiler.source>1.7</maven.compiler.source>
11         <maven.compiler.target>1.7</maven.compiler.target>
12     </properties>
13     <build>
14         <plugins>
15             <plugin>
16                 <groupId>org.apache.maven.plugins</groupId>
17                 <artifactId>maven-compiler-plugin</artifactId>
18                 <version>2.3.2</version>
19                 <configuration>
20                     <showDeprecation>true</showDeprecation>
21                 </configuration>
22             </plugin>
23             <plugin>
24                 <groupId>org.codehaus.mojo</groupId>
25                 <artifactId>exec-maven-plugin</artifactId>
26                 <version>1.3.2</version>
27                 <executions>
28                     <execution>
29                         <goals>
30                             <goal>java</goal>
31                         </goals>
32                     </execution>
33                 </executions>
34                 <configuration>
35                     <mainClass>com.darylmathison.memcache.Main</mainClass>
36                 </configuration>
37             </plugin>
38         </plugins>
39     </build>
40     <dependencies>
41         <dependency>
42             <groupId>net.spy</groupId>
43             <artifactId>spymemcached</artifactId>
44             <version>2.11.5</version>
45         </dependency>
46     </dependencies>
47 </project>

Python

Next, I found python3-memcached for Python. It uses the classic setup.py procedure to install.

Server

Not much of a cache if the server is missing. One can download Hazelcast at hazelcast.org/download, extract the contents, cd into the bin directory and run the server.bat or server script according to one’s OS. As setting up servers go, that is the easiest one I have ever done.

Situation

The “expensive” operation that I am trying to make cheaper is Fibonacci numbers. Because Python and Java can both understand unicode, the values are stored as unicode strings. The key is a unicode string of the number of the sequence or the number of rounds it takes to get there.

Code

Java

package com.darylmathison.memcache;

import java.io.IOException;
import java.net.InetSocketAddress;
import net.spy.memcached.MemcachedClient;

/**
 *
 * @author Daryl
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        try {
            MemcachedClient client = new MemcachedClient(new InetSocketAddress("localhost", 5701));
            for(int i = 2; i < 20; i++) {
                System.out.println("value of round " + i + " is " + fibonacci(i, client));
            }
            client.shutdown();
        } catch(IOException ioe) {
            ioe.printStackTrace();
        }
    }
    
    private static long fibonacci(int rounds, MemcachedClient client) {
        String cached = (String)client.get(String.valueOf(rounds));
        if(cached != null) {
            System.out.print("cached ");
            return Long.parseLong(cached);
        }
        
        long[] lastTwo = new long[] {1, 1};
        
        for(int i = 0; i < rounds; i++) {
            long last = lastTwo[1];
            lastTwo[1] = lastTwo[0] + lastTwo[1];
            lastTwo[0] = last;
        }
        
        client.set(String.valueOf(rounds), 360, String.valueOf(lastTwo[1]));
        return lastTwo[1];
     }
}

Python

Here is the Python client. As a pythonian, I tried to be as pythonic as possible.

import memcache

client = memcache.Client(['localhost:5701'])

def fibonacci(round):
    f = [1, 1, 1]
    
    for i in range(round):
        f[-1] = sum(f[:2])
        f[0], f[1] = f[1], f[2]
        
    return f[2]

def retrievefib(round):
    fib = client.get(str(round))
    if not fib:
        fib = fibonacci(round)
        client.set(str(round), str(fib))
    else:
        print("cached")
        
    return fib

def main():
    store = [ x for x in range(20) if x % 2 == 0]
    for i in store:
        retrievefib(i)
    
    for i in range(20):
        print(retrievefib(i))

if __name__ == "__main__":
    main()

Conclusion

Well, here is an example of Hazelcast as being the powerhouse behind the scenes. This is a place where I think it shines the most. One doesn’t have to create whole new crafty, distributed applications to take advantage of Hazelcast. All one has to do is use known practices and let Hazelcast do the hard work. The source for this post can be found here for the Java code and here for the Python code.

References

http://en.wikipedia.org/wiki/Fibonacci_number
https://code.google.com/p/spymemcached/
https://pypi.python.org/pypi/python3-memcached/1.51

Beginner’s Guide to Hazelcast Webinar Source Code Links

I promised during the question and answer section of my presentation that I would post my code so everyone can have access to it.  I am going to do one better and give links to all my Hazelcast source code examples.  They are on GitHub so one can do a clone and pull them down via their favorite git client.  I use Netbeans so if one is using Netbeans, one can open up the project contained within the checkout.

Beginner’s Guide to Hazelcast Part 1

https://github.com/darylmathison/hazelcast-simple-app-example

Beginner’s Guide to Hazelcast Part 2

https://github.com/darylmathison/hazelcast-collections-example

Beginner’s Guide to Hazelcast Part 3

https://github.com/darylmathison/hazelcast-primitives-example

Beginner’s Guide to Hazelcast Part 4

https://github.com/darylmathison/hazelcast-executor-service-example

Beginner’s Guide to Hazelcast Webinar

https://github.com/darylmathison/hazelcast-webinar-example

Beginner’s Guide to Hazelcast Part 4

This is the fourth installment of my Hazelcast series. If one has not seen the other 3, I suggest one go to Part 1Part 2 and Part 3.

Logging

Logging is an important feature of any application and my examples are no different. System.out.println can be a useful tool for telling the user what is going on in console applications. But let’s face it, if one is reading how to use a tool for distributed applications, that person is really not a beginner. Seeing a series of logging messages should not scare anyone. In fact, for the examples in this post, they are necessary to know what is going on by whom. We will be talking about threaded programming after all.

The good folks at Hazelcast seem to have agreed that logging is important and so have many different ways to define what library is logging. The logging framework only depends on JDK logging and has a number of adapters that even allow for custom logging frameworks. One’s logging adapter of choice is set by the property, hazelcast.logging.type to the following settings:

  • JDK logging, This is the default.
  • log4j
  • slf4j
  • none

I used Log4j2 so I picked slf4j and put in the four jar files needed to get it working.

Spinning Distributed Threads

Like many classes in Hazelcast, IExecutorService implements an interface from Java’s libraries, the ExecutorService. This interface defines what it is to be a thread pool. The interface is part of the java.util.concurrent package and has been around since Java 1.5. The package also has implementations of it one can access from java.util.concurrent.Executors. I wish I had something like this in Java 1.4 or 1.3 or 1.2 or 1.1. Making thread pools were fun until deadlocks happened. Now I can use Java library’s pools, good enough for me.

ExecutorServices have an interesting “feature.” One must shut them down or the service will not go away. The first time I used them, I caused a memory leak and shutdown the JVM. I caught the bug during my own testing so the customer never had to see my learning experience. IExecutorService has a different wrinkle. The service will not go away until all the threads finish. This caused many unclean shutdowns. You have been warned!

IExecutorServices can share out threads several different ways. Here they are in detail

Any ‘Ole Instance

This is when one calls just the submit(Callable call).  This does more than just set a thread randomly into the cluster.  It does some load balancing with that thread so an instance does not get clobbered with threads.

To a Particular Member

This is done via the submit(Callable call, Member member) method.  This sends a thread to a particular member of the cluster.   No load balancing here; just sending to a member.  Be careful, one can easily overload a member and really put the brakes on any processing being done.  I could see this as a way to create a custom load balancer.

To a Collection of Members

Yeah, one can send a thread to multiple members.  When i was doing my example coding, the members all act like they got their own thread and are not sharing one.  If one implements Callable<T> as their thread implementation, the method returns a Map of Futures using the members as the key.  If one uses Runnable, it returns nothing.

To The Member With the Right Key

Entries to a IMap can be anywhere on the cluster. If processing is needed to be done on that entry, a local thread would have to pull up the entry over the network. This can be a problem if the entry is very large. A better way would be to transfer the hopefully smaller thread over to the entry. To do that, the cluster needs to know where to send it. Hence, the call submit(Callable call, Object key).

To All Members

This works the same way as submitting to a collection of members but it is all of them, as in every member in the cluster.  This could get “fun” if one has a large number of members in a cluster.  I think I have heard as much as a 1000 members in one cluster.  Make sure this is what one wants before it is called.

Using an ExecutionCallback

This is basically a way to send out some threads and let the results come back asynchronously.  One uses an ExecutionCallback if one thread is submitted.  One uses MultiExecutionCallback if more than one member is involved.

Example Code

Before I start, let me say that I do not have an example for every method in IExecutorService.  I do have an example for every type discussed, however.  Another thing about the example code.  For instructional purposes I have done some copy-and-paste coding in prior posts so each example can stand on its own and one can get a context of what goes where.  I did this quite a bit in part 3.  If one did not notice it, look at it again.

This time I did not do it because there would have been a lot of code copied and the results would have been pretty ugly.  I used an Enum and I think the results were very good.  I thought an Enum was a good choice because of the limited number of examples and allowed me to be able to show the code in chunks that are understandable if the framework was shown first.

With that explanation, lets move on!

Framework

This are the main bits. It consists of the main class and the thread class.  Notice how the main class shows each way a thread can submitted being called.

Main

package hazelcastservice;

import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.IExecutorService;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.RejectedExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author Daryl
 */
public class Main {
    private static final Logger logger = LoggerFactory.getLogger(Main.class);
    public static final String SERVICE_NAME = "spinnerella";
    public static final int NUM_INSTANCES = 5;
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        System.setProperty("hazelcast.logging.type", "slf4j");
        List<HazelcastInstance> instances = new ArrayList<>(NUM_INSTANCES);
        for(int i = 0; i < NUM_INSTANCES; i++) {
            instances.add(Hazelcast.newHazelcastInstance());
            logger.info("instance {} up", i);
        }

        IExecutorService spinner = instances.get(0).getExecutorService(SERVICE_NAME);
        try {
            HazelcastIExecutorServiceExamples.TO_SOME_MEMBER.example(instances, spinner);
            HazelcastIExecutorServiceExamples.TO_PARTICULAR_MEMBER.example(instances, spinner);
            HazelcastIExecutorServiceExamples.ON_THE_KEY_OWNER.example(instances, spinner);
            HazelcastIExecutorServiceExamples.ON_A_SET_OF_MEMBERS.example(instances, spinner);
            HazelcastIExecutorServiceExamples.ON_ALL_MEMBERS.example(instances, spinner);
            HazelcastIExecutorServiceExamples.CALLBACK.example(instances, spinner);
            HazelcastIExecutorServiceExamples.MULTIPLE_MEMBERS_WITH_CALLBACK.example(instances, spinner);
            
            //Lets setup a loop to make sure they are all done (Especially the callback ones)
            for(HazelcastIExecutorServiceExamples example: HazelcastIExecutorServiceExamples.values()) {
                while(!example.isDone()) {
                    Thread.sleep(1000);
                }
            }
        } catch(ExecutionException ee) {
            logger.warn("Can't finish the job", ee);
        } catch(InterruptedException ie) {
            logger.warn("Everybody out of the pool", ie);
        } finally {
            // time to clean up my toys
            boolean allClear = false;
            
            while(!allClear) {
                try {
                    Thread.sleep(1000);
                    Hazelcast.shutdownAll();
                    allClear = true;
                } catch(InterruptedException ie) {
                    //got interrupted. try again
                } catch(RejectedExecutionException ree) {
                    logger.debug("caught a RejectedExecutionException");
                    allClear = false;
                }
            }
            
            logger.info("All done");
        }
    }
}

Thread

package hazelcastservice;

import java.io.Serializable;
import java.util.Random;
import java.util.concurrent.Callable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This class was inspired by the song "I Like to Move it" from the movie 
 * Madagascar by Dreamworks.  I offer NO apologies for using it.  
 * 
 * To those software developers who like consistent results, I used java.util.Random to
 * make it loop inconsistently each time call is called.  
 * 
 * Sometimes you need to make your own entertainment.
 * @author Daryl
 */
public class MoveItMoveIt implements Callable<Integer>, Serializable {
    private static final Logger logger = LoggerFactory.getLogger(MoveItMoveIt.class);
    private static final int UPPER_BOUND = 15;
        
    @Override
    public Integer call() throws Exception {
        Random random = new Random();
        int howMany = random.nextInt(UPPER_BOUND);
//        int howMany = 2;
        for(int i = 0; i < howMany; i++) {
            logger.info("I like to Move it Move it!");
        }
        logger.info("Move it!");
        return howMany;
    }
}

The Particulars

Here I go showing the different types of calls that were discussed. Remember that these are chunks of an Enum class. The done is a protected variable and the public void example(List<HazelcastInstance> instances, IExecutorService spinner) needed to implemented.

Any ‘Ole Instance

TO_SOME_MEMBER() {
        @Override
        public void example(List<HazelcastInstance> instances, IExecutorService spinner)
                throws ExecutionException, InterruptedException {
            logger.info("Submit to some member.");
            Future<Integer> howMany = spinner.submit(new MoveItMoveIt());
            logger.info("It moved it {} times", howMany.get());
            done = true;
        }
    }

To a Particular Member

TO_PARTICULAR_MEMBER {
        @Override
        public void example(List<HazelcastInstance> instances, IExecutorService spinner)
                throws ExecutionException, InterruptedException {
            logger.info("Submit to a particular member.");
            Member member = getRandomMember(instances);
            logger.debug("member is {}", member);
            Future<Integer> howMany = spinner.submitToMember(new MoveItMoveIt(), member);
            logger.info("It moved it {} times.", howMany.get());
            done = true;
        }
        
        private Member getRandomMember(List<HazelcastInstance> instances) {
            Set<Member> members = instances.get(0).getCluster().getMembers();
            int i = 0;
            int max = new Random().nextInt(instances.size());
            Iterator<Member> iterator = members.iterator();
            Member member = iterator.next();
            while(iterator.hasNext() && (i < max)) {
                member = iterator.next();
                i++;
            }
            return member;
        }
    }

To a Collection of Members

ON_A_SET_OF_MEMBERS {
        @Override
        public void example(List<HazelcastInstance> instances, IExecutorService spinner)
            throws ExecutionException, InterruptedException {
            logger.info("Send to some of the members");
            Set<Member> randomMembers = getRandomMembers(instances);
            Map<Member, Future<Integer>> results = 
                    spinner.submitToMembers(new MoveItMoveIt(), randomMembers);
            for(Future<Integer> howMany: results.values()) {
                logger.info("It moved {} times", howMany.get());
            }
            done = true;
        }
        
        private Set<Member> getRandomMembers(List<HazelcastInstance> instances) {
            int max = new Random().nextInt(instances.size());
            Set<Member> newSet = new HashSet<>(instances.size());
            int k = 0;
            Iterator<Member> i = instances.get(0).getCluster().getMembers().iterator();
            while(i.hasNext() && k < max) {
                newSet.add(i.next());
                k++;
            }
            return newSet;
        }
    }

To The Member With the Right Key

ON_THE_KEY_OWNER {
        @Override
        public void example(List<HazelcastInstance> instances, IExecutorService spinner)
            throws ExecutionException, InterruptedException {
            logger.info("Send to the one owning the key");
            HazelcastInstance randomInstance = getRandomInstance(instances);
            IMap<Long, Boolean> map = randomInstance.getMap("default");
            Long one = 1L;
            map.put(one, Boolean.TRUE);
            
            Future<Integer> howMany = spinner.submitToKeyOwner(new MoveItMoveIt(), one);
            logger.info("It moved it {} times.", howMany.get());
            done = true;
        }
        
        private HazelcastInstance getRandomInstance(List<HazelcastInstance> instances) {
            return instances.get(new Random().nextInt(instances.size()));
        }

    }

To All Members

   ON_ALL_MEMBERS {
        @Override
        public void example(List<HazelcastInstance> instances, IExecutorService spinner)
            throws ExecutionException, InterruptedException {
            logger.info("Send to all members");
            Map<Member, Future<Integer>> results = 
                    spinner.submitToAllMembers(new MoveItMoveIt());
            for(Future<Integer> howMany: results.values()) {
                logger.info("It moved {} times", howMany.get());
            }
            done = true;
        }
    }

Using an ExecutionCallback

This example code contains two chunks of code to show a single callback and a multiple callback.

CALLBACK {
        @Override
        public void example(List<HazelcastInstance> instances, IExecutorService spinner)
            throws ExecutionException, InterruptedException {
            logger.info("example with a callback");
            spinner.submit(new MoveItMoveIt(), new ExecutionCallback<Integer>() {
                @Override
                public void onResponse(Integer response) {
                    logger.info("It moved {} times", response);
                    done = true;
                }

                @Override
                public void onFailure(Throwable thrwbl) {
                    logger.error("trouble in the callback", thrwbl);
                    done = true;
                }
            });
        }        
    },
    MULTIPLE_MEMBERS_WITH_CALLBACK {
        @Override
        public void example(List<HazelcastInstance> instances, IExecutorService spinner)
            throws ExecutionException, InterruptedException {
            logger.info("running on multiple members with callback");
            spinner.submitToAllMembers(new MoveItMoveIt(), new MultiExecutionCallback() {

                @Override
                public void onResponse(Member member, Object o) {
                    logger.info("member finished with {} moves", o);
                }

                @Override
                public void onComplete(Map<Member, Object> map) {
                    logger.info("All members completed");
                    for(Object value: map.values()) {
                        logger.info("It moved {} times", value);
                    }
                    done = true;
                }
            });
        }

Conclusion

It was good to publish my own code/ideas again on my blog. I took a quick look at the power of the IExecutorService by Hazelcast. My example code followed the DRY principle. The code in its entirety can be found here.

References

As always with my Hazelcast guides, my information comes from Hazelcast documentation that can be found at here.