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.DataHandler 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.
 */

/*
 * %W% %G%
 */ 

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

import java.util.*;
import java.io.*;
import com.sun.messaging.jmq.jmsserver.data.TransactionUID;
import com.sun.messaging.jmq.jmsserver.data.TransactionList;
import com.sun.messaging.jmq.jmsserver.data.PacketRouter;
import com.sun.messaging.jmq.jmsserver.data.PacketHandler;
import com.sun.messaging.jmq.jmsserver.core.Destination;
import com.sun.messaging.jmq.jmsserver.core.DestinationList;
import com.sun.messaging.jmq.jmsserver.core.Producer;
import com.sun.messaging.jmq.jmsserver.core.ProducerUID;
import com.sun.messaging.jmq.jmsserver.core.DestinationUID;
import com.sun.messaging.jmq.jmsserver.core.MessageDeliveryTimeInfo;
import com.sun.messaging.jmq.jmsserver.persist.api.PartitionedStore;
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.core.Consumer;
import com.sun.messaging.jmq.jmsserver.core.PacketReference;
import com.sun.messaging.jmq.jmsserver.util.BrokerException;
import com.sun.messaging.jmq.jmsserver.resources.BrokerResources;
import com.sun.messaging.jmq.jmsserver.Globals;
import com.sun.messaging.jmq.jmsserver.FaultInjection;
import com.sun.messaging.jmq.jmsserver.Broker;
import com.sun.messaging.jmq.jmsserver.BrokerStateHandler;
import com.sun.messaging.jmq.jmsserver.memory.MemoryGlobals;
import com.sun.messaging.jmq.util.selector.SelectorFormatException;
import com.sun.messaging.jmq.util.log.Logger;



/**
 * Handler class which deals with normal (topic or queue) JMS messages
 */
public class DataHandler extends PacketHandler 
{
    private static boolean DEBUG = false;
    

    private int msgProcessCnt = 0; // used for fault injection
    private FaultInjection fi = null;

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

    /**
     * Method to handle normal data messages
     */
    public boolean handle(IMQConnection con, Packet msg) 
        throws BrokerException
    {
        boolean sentReply = false;

        return handle(con, msg, false);

    }
 
    /**
     * Method to handle normal/admin data messages
     */
    protected boolean handle(IMQConnection con, Packet msg, boolean isadmin) 
    throws BrokerException {

        Hashtable props = null; // used for fault injection
        if (!isadmin && fi.FAULT_INJECTION) {
           msgProcessCnt ++; // for fault injection
           try {
               props = msg.getProperties();
           } catch (Exception ex) {
               props = new Properties();
           }
        } else {
           msgProcessCnt = 0;
        }


        boolean ack = msg.getSendAcknowledge();
        long cid = msg.getConsumerID();
        String refid = (((IMQBasicConnection)con).getDumpPacket() || 
                        ((IMQBasicConnection)con).getDumpOutPacket()) ?
                       msg.getSysMessageID().toString() : "";

        boolean isIndemp = msg.getIndempotent();

       String reason = null;
       List failedrefs = null;
       int status = Status.OK;
       boolean removeMsg = false;
       HashMap routedSet = null;
       List deliveryDelayReadyList = 
                   new ArrayList();
       boolean route = false;
       Producer pausedProducer = null;
       boolean transacted = false;
       try {
           pausedProducer = checkFlow(msg, con);
           transacted = (msg.getTransactionID() != 0);

            // OK .. handle Fault Injection
            if (!isadmin && fi.FAULT_INJECTION) {
                Map m = new HashMap();
                if (props != null) {
                    m.putAll(props);
                }
                m.put("mqMsgCount", new Integer(msgProcessCnt));
                m.put("mqIsTransacted", Boolean.valueOf(transacted));
                fi.checkFaultAndExit(FaultInjection.FAULT_SEND_MSG_1, m, 2, false);
                if (fi.checkFault(FaultInjection.FAULT_SEND_MSG_1_EXCEPTION, m)) {
                    fi.unsetFault(FaultInjection.FAULT_SEND_MSG_1_EXCEPTION);
                    throw new BrokerException("FAULT INJECTION: "+
                        FaultInjection.FAULT_SEND_MSG_1_EXCEPTION);
                }
                if (fi.checkFaultAndSleep(FaultInjection.FAULT_SEND_MSG_1_SLEEP, m, true)) {
                    fi.unsetFault(FaultInjection.FAULT_SEND_MSG_1_SLEEP);
                }
                if (fi.checkFaultAndSleep(FaultInjection.FAULT_SEND_MSG_1_SLEEP_EXCEPTION, m, true)) {
                    fi.unsetFault(FaultInjection.FAULT_SEND_MSG_1_SLEEP_EXCEPTION);
                    throw new BrokerException("FAULT INJECTION: "+
                        FaultInjection.FAULT_SEND_MSG_1_SLEEP_EXCEPTION);
                }
            }


            DestinationUID realduid = DestinationUID.getUID(msg.getDestination(), msg.getIsQueue());
            if (DEBUG) {
                logger.log(Logger.INFO, "DataHandler:Received JMS Message["+
                    msg.toString()+" : "+realduid+"]TID="+msg.getTransactionID()+
                    " on connection "+con+", isadmin="+isadmin);
            }

            // get the list of "real" destination UIDs (this will be one if the
            // destination if not a wildcard and 0 or more if it is

            List[] dds = DL.findMatchingIDs(con.getPartitionedStore(), realduid);
            List duids = dds[0];

            boolean packetUsed = false;

            // IMPORTANT NOTE:
            // IF A MESSAGE IS BEING SENT TO A WILDCARD TOPIC AND A FAILURE
            // OCCURS ON ONE OF THE SENDS PROCESSING THAT MESSAGE WILL CONTINUE
            // A MESSAGE WILL BE LOGGED 
            //
            // THIS FACT NEEDS TO BE DOCUMENTED SOMEWHERE

            if (duids.size() == 0) {
                route = false; // nothing to do
            } else {
                Iterator itr = duids.iterator();
                while (itr.hasNext()) {
                    PacketReference ref = null;
                    Exception lastthr = null;
                    boolean isLast = false;
                    DestinationUID duid = (DestinationUID)itr.next();
                    isLast = !itr.hasNext();

                    Destination[] ds = DL.getDestination(con.getPartitionedStore(), duid);
                    Destination d = ds[0];
                    try {

                        if (d == null) {
                            throw new BrokerException("Unknown Destination:" + msg.getDestination());
                        }
                        if (realduid.isWildcard() && d.isTemporary()) {
                            logger.log(Logger.DEBUG,"L10N-XXX: Wildcard production with destination name of "
                                         + realduid +  " to temporary destination " +
                                         d.getUniqueName() + " is not supported, ignoring");
                             continue;
                        }
                        if (realduid.isWildcard() && d.isInternal()) {
                            logger.log(Logger.DEBUG,"L10N-XXX: Wildcard production with destination name of "
                                         + realduid +  " to internal destination " +
                                         d.getUniqueName() + " is not supported, ignoring");
                             continue;
                        }

                        if (realduid.isWildcard() && d.isDMQ() ) {
                            logger.log(Logger.DEBUG,"L10N-XXX: Wildcard production with destination name of "
                                         + realduid +  " to the DeadMessageQueue" +
                                         d.getUniqueName() + " is not supported, ignoring");
                             continue;
                        }
                        if (pausedProducer != null) {
                             pauseProducer(d, duid, pausedProducer, con);
                             pausedProducer = null;
                        }
    
                        if (packetUsed) {
                            // create a new Packet for the message
                            // we need a new sysmsgid with it
                            Packet newp = new Packet();
                            newp.fill(msg);
                            newp.generateSequenceNumber(true);
                            newp.generateTimestamp(true);
                            newp.prepareToSend();
                            newp.generateSequenceNumber(false);
                            newp.generateTimestamp(false);
                            msg = newp;
                        }
                        packetUsed = true;
    
                        // OK generate a ref. This checks message size and
                        // will be needed for later operations
                        ref = createReference(msg, duid, con, isadmin);
    
                        // dont bother calling route if there are no messages
                        //
                        // to improve performance, we route and later forward
                        route |= queueMessage(d, ref, transacted);
    
                        // ok ... 
                        if (isLast && route && ack && !ref.isPersistent()) {
                            sendAcknowledge(refid, cid, status, con, reason, props, transacted);
                            ack = false;
                        }
    
                        Set s = routeMessage(con.getPartitionedStore(), 
                                             transacted, ref, route, d, 
                                             deliveryDelayReadyList);
                       
                        if (s != null && !s.isEmpty()) {
                            if (routedSet == null) {
                                routedSet = new HashMap();
                            }
                            routedSet.put(ref, s);
                        }

                        // handle producer flow control
                        pauseProducer(d, duid, pausedProducer, con);
                    } catch (Exception ex) {
                        if (ref != null) {
                            if (failedrefs == null) {
                                failedrefs = new ArrayList();
                            }
                            failedrefs.add(ref);
                        }
                        lastthr = ex;
                        logger.log(Logger.DEBUG, BrokerResources.W_MESSAGE_STORE_FAILED,
                                   con.toString(), ex);
                    } finally {
                        if (pausedProducer != null) {
                            pauseProducer(d, duid, pausedProducer, con);
                            pausedProducer = null;
                        }
                        if (isLast && lastthr != null) {
                            throw lastthr;
                        }
                    }
                } //while
            }

        } catch (BrokerException ex) {

            // dont log on dups if indemponent
            int loglevel = (isIndemp && ex.getStatusCode() 
                   == Status.NOT_MODIFIED) ? Logger.DEBUG 
                      : Logger.WARNING;
            logger.log(loglevel, 
                      BrokerResources.W_MESSAGE_STORE_FAILED,
                      con.toString(), ex);
            reason =  ex.getMessage();

            //LKS - we may want an improved error message in the wildcard case

            status = ex.getStatusCode();
        } catch (IOException ex) {
            logger.log(Logger.WARNING, BrokerResources.W_MESSAGE_STORE_FAILED,
                      con.toString(), ex);
            reason =  ex.getMessage();
            status = Status.ERROR;
        } catch (SecurityException ex) {
            logger.log(Logger.WARNING, BrokerResources.W_MESSAGE_STORE_FAILED,
                      con.toString(), ex);
            reason =  ex.getMessage();
            status = Status.FORBIDDEN;
        } catch (OutOfMemoryError err) {
            logger.logStack(Logger.WARNING, BrokerResources.W_MESSAGE_STORE_FAILED,
                      con.toString() + ":" + msg.getPacketSize(), err);
            reason =  err.getMessage();
            status = Status.ERROR;
        } catch (Exception ex) {

            logger.logStack(Logger.WARNING, BrokerResources.W_MESSAGE_STORE_FAILED,
                      con.toString(), ex);
             reason =  ex.getMessage();
             status = Status.ERROR;
        }

        if (status == Status.ERROR && failedrefs != null ) {
            // make sure we remove the message
            //
            // NOTE: we only want to remove the last failure (its too late
            // for the rest).  In the non-wildcard case, this will be the
            // only entry. In the wildcard cause, it will be the one that had an issue
            Iterator itr = failedrefs.iterator();
            while (itr.hasNext()) {
                PacketReference ref = (PacketReference)itr.next();
                Destination[] ds = DL.getDestination(con.getPartitionedStore(), ref.getDestinationUID());
                Destination d = ds[0];
                if (d != null) {
                    cleanupOnError(d, ref);
                }

            }
        }

        if (ack) {
            sendAcknowledge(refid, cid, status, con, reason, props, transacted);
        }

        if (route && routedSet != null) {
            Iterator itr = routedSet.keySet().iterator();
            while (itr.hasNext()) {
                PacketReference pktref = (PacketReference)itr.next();
                DestinationUID duid = pktref.getDestinationUID();
                Set s = (Set)routedSet.get(pktref);
                Destination[] ds = DL.getDestination(con.getPartitionedStore(), duid);
                Destination dest = ds[0];
                if (dest == null) {
                    Object[] emsg = { pktref, s, duid };
                    logger.log(logger.WARNING, br.getKString(
                        br.W_ROUTE_PRODUCED_MSG_DEST_NOT_FOUND, emsg));
                    continue;
                }
                try {
                    forwardMessage(dest, pktref, s);
                } catch (Exception e) {
                    Object[] emsg = { pktref, duid, s };
                    logger.logStack(logger.WARNING, br.getKString(
                        br.X_ROUTE_PRODUCED_MSG_FAIL, emsg), e);
                }
            }
        }
        if (deliveryDelayReadyList.size() > 0) {
            MessageDeliveryTimeInfo di = null;
            Iterator itr = 
                     deliveryDelayReadyList.iterator();
            while (itr.hasNext()) {
                di = itr.next();
                di.setDeliveryReady();
            }
        }
 
        return isadmin; // someone else will free
    }

    public void sendAcknowledge(String refid,
          long cid, int status, IMQConnection con,
          String reason, Hashtable props /* fi only */, 
          boolean transacted /*fi only */) {

            // OK .. handle Fault Injection
            if (!con.isAdminConnection() && fi.FAULT_INJECTION) {
                Map m = new HashMap();
                if (props != null)
                    m.putAll(props);
                m.put("mqMsgCount", new Integer(msgProcessCnt));
                m.put("mqIsTransacted", Boolean.valueOf(transacted));
                fi.checkFaultAndExit(FaultInjection.FAULT_SEND_MSG_2,
                     m, 2, false);
            }
        // send the reply (if necessary)
            Packet pkt = new Packet(con.useDirectBuffers());
            pkt.setPacketType(PacketType.SEND_REPLY);
            pkt.setConsumerID(cid);
            Hashtable hash = new Hashtable();
            hash.put("JMQStatus", new Integer(status));
            if (reason != null)
                hash.put("JMQReason", reason);
            if (((IMQBasicConnection)con).getDumpPacket() ||
                ((IMQBasicConnection)con).getDumpOutPacket()) 
                hash.put("JMQReqID", refid);
            pkt.setProperties(hash);
            con.sendControlMessage(pkt);
            // OK .. handle Fault Injection
            if (!con.isAdminConnection() && fi.FAULT_INJECTION) {
                Map m = new HashMap();
                if (props != null)
                    m.putAll(props);
                m.put("mqMsgCount", new Integer(msgProcessCnt));
                m.put("mqIsTransacted", Boolean.valueOf(transacted));
                fi.checkFaultAndExit(FaultInjection.FAULT_SEND_MSG_3,
                     m, 2, false);
            }
    }

    public Producer checkFlow(Packet msg, IMQConnection con) {

           Producer pausedProducer = null;
           // check and clearout the F bit (before anything)
           if (msg.getFlowPaused()) {
               con.flowPaused(0);
               msg.setFlowPaused(false);
           } 
           long pid = msg.getProducerID();
           ProducerUID puid = new ProducerUID(pid);
           Producer p = (Producer)Producer.getProducer(puid);
           if (p != null)
               p.addMsg(); // increment counter
           // see if we need to resume flow
           if (msg.getConsumerFlow()) {
               pausedProducer = p;
               if (pausedProducer == null) {
                   logger.log(Logger.INFO,"Internal Error: Unknown ProducerUID " + puid);
               } else if (pausedProducer.getConnectionUID() != con.getConnectionUID()) {
                   logger.log(Logger.INFO,"Internal Error: Producer " + pausedProducer
                      + " not on this connection " + con.getConnectionUID());

               }
               msg.setConsumerFlow(false);
           }
           return pausedProducer;

    }

    public PacketReference createReference(Packet msg, DestinationUID duid,
                           IMQConnection con, boolean isadmin) 
                           throws BrokerException {
            // OK generate a ref. This checks message size and
            // will be needed for later operations
            PacketReference ref = PacketReference.createReference(
                                    con.getPartitionedStore(), msg, duid, con);
            if (isadmin) {
                ref.overridePersistence(false);
            }
            return ref;
    }

    public boolean queueMessage(Destination d, PacketReference ref, boolean transacted)
        throws BrokerException
    {

        return d.queueMessage(ref, transacted);
    }



    public Set routeMessage(PartitionedStore storep, boolean transacted,
               PacketReference ref, boolean route, 
               Destination d, List readylist)
               throws BrokerException, SelectorFormatException {

            String reason = null;
            int status = Status.OK;
            Set s = null;
            MessageDeliveryTimeInfo di = ref.getDeliveryTimeInfo();
            //if transacted, just store, dont route
            if (transacted) {
                try {
                    TransactionList[] tls = DL.getTransactionList(storep);
                    TransactionList tl = tls[0];
                    tl.addMessage(ref);
                } catch (Exception ex) {
                    String emsg = br.getKString(br.X_PROCESS_PRODUCED_MESSAGE_FAIL,
                        ref+"[TID="+ref.getTransactionID()+", "+di+"]", ex.getMessage());
                    ref.destroy();
                    logger.logStack((BrokerStateHandler.shuttingDown? 
                        Logger.DEBUG : Logger.WARNING), emsg, ex);
                    reason = emsg;
                    status = Status.ERROR;
                    throw new BrokerException(reason, status);
                }
            } else {
                if (route) {
                    if (di != null && di.getOnTimerState() != null) {
                        d.routeNewMessageWithDeliveryDelay(ref);
                        readylist.add(di);
                    } else {
                        s = d.routeNewMessage(ref);
                    }
                }
            }
            return s;
     }


     public void cleanupOnError(Destination d, PacketReference ref)
     {
            try {
                d.removeMessage(ref.getSysMessageID(), null);
            } catch (Throwable thr) {
               // we should never throw anything .. but this is
               // a just in case [since we dont have any one else
               // to catch it in this case]
               // if something goes wrong removing the message 
               // there is nothing we can do
            }
     }


     public void forwardMessage(Destination d, PacketReference ref, Set s)
         throws BrokerException {

         d.forwardMessage(s, ref);
     }


     public void pauseProducer(Destination d, 
                               Producer pausedProducer, IMQConnection con)
     {
         pauseProducer(d, d.getDestinationUID(), pausedProducer, con);
     }

     public void pauseProducer(Destination d, DestinationUID duid, 
                               Producer pausedProducer, IMQConnection con)
     {
            // handle producer flow control
            if (pausedProducer != null) { 
                if (d != null) {
                    d.producerFlow(con, pausedProducer);
                } else if (duid != null) {
                    pausedProducer.sendResumeFlow(duid,
                        DL.MAX_PRODUCER_BATCH); 
                }
            }
     }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy