/*
* Copyright (c) 2008-2017, Hazelcast, Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hazelcast.executor;
import com.hazelcast.config.Config;
import com.hazelcast.config.DurableExecutorConfig;
import com.hazelcast.config.ExecutorConfig;
import com.hazelcast.core.ExecutionCallback;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.HazelcastInstanceAware;
import com.hazelcast.core.IExecutorService;
import com.hazelcast.core.Member;
import com.hazelcast.core.MultiExecutionCallback;
import com.hazelcast.core.PartitionAware;
import com.hazelcast.durableexecutor.DurableExecutorService;
import com.hazelcast.spi.impl.executionservice.InternalExecutionService;
import com.hazelcast.test.HazelcastTestSupport;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import static org.junit.Assert.fail;
public class ExecutorServiceTestSupport extends HazelcastTestSupport {
IExecutorService createSingleNodeExecutorService(String name) {
return createSingleNodeExecutorService(name, ExecutorConfig.DEFAULT_POOL_SIZE);
}
protected DurableExecutorService createSingleNodeDurableExecutorService(String name) {
return createSingleNodeDurableExecutorService(name, DurableExecutorConfig.DEFAULT_POOL_SIZE);
}
IExecutorService createSingleNodeExecutorService(String name, int poolSize) {
return createSingleNodeExecutorService(name, poolSize, true);
}
IExecutorService createSingleNodeExecutorService(String name, int poolSize, boolean statsEnabled) {
ExecutorConfig executorConfig = new ExecutorConfig(name, poolSize).setStatisticsEnabled(statsEnabled);
HazelcastInstance instance = createHazelcastInstance(new Config().addExecutorConfig(executorConfig));
return instance.getExecutorService(name);
}
protected DurableExecutorService createSingleNodeDurableExecutorService(String name, int poolSize) {
DurableExecutorConfig executorConfig = new DurableExecutorConfig(name).setPoolSize(poolSize);
HazelcastInstance instance = createHazelcastInstance(new Config().addDurableExecutorConfig(executorConfig));
return instance.getDurableExecutorService(name);
}
protected int findNextKeyForMember(HazelcastInstance instance, Member localMember) {
int key = 0;
while (!localMember.equals(instance.getPartitionService().getPartition(key).getOwner())) {
key++;
}
return key;
}
InternalExecutionService getExecutionService(HazelcastInstance instance) {
return getNode(instance).getNodeEngine().getExecutionService();
}
public static class CountDownLatchAwaitingCallable implements Callable<String> {
public static String RESULT = "Success";
private final CountDownLatch latch;
CountDownLatchAwaitingCallable(CountDownLatch latch) {
this.latch = latch;
}
@Override
public String call() throws Exception {
latch.await(30, TimeUnit.SECONDS);
return RESULT;
}
}
public static class CountingDownExecutionCallback<T> implements ExecutionCallback<T> {
private final AtomicReference<Object> result = new AtomicReference<Object>();
private final CountDownLatch latch;
public CountingDownExecutionCallback(int count) {
this.latch = new CountDownLatch(count);
}
public CountingDownExecutionCallback(CountDownLatch latch) {
this.latch = latch;
}
@Override
public void onResponse(T response) {
if (!result.compareAndSet(null, response)) {
System.out.println("New response received after result is set. Response: " + response
+ " Result: " + result.get());
}
latch.countDown();
}
@Override
public void onFailure(Throwable t) {
if (!result.compareAndSet(null, t)) {
System.out.println("Failure received after result is set. Failure: " + t + " Result: " + result.get());
}
latch.countDown();
}
public CountDownLatch getLatch() {
return latch;
}
public Object getResult() {
return result.get();
}
}
public static class BasicTestCallable implements Callable<String>, Serializable, PartitionAware {
public static String RESULT = "Task completed";
@Override
public String call() {
return RESULT;
}
@Override
public Object getPartitionKey() {
return "key";
}
}
public static class SleepingTask implements Callable<Boolean>, Serializable, PartitionAware {
long sleepSeconds;
public SleepingTask(long sleepSeconds) {
this.sleepSeconds = sleepSeconds;
}
@Override
public Boolean call() throws InterruptedException {
sleepAtLeastSeconds((int) sleepSeconds);
return true;
}
@Override
public Object getPartitionKey() {
return "key";
}
}
public static class NestedExecutorTask implements Callable<String>, Serializable, HazelcastInstanceAware {
private HazelcastInstance instance;
@Override
public String call() throws Exception {
Future future = instance.getExecutorService("NestedExecutorTask").submit(new BasicTestCallable());
return (String) future.get();
}
@Override
public void setHazelcastInstance(HazelcastInstance hazelcastInstance) {
instance = hazelcastInstance;
}
}
public static class MemberCheck implements Callable<Member>, Serializable, HazelcastInstanceAware {
private Member localMember;
@Override
public Member call() throws Exception {
return localMember;
}
@Override
public void setHazelcastInstance(HazelcastInstance hazelcastInstance) {
localMember = hazelcastInstance.getCluster().getLocalMember();
}
}
public static class FailingTestTask implements Callable<String>, Serializable {
@Override
public String call() throws Exception {
throw new IllegalStateException();
}
}
public static class HazelcastInstanceAwareRunnable implements Runnable, HazelcastInstanceAware, Serializable {
private transient boolean initializeCalled;
@Override
public void run() {
if (!initializeCalled) {
fail("setHazelcastInstance() was not called");
}
}
@Override
public void setHazelcastInstance(HazelcastInstance hazelcastInstance) {
initializeCalled = true;
}
}
public static class IncrementAtomicLongIfMemberUUIDNotMatchRunnable implements Runnable, Serializable, HazelcastInstanceAware {
private final String uuid;
private final String name;
private HazelcastInstance instance;
public IncrementAtomicLongIfMemberUUIDNotMatchRunnable(String uuid, String name) {
this.uuid = uuid;
this.name = name;
}
@Override
public void setHazelcastInstance(HazelcastInstance instance) {
this.instance = instance;
}
@Override
public void run() {
if (!instance.getCluster().getLocalMember().getUuid().equals(uuid)) {
instance.getAtomicLong(name).incrementAndGet();
}
}
}
@SuppressWarnings("unused")
public static class NullResponseCountingCallback<T> implements ExecutionCallback<T> {
private final AtomicInteger nullResponseCount = new AtomicInteger(0);
private final CountDownLatch responseLatch;
public NullResponseCountingCallback(int count) {
this.responseLatch = new CountDownLatch(count);
}
@Override
public void onResponse(T response) {
if (response == null) {
nullResponseCount.incrementAndGet();
}
responseLatch.countDown();
}
@Override
public void onFailure(Throwable t) {
System.out.println("Exception received: " + t);
}
public int getNullResponseCount() {
return nullResponseCount.get();
}
public boolean awaitResponseLatch(int seconds)
throws InterruptedException {
return responseLatch.await(seconds, TimeUnit.SECONDS);
}
public CountDownLatch getResponseLatch() {
return responseLatch;
}
}
public static class ResponseCountingMultiExecutionCallback implements MultiExecutionCallback {
private final AtomicInteger count = new AtomicInteger();
private final CountDownLatch latch;
ResponseCountingMultiExecutionCallback(int count) {
this.latch = new CountDownLatch(count);
}
@Override
public void onResponse(Member member, Object value) {
count.incrementAndGet();
}
@Override
public void onComplete(Map<Member, Object> values) {
latch.countDown();
}
public int getCount() {
return count.get();
}
public CountDownLatch getLatch() {
return latch;
}
}
public static class BooleanSuccessResponseCountingCallback implements ExecutionCallback<Boolean> {
private final AtomicInteger successResponseCount = new AtomicInteger(0);
private final CountDownLatch responseLatch;
public BooleanSuccessResponseCountingCallback(int count) {
this.responseLatch = new CountDownLatch(count);
}
@Override
public void onResponse(Boolean response) {
if (response) {
successResponseCount.incrementAndGet();
}
responseLatch.countDown();
}
@Override
public void onFailure(Throwable t) {
}
public int getSuccessResponseCount() {
return successResponseCount.get();
}
public CountDownLatch getResponseLatch() {
return responseLatch;
}
}
public static class IncrementAtomicLongRunnable implements Runnable, Serializable, HazelcastInstanceAware {
private final String name;
private transient HazelcastInstance instance;
public IncrementAtomicLongRunnable(String name) {
this.name = name;
}
@Override
public void setHazelcastInstance(HazelcastInstance instance) {
this.instance = instance;
}
@Override
public void run() {
instance.getAtomicLong(name).incrementAndGet();
}
}
public static class IncrementAtomicLongCallable implements Callable<Long>, Serializable, HazelcastInstanceAware {
private final String name;
private HazelcastInstance instance;
public IncrementAtomicLongCallable(String name) {
this.name = name;
}
@Override
public void setHazelcastInstance(HazelcastInstance instance) {
this.instance = instance;
}
public void run() {
instance.getAtomicLong(name).incrementAndGet();
}
@Override
public Long call() throws Exception {
return instance.getAtomicLong(name).incrementAndGet();
}
}
public static class MemberUUIDCheckCallable implements Callable<Boolean>, HazelcastInstanceAware, Serializable {
private final String uuid;
private HazelcastInstance instance;
public MemberUUIDCheckCallable(String uuid) {
this.uuid = uuid;
}
@Override
public Boolean call() throws Exception {
return instance.getCluster().getLocalMember().getUuid().equals(uuid);
}
@Override
public void setHazelcastInstance(HazelcastInstance instance) {
this.instance = instance;
}
}
public static class ResultSettingRunnable implements Runnable, HazelcastInstanceAware, Serializable {
private final String name;
private transient HazelcastInstance instance;
public ResultSettingRunnable(String name) {
this.name = name;
}
@Override
public void setHazelcastInstance(HazelcastInstance instance) {
this.instance = instance;
}
@Override
public void run() {
final Member member = instance.getCluster().getLocalMember();
instance.getMap(name).put(member, true);
}
}
public static class LocalMemberReturningCallable implements Callable<Member>, HazelcastInstanceAware, Serializable {
private transient HazelcastInstance instance;
@Override
public void setHazelcastInstance(HazelcastInstance instance) {
this.instance = instance;
}
@Override
public Member call() {
return instance.getCluster().getLocalMember();
}
}
public static class ResultHoldingMultiExecutionCallback implements MultiExecutionCallback {
private volatile Map<Member, Object> results;
public Map<Member, Object> getResults() {
return results;
}
@Override
public void onResponse(Member member, Object value) {
}
@Override
public void onComplete(Map<Member, Object> values) {
this.results = values;
}
}
}