/*
*
* 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.Agent;
import org.apache.qpid.qmf2.agent.QmfAgentData;
import org.apache.qpid.qmf2.common.QmfEvent;
import org.apache.qpid.qmf2.common.Handle;
import org.apache.qpid.qmf2.common.ObjectId;
import org.apache.qpid.qmf2.common.QmfData;
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;
import org.apache.qpid.server.model.Exchange;
import org.apache.qpid.server.model.Statistics;
/**
* This class provides a concrete implementation of QmfAgentData for the Queue 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.Queue and does the
* necessary mapping when its mapEncode() method is called (which is used to serialise the QmfAgentData).
*
* @author Fraser Adams
*/
public class Queue extends QmfAgentData
{
private static final Logger _log = LoggerFactory.getLogger(Queue.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 _queueDeclareSchema;
private static final SchemaEventClass _queueDeleteSchema;
/**
* Returns the schema for the Queue class.
* @return the SchemaObjectClass for the Queue class.
*/
public static SchemaObjectClass getSchema()
{
return _schema;
}
/**
* Returns the schema for the Queue Declare Event.
* @return the SchemaEventClass for the Queue Declare Event.
*/
public static SchemaEventClass getQueueDeclareSchema()
{
return _queueDeclareSchema;
}
/**
* Returns the schema for the Queue Delete Event.
* @return the SchemaEventClass for the Queue Delete Event.
*/
public static SchemaEventClass getQueueDeleteSchema()
{
return _queueDeleteSchema;
}
static
{
// Declare the schema for the QMF2 broker class.
_schema = new SchemaObjectClass("org.apache.qpid.broker", "queue");
// TODO
//_schema.addProperty(new SchemaProperty("whatHappened", QmfType.TYPE_STRING));
// Declare the schema for the QMF2 queueDeclare Event class.
_queueDeclareSchema = new SchemaEventClass("org.apache.qpid.broker", "queueDeclare");
// Declare the schema for the QMF2 queueDelete Event class.
_queueDeleteSchema = new SchemaEventClass("org.apache.qpid.broker", "queueDelete");
}
// End of static initialiser.
private final org.apache.qpid.server.model.Queue _queue;
private String _vhostName = "";
private ObjectId _alternateExchange = null;
private String _alternateExchangeName = "";
/**
* Constructor.
* @param vhost the parent VirtualHost ConfiguredObject from the broker model.
* @param queue the Queue ConfiguredObject from the broker model.
*/
public Queue(final org.apache.qpid.server.model.VirtualHost vhost,
final org.apache.qpid.server.model.Queue queue)
{
super(getSchema());
_queue = queue;
String name = _queue.getName();
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
{
_vhostName = "vhost:" + vhost.getName() + "/";
name = _vhostName + name;
setCompareKey(name);
}
LifetimePolicy lifetimePolicy = (LifetimePolicy)_queue.getAttribute("lifetimePolicy");
boolean autoDelete = (lifetimePolicy == LifetimePolicy.AUTO_DELETE) ? true : false;
// TODO vhostRef - currently just use its name to try and get things working with standard command line tools.
setValue("name", name);
setValue("durable", _queue.getAttribute("durable"));
setValue("autoDelete", autoDelete);
setValue("exclusive", _queue.getAttribute("exclusive"));
// altExchange needs to be set later, done in mapEncode() for convenience, because it isn't set during
// Queue construction in the Java Broker.
// TODO arguments properties.
// ObjectId needs to be set here in Queue because the QMF2 version of qpid-config uses a hardcoded
// _object_name as below in the _object_id that it sets in the getQueue() call and in queueRef.
// It *shouldn't* do this and should really use the _object_id of the queue object returned by
// getObjects("queue"), 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:queue:" + name, 0));
}
/**
* TODO
*
*/
public void invokeMethod(Agent agent, Handle handle, String methodName, QmfData inArgs)
{
/*if (methodName.equals("purge"))
{
//broker.create(inArgs);
}
else if (methodName.equals("reroute"))
{
//broker.create(inArgs);
}
else*/
{
agent.raiseException(handle, methodName + " not yet implemented on Queue.");
}
}
/**
* Factory method to create a Queue Declare Event Object with timestamp of now.
* @return the newly created Queue Declare Event Object.
*/
public QmfEvent createQueueDeclareEvent()
{
QmfEvent queueDeclare = new QmfEvent(_queueDeclareSchema);
queueDeclare.setSeverity("info");
// TODO the _alternateExchangeName gets set some time after the Constructor - how do I get its value for
// the queueDeclareEvent???!!!
queueDeclare.setValue("altEx", _alternateExchangeName);
queueDeclare.setValue("args", Collections.EMPTY_MAP); // TODO
queueDeclare.setValue("autoDel", getBooleanValue("autoDelete"));
queueDeclare.setValue("disp", "created");
queueDeclare.setValue("durable", getBooleanValue("durable"));
queueDeclare.setValue("excl", getBooleanValue("durable"));
queueDeclare.setValue("qName", getStringValue("name"));
// TODO Not sure of a way to get these for Java Broker Exchange.
//queueDeclare.setValue("rhost", _connection.getName());
//queueDeclare.setValue("user", getStringValue("authIdentity"));
return queueDeclare;
}
/**
* Factory method to create a Queue Delete Event Object with timestamp of now.
* @return the newly created Queue Delete Event Object.
*/
public QmfEvent createQueueDeleteEvent()
{
QmfEvent queueDelete = new QmfEvent(_queueDeleteSchema);
queueDelete.setSeverity("info");
queueDelete.setValue("qName", getStringValue("name"));
// TODO Not sure of a way to get these for Java Broker Exchange.
//queueDelete.setValue("rhost", _connection.getName());
//queueDelete.setValue("user", getStringValue("authIdentity"));
return queueDelete;
}
/**
* This method maps the org.apache.qpid.server.model.Queue 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<String, Object> mapEncode()
{
// Set the altExchange reference if an alternateExchange exists and hasn't already been set.
// Not sure how to set this closer to the Constructor. At the moment the _alternateExchangeName gets set
// too late to populate the "altEx" property of the queueDeclareEvent.
if (_alternateExchange == null)
{
Exchange altEx = (Exchange)_queue.getAttribute("alternateExchange");
if (altEx != null)
{
_alternateExchangeName = _vhostName + altEx.getName();
_alternateExchange = new ObjectId("", "org.apache.qpid.broker:exchange:" + _alternateExchangeName, 0);
setRefValue("altExchange", _alternateExchange);
}
}
// Statistics
Statistics stats = _queue.getStatistics();
setValue("msgTotalEnqueues", stats.getStatistic("totalEnqueuedMessages"));
setValue("msgTotalDequeues", stats.getStatistic("totalDequeuedMessages"));
// msgTxnEnqueues not implemented in Qpid 0.20
// msgTxnDequeues not implemented in Qpid 0.20
setValue("msgPersistEnqueues", stats.getStatistic("persistentEnqueuedMessages"));
setValue("msgPersistDequeues", stats.getStatistic("persistentDequeuedMessages"));
setValue("msgDepth", stats.getStatistic("queueDepthMessages"));
setValue("byteDepth", stats.getStatistic("queueDepthBytes"));
setValue("byteTotalEnqueues", stats.getStatistic("totalEnqueuedBytes"));
setValue("byteTotalDequeues", stats.getStatistic("totalDequeuedBytes"));
// byteTxnEnqueues not implemented in Qpid 0.20
// byteTxnDequeues not implemented in Qpid 0.20
setValue("bytePersistEnqueues", stats.getStatistic("persistentEnqueuedBytes"));
setValue("bytePersistDequeues", stats.getStatistic("persistentDequeuedBytes"));
// Flow-to-disk Statistics not implemented in Qpid 0.20
// releases & acquires not implemented in Qpid 0.20
// discardsTtl (discardsTtlMessages) not implemented in Qpid 0.20
// discardsRing not implemented in Qpid 0.20
// discardsLvq not implemented in Qpid 0.20
// discardsOverflow not implemented in Qpid 0.20
// discardsSubscriber not implemented in Qpid 0.20
// discardsPurge not implemented in Qpid 0.20
// reroutes not implemented in Qpid 0.20
setValue("consumerCount", stats.getStatistic("consumerCount"));
setValue("bindingCount", stats.getStatistic("bindingCount"));
setValue("unackedMessages", stats.getStatistic("unacknowledgedMessages"));
setValue("messageLatency", "Not yet implemented");
// flowStopped not implemented in Qpid 0.20
// flowStoppedCount not implemented in Qpid 0.20
update(); // TODO only update if statistics have actually changed.
return super.mapEncode();
}
}