Search in sources :

Example 6 with SchemaClassId

use of org.apache.qpid.qmf2.common.SchemaClassId 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)

Example 7 with SchemaClassId

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

the class JSON method fromQmfData.

/**
     * Serialise a QmfData Object to JSON. If the Object is a QmfConsoleData we serialise the ObjectId as a String
     * which is the same encoding used for the various "ref" properies in fromObject().
     * @param data the QmfData that we wish to serialise to JSON.
     * @return the JSON String encoding.
     */
public static final String fromQmfData(final QmfData data) {
    String consoleDataInfo = "";
    if (data instanceof QmfConsoleData) {
        QmfConsoleData consoleData = (QmfConsoleData) data;
        SchemaClassId sid = consoleData.getSchemaClassId();
        long[] ts = consoleData.getTimestamps();
        String objectId = "\"_object_id\":\"" + consoleData.getObjectId().toString() + "\",";
        String schemaId = "\"_schema_id\":{" + "\"_package_name\":\"" + sid.getPackageName() + "\",\"_class_name\":\"" + sid.getClassName() + "\",\"_type\":\"" + sid.getType() + "\",\"_hash\":\"" + sid.getHashString() + "\"},";
        String timestamps = "\"_update_ts\":" + ts[0] + "," + "\"_create_ts\":" + ts[1] + "," + "\"_delete_ts\":" + ts[2] + ",";
        consoleDataInfo = objectId + schemaId + timestamps;
    }
    return "{" + consoleDataInfo + encodeMapContents(data.mapEncode()) + "}";
}
Also used : QmfConsoleData(org.apache.qpid.qmf2.console.QmfConsoleData) SchemaClassId(org.apache.qpid.qmf2.common.SchemaClassId)

Example 8 with SchemaClassId

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

the class QmfConsoleData method initialise.

/**
     * Sets the state of the QmfConsoleData, used as an assignment operator.
     * 
     * @param m the Map used to initialise the QmfConsoleData
     */
@SuppressWarnings("unchecked")
public void initialise(final Map m) {
    Map<String, Object> values = (Map<String, Object>) m.get("_values");
    _values = (values == null) ? m : values;
    Map<String, String> subtypes = (Map<String, String>) m.get("_subtypes");
    _subtypes = subtypes;
    setSchemaClassId(new SchemaClassId((Map) m.get("_schema_id")));
    setObjectId(new ObjectId((Map) m.get("_object_id")));
    long currentTime = System.currentTimeMillis() * 1000000l;
    _updateTimestamp = m.containsKey("_update_ts") ? getLong(m.get("_update_ts")) : currentTime;
    _createTimestamp = m.containsKey("_create_ts") ? getLong(m.get("_create_ts")) : currentTime;
    _deleteTimestamp = m.containsKey("_delete_ts") ? getLong(m.get("_delete_ts")) : currentTime;
}
Also used : ObjectId(org.apache.qpid.qmf2.common.ObjectId) Map(java.util.Map) HashMap(java.util.HashMap) SchemaClassId(org.apache.qpid.qmf2.common.SchemaClassId)

Example 9 with SchemaClassId

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

the class Agent method registerObjectClass.

/**
     * Register a schema for an object class with the Agent.
     * <p>
     * The Agent must have a registered schema for an object class before it can handle objects of that class.
     *
     * @param schema the SchemaObjectClass to be registered
     */
public final void registerObjectClass(final SchemaObjectClass schema) {
    SchemaClassId classId = schema.getClassId();
    _schemaCache.put(classId, schema);
}
Also used : SchemaClassId(org.apache.qpid.qmf2.common.SchemaClassId)

Example 10 with SchemaClassId

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

the class Agent method handleQueryRequest.

/**
     * Handle the query request and send the response back to the Console.
     * @param handle the reply handle that contains the replyTo Address.
     * @param query the inbound query from the Console.
     */
@SuppressWarnings("unchecked")
private final void handleQueryRequest(final Handle handle, final QmfQuery query) {
    QmfQueryTarget target = query.getTarget();
    if (target == QmfQueryTarget.SCHEMA_ID) {
        List<Map> results = new ArrayList<Map>(_schemaCache.size());
        // Look up all SchemaClassId objects
        for (SchemaClassId classId : _schemaCache.keySet()) {
            results.add(classId.mapEncode());
        }
        // Send the response back to the Console.
        queryResponse(handle, results, "_schema_id");
    } else if (target == QmfQueryTarget.SCHEMA) {
        List<Map> results = new ArrayList<Map>(1);
        // Look up a SchemaClass object by the SchemaClassId obtained from the query
        SchemaClassId classId = query.getSchemaClassId();
        SchemaClass schema = _schemaCache.get(classId);
        if (schema != null) {
            results.add(schema.mapEncode());
        }
        // Send the response back to the Console.
        queryResponse(handle, results, "_schema");
    } else if (target == QmfQueryTarget.OBJECT_ID) {
        List<Map> results = new ArrayList<Map>(_objectIndex.size());
        // Look up all ObjectId objects
        for (ObjectId objectId : _objectIndex.keySet()) {
            results.add(objectId.mapEncode());
        }
        // Send the response back to the Console.
        queryResponse(handle, results, "_object_id");
    } else if (target == QmfQueryTarget.OBJECT) {
        // If this is implementing the AgentExternal model we pass the QmfQuery on in a QueryWorkItem
        if (this instanceof AgentExternal) {
            _eventListener.onEvent(new QueryWorkItem(handle, query));
            return;
        } else {
            //qmfContentType = "_data";
            if (query.getObjectId() != null) {
                List<Map> results = new ArrayList<Map>(1);
                // Look up a QmfAgentData object by the ObjectId obtained from the query
                ObjectId objectId = query.getObjectId();
                QmfAgentData object = _objectIndex.get(objectId);
                if (object != null && !object.isDeleted()) {
                    results.add(object.mapEncode());
                }
                // Send the response back to the Console.
                queryResponse(handle, results, "_data");
            } else {
                // Look up QmfAgentData objects by the SchemaClassId obtained from the query
                // This is implemented by a linear search and allows searches with only the className specified.
                // Linear searches clearly don't scale brilliantly, but the number of QmfAgentData objects managed
                // by an Agent is generally fairly small, so it should be OK. Note that this is the same approach
                // taken by the C++ broker ManagementAgent, so if it's a problem here........
                // N.B. the results list declared here is a generic List of Objects. We *must* only pass a List of
                // Map to queryResponse(), but conversely if the response items are sortable we need to sort them
                // before doing mapEncode(). Unfortunately we don't know if the items are sortable a priori so
                // we either add a Map or we add a QmfAgentData, then sort then mapEncode() each item. I'm not
                // sure of a more elegant way to do this without creating two lists, which might not be so bad
                // but we don't know the size of the list a priori either.
                List results = new ArrayList(_objectIndex.size());
                // It's unlikely that evaluating this query will return a mixture of sortable and notSortable 
                // QmfAgentData objects, but it's best to check if that has occurred as accidentally passing a
                // List of QmfAgentData instead of a List of Map to queryResponse() will break things.
                boolean sortable = false;
                boolean notSortable = false;
                for (QmfAgentData object : _objectIndex.values()) {
                    if (!object.isDeleted() && query.evaluate(object)) {
                        if (object.isSortable()) {
                            // If QmfAgentData is marked sortable we add the QmfAgentData object to the List
                            // so we can sort first before mapEncoding.
                            results.add(object);
                            sortable = true;
                        } else {
                            // If QmfAgentData is not marked sortable we mapEncode immediately and add the Map to List.
                            results.add(object.mapEncode());
                            notSortable = true;
                        }
                    }
                }
                // results List to avoid sending unconvertable data. Hopefully this condition should never occur.
                if (sortable && notSortable) {
                    _log.info("Query resulted in inconsistent mixture of sortable and non-sortable data.");
                    results.clear();
                } else if (sortable) {
                    Collections.sort(results);
                    int length = results.size();
                    for (int i = 0; i < length; i++) {
                        QmfAgentData object = (QmfAgentData) results.get(i);
                        results.set(i, object.mapEncode());
                    }
                }
                // Send the response back to the Console.
                queryResponse(handle, results, "_data");
            }
        }
    } else {
        raiseException(handle, "Query for _what => '" + target + "' not supported");
        return;
    }
}
Also used : ObjectId(org.apache.qpid.qmf2.common.ObjectId) ArrayList(java.util.ArrayList) QmfQueryTarget(org.apache.qpid.qmf2.common.QmfQueryTarget) SchemaClassId(org.apache.qpid.qmf2.common.SchemaClassId) SchemaClass(org.apache.qpid.qmf2.common.SchemaClass) ArrayList(java.util.ArrayList) List(java.util.List) HashMap(java.util.HashMap) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap)

Aggregations

SchemaClassId (org.apache.qpid.qmf2.common.SchemaClassId)14 SchemaClass (org.apache.qpid.qmf2.common.SchemaClass)7 HashMap (java.util.HashMap)6 Map (java.util.Map)6 ArrayList (java.util.ArrayList)5 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)5 JMSException (javax.jms.JMSException)4 ObjectId (org.apache.qpid.qmf2.common.ObjectId)4 MapMessage (javax.jms.MapMessage)3 Message (javax.jms.Message)3 AMQPMessage (org.apache.qpid.qmf2.common.AMQPMessage)3 QmfException (org.apache.qpid.qmf2.common.QmfException)3 QmfQuery (org.apache.qpid.qmf2.common.QmfQuery)3 SchemaObjectClass (org.apache.qpid.qmf2.common.SchemaObjectClass)3 List (java.util.List)2 Destination (javax.jms.Destination)1 Handle (org.apache.qpid.qmf2.common.Handle)1 QmfEvent (org.apache.qpid.qmf2.common.QmfEvent)1 QmfQueryTarget (org.apache.qpid.qmf2.common.QmfQueryTarget)1 SchemaEventClass (org.apache.qpid.qmf2.common.SchemaEventClass)1