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

io.vertx.tp.plugin.shared.SharedClientImpl Maven / Gradle / Ivy

There is a newer version: 0.9.0
Show newest version
package io.vertx.tp.plugin.shared;

import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;
import io.vertx.core.json.JsonObject;
import io.vertx.core.shareddata.AsyncMap;
import io.vertx.core.shareddata.LocalMap;
import io.vertx.core.shareddata.SharedData;
import io.vertx.up.exception.web._501SharedDataModeException;
import io.vertx.up.fn.Fn;
import io.vertx.up.log.Annal;
import io.vertx.up.uca.container.Kv;

import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

@SuppressWarnings("all")
public class SharedClientImpl implements SharedClient {

    private static final Annal LOGGER = Annal.get(SharedClientImpl.class);

    private static final ConcurrentMap CLIENTS =
            new ConcurrentHashMap<>();

    private final transient Vertx vertx;
    private transient LocalMap syncMap;
    private transient AsyncMap asyncMap;
    private transient boolean isAsync;

    SharedClientImpl(final Vertx vertx) {
        this.vertx = vertx;
    }

    SharedClient create(final JsonObject config, final String name) {
        return Fn.pool(CLIENTS, name, () -> {
            final boolean async = null != config && config.containsKey("async") ?
                    config.getBoolean("async") : Boolean.FALSE;
            if (async) {
                // Switch reference for async map to be sure it's initialized.
                this.createAsync(name, res -> this.asyncMap = res.result().fetchAsync());
            } else {
                this.createSync(name);
            }
            return this;
        });
    }

    @Override
    public AsyncMap fetchAsync() {
        return this.asyncMap;
    }

    @Override
    public LocalMap fetchSync() {
        return this.syncMap;
    }

    @Override
    public SharedClient switchClient(final String name) {
        final SharedClient client;
        if (this.isAsync) {
            // Switch reference for async map to be sure it's initialized.
            client = new SharedClientImpl(this.vertx).create(new JsonObject().put("async", Boolean.TRUE), name);
        } else {
            client = new SharedClientImpl(this.vertx).create(new JsonObject().put("async", Boolean.FALSE), name);
        }
        return client;
    }

    private SharedClient createSync(final String name) {
        final SharedData sd = this.vertx.sharedData();
        // Sync map created
        this.syncMap = sd.getLocalMap(name);
        LOGGER.info(Info.INFO_SYNC, String.valueOf(this.syncMap.hashCode()));
        this.isAsync = false;
        return this;
    }

    private SharedClient createAsync(final String name,
                                     final Handler> handler) {
        final SharedData sd = this.vertx.sharedData();
        // Async map created
        LOGGER.info(Info.INFO_ASYNC_START);
        sd.getAsyncMap(name, res -> {
            if (res.succeeded()) {
                this.asyncMap = res.result();
                LOGGER.info(Info.INFO_ASYNC_END, String.valueOf(this.asyncMap.hashCode()));
                this.isAsync = true;
                handler.handle(Future.succeededFuture(this));
            }
        });
        return this;
    }

    @Override
    public Kv put(final K key, final V value) {
        this.ensure(false);
        final V reference = this.syncMap.get(key);
        // Add & Replace
        Fn.safeSemi(null == reference, LOGGER,
                () -> this.syncMap.put(key, value),
                () -> this.syncMap.replace(key, value));
        return Kv.create(key, value);
    }

    @Override
    public Kv put(final K key, final V value, final int seconds) {
        Kv result = this.put(key, value);
        LOGGER.info(Info.INFO_TIMER_PUT, key, String.valueOf(seconds));
        this.vertx.setTimer(seconds * 1000, id -> {
            final V existing = this.get(key);
            if (Objects.nonNull(existing)) {
                LOGGER.info(Info.INFO_TIMER_EXPIRE, key);
                this.remove(key);
            } else {
                LOGGER.info(Info.INFO_TIMER_REMOVED, key);
            }
        });
        return result;
    }

    @Override
    public SharedClient put(final K key, final V value,
                                  final Handler>> handler) {
        this.ensure(true);
        this.asyncMap.get(key, res -> {
            if (res.succeeded()) {
                final V reference = res.result();
                Fn.safeSemi(null == reference, LOGGER,
                        () -> this.asyncMap.put(key, value, added -> {
                            if (added.succeeded()) {
                                handler.handle(Future.succeededFuture(Kv.create(key, value)));
                            }
                        }),
                        () -> this.asyncMap.replace(key, value, replaced -> {
                            if (replaced.succeeded()) {
                                handler.handle(Future.succeededFuture(Kv.create(key, value)));
                            }
                        }));
            }
        });
        return this;
    }

    @Override
    public SharedClient put(final K key, final V value, final int seconds,
                                  final Handler>> handler) {
        final SharedClient reference = this.put(key, value, handler);
        LOGGER.info(Info.INFO_TIMER_PUT, key, String.valueOf(seconds));
        this.vertx.setTimer(seconds * 1000, id -> this.remove(key, res -> LOGGER.info(Info.INFO_TIMER_EXPIRE, key)));
        return reference;
    }

    @Override
    public Kv remove(final K key) {
        this.ensure(false);
        final V removed = this.syncMap.remove(key);
        return Kv.create(key, removed);
    }

    @Override
    public V get(final K key) {
        this.ensure(false);
        return this.syncMap.get(key);
    }

    @Override
    public V get(final K key, final boolean once) {
        final V value = this.get(key);
        if (once) {
            this.remove(key);
        }
        return value;
    }

    @Override
    public SharedClient remove(final K key,
                                     final Handler>> handler) {
        this.ensure(true);
        this.asyncMap.remove(key, res -> {
            if (res.succeeded()) {
                final V reference = res.result();
                handler.handle(Future.succeededFuture(Kv.create(key, reference)));
            }
        });
        return this;
    }

    @Override
    public SharedClient get(final K key,
                                  final Handler> handler) {
        this.ensure(true);
        this.asyncMap.get(key, handler);
        return this;
    }

    @Override
    public SharedClient get(K key, boolean once,
                                  Handler> handler) {
        final SharedClient reference = this.get(key, handler);
        if (once) {
            this.asyncMap.remove(key, handler);
        }
        return reference;
    }

    private void ensure(final boolean expected) {
        Fn.outWeb(this.isAsync != expected, LOGGER,
                _501SharedDataModeException.class, this.getClass(), this.isAsync);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy