/* * * * Copyright 1997-2006 BBNT Solutions, LLC * under sponsorship of the Defense Advanced Research Projects * Agency (DARPA). * * You can redistribute this software and/or modify it under the * terms of the Cougaar Open Source License as published on the * Cougaar Open Source Website (www.cougaar.org). * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * */ package org.cougaar.demo.ping; import org.cougaar.core.blackboard.IncrementalSubscription; import org.cougaar.core.mts.MessageAddress; import org.cougaar.core.plugin.TodoPlugin; import org.cougaar.core.relay.SimpleRelay; import org.cougaar.core.relay.SimpleRelaySource; import org.cougaar.util.Arguments; import org.cougaar.util.annotations.Cougaar; import org.cougaar.util.annotations.Subscribe; /** * This plugin is an example ping source that sends relays to a remote agent. *

* There can be multiple copies of this plugin in a single agent, but every * {@link PingSender} must have a unique target. The target is specified as a * plugin parameter: *

*
target=String
*
Required remote agent name. If the agent doesn't exist then we wait * forever -- there's no alarm-based timeout in this plugin implementation.
*

* *
delayMillis=long
*
Delay milliseconds between relay iterations. Set the delay to zero to * run the pings as fast as possible.
*

* *

verbose=boolean
*
Output SHOUT-level logging messages. This can also be disabled by * modifying the Cougaar logging configuration to set: *
 *         log4j.category.org.cougaar.demo.ping.PingSender=FATAL
 *         log4j.category.org.cougaar.demo.ping.PingReceiver=FATAL
 * 
* * For simplicity we support this as a plugin parameter, so new users don't need * to configure the logging service. If enabled, also consider turning off "+/-" * message send/receive logging by setting: *
 *         -Dorg.cougaar.core.agent.quiet=true
 * 
* *
*

*

* * @property org.cougaar.demo.ping.PingSender.delayMillis=5000 * PingSender delay between ping iterations, if not set as a plugin parameter. * * @property org.cougaar.demo.ping.PingSender.verbose=true * PingSender should output SHOUT-level logging messages, if not set as a * plugin parameter. * * @see PingReceiver Required plugin for every agent that will receive ping * relays. * * @see PingServlet Optional browser-based GUI. */ public class PingSender extends TodoPlugin { @Cougaar.Arg(name="target", required=true) public MessageAddress target; @Cougaar.Arg(name="delayMillis", defaultValue="5000") public long delayMillis; @Cougaar.Arg(name="verbose", defaultValue="true") public boolean verbose; public void setArguments(Arguments args) { super.setArguments(args); if (target.equals(agentId)) { throw new IllegalArgumentException("Target matches self: " + target); } } protected void setupSubscriptions() { super.setupSubscriptions(); // Get our initial counter value, which is zero unless we're restarting // from an agent move or persistence snapshot int counter = getInitialCounter(); // Send our first relay to our target sendNow(null, new Integer(counter)); // When our target publishes a response, our "execute()" method will // be called. } /** Create our "isMyRelay" subscription and handle CHANGE callbacks */ @Cougaar.Execute(on=Subscribe.ModType.CHANGE, when="isRelayForAgent") public void executeRelay(SimpleRelay relay) { // Print the target's response if (verbose && log.isShoutEnabled()) { log.shout("Received response " + relay.getReply() + " from " + target); } // Figure out our next content value // // For scalability testing we could make this a large byte array. int oldContent = (Integer) relay.getQuery(); Integer newContent = new Integer(++oldContent); if (delayMillis > 0) { sendLater(relay, newContent); } else { sendNow(relay, newContent); } } public boolean isRelayForAgent(SimpleRelay relay) { return agentId.equals(relay.getSource()) && target.equals(relay.getTarget()); } /** Get our initial ping iteration counter value */ private int getInitialCounter() { // Check to see if we've already sent a ping, in case we're restarting // from an agent move or persistence snapshot. int ret = 0; if (blackboard.didRehydrate()) { // Get the counter from our sent ping, if any, then remove it IncrementalSubscription sub = getSubscription("isRelayForAgent"); for (Object o: sub) { SimpleRelay relay = (SimpleRelay) o; ret = ((Integer) relay.getQuery()).intValue(); blackboard.publishRemove(relay); } if (verbose && log.isShoutEnabled()) { log.shout("Resuming pings to " + target + " at counter " + ret); } } return ret; } /** Send our next relay iteration now */ private void sendNow(SimpleRelay priorRelay, Object content) { if (priorRelay != null) { // Remove query both locally and at the remote target, to cleanup // the blackboard. blackboard.publishRemove(priorRelay); } // Send a new relay to the target SimpleRelay relay = new SimpleRelaySource(uids.nextUID(), agentId, target, content); if (verbose && log.isShoutEnabled()) { log.shout("Sending ping " + content + " to " + target); } blackboard.publishAdd(relay); } /** Send our next relay in delayMillis */ private void sendLater(final SimpleRelay priorRelay, final Object newContent) { // Run sendNow later, still in the blackboard execution context. if (verbose && log.isShoutEnabled()) { log.shout("Will send ping " + newContent + " to " + target + " in " + delayMillis / 1000 + " seconds"); } executeLater(delayMillis, new Runnable() { public void run() { sendNow(priorRelay, newContent); } }); } }