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

Last change on this file since 6 was 6, checked in by bart, 5 years ago

Added parameter support

File size: 12.5 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>
16 <option value="SAOP">SAOP</option>
17 </select>
18
19 <br /> Deadline:
20 <input type="number" id="deadlinevalue" name="deadline" min="1"
21 max="10000" value="10" />
22 <select id="deadlinetype">
23 <option value="TIME">seconds</option>
24 <option value="ROUNDS">rounds</option>
25 </select>
26
27 <br /> Domain/Profile Server:
28 <input type="url" name="url" id="profilesserverurl"
29 value="localhost:8080/profilesserver-1.0.0"
30 pattern=".*:[0-9]+/profilesserver" size="30"
31 onchange="connectDomain()"> </input>
32 <br /> Domain:
33 <select id="domainselection" onchange="selectDomain()">
34 <!-- <option>Waiting for profiles server</option> -->
35 </select>
36
37 <br />
38 <br />
39
40 <div id="box" class="box">
41 <br /> <b>Participants</b> <br /> Parties Server: <input type="url"
42 name="url" id="partiesserverurl"
43 value="localhost:8080/partiesserver-1.0.0"
44 pattern=".*:[0-9]+/partiesserver" size="30"
45 onchange="connectParties()"> </input> <br /> <br /> <b>Edit
46 next party</b> <br /> Party: <select id="partyselection">
47 </select> <br /> Profile: <select id="profileselection">
48 </select> <br /> Parameters: { <input type="text" id="parameters"
49 onchange="updateParameters()" value="" maxlength="100" /> } <br /> <br />
50
51 <button onclick="addParty()">Add</button>
52
53
54 <br /> <br /> <b>Selected Profiles, Parties for the session</b>
55 <table>
56 <thead>
57 <th align="left" width='40%'>Party</th>
58 <th align="left" width='20%'>Parameters</th>
59 <th align="left" width='40%'>Profile</th>
60 </thead>
61 <tbody id="partiesList">
62 <tr id="partiesList">
63 </tr>
64
65 </tbody>
66 </table>
67
68 </div>
69
70 <form>
71 <input id="startbutton" type="button" value="Start Session"
72 onclick="start()" />
73 </form>
74
75 <div id="started" style="visibility: hidden">
76 Your session started. Waiting for the results. <br />
77 </div>
78 <div id="results" style="visibility: hidden">
79 Session completed. <a href="" id="logref">view the log file</a> <br />
80 <a href="" id="plotref">render a utilities plot</a>.
81 </div>
82
83</body>
84
85<script type="application/javascript">
86
87
88
89
90
91 // FIXME quick and dirty code. No clean MVC
92
93
94 <![CDATA[
95 //"use strict";
96
97 var domainwebsocket = null;
98 var partieswebsocket=null;
99 // current setting of parameters
100 var parameters = {};
101
102 // currently known domains (and profiles) as coming from domainwebsocket.
103 // keys are domain names, values are list of profile names
104 var knowndomains={};
105
106
107 /**
108 List of created participants for the session. Each participant is a dictionary.
109 Each dict element contains keys
110 "party" and "profile", both containing a String containing
111 a valid IRI to the party resp. the profile to use.
112 The party should contain a IRI that gives a new instance of the required party.
113 The profile should contain an IRI that gives the profile contents.
114 */
115 var partyprofiles=[];
116
117 /** from http://fitzgeraldnick.com/2010/08/10/settimeout-patterns.html */
118
119 function async (fn) {
120 setTimeout(fn, 1000);
121 }
122
123 function sometimeWhen (test, then) {
124 async(function () {
125 if ( test() ) {
126 then();
127 } else {
128 async(arguments.callee);
129 }
130 });
131 }
132
133
134
135 /**
136 Refresh known domains using given profilesserver URL.
137 Called when user enters URL for domain server.
138 */
139 function connectDomain() {
140 if (domainwebsocket!=null) {
141 domainwebsocket.close();
142 domainwebsocket=null;
143 }
144 var url=document.getElementById("profilesserverurl").value;
145 var target = "ws://"+url+"/websocket/liststream";
146 if ('WebSocket' in window) {
147 domainwebsocket = new WebSocket(target);
148 } else if ('MozWebSocket' in window) {
149 domainwebsocket = new MozWebSocket(target);
150 } else {
151 alert('WebSocket is not supported by this browser. Please use a newer browser');
152 return;
153 }
154 domainwebsocket.onopen = function () {
155 // whatever.
156 };
157 domainwebsocket.onmessage = function (event) {
158 updateDomainComboBox(JSON.parse(event.data));
159 };
160 domainwebsocket.onclose = function (event) {
161 alert('Info: Server closed connection. Code: ' + event.code +
162 (event.reason == "" ? "" : ", Reason: " + event.reason));
163 domainwebsocket=null;
164 updateDomainComboBox({});
165 };
166 }
167
168 /**
169 Sets a new knowndomains value and Updates the contents of the domain selector combobox.
170 @param the known domains, a map of the form {"jobs":["jobs1","jobs2"]}
171 where the keys are the names of the available domains nd the values a list of the available profiles in that domain.
172
173 */
174 function updateDomainComboBox(newdomains) {
175 knowndomains=newdomains
176 var combobox = document.getElementById("domainselection");
177 combobox.options.length=0;
178 for (var domain in knowndomains) {
179 var option = document.createElement('option');
180 option.text = option.value = domain;
181 combobox.add(option, 0);
182 }
183 selectDomain();
184 }
185 /**
186 Refresh known parties using given partiesserver URL.
187 Called when user enters URL for parties server.
188 */
189 function connectParties() {
190 if (partieswebsocket!=null) {
191 partieswebsocket.close();
192 partieswebsocket=null;
193 }
194 var url=document.getElementById("partiesserverurl").value;
195 var target = "ws://"+url+"/available";
196 if ('WebSocket' in window) {
197 partieswebsocket = new WebSocket(target);
198 } else if ('MozWebSocket' in window) {
199 partieswebsocket = new MozWebSocket(target);
200 } else {
201 alert('WebSocket is not supported by this browser. Please use a newer browser');
202 return;
203 }
204 partieswebsocket.onopen = function () {
205 // whatever.
206 };
207 partieswebsocket.onmessage = function (event) {
208 updateParties(JSON.parse(event.data));
209 };
210 partieswebsocket.onclose = function (event) {
211 alert('Info: Server closed connection. Code: ' + event.code +
212 (event.reason == "" ? "" : ", Reason: " + event.reason));
213 partieswebsocket=null;
214 updateParties({});
215 };
216 }
217
218
219 /**
220 refresh table: copy all parties elements in there.
221 Typically parties is something like
222 [{"uri":"http:130.161.180.1:8080/partiesserver/run/randomparty-1.0.0",
223 "capabilities":{"protocols":["SAOP"]},
224 "description":"places random bids until it can accept an offer with utility >0.6",
225 "id":"randomparty-1.0.0",
226 "partyClass":"geniusweb.exampleparties.randomparty.RandomParty"},
227 ...]
228 */
229 function updateParties(parties) {
230 var combobox = document.getElementById("partyselection");
231 combobox.options.length=0;
232 for (var party in parties) {
233 var option = document.createElement('option');
234 option.text = option.value = parties[party].uri;
235 combobox.add(option, 0);
236 }
237 }
238
239
240 /**
241 updates parameters field to match the given text.
242 */
243 function updateParameters() {
244 var text="{"+document.getElementById("parameters").value+"}";
245 try {
246 parameters=JSON.parse(text);
247 } catch(e) {
248 alert("Parameters can not be parsed. "+e);
249 return;
250 }
251 }
252
253 /**
254 Called when the selected domain changes. Assumes knowndomains has been set.
255 Updates the available profiles in the profile combobox.
256 @param selection the name of the selected domain.
257 */
258 function selectDomain() {
259 // determined current selection
260 var domaincombobox = document.getElementById("domainselection");
261 if (domaincombobox.options.length==0) return; // fixme clean profiles options?
262 var domain = domaincombobox.options[domaincombobox.selectedIndex].value;
263
264 var profilecombo = document.getElementById("profileselection");
265 profilecombo.options.length=0;
266 for (var profile in knowndomains[domain]) {
267 var option = document.createElement('option');
268 option.text = option.value = knowndomains[domain][profile];
269 profilecombo.add(option, 0);
270 }
271 }
272
273 /**
274 Called when user clicks "Add"
275 */
276 function addParty() {
277 var partycombo = document.getElementById("partyselection");
278 var profilecombo = document.getElementById("profileselection");
279
280 if (partycombo.options.length==0) {
281 alert("Please set partier server and select a party");
282 return;
283 }
284 if (profilecombo.options.length==0) {
285 alert("Please set domain/profile server and select a domain and a profile");
286 return;
287 }
288 var newpartyprof = {};
289
290 newpartyprof["party"]={"partyref":partycombo.options[partycombo.selectedIndex].value,
291 "parameters":parameters };
292 newpartyprof["profile"]=profilecombo.options[profilecombo.selectedIndex].value;
293
294 partyprofiles.push(newpartyprof)
295 updatePartyProfileTable(); // what, MVC?
296 }
297
298 /** updates the party and profiles table, to match the #partyprofiles list. */
299 function updatePartyProfileTable() {
300 var table = document.getElementById("partiesList");
301 table.innerHTML = ""; // clear table
302 for ( var pp in partyprofiles) {
303 var row = table.insertRow(-1);
304 var cell1 = row.insertCell(-1);
305 var cell2 = row.insertCell(-1);
306 var cell3 = row.insertCell(-1);
307 cell1.innerHTML = partyprofiles[pp]["party"]["partyref"];
308 cell2.innerHTML = JSON.stringify(partyprofiles[pp]["party"]["parameters"]);
309 cell3.innerHTML = partyprofiles[pp]["profile"];
310 }
311
312 }
313
314 var x=1;
315 /**
316 start the session as currently set on this page.
317 We need to send a SessionSettings object to the server, which typically looks like this
318 but is protocol dependent (currently we do SAOP)
319
320 {"SAOPSettings":
321 {"participants":[
322 {"party":{"partyref":"http://party1","parameters":{}},"profile":"ws://profile1"},
323 {"party":{"partyref",}"http://party2","parameters":{}},"profile":"ws://profile2"}],
324 "deadline":{"deadlinetime":{"durationms":100}}}}
325
326 participants are already in the global partyprofiles dictionary
327 */
328 function start() {
329 if (Object.keys(partyprofiles).length <2) {
330 alert("At least 2 parties are needed to run a session.");
331 return;
332 }
333
334 // see https://www.w3schools.com/xml/dom_httprequest.asp
335 document.getElementById("startbutton").disabled=true;
336 document.getElementById("started").setAttribute("style","");
337
338 var xmlHttp = new XMLHttpRequest();
339 xmlHttp.onreadystatechange = function() {
340 if (this.readyState == 4) {
341 if (this.status == 200) {
342 var logurl="log/"+this.responseText+".json";
343 document.getElementById("logref").href=logurl;
344 document.getElementById("plotref").href="plotlog.xhtml?id="+this.responseText;
345
346 sometimeWhen(function() { return urlExists(logurl) },
347 function() { document.getElementById("results").setAttribute("style",""); });
348
349 }
350 else
351 alert("request failed:"+this.statusText);
352 }
353 }
354 xmlHttp.open("POST", "run", true);
355 xmlHttp.send(makeRequest());
356
357 }
358
359
360 /**
361 @return true iff the URL exists.
362 */
363 function urlExists(urlToFile) {
364 // Warning. Synchronous XMLHttpRequest on the main thread is
365 // deprecated because of its detrimental effects to the end user’s
366 // experience. For more help http://xhr.spec.whatwg.org/
367 var xhr = new XMLHttpRequest();
368 xhr.open('HEAD', urlToFile, false);
369 xhr.send();
370
371 return (xhr.status == "200")
372 }
373
374 /**
375 @return a json request package for the run server
376 */
377 function makeRequest() {
378 var deadline={};
379 var value = document.getElementById("deadlinevalue").value;
380 var dtypecombo = document.getElementById("deadlinetype");
381 if (dtypecombo.options[dtypecombo.selectedIndex].value=="TIME") {
382 deadline["deadlinetime"] = { "durationms": 1000*value};
383 } else {
384 // ROUNDS
385 deadline["deadlinerounds"] = {"rounds": value, "durationms":10000};
386 }
387
388
389 return JSON.stringify({"SAOPSettings": { "participants": partyprofiles, "deadline":deadline }});
390
391 }
392
393
394 /**
395 Initialize the page after html is loaded.
396 */
397 function init() {
398 document.getElementById("partiesserverurl").value =window.location.hostname+":8080/partiesserver-1.0.0"
399 document.getElementById("profilesserverurl").value =window.location.hostname+":8080/profilesserver-1.0.0"
400 connectDomain();
401 connectParties();
402
403 }
404 ]]>
405
406
407
408
409</script>
410
411</html>
Note: See TracBrowser for help on using the repository browser.