summaryrefslogtreecommitdiff
path: root/sources/examples/auction.scala
blob: ecf121ef7d4e4d6ef1f4e16138cc18817b0bfb27 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
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();
  }

}