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

org.redisson.RedissonBaseAdder Maven / Gradle / Ivy

There is a newer version: 0.40.13
Show newest version
/**
 * Copyright 2018 Nikita Koksharov
 *
 * 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 org.redisson;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.redisson.api.RFuture;
import org.redisson.api.RSemaphore;
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.redisson.api.listener.MessageListener;
import org.redisson.client.ChannelName;
import org.redisson.client.codec.LongCodec;
import org.redisson.command.CommandAsyncExecutor;
import org.redisson.misc.RPromise;
import org.redisson.misc.RedissonPromise;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;

/**
 * 
 * @author Nikita Koksharov
 *
 */
public abstract class RedissonBaseAdder extends RedissonExpirable {

    private class ResetListener implements FutureListener {
        
        private final RPromise result;

        private ResetListener(RPromise result) {
            this.result = result;
        }

        @Override
        public void operationComplete(Future future) throws Exception {
            if (!future.isSuccess()) {
                result.tryFailure(future.cause());
                return;
            }
            
            acquireAsync(future.getNow().intValue()).addListener(new FutureListener() {
                @Override
                public void operationComplete(Future future) throws Exception {
                    if (!future.isSuccess()) {
                        result.tryFailure(future.cause());
                        return;
                    }

                    result.trySuccess(null);
                }
            });
        }

        protected RFuture acquireAsync(int value) {
            return semaphore.acquireAsync(value);
        }
    }

    private class SumListener implements FutureListener {
        
        private final RPromise result;

        private SumListener(RPromise result) {
            this.result = result;
        }

        @Override
        public void operationComplete(Future future) throws Exception {
            if (!future.isSuccess()) {
                result.tryFailure(future.cause());
                return;
            }

            acquireAsync(future.getNow().intValue()).addListener(new FutureListener() {
                @Override
                public void operationComplete(Future future) throws Exception {
                    if (!future.isSuccess()) {
                        result.tryFailure(future.cause());
                        return;
                    }

                    RFuture valueFuture = getAndDeleteAsync();
                    valueFuture.addListener(new FutureListener() {
                        @Override
                        public void operationComplete(Future future) throws Exception {
                            if (!future.isSuccess()) {
                                result.tryFailure(future.cause());
                                return;
                            }
                            
                            result.trySuccess(future.getNow());
                        }
                    });
                }
            });
        }

        protected RFuture acquireAsync(int value) {
            return semaphore.acquireAsync(value);
        }
    }

    private static final Logger log = LoggerFactory.getLogger(RedissonBaseAdder.class);
    
    private static final long CLEAR_MSG = 0;
    private static final long SUM_MSG = 1;

    private final RSemaphore semaphore;
    private final RTopic topic;
    private final int listenerId;
    
    public RedissonBaseAdder(CommandAsyncExecutor connectionManager, String name, RedissonClient redisson) {
        super(connectionManager, name);
        
        topic = redisson.getTopic(suffixName(getName(), "topic"), LongCodec.INSTANCE);
        semaphore = redisson.getSemaphore(suffixName(getName(), "semaphore"));
        listenerId = topic.addListener(Long.class, new MessageListener() {
            
            @Override
            public void onMessage(CharSequence channel, Long msg) {
                if (msg == SUM_MSG) {
                    RFuture addAndGetFuture = addAndGetAsync();
                    addAndGetFuture.addListener(new FutureListener() {
                        @Override
                        public void operationComplete(Future future) throws Exception {
                            if (!future.isSuccess()) {
                                log.error("Can't increase sum", future.cause());
                                return;
                            }
                            
                            semaphore.releaseAsync().addListener(new FutureListener() {
                                @Override
                                public void operationComplete(Future future) throws Exception {
                                    if (!future.isSuccess()) {
                                        log.error("Can't release semaphore", future.cause());
                                        return;
                                    }
                                }
                            });
                        }
                    });
                }
                
                if (msg == CLEAR_MSG) {
                    doReset();
                    semaphore.releaseAsync().addListener(new FutureListener() {
                        @Override
                        public void operationComplete(Future future) throws Exception {
                            if (!future.isSuccess()) {
                                log.error("Can't release semaphore", future.cause());
                                return;
                            }
                        }
                    });
                }
            }

        });
        
    }

    protected abstract void doReset();

    public void reset() {
        get(resetAsync());
    }
    
    public void reset(long timeout, TimeUnit timeUnit) {
        get(resetAsync(timeout, timeUnit));
    }
    
    public RFuture sumAsync() {
        final RPromise result = new RedissonPromise();
        
        RFuture future = topic.publishAsync(SUM_MSG);
        future.addListener(new SumListener(result));
        
        return result;
    }
    
    public RFuture sumAsync(final long timeout, final TimeUnit timeUnit) {
        RPromise result = new RedissonPromise();
        
        RFuture future = topic.publishAsync(SUM_MSG);
        future.addListener(new SumListener(result) {
            @Override
            protected RFuture acquireAsync(int value) {
                return tryAcquire(timeout, timeUnit, value);
            }

        });
        
        return result;
    }

    protected RFuture tryAcquire(long timeout, TimeUnit timeUnit, int value) {
        final RPromise acquireResult = new RedissonPromise();
        semaphore.tryAcquireAsync(value, timeout, timeUnit).addListener(new FutureListener() {
            @Override
            public void operationComplete(Future future) throws Exception {
                if (!future.isSuccess()) {
                    acquireResult.tryFailure(future.cause());
                    return;
                }
                
                if (future.getNow()) {
                    acquireResult.trySuccess(null);
                } else {
                    acquireResult.tryFailure(new TimeoutException());
                }
            }
        });
        return acquireResult;
    }

    public RFuture resetAsync() {
        final RPromise result = new RedissonPromise();
        
        RFuture future = topic.publishAsync(CLEAR_MSG);
        future.addListener(new ResetListener(result));
        
        return result;
    }
    
    public RFuture resetAsync(final long timeout, final TimeUnit timeUnit) {
        final RPromise result = new RedissonPromise();
        
        RFuture future = topic.publishAsync(CLEAR_MSG);
        future.addListener(new ResetListener(result) {
            @Override
            protected RFuture acquireAsync(int value) {
                return tryAcquire(timeout, timeUnit, value);
            }
        });
        
        return result;
    }

    public void destroy() {
        topic.removeListener(listenerId);
    }

    protected abstract RFuture addAndGetAsync();

    protected abstract RFuture getAndDeleteAsync();

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy