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
134
135
136
137
138
139
140
141
142
143
|
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) extends AuctionMessage // make a bid
case class Inquire(client: Actor) extends AuctionMessage // inquire status
trait AuctionReply
case class Status(asked: int, expiration: Date) // asked sum, expiration date
extends AuctionReply
case class BestOffer() extends AuctionReply // yours is the best offer
case class BeatenOffer(maxBid: int) extends AuctionReply // offer beaten by maxBid
case class AuctionConcluded(seller: Actor, client: Actor) // auction concluded
extends AuctionReply
case class AuctionFailed() extends AuctionReply // failed with no bids
case class 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 auction {
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) = Console.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 kill(delay: Int) = new java.util.Timer().schedule(
new java.util.TimerTask {
override def run() = {
Console.println("[killed]")
System.exit(0)
}
},
delay) // in milliseconds
def main(args: Array[String]) = {
seller.start()
auction.start()
client(1, 20, 200).start()
client(2, 10, 300).start()
kill(20000)
}
}
|