The Story of the Pizza Party

For Powerpoint slides describing the application, see The Tutorial project documents page.

The Pizza Party Application shows 8 Cougaar agents split across two processes ("Nodes"), planning a pizza party.

This simple application shows Cougaar agents acting as social planners for 4 friends: Alice, Bob, Mark, and Tony. Alice is planning a pizza party. Her Cougaar Agent takes care of inviting all her friends on her buddy list "FriendsOfMark" (maybe it's a surprise party for Mark?). The Agents for Bob, Mark, and Tony take care of answering for them. Because it is a pizza party, they must tell Alice whether they like "Meat" or "Veggie" pizza.

Once Alice knows how much of what kinds of pizza to order, she must find a Pizza Provider. Pizza Providers sell "Meat" and/or "Veggie" pizzas -- and Alice wants to order all her pizza from one provider.

This sample includes 2 versions of the application, to show more Cougaar features. The first version ("non SD" - use "pizza/configs/pizzaparty/PizzaNode1.xml" and "PizzaNode2.xml") shows a static relationships between Alice and a Pizza Provider, "JoesLocalPizzaShack". In this example, the relationship between Alice is pre-configured, and Alice has no way to find any other providers. In our example, Joes only sells Meat pizza - so some of Alice's guests will not be happy, and her planning fails!

In the second version ("SD" - use "SDPizzaNode1.xml" and "SDPizzaNode2.xml"), Alice knows how to do "Service Discovery". She does look-ups in the Yellow Pages, where pizza parlors advertise their services. This is how she finds Joes originally, and this is how she can find a new provider, if Joes isn't good enough.

Exploring the Pizza Party Application

As you begin to explore the pizza party application, the first thing you may want to do is to look at the "society.xml" files - that is, the XML files that define the components of the Cougaar agents you are running. For the SD version, look at pizza/configs/pizzaparty/SDPizzaNode1.xml and SDPizzaNode2.xml. Here you will see Nodes have VM paramters specified with <vm_parameter/> tags(-D args, interpreted and used by the "cougaar" execution script), and can also have components (using <component> tags) (plugins). In particular, nodes have Agents (a special kind of components), like "Alice". Agents in turn have other components - plugins - like the PizzaPrototypePlugin. For details on the society.xml format, see the core module javadoc and the CDG.

The other data file you may want to look at is the Communities definition file, pizza/configs/pizzaparty/communities.xml. Each of these files is heavily commented. For further details on Communities, see the community module javadoc and the CDG.

At this point, you can start looking through the Javadoc and source code for the Pizza Party components. As with most Cougaar applications, the main actors are the Plugins in the Agents. A good place to start is the Javadoc for the org.cougaar.pizza.plugin package, which is captured below.

org.cougaar.pizza.plugin Package Javadoc

The org.cougaar.pizza.plugin.PizzaPrototypePlugin and org.cougaar.pizza.plugin.KitchenPrototypePlugins give Alice, Joes, and Dominoes access to Asset Prototypes. The KitchenPrototypePlugin also creates the single Kitchen Asset, with the correct PGs indicating whether that Pizza Provider serves meat and/or veggie pizzas.

The org.cougaar.pizza.plugin.InvitePlugin is used at Alice to send an invitation to all her friends on her buddy list, "FriendsOfMark" -- a Community (defined in pizza/configs/pizzaparty/communities.xml). Her invitation is an org.cougaar.pizza.relay.RSVPRelaySource that asks "Meat or Veggie". Each member of the Community receives the Relay, and responds using the org.cougaar.pizza.plugin.RSVPPlugin. They then use the org.cougaar.pizza.plugin.util.PizzaPreferenceHelper to look at the local self Entity, looking for the org.cougaar.pizza.Constants.Roles#CARNIVORE or org.cougaar.pizza.Constants.Roles#VEGETARIAN Roles, to decide what kind of pizza they eat. They then set that org.cougaar.pizza.relay.RSVPReply Response on the org.cougaar.pizza.relay.RSVPRelayTarget Relay, which the infrastructure forwards back to Alice. At Alice, the infrastructure collects all the RSVPs on a org.cougaar.pizza.plugin.PizzaPreferences object, and after waiting to give everyone a chance to responsd, the InvitePlugin, publishes the PizzaPreferences object summarizing what pizza Alice wants to order.

At this point, you might use the "/pizza" (org.cougaar.pizza.servlet.PizzaPreferenceServlet) servlet to see who responded and what kinds of pizza Alice needs to order. Keep watching this servlet to see Alice order her pizza, and whether it succeeds.

There are then 2 options. In the non ServiceDiscovery version (using society.xml files pizza/configs/pizzaparty/PizzaNode1.xml and PizzaNode2.xml), the org.cougaar.pizza.plugin.PlaceOrderPlugin at Alice acts next. In the ServiceDiscovery version (SDPizzaNode1.xml and SDPizzaNode2.xml), it is the org.cougaar.pizza.plugin.SDPlaceOrderPlugin, which is a simple extension of the PlaceOrderPlugin. The PlaceOrderPlugin sees the PizzaPreferences on its Subscription, and prepares to order the pizza. First it looks to see if it has a Relationship on the self Entity to any PizzaProviders. In the SD version it does not, and must now do ServiceDiscovery. In the non-SD version, it does. So it then creates an org.cougaar.pizza.Constants.Verbs#ORDER Task, ordering org.cougaar.pizza.Constants#PIZZA. It then expands that - one for meat pizza (with an appropriate number of servings depending on RSVPs) and one for veggie. It Allocates those child tasks to the pizza provider it found on its self Entity (Joes in our example).

In the SD version, the SDPlaceOrderPlugin kicks off ServiceDiscovery by publishing a org.cougaar.pizza.Constants.Verbs#FIND_PROVIDERS Task, with an IndirectObject indicating it wants a PizzaProvider. The org.cougaar.servicediscovery.plugin.SDClientPlugin subscribes to those Tasks, and then publishes an MMQueryRequest, including an MMRoleQuery that specifies it wants a PizzaProvider, and includes the service scoring function (org.cougaar.pizza.plugin.util.RoleWithBlacklistScorer) to use in weighing different possible providers.

The org.cougaar.pizza.plugin.MatchmakerPlugin picks up the MMQueryRequest, and issues an asynchronous query to the Yellow Pages, asking it to walk up the hierarchy of Yellow Pages Communities as necessary, to find providers matching the query (so it finds Cambridge first, and then MA, as necessary). On getting a callback with a provider, it publishChanges the MMQueryRequest.

The org.cougaar.pizza.plugin.SDClientPlugin picks up the answer to its request, and sends a ServiceContractRelay to the named provider Agent, asking for a Relationship. Our example uses the org.cougaar.servicediscovery.plugin.AgreeableProviderPlugin from the servicediscovery module, which will immediately say yes (a more complex plugin might for example check capacity). The infrastructure then establishes the needed Relationship.

Once the SDClientPlugin sees that it has a Contract for the Role it was looking for, it marks the FindProviders Task with a confident Success Disposition. The SDPlaceOrderPlugin sees the change to the Disposition, and uses that to grab the new PizzaProvider. Then it continues just like the PlaceOrderPlugin, issuing Order Tasks that it allocates to the provider.

OK, so now, in both SD and non-SD versions, the PlaceOrderPlugin has allocated Pizza Order tasks to the Pizza Provider. In both cases, this should be Joes. The infrastructure copies the Order tasks to Joes Blackboard (because they were Allocated to the Joes Entity).

At Joes, the org.cougaar.pizza.plugin.ProcessOrderPlugin sees the new Order Tasks. It matches the PGs on the Task's Indirect Object Pizza Asset indicating the kind of pizza needed, with the PGs on its local KitchenAsset, and responds with Success or Fail, depending on whether it makes the kind of pizza needed. Joes does not make Veggie pizza, so will Fail that particular Task.

The PlaceOrderPlugin propagates that result up to its root Order Task, and logs the results. In the non-SD world, this is the end of the line. Alice only knows about Joes, so can't make her Vegetarian guests happy. :-(

In the SD version of the application, the SDPlaceOrderPlugin sees the failure on the order, and decides to find a new provider. It publishes a new FindProviders task, specifying that the previous provider (Joes) should be excluded - since Joes cant satisfy the Order. From there, it continues as before. The SD Plugins look for the next provider that meets the (stricter) criteria. They walk up from the Cambridge YP Community and find Dominos in the MA community. The SDPlaceOrderPlugin issues all new Orders to Dominos, which can meet Alices needs.

The party is on!