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

com.hazelcast.executor.impl.ExecutionCallbackAdapterFactory Maven / Gradle / Ivy

There is a newer version: 5.4.0
Show newest version
/*
 * Copyright (c) 2008-2016, 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.impl;

import com.hazelcast.core.ExecutionCallback;
import com.hazelcast.core.Member;
import com.hazelcast.core.MultiExecutionCallback;
import com.hazelcast.logging.ILogger;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;

class ExecutionCallbackAdapterFactory {

    //Updates the ExecutionCallbackAdapterFactory.done field. An AtomicBoolean is simpler, but creates another unwanted
    //object. Using this approach, you don't create that object.
    private static final AtomicReferenceFieldUpdater DONE =
            AtomicReferenceFieldUpdater.newUpdater(ExecutionCallbackAdapterFactory.class, Boolean.class, "done");

    private final MultiExecutionCallback multiExecutionCallback;
    private final ConcurrentMap responses;
    private final Collection members;
    private final ILogger logger;
    @SuppressWarnings("CanBeFinal")
    private volatile Boolean done = FALSE;

    ExecutionCallbackAdapterFactory(ILogger logger, Collection members,
                                    MultiExecutionCallback multiExecutionCallback) {
        this.multiExecutionCallback = multiExecutionCallback;
        this.responses = new ConcurrentHashMap(members.size());
        this.members = new HashSet(members);
        this.logger = logger;
    }

    private void onResponse(Member member, Object response) {
        assertNotDone();
        assertIsMember(member);
        triggerOnResponse(member, response);
        placeResponse(member, response);
        triggerOnComplete();
    }

    private void triggerOnComplete() {
        if (members.size() != responses.size() || !setDone()) {
            return;
        }

        Map realResponses = new HashMap(members.size());
        for (Map.Entry entry : responses.entrySet()) {
            Member key = entry.getKey();
            Object value = entry.getValue().value;
            realResponses.put(key, value);
        }
        multiExecutionCallback.onComplete(realResponses);
    }

    private boolean setDone() {
        return DONE.compareAndSet(this, FALSE, TRUE);
    }

    private void triggerOnResponse(Member member, Object response) {
        try {
            multiExecutionCallback.onResponse(member, response);
        } catch (Throwable e) {
            logger.warning(e.getMessage(), e);
        }
    }

    private void placeResponse(Member member, Object response) {
        ValueWrapper current = responses.put(member, new ValueWrapper(response));

        if (current != null) {
            logger.warning("Replacing current callback value[" + current.value
                    + " with value[" + response + "].");
        }
    }

    private void assertIsMember(Member member) {
        if (!members.contains(member)) {
            throw new IllegalArgumentException(member + " is not known by this callback!");
        }
    }

    private void assertNotDone() {
        if (done) {
            throw new IllegalStateException("This callback is invalid!");
        }
    }

     ExecutionCallback callbackFor(Member member) {
        return new InnerExecutionCallback(member);
    }

    private static final class ValueWrapper {
        final Object value;

        private ValueWrapper(Object value) {
            this.value = value;
        }
    }

    private final class InnerExecutionCallback implements ExecutionCallback {
        private final Member member;

        private InnerExecutionCallback(Member member) {
            this.member = member;
        }

        @Override
        public void onResponse(V response) {
            ExecutionCallbackAdapterFactory.this.onResponse(member, response);
        }

        @Override
        public void onFailure(Throwable t) {
            ExecutionCallbackAdapterFactory.this.onResponse(member, t);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy