ChannelCloseMethodHandler.java
001 /*
002  *
003  * Licensed to the Apache Software Foundation (ASF) under one
004  * or more contributor license agreements.  See the NOTICE file
005  * distributed with this work for additional information
006  * regarding copyright ownership.  The ASF licenses this file
007  * to you under the Apache License, Version 2.0 (the
008  * "License"); you may not use this file except in compliance
009  * with the License.  You may obtain a copy of the License at
010  *
011  *   http://www.apache.org/licenses/LICENSE-2.0
012  *
013  * Unless required by applicable law or agreed to in writing,
014  * software distributed under the License is distributed on an
015  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016  * KIND, either express or implied.  See the License for the
017  * specific language governing permissions and limitations
018  * under the License.
019  *
020  */
021 package org.apache.qpid.client.handler;
022 
023 import org.apache.qpid.AMQChannelClosedException;
024 import org.apache.qpid.AMQException;
025 import org.apache.qpid.AMQInvalidRoutingKeyException;
026 import org.apache.qpid.client.AMQNoConsumersException;
027 import org.apache.qpid.client.AMQNoRouteException;
028 import org.apache.qpid.client.protocol.AMQProtocolSession;
029 import org.apache.qpid.client.state.StateAwareMethodListener;
030 import org.apache.qpid.framing.AMQFrame;
031 import org.apache.qpid.framing.AMQShortString;
032 import org.apache.qpid.framing.ChannelCloseBody;
033 import org.apache.qpid.framing.ChannelCloseOkBody;
034 import org.apache.qpid.protocol.AMQConstant;
035 
036 import org.slf4j.Logger;
037 import org.slf4j.LoggerFactory;
038 
039 public class ChannelCloseMethodHandler implements StateAwareMethodListener<ChannelCloseBody>
040 {
041     private static final Logger _logger = LoggerFactory.getLogger(ChannelCloseMethodHandler.class);
042 
043     private static ChannelCloseMethodHandler _handler = new ChannelCloseMethodHandler();
044 
045     public static ChannelCloseMethodHandler getInstance()
046     {
047         return _handler;
048     }
049 
050     public void methodReceived(AMQProtocolSession session, ChannelCloseBody method, int channelId)
051         throws AMQException
052     {
053         _logger.debug("ChannelClose method received");
054 
055         AMQConstant errorCode = AMQConstant.getConstant(method.getReplyCode());
056         AMQShortString reason = method.getReplyText();
057         if (_logger.isDebugEnabled())
058         {
059             _logger.debug("Channel close reply code: " + errorCode + ", reason: " + reason);
060         }
061 
062 
063 
064         ChannelCloseOkBody body = session.getMethodRegistry().createChannelCloseOkBody();
065         AMQFrame frame = body.generateFrame(channelId);
066         session.writeFrame(frame);
067 
068         if (errorCode != AMQConstant.REPLY_SUCCESS)
069         {
070             if (_logger.isDebugEnabled())
071             {
072                 _logger.debug("Channel close received with errorCode " + errorCode + ", and reason " + reason);
073             }
074 
075             if (errorCode == AMQConstant.NO_CONSUMERS)
076             {
077                 throw new AMQNoConsumersException("Error: " + reason, null, null);
078             }
079             else if (errorCode == AMQConstant.NO_ROUTE)
080             {
081                 throw new AMQNoRouteException("Error: " + reason, null, null);
082             }
083             else if (errorCode == AMQConstant.INVALID_ARGUMENT)
084             {
085                 _logger.debug("Broker responded with Invalid Argument.");
086 
087                 throw new org.apache.qpid.AMQInvalidArgumentException(String.valueOf(reason)null);
088             }
089             else if (errorCode == AMQConstant.INVALID_ROUTING_KEY)
090             {
091                 _logger.debug("Broker responded with Invalid Routing Key.");
092 
093                 throw new AMQInvalidRoutingKeyException(String.valueOf(reason)null);
094             }
095             else
096             {
097                 throw new AMQChannelClosedException(errorCode, "Error: " + reason, null);
098             }
099 
100         }
101         // fixme why is this only done when the close is expected...
102         // should the above forced closes not also cause a close?
103         // ----------
104         // Closing the session only when it is expected allows the errors to be processed
105         // Calling this here will prevent failover. So we should do this for all exceptions
106         // that should never cause failover. Such as authentication errors.
107 
108         session.channelClosed(channelId, errorCode, String.valueOf(reason));
109     }
110 }