use of org.apache.qpid.qmf2.console.Agent in project qpid by apache.
the class Console method invokeMethod.
/**
* Invoke the named method on the named Agent.
* <p>
* Intended to by called by the AgentProxy. Shouldn't generally be called directly by Console applications.
*
* @param agent the Agent to invoke the method on.
* @param content an unordered set of key/value pairs comprising the method arguments.
* @param replyHandle the correlation handle used to tie asynchronous method requests with responses
* @param timeout the time to wait for a reply from the Agent, a value of -1 means use the default timeout
* @return the method response Arguments in Map form
*/
public MethodResult invokeMethod(final Agent agent, final Map<String, Object> content, final String replyHandle, int timeout) throws QmfException {
if (!agent.isActive()) {
throw new QmfException("Called invokeMethod() with inactive agent");
}
String agentName = agent.getName();
timeout = (timeout < 1) ? _replyTimeout : timeout;
try {
Destination destination = (replyHandle == null) ? _replyAddress : _asyncReplyAddress;
MapMessage request = _syncSession.createMapMessage();
request.setJMSReplyTo(destination);
request.setJMSCorrelationID(replyHandle);
request.setStringProperty("x-amqp-0-10.app-id", "qmf2");
request.setStringProperty("method", "request");
request.setStringProperty("qmf.opcode", "_method_request");
request.setStringProperty("qpid.subject", agentName);
for (Map.Entry<String, Object> entry : content.entrySet()) {
request.setObject(entry.getKey(), entry.getValue());
}
// it would be somewhat unfortunate if their response got interleaved with ours!!
synchronized (this) {
_requester.send(request);
if (replyHandle == null) {
// If this is a synchronous request get the response
Message response = _responder.receive(timeout * 1000);
if (response == null) {
_log.info("No response received in invokeMethod()");
throw new QmfException("No response received for Console.invokeMethod()");
}
MethodResult result = new MethodResult(AMQPMessage.getMap(response));
QmfException exception = result.getQmfException();
if (exception != null) {
throw exception;
}
return result;
}
}
// If this is an asynchronous request return without waiting for a response
return null;
} catch (JMSException jmse) {
_log.info("JMSException {} caught in invokeMethod()", jmse.getMessage());
throw new QmfException(jmse.getMessage());
}
}
use of org.apache.qpid.qmf2.console.Agent 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.console.Agent in project qpid by apache.
the class Console method addConnection.
/**
* Connect the console to the AMQP cloud.
* <p>
* This is an extension to the standard QMF2 API allowing the user to specify address options in order to allow
* finer control over the Console's request and reply queues, e.g. explicit name, non-default size or durability.
*
* @param conn a javax.jms.Connection
* @param addressOptions options String giving finer grained control of the receiver queue.
* <p>
* As an example the following gives the Console's queues the name test-console, size = 500000000 and ring policy.
* <pre>
* " ; {link: {name:'test-console', x-declare: {arguments: {'qpid.policy_type': ring, 'qpid.max_size': 500000000}}}}"
* </pre>
* Note that the Console uses several queues so this will actually create a test-console queue plus a
* test-console-async queue and a test-console-event queue.
* <p>
* If a name parameter is not present temporary queues will be created, but the other options will still be applied.
*/
public void addConnection(final Connection conn, final String addressOptions) throws QmfException {
// to the same Console instance at the same time.
synchronized (this) {
if (_connection != null) {
throw new QmfException("Multiple connections per Console is not supported");
}
_connection = conn;
}
try {
String syncReplyAddressOptions = addressOptions;
String asyncReplyAddressOptions = addressOptions;
String eventAddressOptions = addressOptions;
if (!addressOptions.equals("")) {
// If there are address options supplied we need to check if a name parameter is present.
String[] split = addressOptions.split("name");
if (split.length == 2) {
// If options contains a name parameter we extract it and create variants for async and event queues.
// Look for the end of the key/value block
split = split[1].split("[,}]");
// Remove initial colon, space any any quotes.
String nameValue = split[0].replaceAll("[ :'\"]", "");
// Hopefully at this point nameValue is actually the value of the name parameter.
asyncReplyAddressOptions = asyncReplyAddressOptions.replace(nameValue, nameValue + "-async");
eventAddressOptions = eventAddressOptions.replace(nameValue, nameValue + "-event");
}
}
String topicBase = "qmf." + _domain + ".topic";
_syncSession = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// Create a MessageProducer for the QMF topic address used to broadcast requests
Destination topicAddress = _syncSession.createQueue(topicBase);
_broadcaster = _syncSession.createProducer(topicAddress);
// Data Indications, QMF Events, Heartbeats etc. from the broker (or other Agents).
if (!_disableEvents) {
// TODO it should be possible to bind _eventConsumer and _asyncResponder to the same queue
// if I can figure out the correct AddressString to use, probably not a big deal though.
_asyncSession = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// Set up MessageListener on the Event Address
Destination eventAddress = _asyncSession.createQueue(topicBase + "/agent.ind.#" + eventAddressOptions);
_eventConsumer = _asyncSession.createConsumer(eventAddress);
_eventConsumer.setMessageListener(this);
// Create the asynchronous JMSReplyTo _replyAddress and MessageConsumer
_asyncReplyAddress = _asyncSession.createQueue(_address + ".async" + asyncReplyAddressOptions);
_asyncResponder = _asyncSession.createConsumer(_asyncReplyAddress);
_asyncResponder.setMessageListener(this);
}
// so makes sense if only to get that warm and fuzzy feeling of keeping findbugs happy :-)
synchronized (this) {
// Create a MessageProducer for the QMF direct address, mainly used for request/response
Destination directAddress = _syncSession.createQueue("qmf." + _domain + ".direct");
_requester = _syncSession.createProducer(directAddress);
// Create the JMSReplyTo _replyAddress and MessageConsumer
_replyAddress = _syncSession.createQueue(_address + syncReplyAddressOptions);
_responder = _syncSession.createConsumer(_replyAddress);
_connection.start();
// we've any received *real* Agent updates or not.
if (_disableEvents) {
_brokerAgentName = "broker";
Map<String, String> map = new HashMap<String, String>();
map.put("_name", _brokerAgentName);
Agent agent = new Agent(map, this);
_agents.put(_brokerAgentName, agent);
_agentAvailable = true;
} else {
// If Asynchronous Behaviour is enabled Broadcast an Agent Locate message to get Agent info quickly.
broadcastAgentLocate();
}
// Wait until the Broker Agent has been located (this should generally be pretty quick)
while (!_agentAvailable) {
long startTime = System.currentTimeMillis();
try {
wait(_replyTimeout * 1000);
} catch (InterruptedException ie) {
continue;
}
// Measure elapsed time to test against spurious wakeups and ensure we really have timed out
long elapsedTime = (System.currentTimeMillis() - startTime) / 1000;
if (!_agentAvailable && elapsedTime >= _replyTimeout) {
_log.info("Broker Agent not found");
throw new QmfException("Broker Agent not found");
}
}
// Timer used for tidying up Subscriptions.
_timer = new Timer(true);
}
} catch (JMSException jmse) {
// If we can't create the QMF Destinations there's not much else we can do
_log.info("JMSException {} caught in addConnection()", jmse.getMessage());
throw new QmfException("Failed to create sessions or destinations " + jmse.getMessage());
}
}
use of org.apache.qpid.qmf2.console.Agent in project qpid by apache.
the class Agent method raiseEvent.
/**
* Cause the agent to raise the given event.
*
* @param event the QmfEvent to be raised
*/
public final void raiseEvent(final QmfEvent event) {
try {
String packageKey = event.getSchemaClassId().getPackageName().replace(".", "_");
String nameKey = event.getSchemaClassId().getClassName().replace(".", "_");
String severity = event.getSeverity();
String vendorKey = _vendor.replace(".", "_");
String productKey = _product.replace(".", "_");
String instanceKey = _instance.replace(".", "_");
String subject = "agent.ind.event." + packageKey + "." + nameKey + "." + severity + "." + vendorKey + "." + productKey + "." + instanceKey;
Message response = AMQPMessage.createListMessage(_syncSession);
response.setStringProperty("x-amqp-0-10.app-id", "qmf2");
response.setStringProperty("method", "indication");
response.setStringProperty("qmf.opcode", "_data_indication");
response.setStringProperty("qmf.content", "_event");
response.setStringProperty("qmf.agent", _name);
response.setStringProperty("qpid.subject", subject);
List<Map> results = new ArrayList<Map>();
results.add(event.mapEncode());
AMQPMessage.setList(response, results);
_producer.send(_topicAddress, response);
} catch (JMSException jmse) {
_log.info("JMSException {} caught in raiseEvent()", jmse.getMessage());
}
}
use of org.apache.qpid.qmf2.console.Agent 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);
}
Aggregations