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

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

There is a newer version: 3.12.13
Show 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.DurableExecutorDisposeResultCodec;
import com.hazelcast.client.impl.protocol.codec.DurableExecutorIsShutdownCodec;
import com.hazelcast.client.impl.protocol.codec.DurableExecutorRetrieveAndDisposeResultCodec;
import com.hazelcast.client.impl.protocol.codec.DurableExecutorRetrieveResultCodec;
import com.hazelcast.client.impl.protocol.codec.DurableExecutorShutdownCodec;
import com.hazelcast.client.impl.protocol.codec.DurableExecutorSubmitToPartitionCodec;
import com.hazelcast.client.spi.ClientContext;
import com.hazelcast.client.spi.ClientPartitionService;
import com.hazelcast.client.spi.ClientProxy;
import com.hazelcast.client.spi.impl.ClientInvocation;
import com.hazelcast.client.spi.impl.ClientInvocationFuture;
import com.hazelcast.client.util.ClientDelegatingFuture;
import com.hazelcast.core.ExecutionCallback;
import com.hazelcast.core.PartitionAware;
import com.hazelcast.durableexecutor.DurableExecutorService;
import com.hazelcast.durableexecutor.DurableExecutorServiceFuture;
import com.hazelcast.executor.impl.RunnableAdapter;
import com.hazelcast.nio.Bits;
import com.hazelcast.spi.serialization.SerializationService;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import static com.hazelcast.util.Preconditions.checkNotNull;

/**
 * Proxy implementation of {@link DurableExecutorService}.
 */
public final class ClientDurableExecutorServiceProxy extends ClientProxy implements DurableExecutorService {

    private static final ClientMessageDecoder RETRIEVE_RESPONSE_DECODER = new ClientMessageDecoder() {
        @Override
        public  T decodeClientMessage(ClientMessage clientMessage) {
            return (T) DurableExecutorRetrieveResultCodec.decodeResponse(clientMessage).response;
        }
    };

    private final Random random = new Random();

    private int partitionCount;

    public ClientDurableExecutorServiceProxy(String serviceName, String name, ClientContext context) {
        super(serviceName, name, context);
    }

    @Override
    protected void onInitialize() {
        ClientPartitionService partitionService = getContext().getPartitionService();
        partitionCount = partitionService.getPartitionCount();
    }

    @Override
    public  Future retrieveResult(long taskId) {
        int partitionId = Bits.extractInt(taskId, false);
        int sequence = Bits.extractInt(taskId, true);
        ClientMessage clientMessage = DurableExecutorRetrieveResultCodec.encodeRequest(name, sequence);
        ClientInvocationFuture future = new ClientInvocation(getClient(), clientMessage, getName(), partitionId).invoke();
        return new ClientDelegatingFuture(future, getSerializationService(), RETRIEVE_RESPONSE_DECODER);
    }

    @Override
    public void disposeResult(long taskId) {
        int partitionId = Bits.extractInt(taskId, false);
        int sequence = Bits.extractInt(taskId, true);
        ClientMessage clientMessage = DurableExecutorDisposeResultCodec.encodeRequest(name, sequence);
        invokeOnPartition(clientMessage, partitionId);
    }

    @Override
    public  Future retrieveAndDisposeResult(long taskId) {
        int partitionId = Bits.extractInt(taskId, false);
        int sequence = Bits.extractInt(taskId, true);
        ClientMessage clientMessage = DurableExecutorRetrieveAndDisposeResultCodec.encodeRequest(name, sequence);
        ClientInvocationFuture future = new ClientInvocation(getClient(), clientMessage, getName(), partitionId).invoke();
        return new ClientDelegatingFuture(future, getSerializationService(), RETRIEVE_RESPONSE_DECODER);
    }

    @Override
    public void execute(Runnable task) {
        int partitionId = getTaskPartitionId(task);
        Callable callable = createRunnableAdapter(task);
        submitToPartition(callable, partitionId, null);
    }

    @Override
    public void executeOnKeyOwner(Runnable task, Object key) {
        int partitionId = getPartitionId(key);
        Callable callable = createRunnableAdapter(task);
        submitToPartition(callable, partitionId, null);
    }

    @Override
    public  DurableExecutorServiceFuture submitToKeyOwner(Callable task, Object key) {
        int partitionId = getPartitionId(key);
        return submitToPartition(task, partitionId, null);
    }

    @Override
    public DurableExecutorServiceFuture submitToKeyOwner(Runnable task, Object key) {
        int partitionId = getPartitionId(key);
        Callable callable = createRunnableAdapter(task);
        return submitToPartition(callable, partitionId, null);
    }

    @Override
    public  DurableExecutorServiceFuture submit(Callable task) {
        int partitionId = getTaskPartitionId(task);
        return submitToPartition(task, partitionId, null);
    }

    @Override
    public  DurableExecutorServiceFuture submit(Runnable task, T result) {
        int partitionId = getTaskPartitionId(task);
        Callable callable = createRunnableAdapter(task);
        return submitToPartition(callable, partitionId, result);
    }

    @Override
    public DurableExecutorServiceFuture submit(Runnable task) {
        int partitionId = getTaskPartitionId(task);
        Callable callable = createRunnableAdapter(task);
        return submitToPartition(callable, partitionId, null);
    }

    @Override
    public  List> invokeAll(Collection> tasks) throws InterruptedException {
        throw new UnsupportedOperationException();
    }

    @Override
    public  List> invokeAll(Collection> tasks, long timeout, TimeUnit unit)
            throws InterruptedException {
        throw new UnsupportedOperationException();
    }

    @Override
    public  T invokeAny(Collection> tasks) throws InterruptedException, ExecutionException {
        throw new UnsupportedOperationException();
    }

    @Override
    public  T invokeAny(Collection> tasks, long timeout, TimeUnit unit)
            throws InterruptedException, ExecutionException, TimeoutException {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
        return false;
    }

    @Override
    public void shutdown() {
        ClientMessage request = DurableExecutorShutdownCodec.encodeRequest(name);
        invoke(request);
    }

    @Override
    public List shutdownNow() {
        shutdown();
        return Collections.emptyList();
    }

    @Override
    public boolean isShutdown() {
        ClientMessage request = DurableExecutorIsShutdownCodec.encodeRequest(name);
        ClientMessage response = invoke(request);
        DurableExecutorIsShutdownCodec.ResponseParameters resultParameters =
                DurableExecutorIsShutdownCodec.decodeResponse(response);
        return resultParameters.response;
    }

    @Override
    public boolean isTerminated() {
        return isShutdown();
    }

    private  DurableExecutorServiceFuture submitToPartition(Callable task, int partitionId, T result) {
        checkNotNull(task, "task should not be null");

        ClientMessage request = DurableExecutorSubmitToPartitionCodec.encodeRequest(name, toData(task));
        int sequence;
        try {
            ClientMessage response = invokeOnPartition(request, partitionId);
            sequence = DurableExecutorSubmitToPartitionCodec.decodeResponse(response).response;
        } catch (Throwable t) {
            return new ClientDurableExecutorServiceCompletedFuture(t, getUserExecutor());
        }
        ClientMessage clientMessage = DurableExecutorRetrieveResultCodec.encodeRequest(name, sequence);
        ClientInvocationFuture future = new ClientInvocation(getClient(), clientMessage, getName(), partitionId).invoke();
        long taskId = Bits.combineToLong(partitionId, sequence);
        return new ClientDurableExecutorServiceDelegatingFuture(future, getSerializationService(), RETRIEVE_RESPONSE_DECODER,
                result, taskId);
    }

    private Executor getUserExecutor() {
        return getContext().getExecutionService().getUserExecutor();
    }

    private  RunnableAdapter createRunnableAdapter(Runnable command) {
        if (command == null) {
            throw new NullPointerException();
        }
        return new RunnableAdapter(command);
    }

    private int getTaskPartitionId(Object task) {
        if (task instanceof PartitionAware) {
            Object partitionKey = ((PartitionAware) task).getPartitionKey();
            if (partitionKey != null) {
                return getPartitionId(partitionKey);
            }
        }
        return random.nextInt(partitionCount);
    }

    private int getPartitionId(Object key) {
        return getContext().getPartitionService().getPartitionId(key);
    }

    private static class ClientDurableExecutorServiceDelegatingFuture extends ClientDelegatingFuture
            implements DurableExecutorServiceFuture {

        private final long taskId;

        public ClientDurableExecutorServiceDelegatingFuture(ClientInvocationFuture clientInvocationFuture,
                                                            SerializationService serializationService,
                                                            ClientMessageDecoder clientMessageDecoder,
                                                            T defaultValue, long taskId) {
            super(clientInvocationFuture, serializationService, clientMessageDecoder, defaultValue);
            this.taskId = taskId;
        }

        @Override
        public long getTaskId() {
            return taskId;
        }
    }

    private static final class ClientDurableExecutorServiceCompletedFuture implements DurableExecutorServiceFuture {

        private final Object result;
        private final Executor executor;

        private ClientDurableExecutorServiceCompletedFuture(Object result, Executor executor) {
            this.result = result;
            this.executor = executor;
        }

        @Override
        public long getTaskId() {
            throw new IllegalStateException("Task failed to execute!");
        }

        @Override
        public void andThen(ExecutionCallback callback) {
            andThen(callback, executor);
        }

        @Override
        public void andThen(final ExecutionCallback callback, Executor executor) {
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    if (result instanceof Throwable) {
                        callback.onFailure((Throwable) result);
                    } else {
                        callback.onResponse((T) result);
                    }
                }
            });
        }

        @Override
        public boolean cancel(boolean mayInterruptIfRunning) {
            return false;
        }

        @Override
        public boolean isCancelled() {
            return false;
        }

        @Override
        public boolean isDone() {
            return true;
        }

        @Override
        public T get() throws InterruptedException, ExecutionException {
            if (result instanceof Throwable) {
                if (result instanceof ExecutionException) {
                    throw (ExecutionException) result;
                }
                if (result instanceof InterruptedException) {
                    throw (InterruptedException) result;
                }
                throw new ExecutionException((Throwable) result);
            }
            return (T) result;
        }

        @Override
        public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
            return get();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy