/* * * 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.qmf2.agentdata; // Misc Imports import java.util.Collections; import java.util.Map; // Simple Logging Facade 4 Java import org.slf4j.Logger; import org.slf4j.LoggerFactory; // QMF2 Imports import org.apache.qpid.qmf2.agent.QmfAgentData; import org.apache.qpid.qmf2.common.QmfEvent; import org.apache.qpid.qmf2.common.ObjectId; import org.apache.qpid.qmf2.common.SchemaEventClass; //import org.apache.qpid.qmf2.common.SchemaMethod; import org.apache.qpid.qmf2.common.SchemaObjectClass; //import org.apache.qpid.qmf2.common.SchemaProperty; import org.apache.qpid.server.model.LifetimePolicy; /** * This class provides a concrete implementation of QmfAgentData for the Exchange Management Object. * In general it's possible to use QmfAgentData without sub-classing as it's really a "bean" style class * that retains its properties in a Map, but in the case of the Java Broker Management Agent it's useful * to sub-class as we need to map between the properties/statistics as specified in the Java Broker * management model and those specified in qpid/spec/management-schema.xml which is what the C++ broker * uses. This class retains a reference to its peer org.apache.qpid.server.model.Exchange and does the * necessary mapping when its mapEncode() method is called (which is used to serialise the QmfAgentData). * * @author Fraser Adams */ public class Exchange extends QmfAgentData { private static final Logger _log = LoggerFactory.getLogger(Exchange.class); /** * This static initialiser block initialises the QMF2 Schema information needed by the Agent to find * QmfAgentData and QmfEvent Objects of a given type. */ private static final SchemaObjectClass _schema; private static final SchemaEventClass _exchangeDeclareSchema; private static final SchemaEventClass _exchangeDeleteSchema; /** * Returns the schema for the Exchange class. * @return the SchemaObjectClass for the Exchange class. */ public static SchemaObjectClass getSchema() { return _schema; } /** * Returns the schema for the Exchange Declare Event. * @return the SchemaEventClass for the Exchange Declare Event. */ public static SchemaEventClass getExchangeDeclareSchema() { return _exchangeDeclareSchema; } /** * Returns the schema for the Exchange Delete Event. * @return the SchemaEventClass for the Exchange Delete Event. */ public static SchemaEventClass getExchangeDeleteSchema() { return _exchangeDeleteSchema; } static { // Declare the schema for the QMF2 broker class. _schema = new SchemaObjectClass("org.apache.qpid.broker", "exchange"); // TODO //_schema.addProperty(new SchemaProperty("whatHappened", QmfType.TYPE_STRING)); // Declare the schema for the QMF2 exchangeDeclare Event class. _exchangeDeclareSchema = new SchemaEventClass("org.apache.qpid.broker", "exchangeDeclare"); // Declare the schema for the QMF2 exchangeDelete Event class. _exchangeDeleteSchema = new SchemaEventClass("org.apache.qpid.broker", "exchangeDelete"); } // End of static initialiser. private final org.apache.qpid.server.model.Exchange _exchange; private String _name; /** * Constructor. * @param vhost the parent VirtualHost ConfiguredObject from the broker model. * @param exchange the Exchange ConfiguredObject from the broker model. */ public Exchange(final org.apache.qpid.server.model.VirtualHost vhost, final org.apache.qpid.server.model.Exchange exchange) { super(getSchema()); _exchange = exchange; _name = _exchange.getName(); _name = (_name.equals("<>")) ? "" : _name; if (vhost == null) { // Note we include an empty vhost name in the compare key to make sure things get sorted properly. setCompareKey("vhost:/" + _name); } else { _name = "vhost:" + vhost.getName() + "/" + _name; setCompareKey(_name); } // In the Java Broker LifetimePolicy may be PERMANENT, DELETE_ON_CONNECTION_CLOSE, // DELETE_ON_SESSION_END, DELETE_ON_NO_OUTBOUND_LINKS, DELETE_ON_NO_LINKS, IN_USE // We map these to a boolean value to be consistent with the C++ Broker QMF value. // TODO The C++ and Java Brokers should really return consistent information. LifetimePolicy lifetimePolicy = _exchange.getLifetimePolicy(); boolean autoDelete = (lifetimePolicy != LifetimePolicy.PERMANENT) ? true : false; // TODO vhostRef - currently just use its name to try and get things working with standard command line tools. setValue("name", _name); setValue("type", _exchange.getType()); setValue("durable", _exchange.isDurable()); setValue("autoDelete", autoDelete); // TODO figure out mapping from Java Broker model to QMF exchange arguments. // Set to empty Map for now to be consistent with C++ broker. setValue("arguments", Collections.EMPTY_MAP); // ObjectId needs to be set here in Exchange because the QMF2 version of qpid-config uses a hardcoded // _object_name as below in the _object_id that it sets in the getExchange() call and in exchangeRef. // It *shouldn't* do this and should really use the _object_id of the exchange object returned by // getObjects("exchange"), but it does. The following line causes the Agent to use the explicit // ObjectId below rather than constructing its own, which fixes the qpid-config issue. setObjectId(new ObjectId("", "org.apache.qpid.broker:exchange:" + _name, 0)); } /** * Get the peer org.apache.qpid.server.model.Exchange instance. This is mainly used when creating an Alternate * Exchange on a Queue as the underlying method requires an org.apache.qpid.server.model.Exchange. */ public org.apache.qpid.server.model.Exchange getExchange() { return _exchange; } /** * Factory method to create an Exchange Declare Event Object with timestamp of now. * @return the newly created Exchange Declare Event Object. */ public QmfEvent createExchangeDeclareEvent() { QmfEvent exchangeDeclare = new QmfEvent(_exchangeDeclareSchema); exchangeDeclare.setSeverity("info"); exchangeDeclare.setValue("altEx", ""); // Java Broker can't set Alternate Exchange on Exchange exchangeDeclare.setValue("args", Collections.EMPTY_MAP); exchangeDeclare.setValue("autoDel", getBooleanValue("autoDelete")); exchangeDeclare.setValue("disp", "created"); exchangeDeclare.setValue("durable", getBooleanValue("durable")); exchangeDeclare.setValue("exName", _name); exchangeDeclare.setValue("exType", getStringValue("type")); // TODO Not sure of a way to get these for Java Broker Exchange. //exchangeDeclare.setValue("rhost", _connection.getName()); //exchangeDeclare.setValue("user", getStringValue("authIdentity")); return exchangeDeclare; } /** * Factory method to create an Exchange Delete Event Object with timestamp of now. * @return the newly created Exchange Delete Event Object. */ public QmfEvent createExchangeDeleteEvent() { QmfEvent exchangeDelete = new QmfEvent(_exchangeDeleteSchema); exchangeDelete.setSeverity("info"); exchangeDelete.setValue("exName", _name); // TODO Not sure of a way to get these for Java Broker Exchange. //exchangeDelete.setValue("rhost", _connection.getName()); //exchangeDelete.setValue("user", getStringValue("authIdentity")); return exchangeDelete; } /** * This method maps the org.apache.qpid.server.model.Exchange to QMF2 broker properties where possible then * serialises into the underlying Map for transmission via AMQP. This method is called by handleQueryRequest() * in the org.apache.qpid.qmf2.agent.Agent class implementing the main QMF2 Agent behaviour. * * @return the underlying map. */ @Override public Map mapEncode() { // Statistics long msgReceives = _exchange.getMessagesIn(); long msgDrops = _exchange.getMessagesDropped(); long msgRoutes = msgReceives - msgDrops; long byteReceives = _exchange.getBytesIn(); long byteDrops = _exchange.getBytesDropped(); long byteRoutes = byteReceives - byteDrops; setValue("producerCount", _exchange.getPublishers().size()); // We have to modify the value of bindingCount for Exchange because the QmfManagementAgent "hides" the // QMF Objects that relate to its own AMQP Connection/Queues/Bindings so the bindingCount for default direct // qmf.default.direct and qmf.default.topic is different to the actual number of QMF bindings. long bindingCount = _exchange.getBindingCount(); if (_name.equals("")) { bindingCount -= 3; } else if (_name.equals("qmf.default.direct")) { bindingCount -= 2; } else if (_name.equals("qmf.default.topic")) { bindingCount -= 1; } setValue("bindingCount", bindingCount); setValue("msgReceives", msgReceives); setValue("msgDrops", msgDrops); setValue("msgRoutes", msgRoutes); setValue("byteReceives", byteReceives); setValue("byteDrops", byteDrops); setValue("byteRoutes", byteRoutes); update(); // TODO only set update if a statistic has actually changed value. return super.mapEncode(); } }