1. 程式人生 > >基於JADE的一個多 Agent 應用系統(“圖書交易”系統)

基於JADE的一個多 Agent 應用系統(“圖書交易”系統)

和處理賣方 Agent訊息佇列中來至買方的攜帶購買請求資訊(通訊原語為ACCEPT_PROPOSAL)的訊息。該行為在收到該訊息後,從本地圖書雜湊表中查詢是否有購買請求訊息中指定的圖書,若有則刪除該圖書,回覆買方agent一條通訊原語為INFORM的購買成功確認訊息,並終止該書對應的價格管理行為PriceManager;若沒有則回覆買方agent一條通訊原語為FAILURE的購買失敗訊息。 

附原始碼:

BookBuyerAgent.java

package com.leejay.booktrading.buyer;

import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.Behaviour;
import jade.core.behaviours.TickerBehaviour;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;

import java.util.Date;
import java.util.Vector;

public class BookBuyerAgent extends Agent {
	// The list of known seller agents
	private Vector sellerAgents = new Vector();

	// The GUI to interact with the user
	private BookBuyerGui myGui;

	/**
	 * Agent initializations
	 **/
	protected void setup() {
		// Printout a welcome message
		System.out.println("Buyer-agent " + getAID().getName() + " is ready.");

		// Get names of seller agents as arguments
		/*
		 * Object[] args = getArguments(); if (args != null && args.length > 0)
		 * { for (int i = 0; i < args.length; ++i) { AID seller = new
		 * AID((String) args[i], AID.ISLOCALNAME);
		 * sellerAgents.addElement(seller); } }
		 */

		// Show the GUI to interact with the user
		myGui = new BookBuyerGuiImpl();
		myGui.setAgent(this);
		myGui.show();

		/**
		 * This piece of code, to search services with the DF, is explained in
		 * the book in section 4.4.3
		 **/
		// Update the list of seller agents every 6s
		addBehaviour(new SearchSeller(this, 6000));
	}

	/**
	 * Agent clean-up
	 **/
	protected void takeDown() {
		// Dispose the GUI if it is there
		if (myGui != null) {
			myGui.dispose();
		}

		// Printout a dismissal message
		System.out.println("Buyer-agent " + getAID().getName() + "terminated.");
	}

	/**
	 * This method is called by the GUI when the user inserts a new book to buy
	 * 
	 * @param title
	 *            The title of the book to buy
	 * @param maxPrice
	 *            The maximum acceptable price to buy the book
	 * @param deadline
	 *            The deadline by which to buy the book
	 **/
	public void purchase(String title, int maxPrice, Date deadline) {
		// the following line is in the book at page 62
		addBehaviour(new PurchaseManager(this, title, maxPrice, deadline));
	}

	/**
	 * This method is called by the GUI. At the moment it is not implemented.
	 **/
	/*
	 * public void setCreditCard(String creditCarNumber) { }
	 */
	/**
	 * Inner class SearchSeller. This is the behaviour used by Book-buyer agents
	 * to Update the list of seller agents every 6s
	 * 
	 */
	private class SearchSeller extends TickerBehaviour {

		public SearchSeller(Agent a, long time) {
			super(a, time);
		}

		@Override
		protected void onTick() {
			DFAgentDescription template = new DFAgentDescription();
			ServiceDescription templateSd = new ServiceDescription();
			templateSd.setType("book-trade");
			template.addServices(templateSd);
			try {
				DFAgentDescription[] result = DFService.search(getAgent(),
						template);
				//update sellerAgents
				sellerAgents.clear();
				for (int i = 0; i < result.length; i++) {
					sellerAgents.add(result[i].getName());
				}
			} catch (FIPAException fe) {
				fe.printStackTrace();
			}
		}

	}

	/**
	 * Section 4.2.4, Page 62
	 **/
	private class PurchaseManager extends TickerBehaviour {
		private String title;
		private int maxPrice, startPrice =0;
		private long deadline, initTime, deltaT;

		private PurchaseManager(Agent a, String t, int mp, Date d) {
			super(a, 6000); // tick every minute
			title = t;
			maxPrice = mp;
			deadline = d.getTime();
			initTime = System.currentTimeMillis();
			deltaT = deadline - initTime;
		}

		public void onTick() {
			long currentTime = System.currentTimeMillis();
			if (currentTime > deadline) {
				// Deadline expired
				myGui.notifyUser("Cannot buy book " + title);
				stop();
			} else {
				// Compute the currently acceptable price and start a
				// negotiation
				long elapsedTime = currentTime - initTime;
				int acceptablePrice = (int) Math.round(1.0 * maxPrice
						* (1.0 * elapsedTime / deltaT));
				// System.out.println("elapsedTime"+elapsedTime+"deltaT"+deltaT+"acceptablePrice"+acceptablePrice+"maxPrice="+maxPrice);
				myAgent.addBehaviour(new BookNegotiator(title, acceptablePrice,
						this));
			}
		}
	}

	/**
	 * Section 4.3.5 of the book, page 69 Inner class BookNegotiator. This is
	 * the behaviour used by Book-buyer agents to actually negotiate with seller
	 * agents the purchase of a book.
	 **/
	private class BookNegotiator extends Behaviour {
		private String title;
		private int maxPrice; //maxmimum accepted price
		private PurchaseManager manager;
		private AID bestSeller; // The seller agent who provides the best offer
		private int bestPrice; // The best offered price
		private int repliesCnt = 0; // The counter of replies from seller agents
		private MessageTemplate mt; // The template to receive replies
		private int step = 0;

		public BookNegotiator(String t, int p, PurchaseManager m) {
			super(null);
			title = t;
			maxPrice = p;
			manager = m;
		}

		public void action() {
			switch (step) {
			case 0:
				// Send the cfp to all sellers
				ACLMessage cfp = new ACLMessage(ACLMessage.CFP);
				for (int i = 0; i < sellerAgents.size(); ++i) {
					cfp.addReceiver((AID) sellerAgents.elementAt(i));
				}
				cfp.setContent(title);
				cfp.setConversationId("book-trade");
				cfp.setReplyWith("cfp" + System.currentTimeMillis()); // Unique
																		// value
				myAgent.send(cfp);
				myGui.notifyUser("Sent Call for Proposal");

				// Prepare the template to get proposals
				mt = MessageTemplate.and(
						MessageTemplate.MatchConversationId("book-trade"),
						MessageTemplate.MatchInReplyTo(cfp.getReplyWith()));
				step = 1;
				break;
			case 1:
				// Receive all proposals/refusals from seller agents
				ACLMessage reply = myAgent.receive(mt);
				if (reply != null) {
					// Reply received
					if (reply.getPerformative() == ACLMessage.PROPOSE) {
						// This is an offer
						int price = Integer.parseInt(reply.getContent());
						myGui.notifyUser("Received Proposal at " + price
								+ " when maximum acceptable price was "
								+ maxPrice);
						if (bestSeller == null || price < bestPrice) {
							// This is the best offer at present
							bestPrice = price;
							bestSeller = reply.getSender();
						}
					}
					repliesCnt++;
					if (repliesCnt >= sellerAgents.size()) {
						// We received all replies
						step = 2;
					}
				} else {
					block();
				}
				break;
			case 2:
				if (bestSeller != null && bestPrice <= maxPrice) {
					// Send the purchase order to the seller that provided the
					// best offer
					ACLMessage order = new ACLMessage(
							ACLMessage.ACCEPT_PROPOSAL);
					order.addReceiver(bestSeller);
					order.setContent(title);
					order.setConversationId("Book-selling");
					order.setReplyWith("order" + System.currentTimeMillis());
					myAgent.send(order);
					myGui.notifyUser("sent Accept Proposal");
					// Prepare the template to get the purchase order reply
					mt = MessageTemplate.and(MessageTemplate
							.MatchConversationId("book-trade"), MessageTemplate
							.MatchInReplyTo(order.getReplyWith()));
					step = 3;
				} else {
					// If we received no acceptable proposals, terminate
					step = 4;
				}
				break;
			case 3:
				// Receive the purchase order reply
				reply = myAgent.receive(mt);
				if (reply != null) {
					// Purchase order reply received
					if (reply.getPerformative() == ACLMessage.INFORM) {
						// Purchase successful. We can terminate
						myGui.notifyUser("Book " + title
								+ " successfully purchased. Price = "
								+ bestPrice);
						manager.stop();
					}
					step = 4;
				} else {
					block();
				}
				break;
			} // end of switch
		}

		public boolean done() {
			return step == 4;
		}
	} // End of inner class BookNegotiator
}
BookSellerAgent.java
package com.leejay.booktrading.seller;

import jade.core.Agent;
import jade.core.behaviours.CyclicBehaviour;
import jade.core.behaviours.TickerBehaviour;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;

import java.io.File;
import java.io.FileInputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class BookSellerAgent extends Agent {
	// The catalogue of books available for sale
	private Map catalogue = new HashMap();

	// The GUI to interact with the user
	private BookSellerGui myGui;

	public static final String SERVICE_NAME = "sell_service";

	/**
	 * Agent initializations
	 **/
	protected void setup() {
		// Printout a welcome message
		System.out.println("Seller-agent " + getAID().getName() + " is ready.");

		// Create and show the GUI
		myGui = new BookSellerGuiImpl();
		myGui.setAgent(this);
		myGui.show();

		// Add the behaviour serving calls for price from buyer agents
		addBehaviour(new CallForOfferServer());

		// Add the behaviour serving purchase requests from buyer agents
		addBehaviour(new PurchaseOrderServer());

		/**
		 * This piece of code, to register services with the DF, is explained in
		 * the book in section 4.4.2.1
		 **/
		// Register the book-selling service in the yellow pages
		registService();

	}

	/**
	 * Register the book-selling service in the yellow pages
	 */
	private void registService() {
		DFAgentDescription dfd = new DFAgentDescription();
		dfd.setName(getAID());
		ServiceDescription sd = new ServiceDescription();
		sd.setName(SERVICE_NAME);
		sd.setType("Book-selling");
		dfd.addServices(sd);
		try {
			DFService.register(this, dfd);
		} catch (FIPAException fe) {
			fe.printStackTrace();
		}
	}

	/**
	 * Agent clean-up
	 **/
	protected void takeDown() {
		// Dispose the GUI if it is there
		if (myGui != null) {
			myGui.dispose();
		}

		// Printout a dismissal message
		System.out.println("Seller-agent " + getAID().getName()
				+ "terminating.");

		/**
		 * This piece of code, to deregister with the DF, is explained in the
		 * book in section 4.4.2.1, page 73
		 **/
		// Deregister from the yellow pages
		try {
			DFService.deregister(this);
		} catch (FIPAException e) {
			e.printStackTrace();
		}
	}

	/**
	 * This method is called by the GUI when the user inserts a new book for
	 * sale
	 * 
	 * @param title
	 *            The title of the book for sale
	 * @param initialPrice
	 *            The initial price
	 * @param minPrice
	 *            The minimum price
	 * @param deadline
	 *            The deadline by which to sell the book
	 **/
	public void putForSale(String title, int initPrice, int minPrice,
			Date deadline) {
		addBehaviour(new PriceManager(this, title, initPrice, minPrice,
				deadline));
	}

	private class PriceManager extends TickerBehaviour {
		private String title;
		private int minPrice, currentPrice, initPrice, deltaP;
		private long initTime, deadline, deltaT;

		private PriceManager(Agent a, String t, int ip, int mp, Date d) {
			super(a, 6000); // tick every minute
			title = t;
			initPrice = ip;
			currentPrice = initPrice;
			deltaP = initPrice - mp;
			deadline = d.getTime();
			initTime = System.currentTimeMillis();
			deltaT = ((deadline - initTime) > 0 ? (deadline - initTime) : 6000);
		}

		public void onStart() {
			// Insert the book in the catalogue of books available for sale
			catalogue.put(title, this);
			super.onStart();
		}

		public void onTick() {
			long currentTime = System.currentTimeMillis();
			if (currentTime > deadline) {
				// Deadline expired
				myGui.notifyUser("Cannot sell book " + title);
				catalogue.remove(title);
				stop();
			} else {
				// Compute the current price
				long elapsedTime = currentTime - initTime;
				currentPrice = (int) Math.round(initPrice - 1.0 * deltaP
						* (1.0 * elapsedTime / deltaT));
			}
		}

		public int getCurrentPrice() {
			return currentPrice;
		}
	}

	/**
	 * Section 4.3.3 , page 67. Inner class CallForOfferServer. This is the
	 * behaviour used by Book-seller agents to serve incoming call for offer
	 * from buyer agents. If the indicated book is in the local catalogue, the
	 * seller agent replies with a PROPOSE message specifying the price.
	 * Otherwise a REFUSE message is sent back.
	 **/
	private class CallForOfferServer extends CyclicBehaviour {
		private MessageTemplate mt = MessageTemplate
				.MatchPerformative(ACLMessage.CFP);

		public void action() {
			ACLMessage msg = myAgent.receive(mt);
			if (msg != null) {
				// CFP Message received. Process it
				String title = msg.getContent();
				myGui.notifyUser("Received Proposal to buy " + title);
				ACLMessage reply = msg.createReply();
				PriceManager pm = (PriceManager) catalogue.get(title);
				if (pm != null) {
					// The requested book is available for sale. Reply with the
					// price
					reply.setPerformative(ACLMessage.PROPOSE);
					reply.setContent(String.valueOf(pm.getCurrentPrice()));
				} else {
					// The requested book is NOT available for sale.
					reply.setPerformative(ACLMessage.REFUSE);
				}
				myAgent.send(reply);
				myGui.notifyUser(pm != null ? "Sent Proposal to sell at "
						+ reply.getContent()
						: "Refused Proposal as the book is not for sale");
			} else {
				block();
			}
		}
	} // End of inner class CallForOfferServer

	/**
	 * Inner class PurchaseOrdersServer. This is the behaviour used by
	 * Book-seller agents to serve incoming offer acceptances (i.e. purchase
	 * orders) from buyer agents. The seller agent removes the purchased book
	 * from its catalogue and replies with an INFORM message to notify the buyer
	 * that the purchase has been sucesfully completed.
	 */
	private class PurchaseOrderServer extends CyclicBehaviour {
		private MessageTemplate mt = MessageTemplate
				.MatchPerformative(ACLMessage.ACCEPT_PROPOSAL);

		public void action() {
			ACLMessage msg = myAgent.receive(mt);
			if (msg != null) {
				// ACCEPT_PROPOSAL Message received. Process it
				String title = msg.getContent();
				myGui.notifyUser("Received ACCEPT_PROPOSAL to purchase "
						+ title);
				ACLMessage reply = msg.createReply();
				PriceManager pm = (PriceManager) catalogue.get(title);
				if (pm != null) {
					// removes the purchased book from its catalogue
					catalogue.remove(title);
					reply.setPerformative(ACLMessage.INFORM);
					pm.stop();
				} else {
					// The requested book is NOT available for sale.
					reply.setPerformative(ACLMessage.FAILURE);
				}
				myAgent.send(reply);
				myGui.notifyUser(pm != null ? "The book " + title
						+ " has been sold at price = " + pm.getCurrentPrice()
						: "The book is not exist.");
			} else {
				block();
			}
		}
	} // End of inner class PurchaseOrdersServer

}
BookBuyerGui.java
package com.leejay.booktrading.buyer;


public interface BookBuyerGui {
  void setAgent(BookBuyerAgent a);
  void show();
  void hide();
  void notifyUser(String message);
  void dispose();
}
BookBuyerGuiImpl.java
package com.leejay.booktrading.buyer;

import jade.gui.TimeChooser;

import java.awt.*;
import java.awt.event.*;

import javax.swing.*;
import javax.swing.border.*;

import java.util.Date;

/**
   J2SE (Swing-based) implementation of the GUI of the agent that 
   tries to buy books on behalf of its user
 */
public class BookBuyerGuiImpl extends JFrame implements BookBuyerGui {
	private BookBuyerAgent myAgent;
	
	private JTextField titleTF, desiredCostTF, maxCostTF, deadlineTF;
	private JButton setDeadlineB;
	private JButton setCCB, buyB, resetB, exitB;
	private JTextArea logTA;
	
	private Date deadline;
	
	public BookBuyerGuiImpl() {
		super();
		
		addWindowListener(new	WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				myAgent.doDelete();
			}
		} );

		

		JPanel rootPanel = new JPanel();
		rootPanel.setLayout(new GridBagLayout());
    rootPanel.setMinimumSize(new Dimension(330, 125));
    rootPanel.setPreferredSize(new Dimension(330, 125));
		
    ///////////
    // Line 0
    ///////////
		JLabel l = new JLabel("Book to buy:");
    l.setHorizontalAlignment(SwingConstants.LEFT);
    GridBagConstraints gridBagConstraints = new GridBagConstraints();
    gridBagConstraints.gridx = 0;
    gridBagConstraints.gridy = 0;
    gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
    gridBagConstraints.insets = new java.awt.Insets(5, 3, 0, 3);
    rootPanel.add(l, gridBagConstraints);

    titleTF = new JTextField(64);
    titleTF.setMinimumSize(new Dimension(222, 20));
    titleTF.setPreferredSize(new Dimension(222, 20));
    gridBagConstraints = new GridBagConstraints();
    gridBagConstraints.gridx = 1;
    gridBagConstraints.gridy = 0;
    gridBagConstraints.gridwidth = 3;
    gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
    gridBagConstraints.insets = new Insets(5, 3, 0, 3);
    rootPanel.add(titleTF, gridBagConstraints);

    ///////////
    // Line 1
    ///////////
		/*l = new JLabel("Best cost:");
    l.setHorizontalAlignment(SwingConstants.LEFT);
    gridBagConstraints = new GridBagConstraints();
    gridBagConstraints.gridx = 0;
    gridBagConstraints.gridy = 1;
    gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
    gridBagConstraints.insets = new java.awt.Insets(5, 3, 0, 3);
    rootPanel.add(l, gridBagConstraints);

    desiredCostTF = new JTextField(64);
    desiredCostTF.setMinimumSize(new Dimension(70, 20));
    desiredCostTF.setPreferredSize(new Dimension(70, 20));
    desiredCostTF.setEditable(false); //FIXME just for this example
    gridBagConstraints = new GridBagConstraints();
    gridBagConstraints.gridx = 1;
    gridBagConstraints.gridy = 1;
    gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
    gridBagConstraints.insets = new Insets(5, 3, 0, 3);
    rootPanel.add(desiredCostTF, gridBagConstraints);*/

		l = new JLabel("Max cost:");
    l.setHorizontalAlignment(SwingConstants.LEFT);
    l.setMinimumSize(new Dimension(70, 20));
    l.setPreferredSize(new Dimension(70, 20));
    gridBagConstraints = new GridBagConstraints();
    gridBagConstraints.gridx = 2;
    gridBagConstraints.gridy = 1;
    gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
    gridBagConstraints.insets = new java.awt.Insets(5, 3, 0, 3);
    rootPanel.add(l, gridBagConstraints);

    maxCostTF = new JTextField(64);
    maxCostTF.setMinimumSize(new Dimension(70, 20));
    maxCostTF.setPreferredSize(new Dimension(70, 20));
    gridBagConstraints = new GridBagConstraints();
    gridBagConstraints.gridx = 3;
    gridBagConstraints.gridy = 1;
    gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
    gridBagConstraints.insets = new Insets(5, 3, 0, 3);
    rootPanel.add(maxCostTF, gridBagConstraints);

    ///////////
    // Line 2
    ///////////
		l = new JLabel("Deadline:");
    l.setHorizontalAlignment(SwingConstants.LEFT);
    gridBagConstraints = new GridBagConstraints();
    gridBagConstraints.gridx = 0;
    gridBagConstraints.gridy = 2;
    gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
    gridBagConstraints.insets = new java.awt.Insets(5, 3, 0, 3);
    rootPanel.add(l, gridBagConstraints);

    deadlineTF = new JTextField(64);
    deadlineTF.setMinimumSize(new Dimension(146, 20));
    deadlineTF.setPreferredSize(new Dimension(146, 20));
    deadlineTF.setEnabled(false);
    gridBagConstraints = new GridBagConstraints();
    gridBagConstraints.gridx = 1;
    gridBagConstraints.gridy = 2;
    gridBagConstraints.gridwidth = 2;
    gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
    gridBagConstraints.insets = new Insets(5, 3, 0, 3);
    rootPanel.add(deadlineTF, gridBagConstraints);

    setDeadlineB = new JButton("Set");
    setDeadlineB.setMinimumSize(new Dimension(70, 20));
    setDeadlineB.setPreferredSize(new Dimension(70, 20));
		setDeadlineB.addActionListener(new ActionListener(){
	  	public void actionPerformed(ActionEvent e) {
	  		Date d = deadline;
	  		if (d == null) {
	  			d = new Date();
	  		}
	  		TimeChooser tc = new TimeChooser(d);
	  		if (tc.showEditTimeDlg(BookBuyerGuiImpl.this) == TimeChooser.OK) {
	  			deadline = tc.getDate();
	  			deadlineTF.setText(deadline.toString());
	  		}
	  	}
		} );
    gridBagConstraints = new GridBagConstraints();
    gridBagConstraints.gridx = 3;
    gridBagConstraints.gridy = 2;
    gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
    gridBagConstraints.insets = new Insets(5, 3, 0, 3);
    rootPanel.add(setDeadlineB, gridBagConstraints);
    
    /*setCCB = new JButton("Set CreditCard");
		setCCB.addActionListener(new ActionListener(){
	  	public void actionPerformed(ActionEvent e) {
	  		String cc = JOptionPane.showInputDialog(BookBuyerGuiImpl.this, "Insert the Credit Card number");
	  		if (cc != null && cc.length() > 0) {
	  			myAgent.setCreditCard(cc);
	  		}
	  		else {
	  			JOptionPane.showMessageDialog(BookBuyerGuiImpl.this, "Invalid Credit Card number", "WARNING", JOptionPane.WARNING_MESSAGE);
	  		}
	  	}
		} );
		//setCCB.setMinimumSize(new Dimension(70, 20));
    //setCCB.setPreferredSize(new Dimension(70, 20));
    gridBagConstraints = new GridBagConstraints();
    gridBagConstraints.gridx = 0;
    gridBagConstraints.gridy = 3;
    gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER;
    gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
    gridBagConstraints.insets = new Insets(5, 3, 0, 3);
    rootPanel.add(setCCB, gridBagConstraints);*/
		
    rootPanel.setBorder(new BevelBorder(BevelBorder.LOWERED));
    
    getContentPane().add(rootPanel, BorderLayout.NORTH);
    
    
    logTA = new JTextArea();
    logTA.setEnabled(false);
    JScrollPane jsp = new JScrollPane(logTA);
    jsp.setMinimumSize(new Dimension(400, 200));
    jsp.setPreferredSize(new Dimension(400, 200));
    JPanel p = new JPanel();
    p.setBorder(new BevelBorder(BevelBorder.LOWERED));
    p.add(jsp);
    getContentPane().add(p, BorderLayout.CENTER);
  
    
    p = new JPanel();
    buyB = new JButton("Buy");
		buyB.addActionListener(new ActionListener(){
	  	public void actionPerformed(ActionEvent e) {
	  		String title = titleTF.getText();
	  		int desiredCost = -1;
	  		int maxCost = -1;	  		
	  		if (title != null && title.length() > 0) {
	  			if (deadline != null && deadline.getTime() > System.currentTimeMillis()) {
			  		try {
				  		//desiredCost = Integer.parseInt(desiredCostTF.getText());
				  		try {
					  		maxCost = Integer.parseInt(maxCostTF.getText());
					  		// if (maxCost >= desiredCost) {
					  			// myAgent.purchase(title, desiredCost, maxCost, deadline.getTime());
					  			myAgent.purchase(title, maxCost, deadline);
                  notifyUser("PUT FOR BUY: "+title+" at max "+maxCost+" by "+deadline); 
					  		//}
					  		//else {
					  			// Max cost < desiredCost
					  			//JOptionPane.showMessageDialog(BookBuyerGuiImpl.this, "Max cost must be greater than best cost", "WARNING", JOptionPane.WARNING_MESSAGE);
					  		//}					  			
				  		}
				  		catch (Exception ex1) {
				  			// Invalid max cost
				  			JOptionPane.showMessageDialog(BookBuyerGuiImpl.this, "Invalid max cost", "WARNING", JOptionPane.WARNING_MESSAGE);
				  		}
			  		}
			  		catch (Exception ex2) {
			  			// Invalid desired cost
			  			JOptionPane.showMessageDialog(BookBuyerGuiImpl.this, "Invalid best cost", "WARNING", JOptionPane.WARNING_MESSAGE);
			  		}
	  			}
	  			else {
	  				// No deadline specified
		  			JOptionPane.showMessageDialog(BookBuyerGuiImpl.this, "Invalid deadline", "WARNING", JOptionPane.WARNING_MESSAGE);
	  			}
	  		}
  			else {
  				// No book title specified
	  			JOptionPane.showMessageDialog(BookBuyerGuiImpl.this, "No book title specified", "WARNING", JOptionPane.WARNING_MESSAGE);
  			}
	  	}
		} );
    resetB = new JButton("Reset");
		resetB.addActionListener(new ActionListener(){
	  	public void actionPerformed(ActionEvent e) {
	  		titleTF.setText("");
	  		desiredCostTF.setText("");
	  		maxCostTF.setText("");
	  		deadlineTF.setText("");
	  		deadline = null;
	  	}
		} );
    exitB = new JButton("Exit");
		exitB.addActionListener(new ActionListener(){
	  	public void actionPerformed(ActionEvent e) {
	  		myAgent.doDelete();
	  	}
		} );
		
    buyB.setPreferredSize(resetB.getPreferredSize());
    exitB.setPreferredSize(resetB.getPreferredSize());
    
    p.add(buyB);
    p.add(resetB);
    p.add(exitB);
    
    p.setBorder(new BevelBorder(BevelBorder.LOWERED));
    getContentPane().add(p, BorderLayout.SOUTH);
    
    pack();
    
    setResizable(false);
	}

	public void setAgent(BookBuyerAgent a) {
		myAgent = a;
		setTitle(myAgent.getName());
	}
		
	public void notifyUser(String message) {
		logTA.append(message+"\n");
	}
}	
BookSellerGui.java
package com.leejay.booktrading.seller;

public interface BookSellerGui {
  void setAgent(BookSellerAgent a);
  void show();
  void hide();
  void notifyUser(String message);
  void dispose();
}
BookSellerGuiImpl.java
package com.leejay.booktrading.seller;

import jade.gui.TimeChooser;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;

import java.util.Date;

/**
   This is the GUI of the agent that tries to sell books on behalf of its user
 */
public class BookSellerGuiImpl extends JFrame implements BookSellerGui {
	private BookSellerAgent myAgent;
	
	private JTextField titleTF, desiredPriceTF, minPriceTF, deadlineTF;
	private JButton setDeadlineB;
	private JButton setCCB, sellB, resetB, exitB;
	private JTextArea logTA;
	
	private Date deadline;
	
  public void setAgent(BookSellerAgent a) {
		myAgent = a;
		setTitle(myAgent.getName());
  }

	public BookSellerGuiImpl() {
		super();
		
		addWindowListener(new	WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				myAgent.doDelete();
			}
		} );

		

		JPanel rootPanel = new JPanel();
		rootPanel.setLayout(new GridBagLayout());
    rootPanel.setMinimumSize(new Dimension(330, 125));
    rootPanel.setPreferredSize(new Dimension(330, 125));
		
    ///////////
    // Line 0
    ///////////
		JLabel l = new JLabel("Book to sell:");
    l.setHorizontalAlignment(SwingConstants.LEFT);
    GridBagConstraints gridBagConstraints = new GridBagConstraints();
    gridBagConstraints.gridx = 0;
    gridBagConstraints.gridy = 0;
    gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
    gridBagConstraints.insets = new java.awt.Insets(5, 3, 0, 3);
    rootPanel.add(l, gridBagConstraints);

    titleTF = new JTextField(64);
    titleTF.setMinimumSize(new Dimension(222, 20));
    titleTF.setPreferredSize(new Dimension(222, 20));
    gridBagConstraints = new GridBagConstraints();
    gridBagConstraints.gridx = 1;
    gridBagConstraints.gridy = 0;
    gridBagConstraints.gridwidth = 3;
    gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
    gridBagConstraints.insets = new Insets(5, 3, 0, 3);
    rootPanel.add(titleTF, gridBagConstraints);

    ///////////
    // Line 1
    ///////////
		l = new JLabel("Best price:");
    l.setHorizontalAlignment(SwingConstants.LEFT);
    gridBagConstraints = new GridBagConstraints();
    gridBagConstraints.gridx = 0;
    gridBagConstraints.gridy = 1;
    gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
    gridBagConstraints.insets = new java.awt.Insets(5, 3, 0, 3);
    rootPanel.add(l, gridBagConstraints);

    desiredPriceTF = new JTextField(64);
    desiredPriceTF.setMinimumSize(new Dimension(70, 20));
    desiredPriceTF.setPreferredSize(new Dimension(70, 20));
    gridBagConstraints = new GridBagConstraints();
    gridBagConstraints.gridx = 1;
    gridBagConstraints.gridy = 1;
    gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
    gridBagConstraints.insets = new Insets(5, 3, 0, 3);
    rootPanel.add(desiredPriceTF, gridBagConstraints);

		l = new JLabel("Min price:");
    l.setHorizontalAlignment(SwingConstants.LEFT);
    l.setMinimumSize(new Dimension(70, 20));
    l.setPreferredSize(new Dimension(70, 20));
    gridBagConstraints = new GridBagConstraints();
    gridBagConstraints.gridx = 2;
    gridBagConstraints.gridy = 1;
    gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
    gridBagConstraints.insets = new java.awt.Insets(5, 3, 0, 3);
    rootPanel.add(l, gridBagConstraints);

    minPriceTF = new JTextField(64);
    minPriceTF.setMinimumSize(new Dimension(70, 20));
    minPriceTF.setPreferredSize(new Dimension(70, 20));
    gridBagConstraints = new GridBagConstraints();
    gridBagConstraints.gridx = 3;
    gridBagConstraints.gridy = 1;
    gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
    gridBagConstraints.insets = new Insets(5, 3, 0, 3);
    rootPanel.add(minPriceTF, gridBagConstraints);

    ///////////
    // Line 2
    ///////////
		l = new JLabel("Deadline:");
    l.setHorizontalAlignment(SwingConstants.LEFT);
    gridBagConstraints = new GridBagConstraints();
    gridBagConstraints.gridx = 0;
    gridBagConstraints.gridy = 2;
    gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
    gridBagConstraints.insets = new java.awt.Insets(5, 3, 0, 3);
    rootPanel.add(l, gridBagConstraints);

    deadlineTF = new JTextField(64);
    deadlineTF.setMinimumSize(new Dimension(146, 20));
    deadlineTF.setPreferredSize(new Dimension(146, 20));
    deadlineTF.setEnabled(false);
    gridBagConstraints = new GridBagConstraints();
    gridBagConstraints.gridx = 1;
    gridBagConstraints.gridy = 2;
    gridBagConstraints.gridwidth = 2;
    gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
    gridBagConstraints.insets = new Insets(5, 3, 0, 3);
    rootPanel.add(deadlineTF, gridBagConstraints);

    setDeadlineB = new JButton("Set");
    setDeadlineB.setMinimumSize(new Dimension(70, 20));
    setDeadlineB.setPreferredSize(new Dimension(70, 20));
		setDeadlineB.addActionListener(new ActionListener(){
	  	public void actionPerformed(ActionEvent e) {
	  		Date d = deadline;
	  		if (d == null) {
	  			d = new Date();
	  		}
	  		TimeChooser tc = new TimeChooser(d);
	  		if (tc.showEditTimeDlg(BookSellerGuiImpl.this) == TimeChooser.OK) {
	  			deadline = tc.getDate();
	  			deadlineTF.setText(deadline.toString());
	  		}
	  	}
		} );
    gridBagConstraints = new GridBagConstraints();
    gridBagConstraints.gridx = 3;
    gridBagConstraints.gridy = 2;
    gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
    gridBagConstraints.insets = new Insets(5, 3, 0, 3);
    rootPanel.add(setDeadlineB, gridBagConstraints);    
		
    rootPanel.setBorder(new BevelBorder(BevelBorder.LOWERED));
    
    getContentPane().add(rootPanel, BorderLayout.NORTH);
    
    
    logTA = new JTextArea();
    logTA.setEnabled(false);
    JScrollPane jsp = new JScrollPane(logTA);
    jsp.setMinimumSize(new Dimension(400, 200));
    jsp.setPreferredSize(new Dimension(400, 200));
    JPanel p = new JPanel();
    p.setBorder(new BevelBorder(BevelBorder.LOWERED));
    p.add(jsp);
    getContentPane().add(p, BorderLayout.CENTER);
  
    
    p = new JPanel();
    sellB = new JButton("Sell");
		sellB.addActionListener(new ActionListener(){
	  	public void actionPerformed(ActionEvent e) {
	  		String title = titleTF.getText();
	  		int desiredPrice = -1;
	  		int minPrice = -1;	  		
	  		if (title != null && title.length() > 0) {
	  			if (deadline != null && deadline.getTime() > System.currentTimeMillis()) {
			  		try {
				  		desiredPrice = Integer.parseInt(desiredPriceTF.getText());
				  		try {
					  		minPrice = Integer.parseInt(minPriceTF.getText());
					  		if (minPrice <= desiredPrice) {
					  			// myAgent.addToCatalogue(title, desiredPrice, minPrice, deadline.getTime());
					  			myAgent.putForSale(title, desiredPrice, minPrice, deadline);
                  notifyUser("PUT FOR SALE: "+title+" between "+desiredPrice+" and "+minPrice+" by "+deadline); 
					  		}
					  		else {
					  			// minPrice > desiredPrice
					  			JOptionPane.showMessageDialog(BookSellerGuiImpl.this, "Min price must be cheaper than best price", "WARNING", JOptionPane.WARNING_MESSAGE);
					  		}					  			
				  		}
				  		catch (Exception ex1) {
				  			// Invalid max cost
				  			JOptionPane.showMessageDialog(BookSellerGuiImpl.this, "Invalid min price", "WARNING", JOptionPane.WARNING_MESSAGE);
				  		}
			  		}
			  		catch (Exception ex2) {
			  			// Invalid desired cost
			  			JOptionPane.showMessageDialog(BookSellerGuiImpl.this, "Invalid best price", "WARNING", JOptionPane.WARNING_MESSAGE);
			  		}
	  			}
	  			else {
	  				// No deadline specified
		  			JOptionPane.showMessageDialog(BookSellerGuiImpl.this, "Invalid deadline", "WARNING", JOptionPane.WARNING_MESSAGE);
	  			}
	  		}
  			else {
  				// No book title specified
	  			JOptionPane.showMessageDialog(BookSellerGuiImpl.this, "No book title specified", "WARNING", JOptionPane.WARNING_MESSAGE);
  			}
	  	}
		} );
    resetB = new JButton("Reset");
		resetB.addActionListener(new ActionListener(){
	  	public void actionPerformed(ActionEvent e) {
	  		titleTF.setText("");
	  		desiredPriceTF.setText("");
	  		minPriceTF.setText("");
	  		deadlineTF.setText("");
	  		deadline = null;
	  	}
		} );
    exitB = new JButton("Exit");
		exitB.addActionListener(new ActionListener(){
	  	public void actionPerformed(ActionEvent e) {
	  		myAgent.doDelete();
	  	}
		} );
		
    sellB.setPreferredSize(resetB.getPreferredSize());
    exitB.setPreferredSize(resetB.getPreferredSize());
    
    p.add(sellB);
    p.add(resetB);
    p.add(exitB);
    
    p.setBorder(new BevelBorder(BevelBorder.LOWERED));
    getContentPane().add(p, BorderLayout.SOUTH);
    
    pack();
    
    setResizable(false);
	}
	
	public void notifyUser(String message) {
		logTA.append(message+"\n");
	}
}