Search in sources :

Example 1 with AMQPMessage

use of org.apache.qpid.qmf2.common.AMQPMessage in project qpid by apache.

the class Console method onMessage.

/**
 * MessageListener for QMF2 Agent Events, Hearbeats and Asynchronous data indications
 *
 * @param message the JMS Message passed to the listener
 */
public void onMessage(Message message) {
    try {
        String agentName = QmfData.getString(message.getObjectProperty("qmf.agent"));
        String content = QmfData.getString(message.getObjectProperty("qmf.content"));
        String opcode = QmfData.getString(message.getObjectProperty("qmf.opcode"));
        if (opcode.equals("_agent_heartbeat_indication") || opcode.equals("_agent_locate_response")) {
            // This block handles Agent lifecycle information (discover, register, delete)
            if (_agents.containsKey(agentName)) {
                // This block handles Agents that have previously been registered
                Agent agent = _agents.get(agentName);
                long originalEpoch = agent.getEpoch();
                // If we already know about an Agent we simply update the Agent's state using initialise()
                agent.initialise(AMQPMessage.getMap(message));
                // If the Epoch has changed it means the Agent has been restarted so we send a notification
                if (agent.getEpoch() != originalEpoch) {
                    // Clear cache to force a lookup
                    agent.clearSchemaCache();
                    List<SchemaClassId> classes = getClasses(agent);
                    // Discover the schema for this Agent and cache it
                    getSchema(classes, agent);
                    _log.info("Agent {} has been restarted", agentName);
                    if (_discoverAgents && (_agentQuery == null || _agentQuery.evaluate(agent))) {
                        _eventListener.onEvent(new AgentRestartedWorkItem(agent));
                    }
                } else {
                    // Otherwise just send a heartbeat notification
                    _log.info("Agent {} heartbeat", agent.getName());
                    if (_discoverAgents && (_agentQuery == null || _agentQuery.evaluate(agent))) {
                        _eventListener.onEvent(new AgentHeartbeatWorkItem(agent));
                    }
                }
            } else {
                // This block handles Agents that haven't already been registered
                Agent agent = new Agent(AMQPMessage.getMap(message), this);
                List<SchemaClassId> classes = getClasses(agent);
                // Discover the schema for this Agent and cache it
                getSchema(classes, agent);
                _agents.put(agentName, agent);
                _log.info("Adding Agent {}", agentName);
                // the Agent more "user friendly" than using the full Agent name.
                if (agent.getVendor().equals("apache.org") && agent.getProduct().equals("qpidd")) {
                    _log.info("Recording {} as _brokerAgentName", agentName);
                    _brokerAgentName = agentName;
                }
                // wait for the broker Agent to become available.
                if (_brokerAgentName != null) {
                    synchronized (this) {
                        _agentAvailable = true;
                        notifyAll();
                    }
                }
                if (_discoverAgents && (_agentQuery == null || _agentQuery.evaluate(agent))) {
                    _eventListener.onEvent(new AgentAddedWorkItem(agent));
                }
            }
            // The broker Agent sends periodic heartbeats and that Agent should *always* be available given
            // a running broker, so we should get here every "--mgmt-pub-interval" seconds or so, so it's
            // a good place to periodically check for the expiry of any other Agents.
            handleAgentExpiry();
            return;
        }
        if (!_agents.containsKey(agentName)) {
            _log.info("Ignoring Event from unregistered Agent {}", agentName);
            return;
        }
        Agent agent = _agents.get(agentName);
        if (!agent.eventsEnabled()) {
            _log.info("{} has disabled Event reception, ignoring Event", agentName);
            return;
        }
        // If we get to here the Agent from whence the Event came should be registered and should
        // have Event reception enabled, so we should be able to send events to the EventListener
        Handle handle = new Handle(message.getJMSCorrelationID());
        if (opcode.equals("_method_response") || opcode.equals("_exception")) {
            if (AMQPMessage.isAMQPMap(message)) {
                _eventListener.onEvent(new MethodResponseWorkItem(handle, new MethodResult(AMQPMessage.getMap(message))));
            } else {
                _log.info("onMessage() Received Method Response message in incorrect format");
            }
        }
        // refresh() call on QmfConsoleData so the number of results in the returned list *should* be one.
        if (opcode.equals("_query_response") && content.equals("_data")) {
            if (AMQPMessage.isAMQPList(message)) {
                List<Map> list = AMQPMessage.getList(message);
                for (Map m : list) {
                    _eventListener.onEvent(new ObjectUpdateWorkItem(handle, new QmfConsoleData(m, agent)));
                }
            } else {
                _log.info("onMessage() Received Query Response message in incorrect format");
            }
        }
        // This block handles responses to createSubscription and refreshSubscription
        if (opcode.equals("_subscribe_response")) {
            if (AMQPMessage.isAMQPMap(message)) {
                String correlationId = message.getJMSCorrelationID();
                SubscribeParams params = new SubscribeParams(correlationId, AMQPMessage.getMap(message));
                String subscriptionId = params.getSubscriptionId();
                if (subscriptionId != null && correlationId != null) {
                    SubscriptionManager subscription = _subscriptionById.get(subscriptionId);
                    if (subscription == null) {
                        // This is a createSubscription response so the correlationId should be the consoleHandle
                        subscription = _subscriptionByHandle.get(correlationId);
                        if (subscription != null) {
                            _subscriptionById.put(subscriptionId, subscription);
                            subscription.setSubscriptionId(subscriptionId);
                            subscription.setDuration(params.getLifetime());
                            String replyHandle = subscription.getReplyHandle();
                            if (replyHandle == null) {
                                subscription.signal();
                            } else {
                                _eventListener.onEvent(new SubscribeResponseWorkItem(new Handle(replyHandle), params));
                            }
                        }
                    } else {
                        // This is a refreshSubscription response
                        params.setConsoleHandle(subscription.getConsoleHandle());
                        subscription.setDuration(params.getLifetime());
                        subscription.refresh();
                        _eventListener.onEvent(new SubscribeResponseWorkItem(handle, params));
                    }
                }
            } else {
                _log.info("onMessage() Received Subscribe Response message in incorrect format");
            }
        }
        // Subscription Indication - in other words the asynchronous results of a Subscription
        if (opcode.equals("_data_indication") && content.equals("_data")) {
            if (AMQPMessage.isAMQPList(message)) {
                String consoleHandle = handle.getCorrelationId();
                if (consoleHandle != null && _subscriptionByHandle.containsKey(consoleHandle)) {
                    // If we have a valid consoleHandle the data has come from a "real" Subscription.
                    List<Map> list = AMQPMessage.getList(message);
                    List<QmfConsoleData> resultList = new ArrayList<QmfConsoleData>(list.size());
                    for (Map m : list) {
                        resultList.add(new QmfConsoleData(m, agent));
                    }
                    _eventListener.onEvent(new SubscriptionIndicationWorkItem(new SubscribeIndication(consoleHandle, resultList)));
                } else if (_subscriptionEmulationEnabled && agentName.equals(_brokerAgentName)) {
                    // If the data has come from is the broker Agent we emulate a Subscription on the Console
                    for (SubscriptionManager subscription : _subscriptionByHandle.values()) {
                        QmfQuery query = subscription.getQuery();
                        if (subscription.getAgent().getName().equals(_brokerAgentName) && query.getTarget() == QmfQueryTarget.OBJECT) {
                            // Only evaluate broker Agent subscriptions with QueryTarget == OBJECT on the Console.
                            long objectEpoch = 0;
                            consoleHandle = subscription.getConsoleHandle();
                            List<Map> list = AMQPMessage.getList(message);
                            List<QmfConsoleData> resultList = new ArrayList<QmfConsoleData>(list.size());
                            for (Map m : list) {
                                // Evaluate the QmfConsoleData object against the query
                                QmfConsoleData object = new QmfConsoleData(m, agent);
                                if (query.evaluate(object)) {
                                    long epoch = object.getObjectId().getAgentEpoch();
                                    objectEpoch = (epoch > objectEpoch && !object.isDeleted()) ? epoch : objectEpoch;
                                    resultList.add(object);
                                }
                            }
                            if (resultList.size() > 0) {
                                // data from the restarted Agent (in case they need to reset any state).
                                if (objectEpoch > agent.getEpoch()) {
                                    agent.setEpoch(objectEpoch);
                                    // Clear cache to force a lookup
                                    agent.clearSchemaCache();
                                    List<SchemaClassId> classes = getClasses(agent);
                                    // Discover the schema for this Agent and cache it
                                    getSchema(classes, agent);
                                    _log.info("Agent {} has been restarted", agentName);
                                    if (_discoverAgents && (_agentQuery == null || _agentQuery.evaluate(agent))) {
                                        _eventListener.onEvent(new AgentRestartedWorkItem(agent));
                                    }
                                }
                                _eventListener.onEvent(new SubscriptionIndicationWorkItem(new SubscribeIndication(consoleHandle, resultList)));
                            }
                        }
                    }
                }
            } else {
                _log.info("onMessage() Received Subscribe Indication message in incorrect format");
            }
        }
        // The results of an Event delivered from an Agent
        if (opcode.equals("_data_indication") && content.equals("_event")) {
            // There are differences in the type of message sent by Qpid 0.8 and 0.10 onwards.
            if (AMQPMessage.isAMQPMap(message)) {
                // 0.8 broker passes Events as amqp/map encoded as MapMessages (we convert into java.util.Map)
                _eventListener.onEvent(new EventReceivedWorkItem(agent, new QmfEvent(AMQPMessage.getMap(message))));
            } else if (AMQPMessage.isAMQPList(message)) {
                // 0.10 and above broker passes Events as amqp/list encoded as BytesMessage (needs decoding)
                // 0.20 encodes amqp/list in a MapMessage!!?? AMQPMessage hopefully abstracts this detail.
                List<Map> list = AMQPMessage.getList(message);
                for (Map m : list) {
                    _eventListener.onEvent(new EventReceivedWorkItem(agent, new QmfEvent(m)));
                }
            } else {
                _log.info("onMessage() Received Event message in incorrect format");
            }
        }
    } catch (JMSException jmse) {
        _log.info("JMSException {} caught in onMessage()", jmse.getMessage());
    }
}
Also used : ArrayList(java.util.ArrayList) QmfEvent(org.apache.qpid.qmf2.common.QmfEvent) JMSException(javax.jms.JMSException) ArrayList(java.util.ArrayList) List(java.util.List) SchemaClassId(org.apache.qpid.qmf2.common.SchemaClassId) Handle(org.apache.qpid.qmf2.common.Handle) HashMap(java.util.HashMap) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) QmfQuery(org.apache.qpid.qmf2.common.QmfQuery)

Aggregations

ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 List (java.util.List)1 Map (java.util.Map)1 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)1 JMSException (javax.jms.JMSException)1 Handle (org.apache.qpid.qmf2.common.Handle)1 QmfEvent (org.apache.qpid.qmf2.common.QmfEvent)1 QmfQuery (org.apache.qpid.qmf2.common.QmfQuery)1 SchemaClassId (org.apache.qpid.qmf2.common.SchemaClassId)1