use of org.apache.qpid.qmf2.common.QmfQuery in project qpid by apache.
the class Console method createSubscription.
/**
* Creates a subscription to the agent using the given Query.
* <p>
* The consoleHandle is an application-provided handle that will accompany each subscription update sent from
* the Agent. Subscription updates will appear as SUBSCRIPTION_INDICATION WorkItems on the Console's work queue.
* <p>
* The publishInterval is the requested time interval in seconds on which the Agent should publish updates.
* <p>
* The lifetime parameter is the requested time interval in seconds for which this subscription should remain in
* effect. Both the requested lifetime and publishInterval may be overridden by the Agent, as indicated in the
* subscription response.
* <p>
* This method may be called asynchronously by providing a replyHandle argument. When called
* asynchronously, the result of this method call is returned in a SUBSCRIBE_RESPONSE WorkItem with a
* handle matching the value of replyHandle.
* <p>
* Timeout can be used to override the console's default reply timeout.
* <p>
* When called synchronously, this method returns a SubscribeParams object containing the result of the
* subscription request.
*
* @param agent the Agent on which to create the subscription.
* @param query the Query to perform on the Agent
* @param consoleHandle an application-provided handle that will accompany each subscription update sent
* from the Agent.
* @param options a String representation of a Map containing the options in the form
* <pre>"{lifetime:<value>, publishInterval:<value>, replyHandle:<value>, timeout:<value>}"</pre>
* they are optional and may appear in any order.
* <pre>
* <b>lifetime</b> the requested time interval in seconds for which this subscription should remain in effect.
* <b>publishInterval</b> the requested time interval in seconds on which the Agent should publish updates
* <b>replyHandle</b> the correlation handle used to tie asynchronous method requests with responses.
* <b>timeout</b> the time to wait for a reply from the Agent.
* </pre>
*/
public synchronized SubscribeParams createSubscription(final Agent agent, final QmfQuery query, final String consoleHandle, final String options) throws QmfException {
if (consoleHandle == null) {
throw new QmfException("Called createSubscription() with null consoleHandle");
}
if (_subscriptionByHandle.get(consoleHandle) != null) {
throw new QmfException("Called createSubscription() with a consoleHandle that is already in use");
}
if (agent == null) {
throw new QmfException("Called createSubscription() with null agent");
}
if (!agent.isActive()) {
throw new QmfException("Called createSubscription() with inactive agent");
}
String agentName = agent.getName();
// Initialise optional values to defaults;
long lifetime = _subscriptionDuration;
long publishInterval = 10000;
long timeout = _replyTimeout;
String replyHandle = null;
if (options != null) {
// We wrap the Map in a QmfData object to avoid potential class cast issues with the parsed options
QmfData optMap = new QmfData(new AddressParser(options).map());
if (optMap.hasValue("lifetime")) {
lifetime = optMap.getLongValue("lifetime");
}
if (optMap.hasValue("publishInterval")) {
// Multiply publishInterval by 1000 because the QMF2 protocol spec says interval is
// "The request time (in milliseconds) between periodic updates of data in this subscription"
publishInterval = 1000 * optMap.getLongValue("publishInterval");
}
if (optMap.hasValue("timeout")) {
timeout = optMap.getLongValue("timeout");
}
if (optMap.hasValue("replyHandle")) {
replyHandle = optMap.getStringValue("replyHandle");
}
}
try {
MapMessage request = _syncSession.createMapMessage();
// Deliberately forcing all replies to the _asyncReplyAddress
request.setJMSReplyTo(_asyncReplyAddress);
// Deliberately using consoleHandle not replyHandle here
request.setJMSCorrelationID(consoleHandle);
request.setStringProperty("x-amqp-0-10.app-id", "qmf2");
request.setStringProperty("method", "request");
request.setStringProperty("qmf.opcode", "_subscribe_request");
request.setStringProperty("qpid.subject", agentName);
request.setObject("_query", query.mapEncode());
request.setObject("_interval", publishInterval);
request.setObject("_duration", lifetime);
SubscriptionManager subscription = new SubscriptionManager(agent, query, consoleHandle, replyHandle, publishInterval, lifetime);
_subscriptionByHandle.put(consoleHandle, subscription);
_timer.schedule(subscription, 0, publishInterval);
if (_subscriptionEmulationEnabled && agentName.equals(_brokerAgentName)) {
// If the Agent is the broker Agent we emulate the Subscription on the Console
String subscriptionId = UUID.randomUUID().toString();
_subscriptionById.put(subscriptionId, subscription);
subscription.setSubscriptionId(subscriptionId);
final SubscribeParams params = new SubscribeParams(consoleHandle, subscription.mapEncode());
if (replyHandle == null) {
return params;
} else {
final String handle = replyHandle;
Thread thread = new Thread() {
public void run() {
_eventListener.onEvent(new SubscribeResponseWorkItem(new Handle(handle), params));
}
};
thread.start();
}
return null;
}
_requester.send(request);
if (replyHandle == null) {
// If this is an synchronous request get the response
subscription.await(timeout * 1000);
if (subscription.getSubscriptionId() == null) {
_log.info("No response received in createSubscription()");
throw new QmfException("No response received for Console.createSubscription()");
}
return new SubscribeParams(consoleHandle, subscription.mapEncode());
}
// If this is an asynchronous request return without waiting for a response
return null;
} catch (JMSException jmse) {
_log.info("JMSException {} caught in createSubscription()", jmse.getMessage());
throw new QmfException(jmse.getMessage());
}
}
use of org.apache.qpid.qmf2.common.QmfQuery 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;
}
}
use of org.apache.qpid.qmf2.common.QmfQuery in project qpid by apache.
the class Agent method addObject.
/**
* Passes a reference to an instance of a managed QMF object to the Agent.
* <p>
* The object's name must uniquely identify this object among all objects known to this Agent.
* <p>
* This method creates an ObjectId for the QmfAgentData being added, it does this by first checking
* the schema.
* <p>
* If an associated schema exists we look for the set of property names that have been
* specified as idNames. If idNames exists we look for their values within the object and use that
* to create the objectName. If we can't create a sensible name we use a randomUUID.
* @param object the QmfAgentData object to be added
*/
public void addObject(final QmfAgentData object) throws QmfException {
// There are some cases where a QmfAgentData Object might have already set its ObjectId, for example where
// it may need to have a "well known" ObjectId. This is the case with the Java Broker Management Agent
// where tools such as qpid-config might have made assumptions about its ObjectId rather than doing "discovery".
ObjectId addr = object.getObjectId();
if (addr == null) {
SchemaClassId classId = object.getSchemaClassId();
SchemaClass schema = _schemaCache.get(classId);
// Try to create an objectName using the property names that have been specified as idNames in the schema
StringBuilder buf = new StringBuilder();
// Initialise idNames as an empty array as we want to check if a key has been used to construct the name.
String[] idNames = {};
if (schema != null && schema instanceof SchemaObjectClass) {
idNames = ((SchemaObjectClass) schema).getIdNames();
for (String property : idNames) {
buf.append(object.getStringValue(property));
}
}
String objectName = buf.toString();
// exchange has name == "")
if (objectName.length() == 0 && idNames.length == 0)
objectName = UUID.randomUUID().toString();
// Finish up the name by incorporating package and class names
objectName = classId.getPackageName() + ":" + classId.getClassName() + ":" + objectName;
// Now we've got a good name for the object we create its ObjectId and add that to the object
addr = new ObjectId(_name, objectName, _epoch);
object.setObjectId(addr);
}
QmfAgentData foundObject = _objectIndex.get(addr);
if (foundObject != null) {
// If a duplicate object has actually been Deleted we can reuse the address.
if (!foundObject.isDeleted()) {
throw new QmfException("Duplicate QmfAgentData Address");
}
}
_objectIndex.put(addr, object);
// Does the new object match any Subscriptions? If so add a reference to the matching Subscription and publish.
for (Subscription subscription : _subscriptions.values()) {
QmfQuery query = subscription.getQuery();
if (query.getObjectId() != null) {
if (query.getObjectId().equals(addr)) {
object.addSubscription(subscription.getSubscriptionId(), subscription);
object.publish();
}
} else if (query.evaluate(object)) {
object.addSubscription(subscription.getSubscriptionId(), subscription);
object.publish();
}
}
}
use of org.apache.qpid.qmf2.common.QmfQuery in project qpid by apache.
the class AgentExternalTest method addObject.
public void addObject(QmfAgentData object) throws QmfException {
ObjectId addr = _agent.allocObjectId(UUID.randomUUID().toString());
object.setObjectId(addr);
_objectIndex.put(addr, object);
// Does the new object match any Subscriptions? If so add a reference to the matching Subscription and publish.
for (Subscription subscription : _subscriptions.values()) {
QmfQuery query = subscription.getQuery();
if (query.getObjectId() != null) {
if (query.getObjectId().equals(addr)) {
object.addSubscription(subscription.getSubscriptionId(), subscription);
object.publish();
}
} else if (query.evaluate(object)) {
object.addSubscription(subscription.getSubscriptionId(), subscription);
object.publish();
}
}
}
use of org.apache.qpid.qmf2.common.QmfQuery in project qpid by apache.
the class AgentExternalTest method evaluateQuery.
/**
* This method evaluates a QmfQuery over the Agent's data on behalf of a Subscription
*
* @param query the QmfQuery that the Subscription wants to be evaluated over the Agent's data
* @return a List of QmfAgentData objects that match the specified QmfQuery
*/
public List<QmfAgentData> evaluateQuery(QmfQuery query) {
List<QmfAgentData> results = new ArrayList<QmfAgentData>(_objectIndex.size());
if (query.getTarget() == QmfQueryTarget.OBJECT) {
if (query.getObjectId() != null) {
// 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);
}
} else {
// Look up QmfAgentData objects evaluating the query
for (QmfAgentData object : _objectIndex.values()) {
if (!object.isDeleted() && query.evaluate(object)) {
results.add(object);
}
}
}
}
return results;
}
Aggregations