144 | | |
145 | | == Party |
146 | | A party is a program that receives inform messages from the protocol, and can send the actions it wants to take regarding the negotiation back to the protocol. These actions are sent over a websocket that is created by the partiesserver that created the party, which in turn creates this according to a http GET request that comes from a running protocol. The party can also pro-actively search for information and take other actions as it likes, as long as it adheres to the requirements of the protocol (discussed later in this document). |
147 | | |
148 | | The party module contains the inform objects. There are several, and although they have quite specific meanings, their fine details can be tweaked by the protocol. |
149 | | |
150 | | ||inform object||meaning|| |
151 | | ||Settings||usually sent as first inform to a party, indicating start of the session and providing the party name, protocol, profile, deadline etc|| |
152 | | ||YourTurn||Indicating that the party receiving this inform now has the turn. || |
153 | | ||ActionDone||Informing that some party did an action|| |
154 | | ||Finished||Indicating that a session has been finished|| |
155 | | |
156 | | Please check the [source:party/src/main/java/geniusweb/party/inform source code of Inform objects] for all the details especially on the json serialization. |
157 | | |
158 | | The party module also contains basic interfaces for implementing your negotiation party. These interfaces are only relevant to create a party compatible with our reference implementation of the [https://tracinsy.ewi.tudelft.nl/pubtrac/GeniusWebPartiesServer partiesserver]. The main class is Party, which defines the basic functionality required for a negotiation party on our server. The heart of the party is that your Party implements Connectable<Inform,Action>. Connectable contains 2 main functions: connect and disconnect. When connect is called, your party receives a Connection over which it receives Inform objects and can send Action objects. What exactly is sent and received is determined by the protocol (see the protocol section below). For example if the SAOP protocol is used, your party will receive a YourTurn message, after which it decides on its action and sends it into the Connection. See also the example party discussed below. |
159 | | |
160 | | |
161 | | == Timeline |
162 | | The timeline module describes the deadline and a progress objects. |
163 | | The deadline indicates how much time a negotiation session can take and is used to specify the settings for a session or tournament. Two examples: |
164 | | |
165 | | {{{ |
166 | | {"deadlinerounds":{"rounds":100,"durationms":999}} |
167 | | }}} |
168 | | |
169 | | and |
170 | | {{{ |
171 | | {"deadlinetime":{"durationms":2000}} |
172 | | }}} |
173 | | |
174 | | * durationms indicates the maximum run time in milliseconds for the party. The clock starts ticking at the moment the party receives its SessionSettings object. |
175 | | * rounds indicates the maximum number of rounds in the session. The session will end after this number of rounds, deal or no deal. |
176 | | |
177 | | The progress indicates where currently running session is towards the deadline. Progress is contained in the settings object. Round based progress must be updated by the party after each round. |
178 | | |
179 | | |
180 | | |
181 | | |
182 | | == References |
183 | | Parties, domains, profiles and protocols are stored and used on remote machines. |
184 | | We use IRI's (internationalized resource identifier, which looks similar to the well known URLs you use in your web browser) to refer to them. These IRI's are packed inside objects like the PartyRef, ProtocolRef, ProfileRef, DomainRef so that it is clear what type of object the IRI is referring to. |
185 | | For example, when your party is initialized, it usually receives a Settings object that contains a ProfileRef. The intention is that the party fetches the actual profile from the web, using the IRI in the ProtocolRef. See the example party below for an example. |
186 | | |
187 | | There are a number of schemes used for references: |
188 | | |
189 | | ||scheme||used with||example||comments|| |
190 | | ||http:||party||http://localhost:8080/partiesserver/run/randompyparty-1.0.0|| || |
191 | | ||ws:||profile||ws://localhost:8080/profilesserver/websocket/get/jobs/jobs1.json|| || |
192 | | ||file:||profile||file:src/test/settings.json ||gives file relative to local current working dir|| |
193 | | ||classpath:||party||classpath:geniusweb.exampleparties.randomparty.RandomParty||must be in classpath|| |
194 | | |
195 | | == BidSpace |
196 | | The bidspace module contains functionality to support building a negotiation party. We currently have |
197 | | * OpponentModel: this is a category of classes that can estimate the opponent's profile from the bids that he places. |
198 | | * Pareto: this is a category of classes that can compute the pareto frontier from a set of profiles. Pareto optimality is an important mechanism to place optimal bids. |
199 | | * AllBidsList: this can be used to craete a list containing all possible bids in a domain. This list is created in a lazy way, and competely avoids storing the whole list in memory (which might not even fit) |
200 | | |
201 | | |
202 | | |
203 | | == Protocol |
204 | | The protocol module contains the functionality to define and execute a negotiation protocol. |
205 | | There are session protocols and tournament protocols. |
206 | | |
207 | | The basic classes defining a protocol are: |
208 | | * The [source:/protocol/src/main/java/geniusweb/protocol/NegoSettings.java NegoSettings]: these define the settings for the protocol, such as the deadline, the participants and the profile |
209 | | * The [source:/protocol/src/main/java/geniusweb/protocol/NegoState.java NegoState]: this contains the current state of execution of the protocol. To give some example states: "waiting for bid from party 2", "ended with agreement", "ended because party 1 broke the protocol". A state also has various {{{with()}}} functions defining the new state from an old state and a party doing an action. |
210 | | * The [source:/protocol/src/main/java/geniusweb/protocol/NegoProtocol.java NegoProtocol]: this defines what happens when a negotiation starts, when a participant enters halfway the session, what are the allowed actions, what happens if a participant breaks the protocol, etc. |
211 | | |
212 | | |
213 | | |
214 | | |
215 | | = Writing a party in Java |
216 | | |
217 | | Example parties can be found [source:/exampleparties here]. You can easily clone a party with SVN using {{{svn co https://tracinsy.ewi.tudelft.nl/svn/GeniusWeb/exampleparties/randomparty/}}} (this clones randomparty, use a different name to fetch another example). |
218 | | |
219 | | A party is compiled with maven. After compilation ({{{mvn package}}}) you get a {{{target/yourparty-X.Y.Z-jar-with-dependencies.jar}}} that can be copied into the parties server for deployment. |
220 | | |
221 | | The basic structure of an party looks like this |
222 | | {{{ |
223 | | public class RandomParty extends DefaultParty { |
224 | | @Override |
225 | | public void notifyChange(Inform info) { |
226 | | if (info instanceof Settings) { |
227 | | Settings settings = (Settings) info; |
228 | | this.profileint = ProfileConnectionFactory |
229 | | .create(settings.getProfile().getURI(), getReporter()); |
230 | | this.me = settings.getID(); |
231 | | this.progress = settings.getProgress(); |
232 | | } else if (info instanceof ActionDone) { |
233 | | Action otheract = ((ActionDone) info).getAction(); |
234 | | if (otheract instanceof Offer) { |
235 | | lastReceivedBid = ((Offer) otheract).getBid(); |
236 | | } |
237 | | } else if (info instanceof YourTurn) { |
238 | | myTurn(); |
239 | | if (progress instanceof ProgressRounds) { |
240 | | progress = ((ProgressRounds) progress).advance(); |
241 | | } |
242 | | } else if (info instanceof Finished) { |
243 | | getReporter().log(Level.INFO, "Final ourcome:" + info); |
244 | | } |
245 | | } |
246 | | |
247 | | |
248 | | private void myTurn() { |
249 | | Action action; |
250 | | if (isGood(lastReceivedBid)) { |
251 | | action = new Accept(me, lastReceivedBid); |
252 | | } else { |
253 | | // for demo. Obviously full bids have higher util in general |
254 | | AllPartialBidsList bidspace = new AllPartialBidsList( |
255 | | profileint.getProfile().getDomain()); |
256 | | Bid bid = null; |
257 | | for (int attempt = 0; attempt < 20 && !isGood(bid); attempt++) { |
258 | | long i = random.nextInt(bidspace.size().intValue()); |
259 | | bid = bidspace.get(BigInteger.valueOf(i)); |
260 | | } |
261 | | action = new Offer(me, bid); |
262 | | } |
263 | | getConnection().send(action); |
264 | | } |
265 | | |
266 | | private boolean isGood(Bid bid) { |
267 | | return bid != null |
268 | | && ((LinearAdditiveUtilitySpace) profileint.getProfile()) |
269 | | .getUtility(bid).doubleValue() > 0.6; |
270 | | } |
271 | | |
272 | | @Override |
273 | | public Capabilities getCapabilities() { |
274 | | return new Capabilities(new HashSet<>( |
275 | | Arrays.asList(new ProtocolRef(new URI("SAOP"))))); |
276 | | } |
277 | | |
278 | | @Override |
279 | | public String getDescription() { |
280 | | return "places random bids until it can accept an offer with utility >0.6"; |
281 | | } |
282 | | |
283 | | } |
284 | | }}} |
285 | | |
286 | | == Preparing the jar file |
287 | | In order to put your party on the [https://tracinsy.ewi.tudelft.nl/pubtrac/GeniusWebPartiesServer partiesserver] for running, you need a jar file of your party. |
288 | | |
289 | | Normally the party includes all dependencies. The jar files are loaded with an isolated jar class loader that should avoid collisions with possibly identically named but possibly different packages in other jar files. |
290 | | |
291 | | |
292 | | Party jar files must have a Main-Class set in the MANIFEST.MF file. This main-class must implement Party and have a no-arg constructor. |
293 | | |
294 | | The example randomparty does this from the maven build script. |
295 | | |
296 | | We recommend to do initialization of the party only in the init() and not in the constructor or static code. |
297 | | This because instances of your class can be made both for extracting general info as getDescription(), or to really run your class. |
298 | | |
299 | | |
300 | | = Writing a party in Python |
301 | | We provide a python-to-java adapter so that you can easily write your party in python instead of Java. You can check the full working example code [source:/exampleparties/randompartypy/src/main/resources/RandomParty.py here]. A python-based party looks like this: |
302 | | {{{ |
303 | | class RandomParty (DefaultParty): |
304 | | def notifyChange(self, info): |
305 | | if isinstance(info, Settings) : |
306 | | self.profile = ProfileConnectionFactory.create(info.getProfile().getURI(), self.getReporter()); |
307 | | self.me = info.getID() |
308 | | self.progress = info.getProgress() |
309 | | elif isinstance(info , ActionDone): |
310 | | self.lastActor = info.getAction().getActor() |
311 | | otheract = info.getAction() |
312 | | if isinstance(otheract, Offer): |
313 | | self.lastReceivedBid = otheract.getBid() |
314 | | elif isinstance(info , YourTurn): |
315 | | self._myTurn() |
316 | | if isinstance(self.progress, ProgressRounds) : |
317 | | self.progress = self.progress.advance(); |
318 | | |
319 | | |
320 | | |
321 | | def getCapabilities(self): # -> Capabilities |
322 | | return Capabilities(HashSet([ ProtocolRef(URI("SAOP"))])) |
323 | | |
324 | | def getDescription(self): |
325 | | return "places random bids until it can accept an offer with utility >0.6. Python version" |
326 | | |
327 | | def terminate(self): |
328 | | self.profile.disconnect() |
329 | | |
330 | | def _myTurn(self): |
331 | | if self.lastReceivedBid != None and self.profile.getProfile().getUtility(self.lastReceivedBid).doubleValue() > 0.6: |
332 | | action = Accept(self.me, self.lastReceivedBid) |
333 | | else: |
334 | | bidspace = AllPartialBidsList(self.profile.getProfile().getDomain()) |
335 | | bid = None |
336 | | for attempt in range(20): |
337 | | i = self.random.nextInt(bidspace.size()) # warning: jython implicitly converts BigInteger to long. |
338 | | bid = bidspace.get(BigInteger.valueOf(i)) |
339 | | if self._isGood(bid): |
340 | | break |
341 | | action = Offer(self.me, bid); |
342 | | self.getConnection().send(action) |
343 | | |
344 | | def _isGood(self, bid): |
345 | | return bid != None and self.profile.getProfile().getUtility(bid).doubleValue() > 0.6; |
346 | | |
347 | | }}} |
348 | | |
349 | | You need to wrap your python party into a jar wrapper to get it accepted by the parties server. To do this, check the javadoc with the [source:/pythonadapter/src/main/java/geniusweb/pythonadapter/PythonPartyAdapter.java PythonPartyAdapter]. |
350 | | |
351 | | |
352 | | = Writing a party in other languages |
353 | | If you want to use another language than java or python2 to write your parties, you have a number of options |
354 | | * Make your own adapter that runs your language from Java. Check [source:pythonadapter/src/main/java/geniusweb/pythonadapter/PythonPartyAdapter.java our pythonadapter] for an example how this can be done. |
355 | | * Write your own partiesserver that correctly implements the [https://tracinsy.ewi.tudelft.nl/pubtrac/GeniusWebPartiesServer partiesserver interface]. This boils down to creating a webserver that correctly can handle calls to a number of prescribed URLs and websockets. |
356 | | |
357 | | = JSON layout |
358 | | This section discusses how domains and profiles are looking in JSON. JSON is the communication format, java instances of Domain, Profile and Bid can easily be converted back and forth to JSON using the jackson objectmapper (see the test and example codes) |
359 | | |
360 | | == Create a domain |
361 | | |
| 237 | == Party |
| 238 | A party is a program that receives inform messages from the protocol, and can send the actions it wants to take regarding the negotiation back to the protocol. These actions are sent over a websocket that is created by the partiesserver that created the party, which in turn creates this according to a http GET request that comes from a running protocol. The party can also pro-actively search for information and take other actions as it likes, as long as it adheres to the requirements of the protocol (discussed later in this document). |
| 239 | |
| 240 | The party module contains the inform objects. There are several, and although they have quite specific meanings, their fine details can be tweaked by the protocol. |
| 241 | |
| 242 | ||inform object||meaning|| |
| 243 | ||Settings||usually sent as first inform to a party, indicating start of the session and providing the party name, protocol, profile, deadline etc|| |
| 244 | ||YourTurn||Indicating that the party receiving this inform now has the turn. || |
| 245 | ||ActionDone||Informing that some party did an action|| |
| 246 | ||Finished||Indicating that a session has been finished|| |
| 247 | |
| 248 | Please check the [source:party/src/main/java/geniusweb/party/inform source code of Inform objects] for all the details especially on the json serialization. |
| 249 | |
| 250 | The party module also contains basic interfaces for implementing your negotiation party. These interfaces are only relevant to create a party compatible with our reference implementation of the [https://tracinsy.ewi.tudelft.nl/pubtrac/GeniusWebPartiesServer partiesserver]. The main class is Party, which defines the basic functionality required for a negotiation party on our server. The heart of the party is that your Party implements Connectable<Inform,Action>. Connectable contains 2 main functions: connect and disconnect. When connect is called, your party receives a Connection over which it receives Inform objects and can send Action objects. What exactly is sent and received is determined by the protocol (see the protocol section below). For example if the SAOP protocol is used, your party will receive a YourTurn message, after which it decides on its action and sends it into the Connection. See also the example party discussed below. |
| 251 | |
| 252 | |
| 253 | == Timeline |
| 254 | The timeline module describes the deadline and a progress objects. |
| 255 | The deadline indicates how much time a negotiation session can take and is used to specify the settings for a session or tournament. Two examples: |
| 256 | |
| 257 | {{{ |
| 258 | {"deadlinerounds":{"rounds":100,"durationms":999}} |
| 259 | }}} |
| 260 | |
| 261 | and |
| 262 | {{{ |
| 263 | {"deadlinetime":{"durationms":2000}} |
| 264 | }}} |
| 265 | |
| 266 | * durationms indicates the maximum run time in milliseconds for the party. The clock starts ticking at the moment the party receives its SessionSettings object. |
| 267 | * rounds indicates the maximum number of rounds in the session. The session will end after this number of rounds, deal or no deal. |
| 268 | |
| 269 | The progress indicates where currently running session is towards the deadline. Progress is contained in the settings object. Round based progress must be updated by the party after each round. |
| 270 | |
| 271 | |
| 272 | |
| 273 | |
| 274 | == References |
| 275 | Parties, domains, profiles and protocols are stored and used on remote machines. |
| 276 | We use IRI's (internationalized resource identifier, which looks similar to the well known URLs you use in your web browser) to refer to them. These IRI's are packed inside objects like the PartyRef, ProtocolRef, ProfileRef, DomainRef so that it is clear what type of object the IRI is referring to. |
| 277 | For example, when your party is initialized, it usually receives a Settings object that contains a ProfileRef. The intention is that the party fetches the actual profile from the web, using the IRI in the ProtocolRef. See the example party below for an example. |
| 278 | |
| 279 | There are a number of schemes used for references: |
| 280 | |
| 281 | ||scheme||used with||example||comments|| |
| 282 | ||http:||party||http://localhost:8080/partiesserver/run/randompyparty-1.0.0|| || |
| 283 | ||ws:||profile||ws://localhost:8080/profilesserver/websocket/get/jobs/jobs1.json|| || |
| 284 | ||file:||profile||file:src/test/settings.json ||gives file relative to local current working dir|| |
| 285 | ||classpath:||party||classpath:geniusweb.exampleparties.randomparty.RandomParty||must be in classpath|| |
| 286 | |
| 287 | == BidSpace |
| 288 | The bidspace module contains functionality to support building a negotiation party. We currently have |
| 289 | * OpponentModel: this is a category of classes that can estimate the opponent's profile from the bids that he places. |
| 290 | * Pareto: this is a category of classes that can compute the pareto frontier from a set of profiles. Pareto optimality is an important mechanism to place optimal bids. |
| 291 | * AllBidsList: this can be used to craete a list containing all possible bids in a domain. This list is created in a lazy way, and competely avoids storing the whole list in memory (which might not even fit) |
| 292 | |
| 293 | |
| 294 | |
| 295 | == Protocol |
| 296 | The protocol module contains the functionality to define and execute a negotiation protocol. |
| 297 | There are session protocols and tournament protocols. |
| 298 | |
| 299 | The basic classes defining a protocol are: |
| 300 | * The [source:/protocol/src/main/java/geniusweb/protocol/NegoSettings.java NegoSettings]: these define the settings for the protocol, such as the deadline, the participants and the profile |
| 301 | * The [source:/protocol/src/main/java/geniusweb/protocol/NegoState.java NegoState]: this contains the current state of execution of the protocol. To give some example states: "waiting for bid from party 2", "ended with agreement", "ended because party 1 broke the protocol". A state also has various {{{with()}}} functions defining the new state from an old state and a party doing an action. |
| 302 | * The [source:/protocol/src/main/java/geniusweb/protocol/NegoProtocol.java NegoProtocol]: this defines what happens when a negotiation starts, when a participant enters halfway the session, what are the allowed actions, what happens if a participant breaks the protocol, etc. |
| 303 | |
| 304 | |
| 305 | |
| 306 | |
| 307 | = Writing a party in Java |
| 308 | |
| 309 | Example parties can be found [source:/exampleparties here]. You can easily clone a party with SVN using {{{svn co https://tracinsy.ewi.tudelft.nl/svn/GeniusWeb/exampleparties/randomparty/}}} (this clones randomparty, use a different name to fetch another example). |
| 310 | |
| 311 | A party is compiled with maven. After compilation ({{{mvn package}}}) you get a {{{target/yourparty-X.Y.Z-jar-with-dependencies.jar}}} that can be copied into the parties server for deployment. |
| 312 | |
| 313 | The basic structure of an party looks like this |
| 314 | {{{ |
| 315 | public class RandomParty extends DefaultParty { |
| 316 | @Override |
| 317 | public void notifyChange(Inform info) { |
| 318 | if (info instanceof Settings) { |
| 319 | Settings settings = (Settings) info; |
| 320 | this.profileint = ProfileConnectionFactory |
| 321 | .create(settings.getProfile().getURI(), getReporter()); |
| 322 | this.me = settings.getID(); |
| 323 | this.progress = settings.getProgress(); |
| 324 | } else if (info instanceof ActionDone) { |
| 325 | Action otheract = ((ActionDone) info).getAction(); |
| 326 | if (otheract instanceof Offer) { |
| 327 | lastReceivedBid = ((Offer) otheract).getBid(); |
| 328 | } |
| 329 | } else if (info instanceof YourTurn) { |
| 330 | myTurn(); |
| 331 | if (progress instanceof ProgressRounds) { |
| 332 | progress = ((ProgressRounds) progress).advance(); |
| 333 | } |
| 334 | } else if (info instanceof Finished) { |
| 335 | getReporter().log(Level.INFO, "Final ourcome:" + info); |
| 336 | } |
| 337 | } |
| 338 | |
| 339 | |
| 340 | private void myTurn() { |
| 341 | Action action; |
| 342 | if (isGood(lastReceivedBid)) { |
| 343 | action = new Accept(me, lastReceivedBid); |
| 344 | } else { |
| 345 | // for demo. Obviously full bids have higher util in general |
| 346 | AllPartialBidsList bidspace = new AllPartialBidsList( |
| 347 | profileint.getProfile().getDomain()); |
| 348 | Bid bid = null; |
| 349 | for (int attempt = 0; attempt < 20 && !isGood(bid); attempt++) { |
| 350 | long i = random.nextInt(bidspace.size().intValue()); |
| 351 | bid = bidspace.get(BigInteger.valueOf(i)); |
| 352 | } |
| 353 | action = new Offer(me, bid); |
| 354 | } |
| 355 | getConnection().send(action); |
| 356 | } |
| 357 | |
| 358 | private boolean isGood(Bid bid) { |
| 359 | return bid != null |
| 360 | && ((LinearAdditiveUtilitySpace) profileint.getProfile()) |
| 361 | .getUtility(bid).doubleValue() > 0.6; |
| 362 | } |
| 363 | |
| 364 | @Override |
| 365 | public Capabilities getCapabilities() { |
| 366 | return new Capabilities(new HashSet<>( |
| 367 | Arrays.asList(new ProtocolRef(new URI("SAOP"))))); |
| 368 | } |
| 369 | |
| 370 | @Override |
| 371 | public String getDescription() { |
| 372 | return "places random bids until it can accept an offer with utility >0.6"; |
| 373 | } |
| 374 | |
| 375 | } |
| 376 | }}} |
| 377 | |
| 378 | == Preparing the jar file |
| 379 | In order to put your party on the [https://tracinsy.ewi.tudelft.nl/pubtrac/GeniusWebPartiesServer partiesserver] for running, you need a jar file of your party. |
| 380 | |
| 381 | Normally the party includes all dependencies. The jar files are loaded with an isolated jar class loader that should avoid collisions with possibly identically named but possibly different packages in other jar files. |
| 382 | |
| 383 | |
| 384 | Party jar files must have a Main-Class set in the MANIFEST.MF file. This main-class must implement Party and have a no-arg constructor. |
| 385 | |
| 386 | The example randomparty does this from the maven build script. |
| 387 | |
| 388 | We recommend to do initialization of the party only in the init() and not in the constructor or static code. |
| 389 | This because instances of your class can be made both for extracting general info as getDescription(), or to really run your class. |
| 390 | |
| 391 | |
| 392 | = Writing a party in Python |
| 393 | We provide a python-to-java adapter so that you can easily write your party in python instead of Java. You can check the full working example code [source:/exampleparties/randompartypy/src/main/resources/RandomParty.py here]. A python-based party looks like this: |
| 394 | {{{ |
| 395 | class RandomParty (DefaultParty): |
| 396 | def notifyChange(self, info): |
| 397 | if isinstance(info, Settings) : |
| 398 | self.profile = ProfileConnectionFactory.create(info.getProfile().getURI(), self.getReporter()); |
| 399 | self.me = info.getID() |
| 400 | self.progress = info.getProgress() |
| 401 | elif isinstance(info , ActionDone): |
| 402 | self.lastActor = info.getAction().getActor() |
| 403 | otheract = info.getAction() |
| 404 | if isinstance(otheract, Offer): |
| 405 | self.lastReceivedBid = otheract.getBid() |
| 406 | elif isinstance(info , YourTurn): |
| 407 | self._myTurn() |
| 408 | if isinstance(self.progress, ProgressRounds) : |
| 409 | self.progress = self.progress.advance(); |
| 410 | |
| 411 | |
| 412 | |
| 413 | def getCapabilities(self): # -> Capabilities |
| 414 | return Capabilities(HashSet([ ProtocolRef(URI("SAOP"))])) |
| 415 | |
| 416 | def getDescription(self): |
| 417 | return "places random bids until it can accept an offer with utility >0.6. Python version" |
| 418 | |
| 419 | def terminate(self): |
| 420 | self.profile.disconnect() |
| 421 | |
| 422 | def _myTurn(self): |
| 423 | if self.lastReceivedBid != None and self.profile.getProfile().getUtility(self.lastReceivedBid).doubleValue() > 0.6: |
| 424 | action = Accept(self.me, self.lastReceivedBid) |
| 425 | else: |
| 426 | bidspace = AllPartialBidsList(self.profile.getProfile().getDomain()) |
| 427 | bid = None |
| 428 | for attempt in range(20): |
| 429 | i = self.random.nextInt(bidspace.size()) # warning: jython implicitly converts BigInteger to long. |
| 430 | bid = bidspace.get(BigInteger.valueOf(i)) |
| 431 | if self._isGood(bid): |
| 432 | break |
| 433 | action = Offer(self.me, bid); |
| 434 | self.getConnection().send(action) |
| 435 | |
| 436 | def _isGood(self, bid): |
| 437 | return bid != None and self.profile.getProfile().getUtility(bid).doubleValue() > 0.6; |
| 438 | |
| 439 | }}} |
| 440 | |
| 441 | You need to wrap your python party into a jar wrapper to get it accepted by the parties server. To do this, check the javadoc with the [source:/pythonadapter/src/main/java/geniusweb/pythonadapter/PythonPartyAdapter.java PythonPartyAdapter]. |
| 442 | |
| 443 | |
| 444 | = Writing a party in other languages |
| 445 | If you want to use another language than java or python2 to write your parties, you have a number of options |
| 446 | * Make your own adapter that runs your language from Java. Check [source:pythonadapter/src/main/java/geniusweb/pythonadapter/PythonPartyAdapter.java our pythonadapter] for an example how this can be done. |
| 447 | * Write your own partiesserver that correctly implements the [https://tracinsy.ewi.tudelft.nl/pubtrac/GeniusWebPartiesServer partiesserver interface]. This boils down to creating a webserver that correctly can handle calls to a number of prescribed URLs and websockets. |
| 448 | |
| 449 | = JSON layout |
| 450 | This section discusses how domains and profiles are looking in JSON. JSON is the communication format, java instances of Domain, Profile and Bid can easily be converted back and forth to JSON using the jackson objectmapper (see the test and example codes) |
| 451 | |
| 452 | == Create a domain |
| 453 | |
| 454 | |