source: src/main/webapp/newsession.xhtml@ 16

Last change on this file since 16 was 16, checked in by bart, 4 years ago

Added BOA support, some bug fixes

File size: 18.4 KB
RevLine 
[1]1<?xml version="1.0" encoding="UTF-8"?>
2<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
3<head>
4<title>Profiles and Domains list</title>
5<link rel="stylesheet" type="text/css" href="style.css" />
6
7</head>
8<body onload="init()">
9 <h1>Session</h1>
10
11 On this page you can configure the settings for running a new session
12 and start the session.
13
14 <br /> Protocol:
[8]15 <select id="selectedprotocol" onchange="selectProtocol()">
16 <option value="SAOP">SAOP (stacked alternating offers)</option>
17 <option value="SHAOP">SHAOP (stacked human alternating
18 offers)</option>
[1]19 </select>
20
21 <br /> Deadline:
22 <input type="number" id="deadlinevalue" name="deadline" min="1"
23 max="10000" value="10" />
24 <select id="deadlinetype">
[8]25 <option value="ROUNDS">rounds</option>
[1]26 <option value="TIME">seconds</option>
27 </select>
28
29 <br /> Domain/Profile Server:
30 <input type="url" name="url" id="profilesserverurl"
[16]31 value="localhost:8080/profilesserver-1.4.4"
[1]32 pattern=".*:[0-9]+/profilesserver" size="30"
33 onchange="connectDomain()"> </input>
34 <br /> Domain:
[2]35 <select id="domainselection" onchange="selectDomain()">
[1]36 <!-- <option>Waiting for profiles server</option> -->
37 </select>
38
39 <br />
40 <br />
41
42 <div id="box" class="box">
43 <br /> <b>Participants</b> <br /> Parties Server: <input type="url"
[4]44 name="url" id="partiesserverurl"
[16]45 value="localhost:8080/partiesserver-1.4.4"
[1]46 pattern=".*:[0-9]+/partiesserver" size="30"
[8]47 onchange="connectParties()"> </input> <br /> <br /> <b>Party
48 settings</b> <br /> Party : <select id="partyselection">
49 </select> <br /> Profile: <select id="profileselection"></select> Filter: <input
50 type="text" id="filter" value="" maxlength="40" /> <br />
[16]51 Parameters: {
52 <textarea id="parameters" rows="2" cols="70"
53 onchange="updateParameters()" value="" />
54 } <br /> <br />
[1]55
[8]56 <div id="cobsetting">
[16]57 <input type="checkbox" id="advancedCobSettings"
58 onchange="advancedCobSet()"></input> Advanced COB settings<br />
59 <div id="advancedsettings" style="display: none">
[8]60 <b>COB party settings</b> <br /> Party : <select
61 id="cobpartyselection">
[16]62 </select> <br /> Profile: <select id="cobprofileselection"></select> Filter:
63 <input type="text" id="cobfilter" value="" maxlength="40" /> <br />
64 <!-- -->
65 Parameters: { <textarea id="cobparameters" rows="2" cols="70"
66 onchange="updateCobParameters()" value="" /> } <br />
67 <br />
[8]68 </div>
69 </div>
70
[1]71 <button onclick="addParty()">Add</button>
72
73
74 <br /> <br /> <b>Selected Profiles, Parties for the session</b>
[8]75 <table id="selectedpartiestable" width="100%">
76 <colgroup>
77 <col />
78 <col />
79 <col />
80 <col />
81 <col />
82 <col />
83 </colgroup>
[1]84 <thead>
[8]85 <tr>
86 <th align="center">Party</th>
87 <th align="center">Parameters</th>
88 <th align="center">Profile</th>
89
90 <th align="center">COB Party</th>
91 <th align="center">COB Parameters</th>
92 <th align="center">COB Profile</th>
93 </tr>
[1]94 </thead>
95 <tbody id="partiesList">
96 </tbody>
97 </table>
98
99 </div>
100
101 <form>
102 <input id="startbutton" type="button" value="Start Session"
103 onclick="start()" />
104 </form>
105
106 <div id="started" style="visibility: hidden">
[4]107 Your session started. Waiting for the results. <br />
108 </div>
109 <div id="results" style="visibility: hidden">
[6]110 Session completed. <a href="" id="logref">view the log file</a> <br />
111 <a href="" id="plotref">render a utilities plot</a>.
[1]112 </div>
113
114</body>
115
116<script type="application/javascript">
117
118
[2]119
[4]120
[6]121
[8]122
123
124
[16]125
[1]126 // FIXME quick and dirty code. No clean MVC
127
128
129 <![CDATA[
[2]130 //"use strict";
[1]131
132 var domainwebsocket = null;
133 var partieswebsocket=null;
[6]134 // current setting of parameters
135 var parameters = {};
136
[1]137 // currently known domains (and profiles) as coming from domainwebsocket.
138 // keys are domain names, values are list of profile names
139 var knowndomains={};
140
[6]141
[1]142 /**
143 List of created participants for the session. Each participant is a dictionary.
144 Each dict element contains keys
145 "party" and "profile", both containing a String containing
146 a valid IRI to the party resp. the profile to use.
147 The party should contain a IRI that gives a new instance of the required party.
148 The profile should contain an IRI that gives the profile contents.
149 */
150 var partyprofiles=[];
[8]151
152 var cobpartyprofiles=[];
[1]153
[2]154 /** from http://fitzgeraldnick.com/2010/08/10/settimeout-patterns.html */
155
[8]156 function getAdvancedCobSettings() {
157 return document.getElementById('advancedCobSettings').checked;
158 }
159
160 function advancedCobSet() {
161 document.getElementById('advancedsettings').style.display=(getAdvancedCobSettings()?'':'none');
162 }
163
[2]164 function async (fn) {
165 setTimeout(fn, 1000);
166 }
167
168 function sometimeWhen (test, then) {
169 async(function () {
170 if ( test() ) {
171 then();
172 } else {
173 async(arguments.callee);
174 }
175 });
176 }
177
[8]178 /**
179 Called when user changes the protocol */
180 function selectProtocol() {
181 var visible=getSelectedProtocol() == "SHAOP";
182
183 document.getElementById("cobsetting").style.display=(visible ? 'block': 'none');
184 var tbl = document.getElementById('selectedpartiestable');
185 tbl.getElementsByTagName('col')[3].style.visibility=(visible?'':'collapse');
186 tbl.getElementsByTagName('col')[4].style.visibility=(visible?'':'collapse');
187 tbl.getElementsByTagName('col')[5].style.visibility=(visible?'':'collapse');
188
189 }
[2]190
[1]191 /**
192 Refresh known domains using given profilesserver URL.
193 Called when user enters URL for domain server.
194 */
195 function connectDomain() {
196 if (domainwebsocket!=null) {
197 domainwebsocket.close();
198 domainwebsocket=null;
199 }
200 var url=document.getElementById("profilesserverurl").value;
201 var target = "ws://"+url+"/websocket/liststream";
202 if ('WebSocket' in window) {
203 domainwebsocket = new WebSocket(target);
204 } else if ('MozWebSocket' in window) {
205 domainwebsocket = new MozWebSocket(target);
206 } else {
207 alert('WebSocket is not supported by this browser. Please use a newer browser');
208 return;
209 }
210 domainwebsocket.onopen = function () {
211 // whatever.
212 };
213 domainwebsocket.onmessage = function (event) {
214 updateDomainComboBox(JSON.parse(event.data));
215 };
216 domainwebsocket.onclose = function (event) {
217 alert('Info: Server closed connection. Code: ' + event.code +
218 (event.reason == "" ? "" : ", Reason: " + event.reason));
219 domainwebsocket=null;
220 updateDomainComboBox({});
221 };
222 }
223
224 /**
225 Sets a new knowndomains value and Updates the contents of the domain selector combobox.
226 @param the known domains, a map of the form {"jobs":["jobs1","jobs2"]}
227 where the keys are the names of the available domains nd the values a list of the available profiles in that domain.
228
229 */
230 function updateDomainComboBox(newdomains) {
231 knowndomains=newdomains
232 var combobox = document.getElementById("domainselection");
233 combobox.options.length=0;
234 for (var domain in knowndomains) {
235 var option = document.createElement('option');
236 option.text = option.value = domain;
237 combobox.add(option, 0);
238 }
239 selectDomain();
240 }
241 /**
242 Refresh known parties using given partiesserver URL.
243 Called when user enters URL for parties server.
244 */
245 function connectParties() {
246 if (partieswebsocket!=null) {
247 partieswebsocket.close();
248 partieswebsocket=null;
249 }
250 var url=document.getElementById("partiesserverurl").value;
251 var target = "ws://"+url+"/available";
252 if ('WebSocket' in window) {
253 partieswebsocket = new WebSocket(target);
254 } else if ('MozWebSocket' in window) {
255 partieswebsocket = new MozWebSocket(target);
256 } else {
257 alert('WebSocket is not supported by this browser. Please use a newer browser');
258 return;
259 }
260 partieswebsocket.onopen = function () {
261 // whatever.
262 };
263 partieswebsocket.onmessage = function (event) {
264 updateParties(JSON.parse(event.data));
265 };
266 partieswebsocket.onclose = function (event) {
267 alert('Info: Server closed connection. Code: ' + event.code +
268 (event.reason == "" ? "" : ", Reason: " + event.reason));
269 partieswebsocket=null;
270 updateParties({});
271 };
272 }
273
274
275 /**
276 refresh table: copy all parties elements in there.
277 Typically parties is something like
[16]278 [{"uri":"http:130.161.180.1:8080/partiesserver/run/randomparty-1.4.4",
[1]279 "capabilities":{"protocols":["SAOP"]},
280 "description":"places random bids until it can accept an offer with utility >0.6",
[16]281 "id":"randomparty-1.4.4",
[1]282 "partyClass":"geniusweb.exampleparties.randomparty.RandomParty"},
283 ...]
284 */
285 function updateParties(parties) {
[8]286 updatePartiesCombobox(parties, document.getElementById("partyselection"),['SAOP','SHAOP']);
287 updatePartiesCombobox(parties, document.getElementById("cobpartyselection"),['COB']);
288 }
289
290 /**
291 @param parties a list of parties r(as received from the server)
292 @param combobox a combobox element to put the party URLs in
293 @param behaviours a list of behaviours for the parties. Only these are put in the combobox.
294 */
295 function updatePartiesCombobox(parties, combobox, behaviours) {
[1]296 combobox.options.length=0;
[8]297 for (var p in parties) {
298 var party = parties[p];
299 if (intersect(party.capabilities.behaviours, behaviours).length==0)
300 continue;
[1]301 var option = document.createElement('option');
[8]302 option.text = option.value = party.uri;
[1]303 combobox.add(option, 0);
304 }
305
[8]306 }
307
[6]308 /**
[8]309 @param a a list
310 @param b another list
311 @return intersection of a and b
312 */
313 function intersect(a, b) {
314 var t;
315 if (b.length > a.length) t = b, b = a, a = t; // indexOf to loop over shorter
316 return a.filter(function (e) {
317 return b.indexOf(e) > -1;
318 });
319 }
320
321
322 /**
[6]323 updates parameters field to match the given text.
324 */
325 function updateParameters() {
326 var text="{"+document.getElementById("parameters").value+"}";
327 try {
328 parameters=JSON.parse(text);
329 } catch(e) {
330 alert("Parameters can not be parsed. "+e);
331 return;
332 }
333 }
[1]334
335 /**
336 Called when the selected domain changes. Assumes knowndomains has been set.
337 Updates the available profiles in the profile combobox.
338 @param selection the name of the selected domain.
339 */
340 function selectDomain() {
341 // determined current selection
342 var domaincombobox = document.getElementById("domainselection");
343 if (domaincombobox.options.length==0) return; // fixme clean profiles options?
344 var domain = domaincombobox.options[domaincombobox.selectedIndex].value;
345
[8]346 updateProfileComboBox(document.getElementById("profileselection"), knowndomains[domain]);
347 updateProfileComboBox(document.getElementById("cobprofileselection"), knowndomains[domain]);
348 }
349
350 function updateProfileComboBox(profilecombo, options) {
[1]351 profilecombo.options.length=0;
[8]352 for (var profile in options) {
[1]353 var option = document.createElement('option');
[8]354 option.text = option.value = options[profile];
[1]355 profilecombo.add(option, 0);
356 }
[8]357
[1]358 }
359
360 /**
361 Called when user clicks "Add"
362 */
363 function addParty() {
[8]364 addNormalParty();
365 addCobParty();
366 updatePartyProfileTable(); // what, MVC?
367 }
368
369 function addNormalParty() {
[1]370 var partycombo = document.getElementById("partyselection");
371 var profilecombo = document.getElementById("profileselection");
[8]372 var filteroptions = document.getElementById("filter").value;
[1]373
374 if (partycombo.options.length==0) {
375 alert("Please set partier server and select a party");
376 return;
377 }
378 if (profilecombo.options.length==0) {
379 alert("Please set domain/profile server and select a domain and a profile");
380 return;
381 }
[8]382
383 if (filteroptions!="") {
384 filteroptions="?"+filteroptions;
385 }
[1]386 var newpartyprof = {};
[8]387 newpartyprof["party"]={"partyref":partycombo.options[partycombo.selectedIndex].value ,
[6]388 "parameters":parameters };
[8]389 newpartyprof["profile"]=profilecombo.options[profilecombo.selectedIndex].value +filteroptions;
[1]390
391 partyprofiles.push(newpartyprof)
392 }
393
[8]394
395 function addCobParty() {
396 // we assume a sensible default has been loaded into the combo and set,
397 // regardless it being invisible
398 var partycombo = document.getElementById("cobpartyselection");
399 if (partycombo.options.length==0) {
400 alert("Please set cpb partier server and select a party");
401 return;
402 }
403
404 var newpartyprof = {};
405 if (getAdvancedCobSettings()) {
406 var profilecombo = document.getElementById("cobprofileselection");
407 var filteroptions = document.getElementById("cobfilter").value;
408
409 if (profilecombo.options.length==0) {
410 alert("Please set a cob profile");
411 return;
412 }
413 if (filteroptions!="") {
414 filteroptions="?"+filteroptions;
415 }
416 newpartyprof["party"]={"partyref":partycombo.options[partycombo.selectedIndex].value ,
417 "parameters":parameters };
418 newpartyprof["profile"]=profilecombo.options[profilecombo.selectedIndex].value +filteroptions;
419 } else {
420 var profilecombo = document.getElementById("profileselection");
421 newpartyprof["party"]={"partyref":partycombo.options[partycombo.selectedIndex].value ,
422 "parameters":{} };
423 newpartyprof["profile"]=profilecombo.options[profilecombo.selectedIndex].value;
424 }
425 cobpartyprofiles.push(newpartyprof)
426 }
427
428
[1]429 /** updates the party and profiles table, to match the #partyprofiles list. */
430 function updatePartyProfileTable() {
431 var table = document.getElementById("partiesList");
432 table.innerHTML = ""; // clear table
433 for ( var pp in partyprofiles) {
434 var row = table.insertRow(-1);
435 var cell1 = row.insertCell(-1);
436 var cell2 = row.insertCell(-1);
[6]437 var cell3 = row.insertCell(-1);
[8]438 var cell4 = row.insertCell(-1);
439 var cell5 = row.insertCell(-1);
440 var cell6 = row.insertCell(-1);
441
[6]442 cell1.innerHTML = partyprofiles[pp]["party"]["partyref"];
[16]443 // help browser breaking too large strings
444 cell2.innerHTML = JSON.stringify(partyprofiles[pp]["party"]["parameters"]).replace(/,/g,", ");
445 cell2.setAttribute("style","overflow-wrap: anywhere;");
[6]446 cell3.innerHTML = partyprofiles[pp]["profile"];
[8]447 cell4.innerHTML = cobpartyprofiles[pp]["party"]["partyref"];
[16]448 cell5.innerHTML = JSON.stringify(cobpartyprofiles[pp]["party"]["parameters"]).replace(/,/g,", ");
449 cell5.setAttribute("style","overflow-wrap: anywhere;");
[8]450 cell6.innerHTML = cobpartyprofiles[pp]["profile"];
[1]451 }
452
453 }
454
[2]455 var x=1;
[1]456 /**
457 start the session as currently set on this page.
458 We need to send a SessionSettings object to the server, which typically looks like this
459 but is protocol dependent (currently we do SAOP)
460
461 {"SAOPSettings":
462 {"participants":[
[6]463 {"party":{"partyref":"http://party1","parameters":{}},"profile":"ws://profile1"},
464 {"party":{"partyref",}"http://party2","parameters":{}},"profile":"ws://profile2"}],
[1]465 "deadline":{"deadlinetime":{"durationms":100}}}}
466
467 participants are already in the global partyprofiles dictionary
468 */
469 function start() {
470 if (Object.keys(partyprofiles).length <2) {
471 alert("At least 2 parties are needed to run a session.");
472 return;
473 }
474
475 // see https://www.w3schools.com/xml/dom_httprequest.asp
[5]476 document.getElementById("startbutton").disabled=true;
477 document.getElementById("started").setAttribute("style","");
478
479 var xmlHttp = new XMLHttpRequest();
[1]480 xmlHttp.onreadystatechange = function() {
481 if (this.readyState == 4) {
482 if (this.status == 200) {
[4]483 var logurl="log/"+this.responseText+".json";
484 document.getElementById("logref").href=logurl;
[1]485 document.getElementById("plotref").href="plotlog.xhtml?id="+this.responseText;
486
[4]487 sometimeWhen(function() { return urlExists(logurl) },
488 function() { document.getElementById("results").setAttribute("style",""); });
[2]489
[1]490 }
491 else
492 alert("request failed:"+this.statusText);
493 }
494 }
495 xmlHttp.open("POST", "run", true);
496 xmlHttp.send(makeRequest());
497
498 }
499
[4]500
501 /**
502 @return true iff the URL exists.
503 */
504 function urlExists(urlToFile) {
505 // Warning. Synchronous XMLHttpRequest on the main thread is
506 // deprecated because of its detrimental effects to the end user’s
507 // experience. For more help http://xhr.spec.whatwg.org/
508 var xhr = new XMLHttpRequest();
509 xhr.open('HEAD', urlToFile, false);
510 xhr.send();
511
512 return (xhr.status == "200")
513 }
[1]514
[8]515 function getSelectedProtocol() {
516 var protocolcombo = document.getElementById("selectedprotocol");
517 return protocolcombo.options[protocolcombo.selectedIndex].value;
518 }
[1]519 /**
520 @return a json request package for the run server
521 */
522 function makeRequest() {
[8]523
524 if (getSelectedProtocol()=="SHAOP") {
525 return makeShaopRequest();
526 } else {
527 return makeSaopRequest();
528 }
529 }
530
531 /**
532 @return a SAOP request
533 */
534 function makeSaopRequest() {
[1]535 var deadline={};
536 var value = document.getElementById("deadlinevalue").value;
537 var dtypecombo = document.getElementById("deadlinetype");
538 if (dtypecombo.options[dtypecombo.selectedIndex].value=="TIME") {
539 deadline["deadlinetime"] = { "durationms": 1000*value};
540 } else {
541 // ROUNDS
542 deadline["deadlinerounds"] = {"rounds": value, "durationms":10000};
543 }
544
545 return JSON.stringify({"SAOPSettings": { "participants": partyprofiles, "deadline":deadline }});
[8]546 }
[1]547
[8]548 /**
549 @return a SHAOP request
550 */
551 function makeShaopRequest() {
552 var deadline={};
553 var value = document.getElementById("deadlinevalue").value;
554 var dtypecombo = document.getElementById("deadlinetype");
555 if (dtypecombo.options[dtypecombo.selectedIndex].value=="TIME") {
556 deadline["deadlinetime"] = { "durationms": 1000*value};
557 } else {
558 // ROUNDS
559 deadline["deadlinerounds"] = {"rounds": value, "durationms":10000};
560 }
561
562 var parties=[];
563 for (let i=0; i< partyprofiles.length; i++) {
564 var group={};
565 group['shaop'] = partyprofiles[i];
566 group['cob'] = cobpartyprofiles[i];
567
568 parties.push(group);
569 }
570 return JSON.stringify({"SHAOPSettings": { "participants": parties, "deadline":deadline }});
[1]571 }
[8]572
[1]573
574 /**
575 Initialize the page after html is loaded.
576 */
577 function init() {
[8]578 selectProtocol();
[16]579 document.getElementById("partiesserverurl").value =window.location.hostname+":8080/partiesserver-1.4.4"
580 document.getElementById("profilesserverurl").value =window.location.hostname+":8080/profilesserver-1.4.4"
[1]581 connectDomain();
582 connectParties();
583
584 }
585 ]]>
586
587
[4]588
[6]589
[8]590
591
592
[16]593
[1]594</script>
595
596</html>
Note: See TracBrowser for help on using the repository browser.