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

mq5.0-source.main.mq-broker.broker-core.src.main.java.com.sun.messaging.jmq.jmsserver.data.handlers.ConsumerHandler Maven / Gradle / Ivy

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2000-2013 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

/*
 * @(#)ConsumerHandler.java
 */ 

package com.sun.messaging.jmq.jmsserver.data.handlers;

import java.util.*;
import java.io.*;
import com.sun.messaging.jmq.jmsserver.data.PacketHandler;
import com.sun.messaging.jmq.util.DestType;
import com.sun.messaging.jmq.io.*;
import com.sun.messaging.jmq.jmsserver.service.Connection;
import com.sun.messaging.jmq.jmsserver.service.imq.IMQConnection;
import com.sun.messaging.jmq.jmsserver.service.imq.IMQBasicConnection;
import com.sun.messaging.jmq.jmsserver.util.BrokerException;
import com.sun.messaging.jmq.jmsserver.util.ConsumerAlreadyAddedException;
import com.sun.messaging.jmq.jmsserver.core.Destination;
import com.sun.messaging.jmq.jmsserver.core.DestinationList;
import com.sun.messaging.jmq.jmsserver.core.DestinationUID;
import com.sun.messaging.jmq.jmsserver.core.SessionUID;
import com.sun.messaging.jmq.jmsserver.core.Session;
import com.sun.messaging.jmq.jmsserver.core.Consumer;
import com.sun.messaging.jmq.jmsserver.core.Subscription;
import com.sun.messaging.jmq.jmsserver.core.ConsumerUID;
import com.sun.messaging.jmq.io.PacketUtil;
import com.sun.messaging.jmq.jmsserver.resources.BrokerResources;
import com.sun.messaging.jmq.util.log.Logger;
import com.sun.messaging.jmq.jmsserver.Globals;
import com.sun.messaging.jmq.util.selector.Selector;
import com.sun.messaging.jmq.util.lists.OutOfLimitsException;
import com.sun.messaging.jmq.util.selector.SelectorFormatException;
import com.sun.messaging.jmq.jmsserver.license.*;
import com.sun.messaging.jmq.jmsserver.management.agent.Agent;
import com.sun.messaging.jmq.jmsserver.FaultInjection;
import com.sun.messaging.jmq.jmsserver.common.handlers.ClientIDHandler;
import com.sun.messaging.jmq.jmsserver.persist.api.PartitionedStore;
import com.sun.messaging.jmq.jmsserver.cluster.api.ClusterBroadcast;


/**
 * Handler class which deals with adding and removing interests from the RouteTable
 */
public class ConsumerHandler extends PacketHandler 
{
    private Logger logger = Globals.getLogger();
    private static boolean DEBUG = false;

    private static boolean DEBUG_CLUSTER_TXN =
        Globals.getConfig().getBooleanProperty(Globals.IMQ + ".cluster.debug.txn");
    private static boolean DEBUG_CLUSTER_MSG =
        Globals.getConfig().getBooleanProperty(Globals.IMQ + ".cluster.debug.msg");

    private DestinationList DL = Globals.getDestinationList();

    static {
        if (!DEBUG) DEBUG = DEBUG_CLUSTER_TXN || DEBUG_CLUSTER_MSG;
    }

    private FaultInjection fi = null;

    public ConsumerHandler() {
        fi = FaultInjection.getInjection();
    }

    boolean ALWAYS_WAIT_ON_DESTROY = Globals.getConfig().getBooleanProperty(Globals.IMQ + ".waitForConsumerDestroy");


    /**
     * Method to handle Consumer(add or delete) messages
     */
    public boolean handle(IMQConnection con, Packet msg) 
        throws BrokerException
    {
        boolean sessionPaused = false;
        boolean conPaused = false;
        Hashtable props = null;
        try {
            props = msg.getProperties();
        } catch (Exception ex) {
            logger.log(Logger.INFO,"Internal Error: unable to retrieve "+
                " properties from consumer message " + msg, ex);
        }
        if (props == null) {
            props = new Hashtable();
        }

        Long lsessionid = (Long)props.get("JMQSessionID");


        Session session = null;


        String err_reason = null;

        Boolean blockprop = (Boolean)props.get("JMQBlock");

        Consumer newc = null;

        assert blockprop == null || msg.getPacketType() == PacketType.DELETE_CONSUMER
               : msg;

        boolean blockprop_bool = (blockprop != null && blockprop.booleanValue());


        boolean isIndemp = msg.getIndempotent();


        // OK ... set up the reply packet
        Packet pkt = new Packet(con.useDirectBuffers());
        pkt.setConsumerID(msg.getConsumerID()); // correlation ID
        Hashtable hash = new Hashtable();
        pkt.setPacketType(msg.getPacketType() + 1);

        int status = Status.OK;
        String warning = BrokerResources.W_ADD_CONSUMER_FAILED;

        ConsumerUID uid = null;
        Integer destType = null;
        Integer oldid = null;
        Subscription sub = null;
        try {
            DL.acquirePartitionLock(true);
            try {

            con.suspend();
            conPaused = true;
            if (msg.getPacketType() == PacketType.ADD_CONSUMER) {
                if (DEBUG) {
                    logger.log(Logger.INFO, "ConsumerHandler: "+
                    "[Received AddConsumer message {0}]", msg.toString());
                }
                pkt.setPacketType(PacketType.ADD_CONSUMER_REPLY);
                if (lsessionid == null) {
                    if (DEBUG) {
                        logger.log(Logger.INFO, "ConsumerHandler: not Raptor consumer packet (no session id)");
                    }
                    // assign session same # as consumer
                    SessionUID sessionID = new SessionUID(
                               con.getConnectionUID().longValue());
                    // single threaded .. we dont have to worry about
                    // someone else creating it
                    session = con.getSession(sessionID);
                    if (session == null) {
                       session = Session.createSession(sessionID, 
                                  con.getConnectionUID(), null, coreLifecycle);
                       con.attachSession(session);
                    }
                } else {
                    SessionUID sessionID = new SessionUID(lsessionid.longValue());
                    session = con.getSession(sessionID);
                    if (session == null) {
                        throw new BrokerException("Internal Error: client set invalid"
                         + " sessionUID " + sessionID + " session does not exist");
                    }
                }

                if (blockprop_bool) { // turn off all processing
                   session.pause("Consumer - Block flag");
                   sessionPaused = true;
                }


                /* XXX-LKS KLUDGE FOR 2.0 compatibility */
                
                // for now, we just pass the consumer ID back on the old
                // packet .. I need to revisit this in the future
                oldid = (Integer)props.get("JMQConsumerID"); // old consumer ID
                if (oldid != null) {
                    hash.put("JMQOldConsumerID", oldid);
                }

                Integer inttype = (Integer )props.get("JMQDestType");
                int type = (inttype == null ? -1 : inttype.intValue());
                if (type == -1) {
                    throw new BrokerException(Globals.getBrokerResources().getString(
                   BrokerResources.X_INTERNAL_EXCEPTION,"Client is not sending DestType, "
                         + "unable to add interest"));
                }

                boolean queue = DestType.isQueue(type) ;

                String destination = (String)props.get("JMQDestination");
                String selector =  (String)props.get("JMQSelector");
                //JMS spec
                if (selector != null && selector.trim().length() == 0) {
                    selector = null;
                }
                boolean mqshare = false; 
                boolean jmsshare = false; //JMS2.0
                boolean nolocal = false;
                Boolean b = (Boolean)props.get("JMQNoLocal");
                if (b != null && b.booleanValue()) {
                    nolocal = true;              
                }
                b  = (Boolean)props.get("JMQShare");
                if (b != null && b.booleanValue()) {
                    mqshare = true;                   
                }
                b = (Boolean)props.get("JMQJMSShare"); //JMS2.0
                if (b != null && b.booleanValue()) {
                    jmsshare = true;                   
                }
                String durablename = (String)props.get("JMQDurableName");
                String subscriptionName = (String)props.get("JMQSharedSubscriptionName"); //JMS2.0

                String clientid = getClientID(props, con);
                Boolean reconnect = (Boolean)props.get("JMQReconnect");
                Integer size = (Integer)props.get("JMQSize");
                if (mqshare && jmsshare) {
                    String emsg = "Client protocol error: both JMQShare and JMQJMSShare set to true";
                    Globals.getLogger().log(Logger.ERROR, emsg); 
                    throw new BrokerException(emsg);
                }
                boolean shared = (mqshare || jmsshare);

                boolean durable = false;
                if (durablename != null) {
                    if (subscriptionName != null) {
                        Object[] args = { Subscription.getDSubLogString(clientid, durablename),
                                          ""+destination, subscriptionName };
                        logger.log(Logger.INFO, br.getKString(
                                   br.I_ADD_CONSUMER_IGNORE_SUBSCRIPTION_NAME, args));
                    }
                    subscriptionName = durablename; 
                    durable = true;
                }

                if (DestType.isTemporary(type)) { 
                    if (durable) {
                        String emsg = br.getKString(br.X_INVALID_DEST_DURA_CONSUMER, 
                                      ""+destination, ""+subscriptionName);
                        logger.log(Logger.ERROR, emsg);
                        throw new BrokerException(emsg, 
                            br.X_INVALID_DEST_DURA_CONSUMER, null,
                            Status.PRECONDITION_FAILED);
                    }
                    if (shared) {
                        String emsg = br.getKString(br.X_INVALID_DEST_SHARE_CONSUMER, 
                                      ""+destination, ""+subscriptionName);
                        logger.log(Logger.ERROR, emsg);
                        throw new BrokerException(emsg, 
                            br.X_INVALID_DEST_SHARE_CONSUMER, null,
                            Status.PRECONDITION_FAILED);
                    }
                }

                ConsumerParameters pm = new ConsumerParameters();
                pm.isqueue = queue;
                pm.destination = destination;
                pm.selector = selector;
                pm.clientid = clientid;
                pm.subscriptionName = subscriptionName;
                pm.durable = durable;
                pm.shared = shared; 
                pm.jmsshare =jmsshare; 
                pm.nolocal = nolocal;

                checkSubscriptionName(pm);
                checkClientID(pm);
                checkNoLocal(pm);

                if (reconnect != null && reconnect.booleanValue()) {
                    Globals.getLogger().log(Logger.ERROR,
                        BrokerResources.E_INTERNAL_BROKER_ERROR,
                        "JMQReconnect not implemented");
                }

                // see if we are a wildcard destination
                DestinationUID dest_uid = null;

                Destination d = null;

                if (DestinationUID.isWildcard(destination)) { // dont create a destination
                    dest_uid = DestinationUID.getUID(destination, DestType.isQueue(type));

                } else {
                    d = null;
                    Destination[] ds = null;
                    while (true ) {
                       ds =  DL.getDestination(con.getPartitionedStore(), destination,
                                     type, true /* autocreate if possible*/,
                                     !con.isAdminConnection());
                       d = ds[0]; //PART
                       if (d == null) {
                           break;
                       }
                       if (d.isAutoCreated())
                           warning = BrokerResources.W_ADD_AUTO_CONSUMER_FAILED;
                       try {
                           d.incrementRefCount();
                       } catch (BrokerException ex) {
                           continue; // was destroyed in process
                       } catch (IllegalStateException ex) {
                            throw new BrokerException(
                                Globals.getBrokerResources().getKString(
                                BrokerResources.X_SHUTTING_DOWN_BROKER),
                                BrokerResources.X_SHUTTING_DOWN_BROKER,
                                ex,
                                Status.ERROR);
                       }
                       break; // we got one
                    }
    
                    if (d == null) {
                        // unable to autocreate destination
                        status  = Status.NOT_FOUND;
                        // XXX error
                        throw new BrokerException(
                            Globals.getBrokerResources().getKString(
                                BrokerResources.X_DESTINATION_NOT_FOUND, destination),
                                BrokerResources.X_DESTINATION_NOT_FOUND,
                                null,
                                Status.NOT_FOUND);
                    }
                    dest_uid = d.getDestinationUID();
                }

                if (jmsshare && mqshare) {
                    Object[] args = { "JMS", 
                                      (!durable ?
                                       Subscription.getNDSubLongLogString(clientid, 
                                          dest_uid, selector, subscriptionName, nolocal):
                                       Subscription.getDSubLogString(clientid, subscriptionName)),
                                      ""+destination, "JMQShare" };
                    logger.log(Logger.INFO, br.getKString(
                               br.I_ADD_SHARE_CONSUMER_IGNORE_CLIENT_FLAG, args));
                    mqshare = false;
                }

                Consumer c = null;
                
                try { 
//LKS
                    Consumer[] retc = _createConsumer( dest_uid,  con,
                         session, selector,  clientid, 
                         subscriptionName, durable, shared, jmsshare, nolocal,
                         (size == null ? -1 : size.intValue()), 
                         msg.getSysMessageID().toString(),  isIndemp, true);

                    c = retc[0];
                    newc = retc[1];
                    sub = (Subscription)retc[2];
                    if (c.getPrefetch() != -1 || size != null) {
                        hash.put("JMQSize", c.getPrefetch());
                    }

                } catch (SelectorFormatException ex) {
                      throw new BrokerException(
                            Globals.getBrokerResources().getKString(
                            BrokerResources.W_SELECTOR_PARSE, ""+selector),
                            BrokerResources.W_SELECTOR_PARSE,
                            ex,
                            Status.BAD_REQUEST);
                } catch (OutOfLimitsException ex) {
                    if (d != null && d.isQueue()) {
                        String args[] = { dest_uid.getName(),
                            String.valueOf(d.getActiveConsumerCount()),
                            String.valueOf(d.getFailoverConsumerCount()) };
                        throw new BrokerException(
                            Globals.getBrokerResources().getKString(
                            BrokerResources.X_S_QUEUE_ATTACH_FAILED, args),
                            BrokerResources.X_S_QUEUE_ATTACH_FAILED,
                            ex,
                            Status.CONFLICT);
                    } else { // durable
                        String args[] = { Subscription.getDSubLogString(clientid, durablename),
                                          dest_uid.getName(),
                                          String.valueOf(ex.getLimit()) };
                        throw new BrokerException(
                            Globals.getBrokerResources().getKString(
                            BrokerResources.X_S_DUR_ATTACH_FAILED, args),
                            BrokerResources.X_S_DUR_ATTACH_FAILED,
                            ex,
                            Status.CONFLICT);
                    }
                } finally {
                    if (d != null) {
                        d.decrementRefCount();
                    }
                }

                // add the consumer to the session
        
                Integer acktype = (Integer)props.get("JMQAckMode");
                if (acktype != null) {
                    c.getConsumerUID().setAckType(acktype.intValue());
                }

                uid = c.getConsumerUID();
                if (props.get("JMQOldConsumerID") != null ) {
                    Object[] args = { uid+(sub == null ? "":"["+sub+"]"),
                                      ""+dest_uid,  props.get("JMQOldConsumerID") }; 
                    logger.log(Logger.INFO, br.getKString(br.I_CREATED_NEW_CONSUMER_FOR_OLD, args));
                }

            } else { // removing Interest
                if (DEBUG) {
                    logger.log(Logger.INFO, "ConsumerHandler: "+
                    "[Received DestroyConsumer message {0}]", msg.toString());
                }

                warning = BrokerResources.W_DESTROY_CONSUMER_FAILED;
                pkt.setPacketType(PacketType.DELETE_CONSUMER_REPLY);

                String durableName = (String)props.get("JMQDurableName");
                String clientID = getClientID(props, con);
                Long cid = (Long)props.get("JMQConsumerID");
                uid = (cid == null ? null :  new ConsumerUID( cid.longValue()));

                if (lsessionid != null) { //  passed on in
                    SessionUID sessionID = new SessionUID(lsessionid.longValue());
                    session = con.getSession(sessionID);
                } else {
                    session = Session.getSession(uid);
                }
                if (session == null && durableName == null && !isIndemp) {
                     if (con.getConnectionState() < Connection.STATE_CLEANED) {
                         logger.log(Logger.ERROR, br.getKString(br.E_UNEXPECTED_EXCEPTION, 
                             br.getKString(br.E_DELETE_CONSUMER_NO_SESSION, 
                             (lsessionid == null ? "":lsessionid), uid+"")+"\n"+
                             com.sun.messaging.jmq.io.PacketUtil.dumpPacket(msg)));
                         Session.dumpAll();
                     }
                }

                // retrieve the LastDelivered property
                Integer bodytype = (Integer)props.get("JMQBodyType");
                int btype = (bodytype == null ? 0 : bodytype.intValue());
                
                SysMessageID lastid = null;
                boolean lastidInTransaction = false;

                if (btype == PacketType.SYSMESSAGEID) {
                    int size = msg.getMessageBodySize();
                    if (size == 0) {
                        logger.log(Logger.INFO,"Warning, bad body in destroy consumer");
                     } else {
                         DataInputStream is = new DataInputStream(
                                msg.getMessageBodyStream());
                         lastid = new SysMessageID();
                         lastid.readID(is);
                         Boolean val = (Boolean)props.get("JMQLastDeliveredIDInTransaction");
                         lastidInTransaction = (val == null ? false : val.booleanValue());
                    
                     }
                }
                if (DEBUG && lastid != null) {
                    logger.log(Logger.INFO, "ConsumerHandler: destroy consumer with lastID ["+
                        lastid+", "+lastidInTransaction+"]"+
                        DL.get(con.getPartitionedStore(), lastid)+" for consumer "+uid);
                }

                Boolean rAll = (Boolean)props.get("JMQRedeliverAll");
                boolean redeliverAll = (rAll == null ? false : rAll.booleanValue());

                if (!sessionPaused && session != null) {
                    sessionPaused = true;
                    session.pause("Consumer removeconsumer");
                }
                destroyConsumer(con, session, uid, durableName, clientID, 
                    lastid, lastidInTransaction, redeliverAll, isIndemp);

            }

            } finally {
            DL.releasePartitionLock(true);
            }

        } catch (BrokerException ex) {

            status = ex.getStatusCode();
            String consumid = null;
            String destination = null;
            try {
                destination = (String) props.get("JMQDestination");
                if (destination == null && msg.getPacketType() 
                     != PacketType.ADD_CONSUMER)
                     destination = "";
                if (oldid != null)
                    consumid = oldid.toString();
                else
                    consumid = "";
            } catch (Exception ex1) {}
            String args[] = {consumid, con.getRemoteConnectionString(), destination};

            err_reason = ex.getMessage();

            if (ex.getStatusCode() == Status.PRECONDITION_FAILED
                  || ex.getStatusCode() == Status.CONFLICT ) {
                logger.log(Logger.WARNING, warning, args, ex);
            } else if (ex.getStatusCode() == Status.BAD_REQUEST) {
                // Probably a bad selector
                logger.log(Logger.WARNING, warning, args, ex);
                if (ex.getCause() != null) {
                    logger.log(Logger.INFO, ex.getCause().toString());
                }
            } else {
                if (isIndemp && msg.getPacketType() == PacketType.DELETE_CONSUMER) {
                    logger.logStack(Logger.DEBUG, "Reprocessing Indempotent message for "
                          + "{0} on destination {2} from {1}",args, ex);
                    status = Status.OK;
                    err_reason = null;
                } else {
                    logger.logStack(Logger.WARNING, warning,args, ex);
                }
            }
        } catch (IOException ex) {
            logger.log(Logger.INFO,"Internal Error: unable to process "+
                " consumer request " + msg, ex);
            props = new Hashtable();
            err_reason = ex.getMessage();
            assert false;
        } catch (SecurityException ex) {
            status = Status.FORBIDDEN;
            err_reason = ex.getMessage();
            String destination = null;
            String consumid = null;
            try {
                destination = (String) props.get("JMQDestination");
                if (oldid != null)
                    consumid = oldid.toString();
            } catch (Exception ex1) {}
            logger.log(Logger.WARNING, warning, destination, consumid,ex);
        } finally {
            if (conPaused) {
                con.resume();
            }
        }
        hash.put("JMQStatus", new Integer(status));

        if (err_reason != null)
            hash.put("JMQReason", err_reason);

        if (uid != null) {
            hash.put("JMQConsumerID", new Long(uid.longValue()));
        }

        if (destType != null)
            hash.put("JMQDestType", destType);

        if (((IMQBasicConnection)con).getDumpPacket() ||
                ((IMQBasicConnection)con).getDumpOutPacket()) 
            hash.put("JMQReqID", msg.getSysMessageID().toString());

        pkt.setProperties(hash);
        con.sendControlMessage(pkt);

        if (sessionPaused)
             session.resume("Consumer - session was paused");

        if (sub != null)
            sub.resume("Consumer - added to sub");
        
        if (newc != null)
            newc.resume("Consumer - new consumer");

        return true;
    }

    private String getClientID(Hashtable props, Connection con) {

        String clientid = (String)con.getClientData(IMQConnection.CLIENT_ID);
        if (clientid == null) {
            clientid = (String)props.get("JMQClientID");
            if (clientid != null) {
                logger.log(Logger.ERROR, BrokerResources.E_INTERNAL_BROKER_ERROR, 
                "Client did not send SET_CLIENTID before adding/removing a consumer, retrieved clientid "+
                 clientid + " from packet properties");
            }
        }
        return clientid;
    } 


    public void destroyConsumer(IMQConnection con, Session session, ConsumerUID uid, 
               String durableName, String clientID, SysMessageID lastid, boolean lastidInTransaction,
               boolean redeliverAll, boolean isIndemp)
               throws BrokerException {

        if (durableName != null) {
            Subscription usub = Subscription.unsubscribe(durableName, clientID);
                    
             if (usub == null) { // already destroyed
                throw new BrokerException(
                    Globals.getBrokerResources().getKString(
                        BrokerResources.X_UNKNOWN_DURABLE_INTEREST,
                        Subscription.getDSubLogString(clientID, durableName)),
                        Status.NOT_FOUND);
             }
             DestinationUID dest_uid = usub.getDestinationUID();
             Destination[] ds = DL.getDestination(con.getPartitionedStore(), dest_uid);
             Destination d = ds[0];
             assert d != null;
             if (d != null) {
                 d.removeConsumer(uid, true);
             }
        } else {
            boolean redeliver = false;
            if (con.getClientProtocolVersion() < Connection.RAPTOR_PROTOCOL ) {
                redeliver = true;
            }

            if (session == null && !isIndemp) {
                if (con.getConnectionState() >= Connection.STATE_CLOSED) {
                    throw new BrokerException(Globals.getBrokerResources().getKString(
                    BrokerResources.X_CONNECTION_CLOSING, con.getConnectionUID()), Status.NOT_FOUND);
                } else {
                    assert session != null;
                    throw new BrokerException(Globals.getBrokerResources().getKString(
                    BrokerResources.X_CONSUMER_SESSION_NOT_FOUND, uid, con.getConnectionUID()), Status.NOT_FOUND);
                }
            }

            if (session != null) { // should only be null w/ indemp
                Consumer c = (Consumer)session.detatchConsumer(uid, lastid,
                                 lastidInTransaction, redeliver, redeliverAll);
                if (DEBUG) {
                logger.log(Logger.INFO, "ConsumerHandler: closed consumer "+c+
                    ", with {lastid="+lastid+", lastidInTransaction="+
                     lastidInTransaction+", redeliver="+redeliver+ ", redeliverAll="+
                     redeliverAll+", isindemp="+isIndemp+"}");
                }
                DestinationUID dest_uid = c.getDestinationUID();
                Destination[] ds = DL.getDestination(con.getPartitionedStore(), dest_uid);
                Destination d = ds[0];
                if (d != null)
                    d.removeConsumer(uid, true);
            }
        }
    }

    public Consumer[] createConsumer(DestinationUID dest_uid, IMQConnection con,
        Session session, String selectorstr, String clientid, 
        String subscriptionName,  boolean durable, 
        boolean shared, boolean jmsshare, boolean nolocal,
        int size, String consumerString, boolean isIndemp, boolean useFlowControl)
        throws BrokerException, SelectorFormatException, IOException {

        ConsumerParameters pm = new ConsumerParameters();
        pm.isqueue = dest_uid.isQueue();
        pm.destination = dest_uid.toString();
        pm.selector = selectorstr;
        pm.clientid = clientid;
        pm.subscriptionName = subscriptionName;
        pm.durable = durable;
        pm.shared = shared; 
        pm.jmsshare = jmsshare; 
        pm.nolocal = nolocal;

        checkSubscriptionName(pm);
        checkClientID(pm);
        checkNoLocal(pm);

        return _createConsumer(dest_uid, con, session, selectorstr, clientid,
            subscriptionName, durable, shared, jmsshare, nolocal,
            size, consumerString, isIndemp, useFlowControl);
    }

    private Consumer[] _createConsumer(DestinationUID dest_uid, IMQConnection con,
        Session session,String selectorstr, String clientid, 
        String subscriptionName,  boolean durable, 
        boolean shared, boolean jmsshare, boolean nolocal,
        int size, String consumerString, boolean isIndemp, boolean useFlowControl)
        throws BrokerException, SelectorFormatException, IOException {

        Consumer c = null;
        Consumer newc = null;
        Subscription sub = null;
        String selector = selectorstr;
        if (selectorstr != null && selectorstr.trim().length() == 0) {
            selector = null;
        }
        // need to deal w/ reconnection AND ackType

        try {

        int prefetch = -1;
        if (isIndemp) { // see if we already created it
            c = Consumer.getConsumer(consumerString);
            if (c != null) 
                prefetch = c.getPrefetch();
        }

        if (c == null) {
            c = new Consumer(dest_uid, selector,
                    nolocal, 
                    con.getConnectionUID());
            c.setCreator(consumerString);
            newc = c;
            newc.pause("Consumer: new consumer");

            // OK, determine if we are a wildcard or not
            Destination[] ds = DL.getDestination(con.getPartitionedStore(), dest_uid);
            Destination d = ds[0]; //PART
            boolean wildcard = dest_uid.isWildcard();

            // NOTE: if d == null, wildcard == true

            int cprefetch = size;
            int dprefetch = (wildcard ? -1 : (!shared
                    ? d.getMaxPrefetch()
                    : d.getSharedConsumerFlowLimit()));
                                       
            prefetch = (dprefetch == -1) ?
                    cprefetch :
                    (cprefetch == -1 ? cprefetch  
                    : (cprefetch > dprefetch?
                    dprefetch : cprefetch));
            c.setPrefetch(prefetch,useFlowControl);

            // actual subscription added to the destination
            if (subscriptionName != null && durable) {
                if (!shared) {
                    logger.log(Logger.INFO,  br.getKString(br.I_CREATE_UNSHARED_DURA,
                        Subscription.getDSubLogString(clientid, subscriptionName), dest_uid));
                } else {
                    logger.log(Logger.INFO,  br.getKString(br.I_CREATE_SHARED_DURA,
                        Subscription.getDSubLogString(clientid, subscriptionName)+
                                     (jmsshare ? "jms":"mq"), dest_uid));
                }
                // durable
                // get the subscription ... this may throw
                // an exception IF we cant 
                sub = Subscription.
                          findCreateDurableSubscription(clientid,
                              subscriptionName, shared, jmsshare, dest_uid,
                              selector, nolocal, true);
                sub.setCreator(consumerString);
                sub.pause("Consumer attaching to durable");

                // add the consumer .. this may throw an
                // exception IF
                sub.attachConsumer(c, con);
                c.localConsumerCreationReady();
   
                Map> dmap = 
                    DL.findMatchingDestinationMap(null, dest_uid);
                LinkedHashSet dset = null;
                Iterator> itr = dmap.values().iterator();
                boolean notify = true;
                while (itr.hasNext()) {
                    dset = itr.next();
                    if (dset == null) {
                        continue;
                    }
                    Iterator itr1 = dset.iterator();
                    while (itr1.hasNext()) {
                        Destination dd = itr1.next();
                        if (dd == null) {
                            continue;
                        }
                        Subscription oldsub = null;
                        try { 
                             oldsub = (Subscription)dd.addConsumer(sub, notify, con);
                        } catch (ConsumerAlreadyAddedException e) {
                             logger.log(logger.INFO, e.getMessage());
                        }
                        if (oldsub != null) {
                            oldsub.purge();
                        }
                    }
                    notify = false;
                }
                sub.sendCreateSubscriptionNotification(c);
            } else if ((wildcard || !d.isQueue()) && shared) {
                logger.log(Logger.INFO,  br.getKString(br.I_CREATE_SHARED_NONDURA_SUB,
                           Subscription.getNDSubLongLogString(clientid, dest_uid, 
                           selectorstr, subscriptionName, nolocal), ""+dest_uid));
                sub = Subscription.createAttachNonDurableSub(c, con,
                                   subscriptionName, shared, jmsshare);
                c.localConsumerCreationReady();
                if (sub != null) {
                    sub.pause("Consumer: attaching to nondurable");
                    Map> dmap = 
                        DL.findMatchingDestinationMap(null, dest_uid);
                    LinkedHashSet dset = null;
                    Iterator> itr = dmap.values().iterator();
                    while (itr.hasNext()) {
                        dset = itr.next();
                        if (dset == null) {
                            continue;
                        }
                        Iterator itr1 = dset.iterator();
                        while (itr1.hasNext()) {
                            Destination dd = itr1.next();
                            if (dd != null) {
                                dd.addConsumer(sub, true, con);
                            }
                        }
                    }
                }
                c.attachToConnection(con.getConnectionUID());
                if (sub != null)
                    sub.sendCreateSubscriptionNotification(c);
            } else {
                c.localConsumerCreationReady();
            	// non-durable
                List dests = null;
                Destination dd = null;
                Map> dmap = 
                               DL.findMatchingDestinationMap(null, dest_uid);
                LinkedHashSet dset = null;
                Iterator> itr = dmap.values().iterator();
                while (itr.hasNext()) {
                    dset = itr.next();
                    if (dset == null) {
                        continue;
                    }
                    Iterator itr1 = dset.iterator();
                    while (itr1.hasNext()) {
                        dd = itr1.next();
                        if (dd != null) {
                            dd.addConsumer(c, true, con);
                        }
                    }
                }
                c.attachToConnection(con.getConnectionUID());
                c.sendCreateConsumerNotification();
            }
        }

        if (fi.FAULT_INJECTION) {
            //e.g. imqcmd debug fault -n consumer.add.1 -o selector="mqDestinationName = 'T:t0.*'" -debug
            HashMap fips = new HashMap();
            fips.put(FaultInjection.DST_NAME_PROP,
                     DestinationUID.getUniqueString(dest_uid.getName(), dest_uid.isQueue()));
            fi.checkFaultAndSleep(FaultInjection.FAULT_CONSUMER_ADD_1, fips);
        }
 
        session.attachConsumer(c);
        if (DEBUG) {
            logger.log(logger.INFO, "Attached consumer "+c+
            "[prefetch="+c.getPrefetch()+", useConsumerFlowControl="+useFlowControl+"] to session "+session);
        }

        Consumer[] retc = new Consumer[3];
        retc[0]=c;
        retc[1]=newc;
        retc[2]=sub;
        return retc;
    } catch (Exception e) {
        Object[] args = { (durable ?
                           Subscription.getDSubLogString(clientid, 
                                                  subscriptionName):
                           (shared ? Subscription.getNDSubLongLogString(clientid, 
                                     dest_uid, selector, subscriptionName, nolocal):"")),
                           con, dest_uid };
        String emsg = Globals.getBrokerResources().getKString(
                          BrokerResources.W_ADD_AUTO_CONSUMER_FAILED, args);
        logger.logStack(logger.ERROR, emsg, e);
        try {
            if (c != null) {
                try {
                    session.detatchConsumer(c.getConsumerUID(), null, false, false, false);
                } catch (Exception e1) {
                    try {
                    c.destroyConsumer((new HashSet()), null, true, false, true);
                    } catch (Exception e2) {}
                };
            }
            Map> dmap = 
                           DL.findMatchingDestinationMap(null, dest_uid);
            LinkedHashSet dset = null;
            Destination dd = null;
            Iterator> itr = dmap.values().iterator();
            while (itr.hasNext()) {
                dset = itr.next();
                if (dset == null) {
                    continue;
                }
                Iterator itr1 = dset.iterator();
                while (itr1.hasNext()) {
                    dd = itr1.next();
                    if (dd == null) {
                        continue;
                    }
                    try {
                        if (c != null) {
                            dd.removeConsumer(c.getConsumerUID(), true);
                        }
                        if (sub != null) {
                            dd.removeConsumer(sub.getConsumerUID(), true);
                        }
                    } catch (Exception e1){}
                }
            }
            try {
                if (sub != null && c != null) {
                    sub.releaseConsumer(c.getConsumerUID());
                }
            } catch (Exception e1) {}

            if (subscriptionName != null && durable) {
                if (sub != null && sub.getCreator() != null && 
                    sub.getCreator().equals(consumerString)) {
                    try {
                        Subscription.unsubscribe(subscriptionName, clientid);
                    } catch (Exception e1) { }
                }
            }
        } catch (Exception e3) {}

        if (e instanceof BrokerException) {
            throw (BrokerException)e;
        }
        if (e instanceof IOException) {
            throw (IOException)e;
        }
        if (e instanceof SelectorFormatException) {
            throw (SelectorFormatException)e;
        }
        throw new BrokerException(emsg, e);
    }
    }

    private static class ConsumerParameters {
        boolean isqueue = true;
        String destination = null;
        String selector = null;
        String clientid = null;
        String subscriptionName = null;
        boolean durable = true;
        boolean shared = true;
        boolean jmsshare = true;
        boolean nolocal = true;
    }

    private void checkNoLocal(ConsumerParameters pm)
        throws BrokerException {

        if (!pm.nolocal) {
            return;
        }
        if (pm.isqueue) {
            Globals.getLogger().log(Logger.ERROR, 
                BrokerResources.E_INTERNAL_BROKER_ERROR,
                "NoLocal is not supported on Queue Receivers");
            throw new BrokerException(
                "Unsupported property on queues JMQNoLocal "+
                 "is set to " + pm.nolocal, Status.ERROR);
        }

        /**
         * JMS 2.0 late update has removed noLocal for JMS 2.0 shared subscription
         * Therefore the following should never happen after checkClientID() OK
         */
        if (pm.clientid == null) { //JMS 2.0 
            if (pm.durable) {
                String emsg = Globals.getBrokerResources().getKString(
                              BrokerResources.X_NO_CLIENTID_NOLOCAL_DURA, 
                              ""+pm.subscriptionName);
                Globals.getLogger().log(Logger.ERROR, emsg); 
                throw new BrokerException(emsg, 
                    BrokerResources.X_NO_CLIENTID_NOLOCAL_DURA, null, 
                    Status.PRECONDITION_FAILED);
            }
            if (pm.shared) {
                String emsg = Globals.getBrokerResources().getKString(
                              BrokerResources.X_NO_CLIENTID_NOLOCAL_SHARE, 
               "["+pm.clientid+":"+pm.destination+":"+pm.selector+":"+pm.subscriptionName+"]");
                Globals.getLogger().log(Logger.ERROR, emsg); 
                throw new BrokerException(emsg, 
                    BrokerResources.X_NO_CLIENTID_NOLOCAL_SHARE, 
                    null, Status.PRECONDITION_FAILED);
            }
        }
    }

    private void checkSubscriptionName(ConsumerParameters pm)
        throws BrokerException {
        if (pm.isqueue && pm.subscriptionName != null) {
            String emsg = "Protocol error: Unexpected subscription name for Queue";
            Globals.getLogger().log(Logger.ERROR, emsg);
            throw new BrokerException(emsg);
        }
        if (pm.durable && 
            (pm.subscriptionName == null || pm.subscriptionName.trim().equals(""))) {
            throw new BrokerException(
                Globals.getBrokerResources().getKString(
                    BrokerResources.X_INVALID_SUBSCRIPTION_NAME_DURA, 
                    ""+pm.subscriptionName, ""+pm.destination),
                    BrokerResources.X_INVALID_SUBSCRIPTION_NAME_DURA, null,
                    Status.PRECONDITION_FAILED);
             
        }

        if (pm.shared && pm.jmsshare &&
            (pm.subscriptionName == null || pm.subscriptionName.trim().equals(""))) {
            throw new BrokerException(
                Globals.getBrokerResources().getKString(
                    BrokerResources.X_INVALID_SUBSCRIPTION_NAME_SHARE, 
                    ""+pm.subscriptionName, ""+pm.destination),
                    BrokerResources.X_INVALID_SUBSCRIPTION_NAME_SHARE, null,
                    Status.PRECONDITION_FAILED);
             
        }
    }

    private void checkClientID(ConsumerParameters pm)
        throws BrokerException {
        if (pm.isqueue) {
            return;
        }
        if (pm.durable && !pm.jmsshare && pm.clientid == null) {
            throw new BrokerException(
                Globals.getBrokerResources().getKString(
                    BrokerResources.X_NO_CLIENTID, ""+pm.subscriptionName),
                    BrokerResources.X_NO_CLIENTID, null,
                    Status.PRECONDITION_FAILED);
        }
        if (!pm.durable && pm.shared && 
            !pm.jmsshare && pm.clientid == null) {
            throw new BrokerException(
                Globals.getBrokerResources().getKString(
                    BrokerResources.X_NON_DURABLE_SHARED_NO_CLIENTID, ""+pm.destination),
                    BrokerResources.X_NON_DURABLE_SHARED_NO_CLIENTID, null,
                    Status.PRECONDITION_FAILED);
        }
        if (pm.durable || pm.shared) {
            if (pm.clientid != null && pm.clientid.trim().length() == 0) {
               throw new BrokerException(
                   Globals.getBrokerResources().getKString(
                       BrokerResources.X_INVALID_CLIENTID, pm.clientid),
                       BrokerResources.X_INVALID_CLIENTID, null,
                       Status.PRECONDITION_FAILED);
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy