package examples; import java.util.Date; import scala.concurrent._; /** A simple demonstrator program implementing an online auction service * The example uses the actor abstraction defined in the API of * package scala.concurrent. */ trait AuctionMessage; case class Offer(bid: int, client: Actor), // make a bid Inquire(client: Actor) extends AuctionMessage; // inquire status trait AuctionReply; case class Status(asked: int, expiration: Date), // asked sum, expiration date BestOffer(), // yours is the best offer BeatenOffer(maxBid: int), // offer beaten by maxBid AuctionConcluded(seller: Actor, client: Actor), // auction concluded AuctionFailed(), // failed with no bids AuctionOver() extends AuctionReply; // bidding is closed class Auction(seller: Actor, minBid: int, closing: Date) extends Actor { val timeToShutdown = 3600000; // msec val bidIncrement = 10; override def run() = { var maxBid = minBid - bidIncrement; var maxBidder: Actor = null; var running = true; while (running) { receiveWithin (closing.getTime() - new Date().getTime()) { case Offer(bid, client) => if (bid >= maxBid + bidIncrement) { if (maxBid >= minBid) maxBidder send BeatenOffer(bid); maxBid = bid; maxBidder = client; client send BestOffer() } else { client send BeatenOffer(maxBid) } case Inquire(client) => client send Status(maxBid, closing) case TIMEOUT() => if (maxBid >= minBid) { val reply = AuctionConcluded(seller, maxBidder); maxBidder send reply; seller send reply } else { seller send AuctionFailed() } receiveWithin(timeToShutdown) { case Offer(_, client) => client send AuctionOver() case TIMEOUT() => running = false } } } } } // ---- Test ------------------------------------------------------------- object testAuction { val random = new java.util.Random(); val minBid = 100; val closing = new Date(new Date().getTime() + 60000); val seller = new Actor { override def run() = {} } val auction = new Auction(seller, minBid, closing); def client(i: int, increment: int, top: int) = new Actor { val name = "Client " + i; def log(msg: String) = System.out.println(name + ": " + msg); var running = true; var max: int = _; var current: int = 0; override def run() = { log("started"); auction send Inquire(this); receive { case Status(maxBid, _) => { log("status(" + maxBid + ")"); max = maxBid } } while (running) { if (max >= top) log("too high for me") else if (current < max) { current = max + increment; Thread.sleep(1 + random.nextInt(1000)); auction send Offer(current, this); } receive { case BestOffer() => { log("bestOffer(" + current + ")"); } case BeatenOffer(maxBid) => { log("beatenOffer(" + maxBid + ")"); max = maxBid; } case AuctionConcluded(seller, maxBidder) => { log("auctionConcluded"); } case AuctionOver() => { running = false; log("auctionOver"); } } } } } def main(args: Array[String]) = { seller.start(); auction.start(); client(1, 20, 200).start(); client(2, 10, 300).start(); } }