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

com.swiftmq.amqp.v100.client.Session Maven / Gradle / Ivy

/*
 * Copyright 2019 IIT Software GmbH
 *
 * IIT Software GmbH licenses this file to You 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.swiftmq.amqp.v100.client;

import com.swiftmq.amqp.AMQPContext;
import com.swiftmq.amqp.v100.client.po.*;
import com.swiftmq.amqp.v100.generated.messaging.addressing.TerminusExpiryPolicy;
import com.swiftmq.amqp.v100.generated.transport.definitions.Error;
import com.swiftmq.tools.concurrent.Semaphore;
import com.swiftmq.tools.pipeline.POObject;

import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * A Session, created from a Connection.
 *
 * @author IIT Software GmbH, Bremen/Germany, (c) 2011, All Rights Reserved
 */
public class Session {
    AMQPContext ctx = null;
    Connection myConnection = null;
    int channel = 0;
    int remoteChannel = 0;
    long incomingWindowSize = 1;
    long outgoingWindowSize = 1;
    SessionDispatcher sessionDispatcher = null;
    volatile TransactionController transactionController = null;
    Set links = ConcurrentHashMap.newKeySet();
    ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    volatile boolean closed = false;
    Error error = null;

    protected Session(AMQPContext ctx, Connection myConnection, long incomingWindowSize, long outgoingWindowSize) {
        this.ctx = ctx;
        this.myConnection = myConnection;
        this.incomingWindowSize = incomingWindowSize;
        this.outgoingWindowSize = outgoingWindowSize;
        sessionDispatcher = new SessionDispatcher(ctx, this, myConnection.getOutboundHandler());
    }

    protected void finishHandshake() throws SessionHandshakeException {
        Semaphore sem = new Semaphore();
        POObject po = new POBegin(sem);
        sessionDispatcher.dispatch(po);
        sem.waitHere();
        sem.reset();
        if (!po.isSuccess()) {
            cancel();
            throw new SessionHandshakeException(po.getException());
        }
    }

    private void verifyState() throws SessionClosedException {
        if (closed)
            throw new SessionClosedException("Session is closed" + (error != null ? ": " + error.getCondition().getValueString() + "/" + error.getDescription().getValue() : ""));
    }

    /**
     * Returns the channel.
     *
     * @return channel
     */
    public int getChannel() {
        return channel;
    }

    protected void setChannel(int channel) {
        this.channel = channel;
        sessionDispatcher.setMyChannel(channel);
    }

    protected SessionDispatcher getSessionDispatcher() {
        return sessionDispatcher;
    }

    protected void remoteClose() {
        myConnection.connectionDispatcher.dispatch(new PORemoteSessionClose(this));
    }

    protected int getRemoteChannel() {
        return remoteChannel;
    }

    protected void setRemoteChannel(int remoteChannel) {
        this.remoteChannel = remoteChannel;
    }

    /**
     * Return the incoming window size.
     *
     * @return incoming window size
     */
    public long getIncomingWindowSize() {
        return incomingWindowSize;
    }

    /**
     * Return the outgoing window size.
     *
     * @return outgoing window size
     */
    public long getOutgoingWindowSize() {
        return outgoingWindowSize;
    }

    /**
     * Creates a message producer on a target.
     *
     * @param target the target, e.g. queue name
     * @param qoS    the quality of service
     * @return message producer
     * @throws AMQPException on error
     */
    public Producer createProducer(String target, int qoS) throws AMQPException {
        return createProducer(target, qoS, null);
    }

    /**
     * Creates a message producer on a target.
     *
     * @param target         the target, e.g. queue name
     * @param qoS            the quality of service
     * @param deliveryMemory delivery memory for recovery
     * @return message producer
     * @throws AMQPException on error
     */
    public Producer createProducer(String target, int qoS, DeliveryMemory deliveryMemory) throws AMQPException {
        verifyState();
        QoS.verify(qoS);
        Semaphore sem = new Semaphore();
        POAttachProducer po = new POAttachProducer(sem, target, qoS, deliveryMemory == null ? new DefaultDeliveryMemory() : deliveryMemory);
        sessionDispatcher.dispatch(po);
        sem.waitHere();
        if (!po.isSuccess())
            throw new AMQPException(po.getException());
        Producer p = (Producer) po.getLink();
        links.add(p);
        return p;
    }

    /**
     * Creates a message consumer on a source.
     *
     * @param source     the source, e.g. queue name
     * @param linkCredit link credit
     * @param qoS        quality of service
     * @param noLocal    if true means it won't receive messages sent on the same topic and connection
     * @param selector   message selector (for SwiftMQ this would be a JMS message selector string)
     * @return message consumer
     * @throws AMQPException on error
     */
    public Consumer createConsumer(String source, int linkCredit, int qoS, boolean noLocal, String selector) throws AMQPException {
        return createConsumer(source, linkCredit, qoS, noLocal, selector, null);
    }

    /**
     * Creates a message consumer on a source.
     *
     * @param source         the source, e.g. queue name
     * @param linkCredit     link credit
     * @param qoS            quality of service
     * @param noLocal        if true means it won't receive messages sent on the same topic and connection
     * @param selector       message selector (for SwiftMQ this would be a JMS message selector string)
     * @param deliveryMemory delivery memory for recovery
     * @return message consumer
     * @throws AMQPException on error
     */
    public Consumer createConsumer(String source, int linkCredit, int qoS, boolean noLocal, String selector, DeliveryMemory deliveryMemory) throws AMQPException {
        verifyState();
        QoS.verify(qoS);
        Semaphore sem = new Semaphore();
        POAttachConsumer po = new POAttachConsumer(sem, source, linkCredit, qoS, noLocal, selector, deliveryMemory == null ? new DefaultDeliveryMemory() : deliveryMemory);
        sessionDispatcher.dispatch(po);
        sem.waitHere();
        if (!po.isSuccess())
            throw new AMQPException(po.getException());
        Consumer c = (Consumer) po.getLink();
        links.add(c);
        return c;
    }

    /**
     * Creates a message consumer on a source without a link credit. This is required for transactional acquisition.
     *
     * @param source   the source, e.g. queue name
     * @param qoS      quality of service
     * @param noLocal  if true means it won't receive messages sent on the same topic and connection
     * @param selector message selector (for SwiftMQ this would be a JMS message selector string)
     * @return message consumer
     * @throws AMQPException on error
     */
    public Consumer createConsumer(String source, int qoS, boolean noLocal, String selector) throws AMQPException {
        verifyState();
        QoS.verify(qoS);
        Semaphore sem = new Semaphore();
        POAttachConsumer po = new POAttachConsumer(sem, source, -1, qoS, noLocal, selector, new DefaultDeliveryMemory());
        sessionDispatcher.dispatch(po);
        sem.waitHere();
        if (!po.isSuccess())
            throw new AMQPException(po.getException());
        Consumer c = (Consumer) po.getLink();
        links.add(c);
        return c;
    }

    /**
     * Creates a temporary destination and a message consumer on it. The temporary destination has a lifetime of
     * the connection.
     *
     * @param qoS quality of service
     * @return message consumer
     * @throws AMQPException on error
     */
    public Consumer createConsumer(int linkCredit, int qoS) throws AMQPException {
        verifyState();
        QoS.verify(qoS);
        Semaphore sem = new Semaphore();
        POAttachConsumer po = new POAttachConsumer(sem, null, linkCredit, qoS, false, null, new DefaultDeliveryMemory());
        sessionDispatcher.dispatch(po);
        sem.waitHere();
        if (!po.isSuccess())
            throw new AMQPException(po.getException());
        Consumer c = (Consumer) po.getLink();
        links.add(c);
        return c;
    }

    /**
     * Creates a durable message consumer on a topic. This is the same as a durable subscriber in JMS. The container id
     * and linkName is used to identify the durable consumer. A durable consumer is backed by a durable link which will
     * only be destroyed by calling "unsubscribe()" from the durable consumer.
     *
     * @param linkName   the name of the link
     * @param source     the source, e.g. queue name
     * @param linkCredit link credit
     * @param qoS        quality of service
     * @param noLocal    if true means it won't receive messages sent on the same topic and connection
     * @param selector   message selector (for SwiftMQ this would be a JMS message selector string)
     * @return message consumer
     * @throws AMQPException on error
     */
    public DurableConsumer createDurableConsumer(String linkName, String source, int linkCredit, int qoS, boolean noLocal, String selector) throws AMQPException {
        return createDurableConsumer(linkName, source, linkCredit, qoS, noLocal, selector, null);
    }

    /**
     * Creates a durable message consumer on a topic. This is the same as a durable subscriber in JMS. The container id
     * and linkName is used to identify the durable consumer. A durable consumer is backed by a durable link which will
     * only be destroyed by calling "unsubscribe()" from the durable consumer.
     *
     * @param linkName       the name of the link
     * @param source         the source, e.g. queue name
     * @param linkCredit     link credit
     * @param qoS            quality of service
     * @param noLocal        if true means it won't receive messages sent on the same topic and connection
     * @param selector       message selector (for SwiftMQ this would be a JMS message selector string)
     * @param deliveryMemory delivery memory for recovery
     * @return message consumer
     * @throws AMQPException on error
     */
    public DurableConsumer createDurableConsumer(String linkName, String source, int linkCredit, int qoS, boolean noLocal, String selector, DeliveryMemory deliveryMemory) throws AMQPException {
        verifyState();
        if (linkName == null)
            throw new AMQPException("Please specify the link name");
        if (!myConnection.containerIdSet)
            throw new AMQPException("Please specify a container id");
        QoS.verify(qoS);
        Semaphore sem = new Semaphore();
        POAttachDurableConsumer po = new POAttachDurableConsumer(sem, linkName, source, linkCredit, qoS, noLocal, selector, TerminusExpiryPolicy.NEVER, deliveryMemory == null ? new DefaultDeliveryMemory() : deliveryMemory);
        sessionDispatcher.dispatch(po);
        sem.waitHere();
        if (!po.isSuccess())
            throw new AMQPException(po.getException());
        DurableConsumer d = (DurableConsumer) po.getLink();
        links.add(d);
        return d;
    }

    protected void detach(Link link) {
            links.remove(link);
    }

    /**
     * Returns the transaction controller of this session.
     *
     * @return transaction controller
     * @throws SessionClosedException if the session is closed
     */
    public TransactionController getTransactionController() throws SessionClosedException {
        verifyState();
        if (transactionController == null)
            transactionController = new TransactionController(this);
        return transactionController;
    }

    protected void dispatch(POObject po) {
        sessionDispatcher.dispatch(po);
    }

    protected void remoteEnd(com.swiftmq.amqp.v100.generated.transport.definitions.Error error) {
        this.error = error;
        cancel();
    }

    private Link[] getLinksCopy() {
        Link[] l = links.toArray(new Link[links.size()]);
            links.clear();
            return l;
    }

    protected void cancel() {
        if (closed)
            return;
        if (links.size() > 0) {
            Link[] l = getLinksCopy();
            for (Link link : l)
                link.cancel();
        }
        myConnection.removeSession(this);
        myConnection.unmapSessionFromRemoteChannel(remoteChannel);
        sessionDispatcher.close();
        closed = true;
    }

    /**
     * Closes the session and all consumers/producers created from this session.
     */
    public void close() {
        if (closed)
            return;
        if (transactionController != null) {
            transactionController.close();
            transactionController = null;
        }
        Semaphore sem = new Semaphore();
        POSendEnd po = new POSendEnd(sem, null);
        sessionDispatcher.dispatch(po);
        sem.waitHere();
        cancel();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy