org.apache.qpid.server.jmx.mbeans.QueueMBean.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.qpid.server.jmx.mbeans.QueueMBean.java

Source

/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF 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 org.apache.qpid.server.jmx.mbeans;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import javax.management.JMException;
import javax.management.MBeanNotificationInfo;
import javax.management.Notification;
import javax.management.ObjectName;
import javax.management.OperationsException;
import javax.management.monitor.MonitorNotification;
import javax.management.openmbean.ArrayType;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.CompositeDataSupport;
import javax.management.openmbean.CompositeType;
import javax.management.openmbean.OpenDataException;
import javax.management.openmbean.OpenType;
import javax.management.openmbean.SimpleType;
import javax.management.openmbean.TabularData;
import javax.management.openmbean.TabularDataSupport;
import javax.management.openmbean.TabularType;
import org.apache.commons.lang.time.FastDateFormat;
import org.apache.log4j.Logger;
import org.apache.qpid.management.common.mbeans.ManagedQueue;
import org.apache.qpid.server.jmx.AMQManagedObject;
import org.apache.qpid.server.jmx.ManagedObject;
import org.apache.qpid.server.message.AMQMessageHeader;
import org.apache.qpid.server.message.ServerMessage;
import org.apache.qpid.server.model.Exchange;
import org.apache.qpid.server.model.LifetimePolicy;
import org.apache.qpid.server.model.Queue;
import org.apache.qpid.server.model.QueueNotificationListener;
import org.apache.qpid.server.model.VirtualHost;
import org.apache.qpid.server.queue.NotificationCheck;
import org.apache.qpid.server.queue.QueueEntry;
import org.apache.qpid.server.queue.QueueEntryVisitor;

public class QueueMBean extends AMQManagedObject implements ManagedQueue, QueueNotificationListener {
    private static final Logger LOGGER = Logger.getLogger(QueueMBean.class);

    private static final String[] VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC_ARRAY = VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC
            .toArray(new String[VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC.size()]);

    private static final OpenType[] MSG_ATTRIBUTE_TYPES;
    private static final CompositeType MSG_DATA_TYPE;
    private static final TabularType MSG_LIST_DATA_TYPE;
    private static final CompositeType MSG_CONTENT_TYPE;
    private static final String[] VIEW_MSG_COMPOSIT_ITEM_NAMES_ARRAY = VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES_DESC
            .toArray(new String[VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES_DESC.size()]);

    static {

        try {
            MSG_ATTRIBUTE_TYPES = new OpenType[] { SimpleType.LONG, // For message id
                    new ArrayType(1, SimpleType.STRING), // For header attributes
                    SimpleType.LONG, // For size
                    SimpleType.BOOLEAN, // For redelivered
                    SimpleType.LONG, // For queue position
                    SimpleType.INTEGER // For delivery count}
            };

            MSG_DATA_TYPE = new CompositeType("Message", "AMQ Message", VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC_ARRAY,
                    VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC_ARRAY, MSG_ATTRIBUTE_TYPES);

            MSG_LIST_DATA_TYPE = new TabularType("Messages", "List of messages", MSG_DATA_TYPE,
                    VIEW_MSGS_TABULAR_UNIQUE_INDEX.toArray(new String[VIEW_MSGS_TABULAR_UNIQUE_INDEX.size()]));

            OpenType[] msgContentAttrs = new OpenType[] { SimpleType.LONG, // For message id
                    SimpleType.STRING, // For MimeType
                    SimpleType.STRING, // For MimeType
                    new ArrayType(SimpleType.BYTE, true) // For message content
            };

            MSG_CONTENT_TYPE = new CompositeType("Message Content", "AMQ Message Content",
                    VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES_DESC
                            .toArray(new String[VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES_DESC.size()]),
                    VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES_DESC.toArray(
                            new String[VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES_DESC.size()]),
                    msgContentAttrs);

        } catch (OpenDataException e) {
            throw new RuntimeException(e);
        }
    }

    private final Queue _queue;
    private final VirtualHostMBean _vhostMBean;

    /** Date/time format used for message expiration and message timestamp formatting */
    public static final String JMSTIMESTAMP_DATETIME_FORMAT = "MM-dd-yy HH:mm:ss.SSS z";

    private static final FastDateFormat FAST_DATE_FORMAT = FastDateFormat.getInstance(JMSTIMESTAMP_DATETIME_FORMAT);

    public QueueMBean(Queue queue, VirtualHostMBean virtualHostMBean) throws JMException {
        super(ManagedQueue.class, ManagedQueue.TYPE, virtualHostMBean.getRegistry());
        _queue = queue;
        _vhostMBean = virtualHostMBean;
        register();
        _queue.setNotificationListener(this);
    }

    public ManagedObject getParentObject() {
        return _vhostMBean;
    }

    public String getObjectInstanceName() {
        return ObjectName.quote(getName());
    }

    public String getName() {
        return _queue.getName();
    }

    public Integer getMessageCount() {
        return getStatisticValue(Queue.QUEUE_DEPTH_MESSAGES).intValue();
    }

    public Integer getMaximumDeliveryCount() {
        return (Integer) _queue.getAttribute(Queue.MAXIMUM_DELIVERY_ATTEMPTS);
    }

    public Long getReceivedMessageCount() {
        return getStatisticValue(Queue.TOTAL_ENQUEUED_MESSAGES).longValue();
    }

    public Long getQueueDepth() {
        return getStatisticValue(Queue.QUEUE_DEPTH_BYTES).longValue();
    }

    public Integer getActiveConsumerCount() {
        return getStatisticValue(Queue.CONSUMER_COUNT_WITH_CREDIT).intValue();
    }

    public Integer getConsumerCount() {
        return getStatisticValue(Queue.CONSUMER_COUNT).intValue();
    }

    public String getOwner() {
        return (String) _queue.getAttribute(Queue.OWNER);
    }

    @Override
    public String getQueueType() {
        return (String) _queue.getAttribute(Queue.TYPE);
    }

    public boolean isDurable() {
        return _queue.isDurable();
    }

    public boolean isAutoDelete() {
        return _queue.getLifetimePolicy() == LifetimePolicy.AUTO_DELETE;
    }

    public Long getMaximumMessageAge() {
        return (Long) _queue.getAttribute(Queue.ALERT_THRESHOLD_MESSAGE_AGE);
    }

    public void setMaximumMessageAge(Long age) {
        _queue.setAttribute(Queue.ALERT_THRESHOLD_MESSAGE_AGE, getMaximumMessageAge(), age);
    }

    public Long getMaximumMessageSize() {
        return (Long) _queue.getAttribute(Queue.ALERT_THRESHOLD_MESSAGE_SIZE);
    }

    public void setMaximumMessageSize(Long size) {
        _queue.setAttribute(Queue.ALERT_THRESHOLD_MESSAGE_SIZE, getMaximumMessageSize(), size);
    }

    public Long getMaximumMessageCount() {
        return (Long) _queue.getAttribute(Queue.ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES);
    }

    public void setMaximumMessageCount(Long value) {
        _queue.setAttribute(Queue.ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES, getMaximumMessageCount(), value);
    }

    public Long getMaximumQueueDepth() {
        return (Long) _queue.getAttribute(Queue.ALERT_THRESHOLD_QUEUE_DEPTH_BYTES);
    }

    public void setMaximumQueueDepth(Long value) {
        _queue.setAttribute(Queue.ALERT_THRESHOLD_QUEUE_DEPTH_BYTES, getMaximumQueueDepth(), value);
    }

    public Long getCapacity() {
        return (Long) _queue.getAttribute(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES);
    }

    public void setCapacity(Long value) {
        _queue.setAttribute(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, getCapacity(), value);
    }

    public Long getFlowResumeCapacity() {
        return (Long) _queue.getAttribute(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES);
    }

    public void setFlowResumeCapacity(Long value) {
        _queue.setAttribute(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, getFlowResumeCapacity(), value);
    }

    public boolean isFlowOverfull() {
        return (Boolean) _queue.getAttribute(Queue.QUEUE_FLOW_STOPPED);
    }

    public boolean isExclusive() {
        return (Boolean) _queue.getAttribute(Queue.EXCLUSIVE);
    }

    public void setExclusive(boolean exclusive) {
        _queue.setAttribute(Queue.EXCLUSIVE, isExclusive(), exclusive);
    }

    public void setAlternateExchange(String exchangeName) throws OperationsException {
        if (exchangeName == null || "".equals(exchangeName)) {
            _queue.setAttribute(Queue.ALTERNATE_EXCHANGE, getAlternateExchange(), null);
        } else {
            VirtualHost virtualHost = _queue.getParent(VirtualHost.class);
            Exchange exchange = MBeanUtils.findExchangeFromExchangeName(virtualHost, exchangeName);

            _queue.setAttribute(Queue.ALTERNATE_EXCHANGE, getAlternateExchange(), exchange);
        }
    }

    public String getAlternateExchange() {
        Exchange alternateExchange = (Exchange) _queue.getAttribute(Queue.ALTERNATE_EXCHANGE);
        return alternateExchange == null ? null : alternateExchange.getName();
    }

    public TabularData viewMessages(int fromIndex, int toIndex) throws IOException, JMException {
        return viewMessages((long) fromIndex, (long) toIndex);
    }

    public TabularData viewMessages(long startPosition, long endPosition) throws IOException, JMException {
        if ((startPosition > endPosition) || (startPosition < 1)) {
            throw new OperationsException("From Index = " + startPosition + ", To Index = " + endPosition
                    + "\n\"From Index\" should be greater than 0 and less than \"To Index\"");
        }

        if ((endPosition - startPosition) > Integer.MAX_VALUE) {
            throw new OperationsException(
                    "Specified MessageID interval is too large. Intervals must be less than 2^31 in size");
        }

        List<QueueEntry> messages = getMessages(startPosition, endPosition);

        TabularDataSupport messageTable = new TabularDataSupport(MSG_LIST_DATA_TYPE);

        // Create the tabular list of message header contents
        long position = startPosition;

        for (QueueEntry queueEntry : messages) {
            ServerMessage serverMsg = queueEntry.getMessage();
            AMQMessageHeader header = serverMsg.getMessageHeader();
            String[] headerAttributes = { "reply-to = " + header.getReplyTo(), "propertyFlags = ",
                    "ApplicationID = " + header.getAppId(), "ClusterID = ", "UserId = " + header.getUserId(),
                    "JMSMessageID = " + header.getMessageId(), "JMSCorrelationID = " + header.getCorrelationId(),
                    "JMSDeliveryMode = " + (serverMsg.isPersistent() ? "Persistent" : "Non_Persistent"),
                    "JMSPriority = " + header.getPriority(), "JMSType = " + header.getType(),
                    "JMSExpiration = " + (header.getExpiration() == 0 ? null
                            : FAST_DATE_FORMAT.format(header.getExpiration())),
                    "JMSTimestamp = " + (header.getTimestamp() == 0 ? null
                            : FAST_DATE_FORMAT.format(header.getTimestamp())) };

            Object[] itemValues = new Object[] { serverMsg.getMessageNumber(), headerAttributes,
                    serverMsg.getSize(), queueEntry.isRedelivered(), position, queueEntry.getDeliveryCount() };

            position++;

            CompositeData messageData = new CompositeDataSupport(MSG_DATA_TYPE,
                    VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC_ARRAY, itemValues);
            messageTable.put(messageData);
        }

        return messageTable;

    }

    public CompositeData viewMessageContent(long messageId) throws IOException, JMException {
        QueueEntry entry = getMessage(messageId);
        if (entry == null) {
            throw new OperationsException(
                    "AMQMessage with message id = " + messageId + " is not in the " + _queue.getName());
        }

        ServerMessage serverMsg = entry.getMessage();
        final int bodySize = (int) serverMsg.getSize();

        byte[] msgContent = new byte[bodySize];

        ByteBuffer buf = ByteBuffer.wrap(msgContent);
        int stored = serverMsg.getContent(buf, 0);

        if (bodySize != stored) {
            LOGGER.error(String.format(
                    "An unexpected amount of content was retrieved "
                            + "(expected %d, got %d bytes) when viewing content for message with ID %d "
                            + "on queue '%s' in virtual host '%s'",
                    bodySize, stored, messageId, _queue.getName(), _vhostMBean.getName()));
        }

        AMQMessageHeader header = serverMsg.getMessageHeader();

        String mimeType = null, encoding = null;
        if (header != null) {
            mimeType = header.getMimeType();

            encoding = header.getEncoding();
        }

        Object[] itemValues = { messageId, mimeType, encoding, msgContent };

        return new CompositeDataSupport(MSG_CONTENT_TYPE, VIEW_MSG_COMPOSIT_ITEM_NAMES_ARRAY, itemValues);

    }

    private QueueEntry getMessage(long messageId) {
        GetMessageVisitor visitor = new GetMessageVisitor(messageId);
        _queue.visit(visitor);
        return visitor.getEntry();
    }

    public void deleteMessageFromTop() throws IOException, JMException {
        VirtualHost vhost = _queue.getParent(VirtualHost.class);
        vhost.executeTransaction(new VirtualHost.TransactionalOperation() {
            public void withinTransaction(final VirtualHost.Transaction txn) {
                _queue.visit(new QueueEntryVisitor() {

                    public boolean visit(final QueueEntry entry) {
                        if (entry.acquire()) {
                            txn.dequeue(entry);
                            return true;
                        }
                        return false;
                    }
                });

            }
        });

    }

    public Long clearQueue() throws IOException, JMException {
        VirtualHost vhost = _queue.getParent(VirtualHost.class);
        final AtomicLong count = new AtomicLong();

        vhost.executeTransaction(new VirtualHost.TransactionalOperation() {
            public void withinTransaction(final VirtualHost.Transaction txn) {
                _queue.visit(new QueueEntryVisitor() {

                    public boolean visit(final QueueEntry entry) {
                        final ServerMessage message = entry.getMessage();
                        if (message != null) {
                            txn.dequeue(entry);
                            count.incrementAndGet();

                        }
                        return false;
                    }
                });

            }
        });
        return count.get();
    }

    public void moveMessages(final long fromMessageId, final long toMessageId, String toQueue)
            throws IOException, JMException {
        if ((fromMessageId > toMessageId) || (fromMessageId < 1)) {
            throw new OperationsException(
                    "\"From MessageId\" should be greater than 0 and less than \"To MessageId\"");
        }

        VirtualHost vhost = _queue.getParent(VirtualHost.class);
        final Queue destinationQueue = MBeanUtils.findQueueFromQueueName(vhost, toQueue);

        vhost.executeTransaction(new VirtualHost.TransactionalOperation() {
            public void withinTransaction(final VirtualHost.Transaction txn) {
                _queue.visit(new QueueEntryVisitor() {

                    public boolean visit(final QueueEntry entry) {
                        final ServerMessage message = entry.getMessage();
                        if (message != null) {
                            final long messageId = message.getMessageNumber();

                            if ((messageId >= fromMessageId) && (messageId <= toMessageId)) {
                                txn.move(entry, destinationQueue);
                            }

                        }
                        return false;
                    }
                });
            }
        });
    }

    public void deleteMessages(final long fromMessageId, final long toMessageId) throws IOException, JMException {
        VirtualHost vhost = _queue.getParent(VirtualHost.class);
        vhost.executeTransaction(new VirtualHost.TransactionalOperation() {
            public void withinTransaction(final VirtualHost.Transaction txn) {
                _queue.visit(new QueueEntryVisitor() {
                    public boolean visit(final QueueEntry entry) {
                        final ServerMessage message = entry.getMessage();
                        if (message != null) {
                            final long messageId = message.getMessageNumber();

                            if ((messageId >= fromMessageId) && (messageId <= toMessageId)) {
                                txn.dequeue(entry);
                            }
                        }
                        return false;
                    }
                });
            }
        });
    }

    public void copyMessages(final long fromMessageId, final long toMessageId, String toQueue)
            throws IOException, JMException {
        if ((fromMessageId > toMessageId) || (fromMessageId < 1)) {
            throw new OperationsException(
                    "\"From MessageId\" should be greater than 0 and less than \"To MessageId\"");
        }

        VirtualHost vhost = _queue.getParent(VirtualHost.class);
        final Queue destinationQueue = MBeanUtils.findQueueFromQueueName(vhost, toQueue);

        vhost.executeTransaction(new VirtualHost.TransactionalOperation() {
            public void withinTransaction(final VirtualHost.Transaction txn) {
                _queue.visit(new QueueEntryVisitor() {

                    public boolean visit(final QueueEntry entry) {
                        final ServerMessage message = entry.getMessage();
                        if (message != null) {
                            final long messageId = message.getMessageNumber();

                            if ((messageId >= fromMessageId) && (messageId <= toMessageId)) {
                                txn.copy(entry, destinationQueue);
                            }

                        }
                        return false;
                    }
                });
            }
        });
    }

    private List<QueueEntry> getMessages(final long first, final long last) {
        final List<QueueEntry> messages = new ArrayList<QueueEntry>((int) (last - first) + 1);
        _queue.visit(new QueueEntryVisitor() {
            private long position = 1;

            public boolean visit(QueueEntry entry) {
                if (position >= first && position <= last) {
                    messages.add(entry);
                }
                position++;
                return position > last;
            }
        });
        return messages;
    }

    protected static class GetMessageVisitor implements QueueEntryVisitor {

        private final long _messageNumber;
        private QueueEntry _entry;

        public GetMessageVisitor(long messageId) {
            _messageNumber = messageId;
        }

        public boolean visit(QueueEntry entry) {
            if (entry.getMessage().getMessageNumber() == _messageNumber) {
                _entry = entry;
                return true;
            }
            return false;
        }

        public QueueEntry getEntry() {
            return _entry;
        }
    }

    @Override
    public void notifyClients(NotificationCheck notification, Queue queue, String notificationMsg) {
        notificationMsg = notification.name() + " " + notificationMsg;

        Notification note = new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this,
                incrementAndGetSequenceNumber(), System.currentTimeMillis(), notificationMsg);

        getBroadcaster().sendNotification(note);
    }

    /**
     * returns Notifications sent by this MBean.
     */
    @Override
    public MBeanNotificationInfo[] getNotificationInfo() {
        String[] notificationTypes = new String[] { MonitorNotification.THRESHOLD_VALUE_EXCEEDED };
        String name = MonitorNotification.class.getName();
        String description = "Either Message count or Queue depth or Message size has reached threshold high value";
        MBeanNotificationInfo info1 = new MBeanNotificationInfo(notificationTypes, name, description);

        return new MBeanNotificationInfo[] { info1 };
    }

    @Override
    public String getDescription() {
        return (String) _queue.getAttribute(Queue.DESCRIPTION);
    }

    @Override
    public void setDescription(String description) {
        _queue.setAttribute(Queue.DESCRIPTION, getDescription(), description);
    }

    private Number getStatisticValue(String name) {
        final Number statistic = (Number) _queue.getStatistics().getStatistic(name);
        return statistic == null ? Integer.valueOf(0) : statistic;
    }
}