All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hazelcast.client.proxy.ClientScheduledExecutorProxy Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2008-2020, 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.client.proxy;

import com.hazelcast.client.impl.clientside.ClientMessageDecoder;
import com.hazelcast.client.impl.protocol.ClientMessage;
import com.hazelcast.client.impl.protocol.codec.ScheduledExecutorGetAllScheduledFuturesCodec;
import com.hazelcast.client.impl.protocol.codec.ScheduledExecutorShutdownCodec;
import com.hazelcast.client.impl.protocol.codec.ScheduledExecutorSubmitToAddressCodec;
import com.hazelcast.client.impl.protocol.codec.ScheduledExecutorSubmitToPartitionCodec;
import com.hazelcast.client.spi.ClientContext;
import com.hazelcast.client.spi.impl.ClientInvocation;
import com.hazelcast.client.spi.impl.ClientInvocationFuture;
import com.hazelcast.client.util.ClientDelegatingFuture;
import com.hazelcast.core.Member;
import com.hazelcast.core.PartitionAware;
import com.hazelcast.logging.ILogger;
import com.hazelcast.logging.Logger;
import com.hazelcast.nio.Address;
import com.hazelcast.nio.serialization.Data;
import com.hazelcast.quorum.QuorumException;
import com.hazelcast.scheduledexecutor.IScheduledExecutorService;
import com.hazelcast.scheduledexecutor.IScheduledFuture;
import com.hazelcast.scheduledexecutor.NamedTask;
import com.hazelcast.scheduledexecutor.ScheduledTaskHandler;
import com.hazelcast.scheduledexecutor.impl.ScheduledRunnableAdapter;
import com.hazelcast.scheduledexecutor.impl.ScheduledTaskHandlerImpl;
import com.hazelcast.scheduledexecutor.impl.TaskDefinition;
import com.hazelcast.util.FutureUtil;
import com.hazelcast.util.UuidUtil;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;

import static com.hazelcast.util.ExceptionUtil.rethrow;
import static com.hazelcast.util.ExceptionUtil.sneakyThrow;
import static com.hazelcast.util.FutureUtil.waitWithDeadline;
import static com.hazelcast.util.Preconditions.checkNotNull;

/**
 * Client proxy implementation of {@link IScheduledExecutorService}.
 */
@SuppressWarnings({"unchecked", "checkstyle:methodcount"})
public class ClientScheduledExecutorProxy
        extends PartitionSpecificClientProxy
        implements IScheduledExecutorService {

    private static final int SHUTDOWN_TIMEOUT = 10;

    private static final ILogger LOGGER = Logger.getLogger(ClientScheduledExecutorProxy.class);

    private static final ClientMessageDecoder SUBMIT_DECODER = new ClientMessageDecoder() {
        @Override
        public Void decodeClientMessage(ClientMessage clientMessage) {
            return null;
        }
    };

    private final FutureUtil.ExceptionHandler shutdownExceptionHandler = new FutureUtil.ExceptionHandler() {
        @Override
        public void handleException(Throwable throwable) {
            if (throwable != null) {
                if (throwable instanceof QuorumException) {
                    sneakyThrow(throwable);
                }
                if (throwable.getCause() instanceof QuorumException) {
                    sneakyThrow(throwable.getCause());
                }
            }
            if (LOGGER.isLoggable(Level.FINEST)) {
                LOGGER.log(Level.FINEST, "Exception while ExecutorService shutdown", throwable);
            }
        }
    };

    public ClientScheduledExecutorProxy(String serviceName, String objectId, ClientContext context) {
        super(serviceName, objectId, context);
    }

    @Override
    public String toString() {
        return "ClientScheduledExecutorProxy{" + "name='" + name + '\'' + '}';
    }

    @Override
    public IScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) {
        Callable adapter = createScheduledRunnableAdapter(command);
        return schedule(adapter, delay, unit);
    }

    @Override
    public  IScheduledFuture schedule(Callable command, long delay, TimeUnit unit) {
        checkNotNull(command, "Command is null");
        checkNotNull(unit, "Unit is null");

        String name = extractNameOrGenerateOne(command);
        int partitionId = getTaskOrKeyPartitionId(command, name);
        TaskDefinition definition = new TaskDefinition(TaskDefinition.Type.SINGLE_RUN, name, command, delay, unit);
        return scheduleOnPartition(name, definition, partitionId);
    }

    @Override
    public IScheduledFuture scheduleAtFixedRate(Runnable command, long initialDelay, long period,
                                                   TimeUnit unit) {
        checkNotNull(command, "Command is null");
        checkNotNull(unit, "Unit is null");

        String name = extractNameOrGenerateOne(command);
        int partitionId = getTaskOrKeyPartitionId(command, name);
        Callable adapter = createScheduledRunnableAdapter(command);
        TaskDefinition definition = new TaskDefinition(TaskDefinition.Type.AT_FIXED_RATE, name, adapter,
                initialDelay, period, unit);

        return scheduleOnPartition(name, definition, partitionId);
    }

    @Override
    public IScheduledFuture scheduleOnMember(Runnable command, Member member, long delay, TimeUnit unit) {
        checkNotNull(member, "Member is null");
        return scheduleOnMembers(command, Collections.singleton(member), delay, unit).get(member);
    }

    @Override
    public  IScheduledFuture scheduleOnMember(Callable command, Member member, long delay, TimeUnit unit) {
        checkNotNull(member, "Member is null");
        return scheduleOnMembers(command, Collections.singleton(member), delay, unit).get(member);
    }

    @Override
    public IScheduledFuture scheduleOnMemberAtFixedRate(Runnable command, Member member, long initialDelay,
                                                           long period, TimeUnit unit) {
        checkNotNull(member, "Member is null");
        return scheduleOnMembersAtFixedRate(command, Collections.singleton(member), initialDelay, period, unit).get(member);
    }

    @Override
    public IScheduledFuture scheduleOnKeyOwner(Runnable command, Object key, long delay, TimeUnit unit) {
        Callable adapter = createScheduledRunnableAdapter(command);
        return scheduleOnKeyOwner(adapter, key, delay, unit);
    }

    @Override
    public  IScheduledFuture scheduleOnKeyOwner(Callable command, Object key, long delay, TimeUnit unit) {
        checkNotNull(command, "Command is null");
        checkNotNull(key, "Key is null");
        checkNotNull(unit, "Unit is null");

        String name = extractNameOrGenerateOne(command);
        int partitionId = getKeyPartitionId(key);
        TaskDefinition definition = new TaskDefinition(TaskDefinition.Type.SINGLE_RUN, name, command,
                delay, unit);
        return scheduleOnPartition(name, definition, partitionId);
    }

    @Override
    public IScheduledFuture scheduleOnKeyOwnerAtFixedRate(Runnable command, Object key, long initialDelay,
                                                             long period, TimeUnit unit) {
        checkNotNull(command, "Command is null");
        checkNotNull(key, "Key is null");
        checkNotNull(unit, "Unit is null");

        String name = extractNameOrGenerateOne(command);
        int partitionId = getKeyPartitionId(key);
        Callable adapter = createScheduledRunnableAdapter(command);
        TaskDefinition definition = new TaskDefinition(TaskDefinition.Type.AT_FIXED_RATE, name, adapter,
                initialDelay, period, unit);
        return scheduleOnPartition(name, definition, partitionId);
    }

    @Override
    public Map> scheduleOnAllMembers(Runnable command, long delay, TimeUnit unit) {
        return scheduleOnMembers(command, getContext().getClusterService().getMemberList(), delay, unit);
    }

    @Override
    public  Map> scheduleOnAllMembers(Callable command, long delay,
                                                                     TimeUnit unit) {
        return scheduleOnMembers(command, getContext().getClusterService().getMemberList(), delay, unit);
    }

    @Override
    public Map> scheduleOnAllMembersAtFixedRate(Runnable command, long initialDelay,
                                                                            long period, TimeUnit unit) {
        return scheduleOnMembersAtFixedRate(command, getContext().getClusterService().getMemberList(),
                initialDelay, period, unit);
    }

    @Override
    public Map> scheduleOnMembers(Runnable command, Collection members, long delay,
                                                              TimeUnit unit) {
        Callable adapter = createScheduledRunnableAdapter(command);
        return scheduleOnMembers(adapter, members, delay, unit);
    }

    @Override
    public  Map> scheduleOnMembers(Callable command, Collection members,
                                                                  long delay, TimeUnit unit) {
        checkNotNull(command, "Command is null");
        checkNotNull(members, "Members is null");
        checkNotNull(unit, "Unit is null");

        String name = extractNameOrGenerateOne(command);
        Map> futures = new HashMap>();
        for (Member member : members) {
            TaskDefinition definition = new TaskDefinition(
                    TaskDefinition.Type.SINGLE_RUN, name, command, delay, unit);

            futures.put(member, (IScheduledFuture) scheduleOnMember(name, member, definition));
        }

        return futures;
    }

    @Override
    public Map> scheduleOnMembersAtFixedRate(Runnable command,
                                                                         Collection members, long initialDelay,
                                                                         long period, TimeUnit unit) {
        checkNotNull(command, "Command is null");
        checkNotNull(members, "Members is null");
        checkNotNull(unit, "Unit is null");

        String name = extractNameOrGenerateOne(command);
        Callable adapter = createScheduledRunnableAdapter(command);
        Map> futures = new HashMap>();
        for (Member member : members) {
            TaskDefinition definition = new TaskDefinition(
                    TaskDefinition.Type.AT_FIXED_RATE, name, adapter, initialDelay, period, unit);

            futures.put(member, scheduleOnMember(name, member, definition));
        }

        return futures;
    }

    @Override
    public  IScheduledFuture getScheduledFuture(ScheduledTaskHandler handler) {
        ClientScheduledFutureProxy futureProxy = new ClientScheduledFutureProxy(handler, getContext());
        return futureProxy;
    }

    @Override
    public  Map>> getAllScheduledFutures() {
        ClientMessage request = ScheduledExecutorGetAllScheduledFuturesCodec.encodeRequest(getName());
        ClientInvocationFuture future = new ClientInvocation(getClient(), request, getName()).invoke();
        ClientMessage response;
        try {
            response = future.get();
        } catch (Exception e) {
            throw rethrow(e);
        }

        Collection>> urnsPerMember =
                ScheduledExecutorGetAllScheduledFuturesCodec.decodeResponse(response).handlers;

        Map>> tasksMap = new HashMap>>();

        for (Map.Entry> entry : urnsPerMember) {
            List> memberTasks = new ArrayList>();
            for (ScheduledTaskHandler scheduledTaskHandler : entry.getValue()) {
                memberTasks.add(new ClientScheduledFutureProxy(scheduledTaskHandler, getContext()));
            }

            tasksMap.put(entry.getKey(), memberTasks);
        }

        return tasksMap;
    }

    @Override
    public void shutdown() {
        Collection members = getContext().getClusterService().getMemberList();
        Collection calls = new LinkedList();

        for (Member member : members) {
            ClientMessage request = ScheduledExecutorShutdownCodec.encodeRequest(getName(), member.getAddress());
            calls.add(doSubmitOnAddress(request, SUBMIT_DECODER, member.getAddress()));
        }

        waitWithDeadline(calls, SHUTDOWN_TIMEOUT, TimeUnit.SECONDS, shutdownExceptionHandler);
    }

    private  ScheduledRunnableAdapter createScheduledRunnableAdapter(Runnable command) {
        checkNotNull(command, "Command can't be null");

        return new ScheduledRunnableAdapter(command);
    }

    private  IScheduledFuture createFutureProxy(ScheduledTaskHandler handler) {
        return new ClientScheduledFutureProxy(handler, getContext());
    }

    private  IScheduledFuture createFutureProxy(int partitionId, String taskName) {
        return createFutureProxy(ScheduledTaskHandlerImpl.of(partitionId, getName(), taskName));
    }

    private  IScheduledFuture createFutureProxy(Address address, String taskName) {
        return createFutureProxy(ScheduledTaskHandlerImpl.of(address, getName(), taskName));
    }

    private int getKeyPartitionId(Object key) {
        return getClient().getPartitionService().getPartition(key).getPartitionId();
    }

    private int getTaskOrKeyPartitionId(Callable task, Object key) {
        if (task instanceof PartitionAware) {
            Object newKey = ((PartitionAware) task).getPartitionKey();
            if (newKey != null) {
                key = newKey;
            }
        }

        return getKeyPartitionId(key);
    }

    private int getTaskOrKeyPartitionId(Runnable task, Object key) {
        if (task instanceof PartitionAware) {
            Object newKey = ((PartitionAware) task).getPartitionKey();
            if (newKey != null) {
                key = newKey;
            }
        }

        return getKeyPartitionId(key);
    }

    private String extractNameOrGenerateOne(Object command) {
        String name = null;
        if (command instanceof NamedTask) {
            name = ((NamedTask) command).getName();
        }

        return name != null ? name : UuidUtil.newUnsecureUuidString();
    }

    private  IScheduledFuture scheduleOnPartition(String name, TaskDefinition definition, int partitionId) {
        TimeUnit unit = definition.getUnit();
        Data commandData = getSerializationService().toData(definition.getCommand());
        ClientMessage request = ScheduledExecutorSubmitToPartitionCodec.encodeRequest(getName(),
                definition.getType().getId(), definition.getName(), commandData,
                unit.toMillis(definition.getInitialDelay()),
                unit.toMillis(definition.getPeriod()));
        try {
            new ClientInvocation(getClient(), request, getName(), partitionId).invoke().get();
        } catch (Exception e) {
            throw rethrow(e);
        }
        return createFutureProxy(partitionId, name);
    }

    private  IScheduledFuture scheduleOnMember(String name, Member member, TaskDefinition definition) {
        TimeUnit unit = definition.getUnit();

        Data commandData = getSerializationService().toData(definition.getCommand());
        ClientMessage request = ScheduledExecutorSubmitToAddressCodec.encodeRequest(getName(), member.getAddress(),
                definition.getType().getId(), definition.getName(), commandData,
                unit.toMillis(definition.getInitialDelay()),
                unit.toMillis(definition.getPeriod()));
        try {
            new ClientInvocation(getClient(), request, getName(), member.getAddress()).invoke().get();
        } catch (Exception e) {
            throw rethrow(e);
        }
        return createFutureProxy(member.getAddress(), name);
    }

    private  ClientDelegatingFuture doSubmitOnAddress(ClientMessage clientMessage,
                                                            ClientMessageDecoder clientMessageDecoder, Address address) {
        try {
            ClientInvocationFuture future = new ClientInvocation(getClient(), clientMessage, getName(), address).invoke();
            return new ClientDelegatingFuture(future, getSerializationService(), clientMessageDecoder);
        } catch (Exception e) {
            throw rethrow(e);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy