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
Line 
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:
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>
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">
25 <option value="ROUNDS">rounds</option>
26 <option value="TIME">seconds</option>
27 </select>
28
29 <br /> Domain/Profile Server:
30 <input type="url" name="url" id="profilesserverurl"
31 value="localhost:8080/profilesserver-1.4.4"
32 pattern=".*:[0-9]+/profilesserver" size="30"
33 onchange="connectDomain()"> </input>
34 <br /> Domain:
35 <select id="domainselection" onchange="selectDomain()">
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"
44 name="url" id="partiesserverurl"
45 value="localhost:8080/partiesserver-1.4.4"
46 pattern=".*:[0-9]+/partiesserver" size="30"
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 />
51 Parameters: {
52 <textarea id="parameters" rows="2" cols="70"
53 onchange="updateParameters()" value="" />
54 } <br /> <br />
55
56 <div id="cobsetting">
57 <input type="checkbox" id="advancedCobSettings"
58 onchange="advancedCobSet()"></input> Advanced COB settings<br />
59 <div id="advancedsettings" style="display: none">
60 <b>COB party settings</b> <br /> Party : <select
61 id="cobpartyselection">
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 />
68 </div>
69 </div>
70
71 <button onclick="addParty()">Add</button>
72
73
74 <br /> <br /> <b>Selected Profiles, Parties for the session</b>
75 <table id="selectedpartiestable" width="100%">
76 <colgroup>
77 <col />
78 <col />
79 <col />
80 <col />
81 <col />
82 <col />
83 </colgroup>
84 <thead>
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>
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">
107 Your session started. Waiting for the results. <br />
108 </div>
109 <div id="results" style="visibility: hidden">
110 Session completed. <a href="" id="logref">view the log file</a> <br />
111 <a href="" id="plotref">render a utilities plot</a>.
112 </div>
113
114</body>
115
116<script type="application/javascript">
117
118
119
120
121
122
123
124
125
126 // FIXME quick and dirty code. No clean MVC
127
128
129 <![CDATA[
130 //"use strict";
131
132 var domainwebsocket = null;
133 var partieswebsocket=null;
134 // current setting of parameters
135 var parameters = {};
136
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
141
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=[];
151
152 var cobpartyprofiles=[];
153
154 /** from http://fitzgeraldnick.com/2010/08/10/settimeout-patterns.html */
155
156 function getAdvancedCobSettings() {
157 return document.getElementById('advancedCobSettings').checked;
158 }
159
160 function advancedCobSet() {
161 document.getElementById('advancedsettings').style.display=(getAdvancedCobSettings()?'':'none');
162 }
163
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
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 }
190
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
278 [{"uri":"http:130.161.180.1:8080/partiesserver/run/randomparty-1.4.4",
279 "capabilities":{"protocols":["SAOP"]},
280 "description":"places random bids until it can accept an offer with utility >0.6",
281 "id":"randomparty-1.4.4",
282 "partyClass":"geniusweb.exampleparties.randomparty.RandomParty"},
283 ...]
284 */
285 function updateParties(parties) {
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) {
296 combobox.options.length=0;
297 for (var p in parties) {
298 var party = parties[p];
299 if (intersect(party.capabilities.behaviours, behaviours).length==0)
300 continue;
301 var option = document.createElement('option');
302 option.text = option.value = party.uri;
303 combobox.add(option, 0);
304 }
305
306 }
307
308 /**
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 /**
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 }
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
346 updateProfileComboBox(document.getElementById("profileselection"), knowndomains[domain]);
347 updateProfileComboBox(document.getElementById("cobprofileselection"), knowndomains[domain]);
348 }
349
350 function updateProfileComboBox(profilecombo, options) {
351 profilecombo.options.length=0;
352 for (var profile in options) {
353 var option = document.createElement('option');
354 option.text = option.value = options[profile];
355 profilecombo.add(option, 0);
356 }
357
358 }
359
360 /**
361 Called when user clicks "Add"
362 */
363 function addParty() {
364 addNormalParty();
365 addCobParty();
366 updatePartyProfileTable(); // what, MVC?
367 }
368
369 function addNormalParty() {
370 var partycombo = document.getElementById("partyselection");
371 var profilecombo = document.getElementById("profileselection");
372 var filteroptions = document.getElementById("filter").value;
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 }
382
383 if (filteroptions!="") {
384 filteroptions="?"+filteroptions;
385 }
386 var newpartyprof = {};
387 newpartyprof["party"]={"partyref":partycombo.options[partycombo.selectedIndex].value ,
388 "parameters":parameters };
389 newpartyprof["profile"]=profilecombo.options[profilecombo.selectedIndex].value +filteroptions;
390
391 partyprofiles.push(newpartyprof)
392 }
393
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
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);
437 var cell3 = row.insertCell(-1);
438 var cell4 = row.insertCell(-1);
439 var cell5 = row.insertCell(-1);
440 var cell6 = row.insertCell(-1);
441
442 cell1.innerHTML = partyprofiles[pp]["party"]["partyref"];
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;");
446 cell3.innerHTML = partyprofiles[pp]["profile"];
447 cell4.innerHTML = cobpartyprofiles[pp]["party"]["partyref"];
448 cell5.innerHTML = JSON.stringify(cobpartyprofiles[pp]["party"]["parameters"]).replace(/,/g,", ");
449 cell5.setAttribute("style","overflow-wrap: anywhere;");
450 cell6.innerHTML = cobpartyprofiles[pp]["profile"];
451 }
452
453 }
454
455 var x=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":[
463 {"party":{"partyref":"http://party1","parameters":{}},"profile":"ws://profile1"},
464 {"party":{"partyref",}"http://party2","parameters":{}},"profile":"ws://profile2"}],
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
476 document.getElementById("startbutton").disabled=true;
477 document.getElementById("started").setAttribute("style","");
478
479 var xmlHttp = new XMLHttpRequest();
480 xmlHttp.onreadystatechange = function() {
481 if (this.readyState == 4) {
482 if (this.status == 200) {
483 var logurl="log/"+this.responseText+".json";
484 document.getElementById("logref").href=logurl;
485 document.getElementById("plotref").href="plotlog.xhtml?id="+this.responseText;
486
487 sometimeWhen(function() { return urlExists(logurl) },
488 function() { document.getElementById("results").setAttribute("style",""); });
489
490 }
491 else
492 alert("request failed:"+this.statusText);
493 }
494 }
495 xmlHttp.open("POST", "run", true);
496 xmlHttp.send(makeRequest());
497
498 }
499
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 }
514
515 function getSelectedProtocol() {
516 var protocolcombo = document.getElementById("selectedprotocol");
517 return protocolcombo.options[protocolcombo.selectedIndex].value;
518 }
519 /**
520 @return a json request package for the run server
521 */
522 function makeRequest() {
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() {
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 }});
546 }
547
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 }});
571 }
572
573
574 /**
575 Initialize the page after html is loaded.
576 */
577 function init() {
578 selectProtocol();
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"
581 connectDomain();
582 connectParties();
583
584 }
585 ]]>
586
587
588
589
590
591
592
593
594</script>
595
596</html>
Note: See TracBrowser for help on using the repository browser.