org.wso2.andes.server.information.management.SubscriptionManagementInformationMBean.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.andes.server.information.management.SubscriptionManagementInformationMBean.java

Source

/*
 * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 * WSO2 Inc. 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.wso2.andes.server.information.management;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.andes.amqp.AMQPUtils;
import org.wso2.andes.kernel.AndesContext;
import org.wso2.andes.kernel.AndesException;
import org.wso2.andes.kernel.DestinationType;
import org.wso2.andes.kernel.MessagingEngine;
import org.wso2.andes.kernel.ProtocolType;
import org.wso2.andes.kernel.subscription.AndesSubscription;
import org.wso2.andes.kernel.subscription.AndesSubscriptionManager;
import org.wso2.andes.management.common.mbeans.SubscriptionManagementInformation;
import org.wso2.andes.mqtt.utils.MQTTUtils;
import org.wso2.andes.server.management.AMQManagedObject;

import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;
import javax.management.MBeanException;
import javax.management.NotCompliantMBeanException;

/**
 * Class to handle data for all subscription related UI functions.
 */
public class SubscriptionManagementInformationMBean extends AMQManagedObject
        implements SubscriptionManagementInformation {

    private static Log log = LogFactory.getLog(SubscriptionManagementInformationMBean.class);

    /**
     * Separator used for render the subscriptions for UI
     */
    private static final String SEPARATOR = ";";

    /**
     * Used when the subscriber connection is not available
     */
    private static final String NOT_AVAILABLE = "N/A";

    /**
     * Subscription store used to query subscription related information
     */
    private AndesSubscriptionManager subscriptionManager;

    /**
     * Instantiates the MBeans related to subscriptions.
     *
     * @throws NotCompliantMBeanException
     */
    public SubscriptionManagementInformationMBean() throws NotCompliantMBeanException {
        super(SubscriptionManagementInformation.class, SubscriptionManagementInformation.TYPE);

        subscriptionManager = AndesContext.getInstance().getAndesSubscriptionManager();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String getObjectInstanceName() {
        return SubscriptionManagementInformation.TYPE;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String[] getSubscriptions(String isDurable, String isActive, String protocolType, String destinationType)
            throws MBeanException {
        try {

            //TODO: fix this method. isActive comes as *
            boolean durableSubscriptionsReq = Boolean.parseBoolean(isDurable);
            Set<AndesSubscription> subscriptionsToDisplay = getSubscriptionsOfBroker(durableSubscriptionsReq, true,
                    protocolType, destinationType);

            Set<AndesSubscription> inactiveSubscriptions = getSubscriptionsOfBroker(durableSubscriptionsReq, false,
                    protocolType, destinationType);
            subscriptionsToDisplay.addAll(inactiveSubscriptions);

            String[] subscriptionArray = new String[subscriptionsToDisplay.size()];

            int index = 0;
            for (AndesSubscription subscription : subscriptionsToDisplay) {
                Long pendingMessageCount = MessagingEngine.getInstance()
                        .getApproximateQueueMessageCount(subscription.getStorageQueue().getName());

                subscriptionArray[index] = renderSubscriptionForUI(subscription.isActive(), destinationType,
                        subscription, pendingMessageCount.intValue());

                index++;
            }
            return subscriptionArray;

        } catch (Exception e) {
            log.error("Error while invoking MBeans to retrieve subscription information", e);
            throw new MBeanException(e, "Error while invoking MBeans to retrieve subscription information");
        }
    }

    /**
     * {@inheritDoc}
     */
    public long getPendingMessageCount(String queueName) throws MBeanException {
        try {
            return MessagingEngine.getInstance().getApproximateQueueMessageCount(queueName);
        } catch (Exception e) {
            log.error("Error while invoking MBeans to calculate the pending message count for storage queue", e);
            throw new MBeanException(e,
                    "Error while invoking MBeans to calculate the pending message count for " + "storage queue");
        }
    }

    /**
     * {@inheritDoc}
     */
    public String[] getFilteredSubscriptions(boolean isDurable, boolean isActive, String protocolType,
            String destinationType, String filteredNamePattern, boolean isFilteredNameByExactMatch,
            String identifierPattern, boolean isIdentifierPatternByExactMatch, String ownNodeId, int pageNumber,
            int maxSubscriptionCount) throws MBeanException {

        try {
            int startingIndex = pageNumber * maxSubscriptionCount;
            String[] subscriptionArray;
            int resultSetSize = maxSubscriptionCount;
            int index = 0;
            int subscriptionDetailsIndex = 0;

            AndesSubscriptionManager subscriptionManager = AndesContext.getInstance().getAndesSubscriptionManager();

            Set<AndesSubscription> searchSubscriptionList = subscriptionManager.getFilteredSubscriptions(isDurable,
                    isActive, ProtocolType.valueOf(protocolType), DestinationType.valueOf(destinationType),
                    filteredNamePattern, isFilteredNameByExactMatch, identifierPattern,
                    isIdentifierPatternByExactMatch, ownNodeId);

            int fullListSize = searchSubscriptionList.size() - startingIndex;

            //Get only paginated subscription from search subscription result
            if (fullListSize >= 0 && fullListSize < maxSubscriptionCount) {
                resultSetSize = (searchSubscriptionList.size() - startingIndex);
            }
            subscriptionArray = new String[resultSetSize];

            for (AndesSubscription subscription : searchSubscriptionList) {
                if (startingIndex <= index) {
                    Long pendingMessageCount = MessagingEngine.getInstance()
                            .getApproximateQueueMessageCount(subscription.getStorageQueue().getName());
                    subscriptionArray[subscriptionDetailsIndex] = renderSubscriptionForUI(isActive, destinationType,
                            subscription, pendingMessageCount.intValue());
                    subscriptionDetailsIndex++;
                    if (subscriptionDetailsIndex == maxSubscriptionCount) {
                        break;
                    }
                }
                index++;
            }

            return subscriptionArray;
        } catch (Exception e) {
            log.error(
                    "Error while invoking MBeans to retrieve subscription information. The given method parameters "
                            + "are: isDurable- " + isDurable + " isActive- " + isActive + " protocolType- "
                            + protocolType + " destinationType- " + destinationType + " filteredNamePattern- "
                            + filteredNamePattern + " isFilteredNameByExactMatch- " + isFilteredNameByExactMatch
                            + " identifierPattern- " + identifierPattern + " isIdentifierPatternByExactMatch- "
                            + isIdentifierPatternByExactMatch + " ownNodeId- " + ownNodeId + " pageNumber- "
                            + pageNumber + " maxSubscriptionCount- " + maxSubscriptionCount,
                    e);
            throw new MBeanException(e, "Error while invoking MBeans to retrieve subscription information");
        }
    }

    /**
     * Create the regex pattern for filtering.
     *
     * @param pattern String value of the patten
     * @return Regex pattern
     */
    private Pattern createRegEx(String pattern) {

        String regex = pattern.replaceAll("\\*", ".*");

        return Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
    }

    /**
     * {@inheritDoc}
     */
    public int getTotalSubscriptionCountForSearchResult(boolean isDurable, boolean isActive, String protocolType,
            String destinationType, String filteredNamePattern, boolean isFilteredNameByExactMatch,
            String identifierPattern, boolean isIdentifierPatternByExactMatch, String ownNodeId)
            throws MBeanException {
        try {
            AndesSubscriptionManager subscriptionManager = AndesContext.getInstance().getAndesSubscriptionManager();
            //get the searched subscriptions
            Set<AndesSubscription> searchSubscriptionList = subscriptionManager.getFilteredSubscriptions(isDurable,
                    isActive, ProtocolType.valueOf(protocolType), DestinationType.valueOf(destinationType),
                    filteredNamePattern, isFilteredNameByExactMatch, identifierPattern,
                    isIdentifierPatternByExactMatch, ownNodeId);

            //count of search subscriptions
            return searchSubscriptionList.size();
        } catch (Exception e) {
            log.error("Error while invoking MBeans to retrieve subscription information", e);
            throw new MBeanException(e, "Error while invoking MBeans to retrieve subscription information");
        }
    }

    private Set<AndesSubscription> getSubscriptionsOfBroker(boolean isDurable, boolean isActive,
            String protocolType, String destinationType) throws AndesException {

        AndesSubscriptionManager subscriptionManager = AndesContext.getInstance().getAndesSubscriptionManager();

        Iterable<AndesSubscription> matchingSubscriptions;
        Set<AndesSubscription> subscriptionsToDisplay = new HashSet<>(10);

        if (!isDurable && !isActive) {
            return subscriptionsToDisplay;
        }

        ProtocolType protocolTypeArg = ProtocolType.valueOf(protocolType);
        DestinationType destinationTypeArg = DestinationType.valueOf(destinationType);
        if (isActive) {
            String messageRouterName;
            switch (destinationTypeArg) {
            case TOPIC:
                if (protocolTypeArg.equals(ProtocolType.AMQP)) {
                    messageRouterName = AMQPUtils.TOPIC_EXCHANGE_NAME;
                } else {
                    messageRouterName = MQTTUtils.MQTT_EXCHANGE_NAME;
                }
                break;
            case QUEUE:
                messageRouterName = AMQPUtils.DIRECT_EXCHANGE_NAME;
                break;
            case DURABLE_TOPIC:
                if (protocolTypeArg.equals(ProtocolType.AMQP)) {
                    messageRouterName = AMQPUtils.TOPIC_EXCHANGE_NAME;
                } else {
                    messageRouterName = MQTTUtils.MQTT_EXCHANGE_NAME;
                }
                break;
            default:
                messageRouterName = AMQPUtils.DIRECT_EXCHANGE_NAME;
                break;
            }

            matchingSubscriptions = subscriptionManager.getAllSubscriptionsByMessageRouter(protocolTypeArg,
                    messageRouterName);

        } else {
            matchingSubscriptions = subscriptionManager.getInactiveSubscriberRepresentations();
        }

        for (AndesSubscription subscription : matchingSubscriptions) {
            if (isDurable == subscription.isDurable()) {
                subscriptionsToDisplay.add(subscription);
            }
        }

        return subscriptionsToDisplay;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int getMessageCount(String subscribedNode, String msgPattern, String destinationName) {
        try {
            Long messageCount = MessagingEngine.getInstance().getApproximateQueueMessageCount(destinationName);
            return messageCount.intValue();
        } catch (Exception e) {
            throw new RuntimeException("Error in retrieving pending message count", e);
        }
    }

    @Override
    public void removeSubscription(String subscriptionId, String destinationName, String protocolType,
            String destinationType) {
        try {
            AndesSubscription subscriptionToRemove = subscriptionManager.getSubscriptionById(subscriptionId);

            if (null != subscriptionToRemove) {
                subscriptionToRemove.forcefullyDisconnectConnections();
            } else {
                throw new AndesException("Subscription to remove not found. Requested id = " + subscriptionId);
            }
        } catch (AndesException e) {
            throw new RuntimeException("Error in accessing subscription information", e);
        }
    }

    /**
     * This method returns the formatted subscription string to be compatible with the UI processor.
     *
     * @param subscription        AndesSubscription object that is to be translated to UI view
     * @param pendingMessageCount Number of pending messages of subscription
     * @return String representation of the subscription meta information and pending message count
     */
    private static String renderSubscriptionForUI(Boolean isActive, String destinationType,
            AndesSubscription subscription, int pendingMessageCount) throws AndesException {

        String subscriptionIdentifier = subscription.getSubscriptionId();

        StringBuilder subscriptionForUI = new StringBuilder(subscriptionIdentifier);
        subscriptionForUI.append(SEPARATOR);
        subscriptionForUI.append(subscription.getStorageQueue().getMessageRouterBindingKey());
        subscriptionForUI.append(SEPARATOR);
        subscriptionForUI.append(subscription.getStorageQueue().getMessageRouter().getName());
        subscriptionForUI.append(SEPARATOR);
        if (subscription.isLocal()) {
            subscriptionForUI.append(subscription.isDurable() ? subscription.getStorageQueue().getName()
                    : subscription.getProtocolQueue());
        } else {
            subscriptionForUI
                    .append(subscription.isDurable() ? subscription.getStorageQueue().getName() : NOT_AVAILABLE);
        }
        subscriptionForUI.append(SEPARATOR);
        subscriptionForUI.append(subscription.isDurable());
        subscriptionForUI.append(SEPARATOR);
        subscriptionForUI.append(isActive);
        subscriptionForUI.append(SEPARATOR);
        subscriptionForUI.append(pendingMessageCount);
        subscriptionForUI.append(SEPARATOR);
        subscriptionForUI.append(((null == subscription.getSubscriberConnection()) ? NOT_AVAILABLE
                : subscription.getSubscriberConnection().getConnectedNode()));
        subscriptionForUI.append(SEPARATOR);
        subscriptionForUI.append(subscription.getStorageQueue().getMessageRouterBindingKey());
        subscriptionForUI.append(SEPARATOR);
        subscriptionForUI.append(subscription.getProtocolType().name());
        subscriptionForUI.append(SEPARATOR);
        subscriptionForUI.append(destinationType);
        subscriptionForUI.append(SEPARATOR);
        subscriptionForUI.append(((null == subscription.getSubscriberConnection()) ? NOT_AVAILABLE
                : subscription.getSubscriberConnection().getConnectedIP()));

        return subscriptionForUI.toString();
    }
}