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

io.nats.stan.SubscriptionImpl Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright (c) 2015-2016 Apcera Inc. All rights reserved. This program and the accompanying
 * materials are made available under the terms of the MIT License (MIT) which accompanies this
 * distribution, and is available at http://opensource.org/licenses/MIT
 *******************************************************************************/

package io.nats.stan;

import io.nats.stan.protobuf.SubscriptionResponse;
import io.nats.stan.protobuf.UnsubscribeRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

class SubscriptionImpl implements Subscription {
    static final Logger logger = LoggerFactory.getLogger(SubscriptionImpl.class);

    static final long DEFAULT_ACK_WAIT = 30 * 1000;
    static final int DEFAULT_MAX_IN_FLIGHT = 1024;

    final ReadWriteLock rwlock = new ReentrantReadWriteLock();
    ConnectionImpl sc;
    String subject;
    String qgroup;
    String inbox;
    String ackInbox;
    io.nats.client.Subscription inboxSub;
    SubscriptionOptions opts = new SubscriptionOptions.Builder().build();
    MessageHandler cb;

    protected SubscriptionImpl() {}

    protected SubscriptionImpl(String subject, String qgroup, MessageHandler cb, ConnectionImpl sc,
            SubscriptionOptions opts) {
        this.subject = subject;
        this.qgroup = qgroup;
        this.cb = cb;
        this.sc = sc;
        if (opts != null) {
            this.opts = opts;
        }
        this.inbox = sc.newInbox();
    }

    protected void rLock() {
        rwlock.readLock().lock();
    }

    protected void rUnlock() {
        rwlock.readLock().unlock();
    }

    protected void wLock() {
        rwlock.writeLock().lock();
    }

    protected void wUnlock() {
        rwlock.writeLock().unlock();
    }

    protected String getAckInbox() {
        return this.ackInbox;
    }

    protected ConnectionImpl getConnection() {
        return this.sc;
    }

    protected String getInbox() {
        return this.inbox;
    }

    protected MessageHandler getMessageHandler() {
        return this.cb;
    }

    @Override
    public String getQueue() {
        return this.qgroup;
    }

    @Override
    public String getSubject() {
        return this.subject;
    }

    @Override
    public SubscriptionOptions getOptions() {
        return this.opts;
    }

    @Override
    public void unsubscribe() throws IOException, TimeoutException {
        ConnectionImpl sc = null;
        String inbox = null;
        String reqSubject = null;
        wLock();
        try {
            sc = this.sc;
            if (sc == null) {
                // FIXME Already closed.
                throw new IllegalStateException(ConnectionImpl.ERR_BAD_SUBSCRIPTION);
            }
            this.sc = null;
            try {
                if (inboxSub != null) {
                    inboxSub.unsubscribe();
                }
            } catch (Exception e) {
                logger.warn("stan: encountered exception unsubscribing from inbox", e);
            }
            inboxSub = null;
            inbox = this.inbox;
        } finally {
            wUnlock();
        }
        // FIXME why do this again?
        // if (sc == null) {
        // throw new IllegalStateException(ConnectionImpl.ERR_BAD_SUBSCRIPTION);
        // }
        sc.lock();
        try {
            if (sc.nc == null) {
                throw new IllegalStateException(ConnectionImpl.ERR_CONNECTION_CLOSED);
            }

            sc.subMap.remove(inbox);
            reqSubject = sc.unsubRequests;
        } finally {
            sc.unlock();
        }

        // Send unsubscribe to server.

        // FIXME(dlc) = Add in durable?
        UnsubscribeRequest usr = UnsubscribeRequest.newBuilder().setClientID(sc.getClientId())
                .setSubject(subject).setInbox(ackInbox).build();
        byte[] bytes = usr.toByteArray();

        io.nats.client.Message reply = null;
        try {
            // logger.trace("Sending UnsubscribeRequest:\n{}", usr);
            // FIXME(dlc) - make timeout configurable.
            reply = sc.nc.request(reqSubject, bytes, 2, TimeUnit.SECONDS);
        } catch (TimeoutException e) {
            throw new TimeoutException(ConnectionImpl.ERR_TIMEOUT);
        }
        SubscriptionResponse response = SubscriptionResponse.parseFrom(reply.getData());
        // logger.trace("Received Unsubscribe SubscriptionResponse:\n{}", response);
        if (!response.getError().isEmpty()) {
            throw new IOException("stan: " + response.getError());
        }
    }

    @Override
    public void close() {
        if (this.sc == null) {
            // already closed
            return;
        }
        try {
            unsubscribe();
        } catch (Exception e) {
            logger.warn("stan: exception during unsubscribe for subject {}", this.subject);
            logger.debug("Stack trace: ", e);
        }
    }

    protected void setAckInbox(String ackInbox) {
        this.ackInbox = ackInbox;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy