Package com.proofpoint.discovery.client

Source Code of com.proofpoint.discovery.client.ServiceDescriptorsUpdater

/*
* Copyright 2010 Proofpoint, Inc.
*
* 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.proofpoint.discovery.client;

import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import com.proofpoint.log.Logger;
import com.proofpoint.node.NodeInfo;
import com.proofpoint.units.Duration;

import javax.annotation.PostConstruct;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.proofpoint.discovery.client.announce.DiscoveryAnnouncementClient.DEFAULT_DELAY;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;

public final class ServiceDescriptorsUpdater
{
    private static final Logger log = Logger.get(ServiceDescriptorsUpdater.class);

    private final ServiceDescriptorsListener target;
    private final String type;
    private final String pool;
    private final DiscoveryLookupClient discoveryClient;
    private final AtomicReference<ServiceDescriptors> serviceDescriptors = new AtomicReference<>();
    private final ScheduledExecutorService executor;

    private final AtomicBoolean started = new AtomicBoolean(false);
    private final ExponentialBackOff errorBackOff;

    public ServiceDescriptorsUpdater(ServiceDescriptorsListener target, String type, ServiceSelectorConfig selectorConfig, NodeInfo nodeInfo, DiscoveryLookupClient discoveryClient, ScheduledExecutorService executor)
    {
        checkNotNull(target, "target is null");
        checkNotNull(type, "type is null");
        checkNotNull(selectorConfig, "selectorConfig is null");
        checkNotNull(nodeInfo, "nodeInfo is null");
        checkNotNull(discoveryClient, "discoveryClient is null");
        checkNotNull(executor, "executor is null");

        this.target = target;
        this.type = type;
        this.pool = firstNonNull(selectorConfig.getPool(), nodeInfo.getPool());
        this.discoveryClient = discoveryClient;
        this.executor = executor;
        this.errorBackOff = new ExponentialBackOff(
                new Duration(1, MILLISECONDS),
                new Duration(1, SECONDS),
                String.format("Discovery server connect succeeded for refresh (%s/%s)", type, pool),
                String.format("Cannot connect to discovery server for refresh (%s/%s)", type, pool),
                log);
    }

    @PostConstruct
    public void start()
    {
        if (started.compareAndSet(false, true)) {
            checkState(!executor.isShutdown(), "CachingServiceSelector has been destroyed");

            // if discovery is available, get the initial set of servers before starting
            try {
                refresh().get(30, TimeUnit.SECONDS);
            }
            catch (Exception ignored) {
            }
        }
    }

    private ListenableFuture<ServiceDescriptors> refresh()
    {
        final ServiceDescriptors oldDescriptors = this.serviceDescriptors.get();

        final ListenableFuture<ServiceDescriptors> future;
        if (oldDescriptors == null) {
            future = discoveryClient.getServices(type, pool);
        }
        else {
            future = discoveryClient.refreshServices(oldDescriptors);
        }

        return chainedCallback(future, new FutureCallback<ServiceDescriptors>()
        {
            @Override
            public void onSuccess(ServiceDescriptors newDescriptors)
            {
                serviceDescriptors.set(newDescriptors);
                target.updateServiceDescriptors(newDescriptors.getServiceDescriptors());
                errorBackOff.success();

                Duration delay = newDescriptors.getMaxAge();
                if (delay == null) {
                    delay = DEFAULT_DELAY;
                }
                scheduleRefresh(delay);
            }

            @Override
            public void onFailure(Throwable t)
            {
                Duration duration = errorBackOff.failed(t);
                scheduleRefresh(duration);
            }
        }, executor);
    }

    private void scheduleRefresh(Duration delay)
    {
        // already stopped?  avoids rejection exception
        if (executor.isShutdown()) {
            return;
        }
        executor.schedule(new Runnable()
        {
            @Override
            public void run()
            {
                refresh();
            }
        }, delay.toMillis(), TimeUnit.MILLISECONDS);
    }

    private static <V> ListenableFuture<V> chainedCallback(
            ListenableFuture<V> future,
            final FutureCallback<? super V> callback,
            Executor executor)
    {
        final SettableFuture<V> done = SettableFuture.create();
        Futures.addCallback(future, new FutureCallback<V>()
        {
            @Override
            public void onSuccess(V result)
            {
                try {
                    callback.onSuccess(result);
                }
                finally {
                    done.set(result);
                }
            }

            @Override
            public void onFailure(Throwable t)
            {
                try {
                    callback.onFailure(t);
                }
                finally {
                    done.setException(t);
                }
            }
        }, executor);
        return done;
    }
}
TOP

Related Classes of com.proofpoint.discovery.client.ServiceDescriptorsUpdater

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.