Merge "Inherit from oparent"
[vfc/nfvo/wfengine.git] / winery / org.eclipse.winery.repository / src / main / webapp / jsp / interfaces / interfaces.jsp
1 <%--
2 /*******************************************************************************
3  * Copyright (c) 2012-2013 University of Stuttgart.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * and the Apache License 2.0 which both accompany this distribution,
7  * and are available at http://www.eclipse.org/legal/epl-v10.html
8  * and http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Contributors:
11  *    Oliver Kopp - initial API and implementation and/or initial documentation
12  *    Yves Schubert - port to bootstrap 3
13  *******************************************************************************/
14 --%>
15 <%@taglib prefix="c"  uri="http://java.sun.com/jsp/jstl/core"%>
16 <%@taglib prefix="t"  tagdir="/WEB-INF/tags" %>
17 <%@taglib prefix="ct" tagdir="/WEB-INF/tags/common" %>
18 <%@taglib prefix="p"  tagdir="/WEB-INF/tags/parameters" %>
19 <%@taglib prefix="w"  uri="http://www.eclipse.org/winery/repository/functions"%>
20
21 <%@page import="org.eclipse.winery.common.Util" %>
22 <%@page import="org.eclipse.winery.repository.Constants" %>
23
24 <link type="text/css" href="${pageContext.request.contextPath}/components/bootstrap-switch/build/css/bootstrap3/bootstrap-switch.css" rel="stylesheet" />
25 <script type="text/javascript" src="${pageContext.request.contextPath}/components/bootstrap-switch/build/js/bootstrap-switch.js"></script>
26
27 <%-- include basic parameters support --%>
28 <p:parametersJS afterLoad="interfaceSelectionChanged();"></p:parametersJS>
29
30 <script>
31 <%final String URI_LIFECYCLE_INTERFACE = "http://www.example.com/interfaces/lifecycle";%>
32 var URI_LIFECYCLE_INTERFACE = "<%=URI_LIFECYCLE_INTERFACE%>";
33
34 /**
35  * @param noUpdate if given, then the selection is not updated. This is required when Winery itself creates interfaces without user intervention. For instance, that is the case at the lifecycle interface
36  */
37 function afterInterfaceCreation(serializedArray, resData, textStatus, jqXHR, noUpdate) {
38         var text = serializedArray[0].value;
39         if (text == URI_LIFECYCLE_INTERFACE) {
40                 // lifecycle interface has been generated
41                 // disable button to generate lifecycle interface
42                 $("#generatelifecycleifacetn").attr("disabled", "disabled");
43         }
44         addSortedSelectionItem($("#interfaces"), text, text);
45         if (!noUpdate) {
46                 interfaceSelectionChanged();
47         }
48 }
49
50 function afterOperationCreation(serializedArray, resData, textStatus, jqXHR) {
51         var text = serializedArray[0].value;
52         addSortedSelectionItem($("#operations"), text, text);
53         operationSelectionChanged();
54 }
55
56 function getIfaceURL() {
57         var iface = $("#interfaces").find(":selected").val();
58         return "${it.urlPrefix}interfaces/" + encodeID(iface) + "/";
59 }
60
61 function getOperationURL() {
62         var op = $("#operations").find(":selected").val();
63         return getIfaceURL() + "operations/" + encodeID(op) + "/";
64 }
65
66 function createInterface() {
67         createResource('Interface', [{'label': 'Name', 'name':'interfaceName'}], '${it.urlPrefix}interfaces/', afterInterfaceCreation);
68 }
69
70 function createOperation() {
71         var url = getIfaceURL() + "operations/";
72         createResource('Operation', [{'label':'Name', 'name':'name'}], url, afterOperationCreation);
73 }
74
75 function disableAllOperationButtons() {
76         $("#addOpBtn").attr("disabled", "disabled");
77         $("#removeOpBtn").attr("disabled", "disabled");
78 }
79
80 function disableAllInputButtons() {
81         $("#addInParBtn").attr("disabled", "disabled");
82         $("#removeInParBtn").attr("disabled", "disabled");
83 }
84
85 function disableAllOutputButtons() {
86         $("#addOutParBtn").attr("disabled", "disabled");
87         $("#removeOutParBtn").attr("disabled", "disabled");
88 }
89
90 function interfaceSelectionChanged(noupdate) {
91         iface = $("#interfaces").find(":selected");
92         if (iface.length == 0) {
93                 // nothing selected
94                 $("#operations").empty();
95                 inputParametersTableInfo.table.fnClearTable();
96                 outputParametersTableInfo.table.fnClearTable();
97                 disableAllOperationButtons();
98                 disableAllInputButtons();
99                 disableAllOutputButtons();
100                 $("#removeIfBtn").attr("disabled", "disabled");
101                 $("#generateiabtn").attr("disabled", "disabled");
102         } else {
103                 $.ajax({
104                         "url": getIfaceURL() + "operations/",
105                         dataType: "JSON",
106                         success: function(data, textStatus, jqXHR) {
107                                 var operations = $("#operations");
108                                 operations.empty();
109                                 $.each(data, function(number, item) {
110                                         var selected;
111                                         if (number == 0) {
112                                                 selected  = ' selected="selected"';
113                                         } else {
114                                                 selected = "";
115                                         }
116                                         operations.append('<option value="' + item + '"' + selected + '>' + item + '</option>');
117                                 });
118                                 operationSelectionChanged();
119                                 $("#removeIfBtn").removeAttr("disabled");
120                                 $("#generateiabtn").removeAttr("disabled");
121                         }
122                 });
123         }
124 }
125
126 function operationSelectionChanged() {
127         if ($("#operations").find(":selected").length == 0) {
128                 inputParametersTableInfo.table.fnClearTable();
129                 outputParametersTableInfo.table.fnClearTable();
130                 disableAllInputButtons();
131                 disableAllOutputButtons();
132                 $("#removeOpBtn").attr("disabled", "disabled");
133                 if ($("#interfaces").children("option").length == 0) {
134                         // no interfaces available
135                         $("#addOpBtn").attr("disabled", "disabled");
136                 } else {
137                         $("#addOpBtn").removeAttr("disabled");
138                 }
139         } else {
140                 updateInputAndOutputParameters(getOperationURL());
141                 $("#addOpBtn").removeAttr("disabled");
142                 $("#removeOpBtn").removeAttr("disabled");
143         }
144 }
145
146
147 function determineNextItemToSelect(currentItem) {
148         var nextToSelect;
149         nextToSelect = currentItem.next();
150         if (nextToSelect.length == 0) {
151                 nextToSelect = currentItem.prev();
152                 // even if nothing found, the following code works:
153                 // X.attr("selected", "selected") does not throw any error if X is empty
154         }
155         return nextToSelect;
156 }
157
158 function deleteThing(thingId, thingName, urlDetermination, changedFunction) {
159         var thing = $("#" + thingId).find(":selected");
160         if (thing.length == 0) {
161                 vShowError("UI in wrong state");
162         } else {
163                 deleteResource(
164                         thingName + " " + thing.text(),
165                         urlDetermination(),
166                         function() {
167                                 nextToSelect = determineNextItemToSelect(thing);
168                                 thing.remove();
169                                 nextToSelect.attr("selected", "selected");
170                                 changedFunction();
171                         }
172                 );
173         }
174 }
175
176 function deleteInterface() {
177         var iface = $("#interfaces").find(":selected").text();
178
179         // if the lifecycle interface is going to be removed,
180         // enable the button to generate the lifecycle interface again
181         var changedFunction;
182         if (iface == URI_LIFECYCLE_INTERFACE) {
183                 changedFunction = function() {
184                         $("#generatelifecycleifacetn").removeAttr("disabled");
185                         interfaceSelectionChanged();
186                 }
187         } else {
188                 changedFunction = interfaceSelectionChanged;
189         }
190
191         deleteThing("interfaces", "Interface", getIfaceURL, changedFunction);
192 }
193
194 function deleteOperation() {
195         deleteThing("operations", "Operation", getOperationURL, operationSelectionChanged);
196 }
197
198 function createArtifactTemplate() {
199         // we use the quick way at implementationartifacts/ to auto-generate an artifact template
200         // see org.eclipse.winery.repository.resources.artifacts.GenericArtifactsResource<ArtifactResource, ArtifactT> for the REST-interface description;
201
202         var url = getTypeImplementationURL() + "implementationartifacts/";
203         var data = $("#artifactTemplateNS, #artifactTemplateName, #autoCreateArtifactTemplate, #artifactType, #autoGenerateIA, #interfaces, #javapackage").serialize();
204
205         // we use the artifact template name as artifact name
206         var artifactName = $("#artifactTemplateName").serialize();
207         artifactName = "artifact" + artifactName.substring(16);
208         data = data + "&" + artifactName;
209
210         $.ajax({
211                 url: url,
212                 data: data,
213                 type: "POST"
214         }).fail(function(jqXHR, textStatus, errorThrown) {
215                 vShowAJAXError("Could not create artifact template", jqXHR, errorThrown);
216                 $("#generateiabtn").button("reset");
217         }).done(function(data, textStatus, jqXHR) {
218                 var location = jqXHR.getResponseHeader("location");
219
220                 vShowSuccess('Successfully generated IA. It is currently downloaded and available <a href="' + location + '/../../">here</a>');
221
222                 // open the downloaded file
223                 window.open(location, "_blank");
224
225                 $("#generateiamodal").modal("hide");
226         });
227 }
228
229 function generateIA() {
230         $("#generateiabtn").button("loading");
231
232         // create type implementation if necessary
233         var typeImplementationHasToBeCreated = $("#nodeTypeImplCreationSwitch").bootstrapSwitch('status'); // "status" instead of "state" (!)
234         if (typeImplementationHasToBeCreated) {
235                 var url = "${pageContext.request.contextPath}/${it.relationshipTypeOrNodeTypeURLFragment}implementations/";
236                 var data = $("#nodetypeimplementationName, #nodetypeimplementationNS, #qnameOfType").serialize();
237                 $.ajax({
238                         url: url,
239                         type: "POST",
240                         data: data
241                 }).fail(function(jqXHR, textStatus, errorThrown) {
242                         vShowAJAXError("Could not create type implementation", jqXHR, errorThrown);
243                         $("#generateiabtn").button("reset");
244                 }).done(function() {
245                         createArtifactTemplate();
246                 });
247         } else {
248                 createArtifactTemplate();
249         }
250 }
251
252 $(function() {
253         $("#generateiamodal").on("show.bs.modal", function() {
254                 // check whether the required artifact type exists
255                 $.ajax({
256                         url: "${pageContext.request.contextPath}/artifacttypes/<%=Util.DoubleURLencode(Constants.NAMESPACE_ARTIFACTTYPE_WAR)%>/<%=Util.DoubleURLencode(Constants.LOCALNAME_ARTIFACTTYPE_WAR)%>/",
257                         type: "HEAD"
258                 }).fail(function(jqXHR, textStatus, errorThrown) {
259                         if (jqXHR.status == 404) {
260                                 vShowError("WAR artifact type does not exist. Please create artifact type WAR");
261                                 $("#generateiabtn").attr("disabled", "disabled");
262                         } else {
263                                 vShowAJAXError("Could not check for existance of WAR artifact type", jqXHR, errorThrown);
264                         }
265                 }).success(function() {
266                         $("#generateiabtn").removeAttr("disabled");
267                 });
268
269                 // dialog is reset at each show
270                 $("#generateiabtn").button("reset");
271
272                 // set java package
273                 $("#javapackage").val("${w:namespaceToJavaPackage(it.namespace)}");
274
275                 // set node type implementation name
276                 $("#nodetypeimplementationName").val("${it.name}_impl");
277
278                 // reset node type implementation namespace
279                 $("#nodetypeimplementationNS").val("${it.namespace}").attr("selected", "selected");
280
281                 // the default type impl could exist
282                 checkNodeTypeImplName();
283
284                 // reset artifact template namespace
285                 $("#artifactTemplateNS").val("${it.namespace}").attr("selected", "selected");
286
287                 require(["artifacttemplateselection", "winery-support"], function(ats, ws) {
288                         // set artifact template name
289                         var iface = $("#interfaces").find(":selected");
290                         var initialATName = "${it.name}_" + ws.makeNCName(iface.text()) + "_IA";
291                         $("#artifactTemplateName").val(initialATName);
292
293                         // check if artifact template is a valid name
294                         ats.checkArtifactTemplateName();
295                 });
296         });
297
298         $("#nodetypeimplementationNS").on("blur", checkNodeTypeImplName).on("change", checkNodeTypeImplName).on("focus", flagNodeTypeImplAsUpdating);
299         $("#nodetypeimplementationName").typing({
300                 start: function(event, $elem) {
301                         flagNodeTypeImplAsUpdating();
302                 },
303                 stop: function(event, $elem) {
304                         checkNodeTypeImplName();
305                 }
306         });
307
308 });
309
310 <%-- adapted from artifacttemplateselection.tag --%>
311
312 function getTypeImplementationURL() {
313         var ns = $("#nodetypeimplementationNS").val();
314         var name = $("#nodetypeimplementationName").val();
315         var url = "${pageContext.request.contextPath}/${it.relationshipTypeOrNodeTypeURLFragment}implementations/" + encodeID(ns) + "/" + encodeID(name) + "/";
316         return url;
317 }
318
319 function checkNodeTypeImplName() {
320         var name = $("#nodetypeimplementationName").val();
321         if (name == "") {
322                 var valid = false;
323                 var invalidReason = "No name provided";
324                 // TODO: setNodeTypeImplNameValidityStatus(valid, invalidReason);
325         } else {
326                 url = getTypeImplementationURL();
327                 $.ajax(url, {
328                         type: 'HEAD',
329                         dataType: 'html',
330                         error: function(jqXHR, textStatus, errorThrown) {
331                                 if (jqXHR.status == 404) {
332                                         // node type implementation does not exist
333                                         $("#nodeTypeImplCreationSwitch").bootstrapSwitch('setState', true);
334                                 } else {
335                                         vShowAJAXError("Could not check for type implementation existance", jqXHR, errorThrown);
336                                         // Alternative: setValidityStatus(false, textStatus);
337                                 }
338                         },
339                         success: function(data, textStatus, jqXHR) {
340                                 // node type implementation exists
341                                 $("#nodeTypeImplCreationSwitch").bootstrapSwitch('setState', false);
342                         }
343                 });
344         }
345 }
346
347 function flagNodeTypeImplAsUpdating() {
348         // not yet implemented
349 }
350
351 function generateLifeCycleInterface() {
352         var data = "interfaceName=" + encodeURIComponent(URI_LIFECYCLE_INTERFACE);
353         $.ajax({
354                 url: '${it.urlPrefix}interfaces/',
355                 data: data,
356                 type: "POST"
357         }).fail(function(jqXHR, textStatus, errorThrown) {
358                 vShowAJAXError("Could not create interface", jqXHR, errorThrown);
359         }).done(function(data, textStatus, jqXHR) {
360                 var serializedArray = [{value:URI_LIFECYCLE_INTERFACE}];
361                 afterInterfaceCreation(serializedArray, data, textStatus, jqXHR, true);
362
363                 var operations = ["install", "configure", "start", "stop", "uninstall"];
364                 var errorOccurred = false;
365
366                 $(operations).each(function(i, operationName) {
367                         // we have to go through one-by-one to keep the order of operations
368                         // no parallel creation possible
369                         // Therefore also "async: false" at the AJAX call
370
371                         var data = "name=" + operationName;
372
373                         var url = getIfaceURL() + "operations/";
374                         $.ajax({
375                                 url: url,
376                                 data: data,
377                                 type: "POST",
378                                 async: false
379                         }).fail(function(jqXHR, textStatus, errorThrown) {
380                                 vShowAJAXError("Could not create operation " + operationName, jqXHR, errorThrown);
381                                 errorOccurred = true;
382                         }).done(function(data, textStatus, jqXHR) {
383                                 serializedArray = [{value:operationName}];
384                                 afterOperationCreation(serializedArray, data, textStatus, jqXHR);
385                         });
386                 });
387
388                 if (!errorOccurred) {
389                         vShowSuccess('Successfully generated lifecycle interface');
390                 }
391         });
392 }
393
394 </script>
395
396 <div id="generateiamodal" class="modal fade">
397         <div class="modal-dialog">
398                 <div class="modal-content">
399                         <div class="modal-header">
400                                 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
401                                 <h4 class="modal-title">Generate Implementation Artifact</h4>
402                         </div>
403                         <div class="modal-body">
404                                 <form role="form">
405                                         <div class="form-group">
406                                                 <label for="javapackage">Java Package</label>
407                                                 <input class="form-control" id="javapackage" name="javapackage" placeholder="Enter java package name" required="required">
408                                         </div>
409
410                                         <div class="form-group-grouping typeimplementation">
411                                                 <div class="form-group">
412                                                         <label for="nodetypeimplementationName">${it.relationshipTypeOrNodeType} Implementation Name</label>
413                                                         <input required="required" class="form-control" id="nodetypeimplementationName" name="name" placeholder="Enter name for node type implementation" pattern="[\i-[:]][\c-[:]]*"><!-- name is an NCName -->
414                                                 </div>
415
416                                                 <t:namespaceChooser nameOfInput="namespace" idOfInput="nodetypeimplementationNS" allNamespaces="${w:allNamespaces()}" selected="${it.namespace}"></t:namespaceChooser>
417
418                                                 <div id="nodeTypeImplCreationSwitch" class="make-switch" data-on-label="will be created" data-off-label="will be reused" style="height:30px; width:250px;">
419                                                         <input type="checkbox" disabled="disabled" checked="checked">
420                                                 </div>
421
422                                                 <input type="hidden" name="type" id="qnameOfType" value="${it.typeQName}">
423                                         </div>
424
425                                         <p class="text-warning">There is no check for the name of the implementation artifact. The artifact template name will be reused as implementation artifact name without any further check.</p>
426
427                                         <ct:artifacttemplateselection repositoryURL="${pageContext.request.contextPath}" defaultNSForArtifactTemplate="${it.namespace}" allNamespaces="${w:allNamespaces()}"></ct:artifacttemplateselection>
428                                         <input type="hidden" name="autoCreateArtifactTemplate" value="true" id="autoCreateArtifactTemplate">
429
430                                         <div class="form-group">
431                                                 <label for="artifacttype">Artifact Type</label>
432                                                 <a class="form-control" target="_blank" href="${pageContext.request.contextPath}/artifacttypes/<%=Util.DoubleURLencode(Constants.NAMESPACE_ARTIFACTTYPE_WAR)%>/<%=Util.DoubleURLencode(Constants.LOCALNAME_ARTIFACTTYPE_WAR)%>/">WAR</a>
433                                                 <input type="hidden" name="artifactType" id="artifactType" value="{<%=Constants.NAMESPACE_ARTIFACTTYPE_WAR%>}<%=Constants.LOCALNAME_ARTIFACTTYPE_WAR%>">
434                                         </div>
435
436                                         <input type="hidden" name="autoGenerateIA" id="autoGenerateIA" value="true">
437                                 </form>
438                         </div>
439                         <div class="modal-footer">
440                                 <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
441                                 <button type="button" class="btn btn-primary" id="generateiabtn" onclick="generateIA();" data-loading-text="Generating...">Generate</button>
442                         </div>
443                 </div><!-- /.modal-content -->
444         </div><!-- /.modal-dialog -->
445 </div><!-- /.modal -->
446
447
448 <div><!--  we do not use bootstrap's "container" as the container leads to an overflow -->
449         <div class="col-xs-4 bordered">
450                 <div class="listheading">
451                         <button class="rightbutton btn btn-danger btn-xs" type="button" onclick="deleteInterface();" disabled="disabled" id="removeIfBtn">Remove</button>
452                         <button class="rightbutton btn btn-primary btn-xs" type="button" onclick="createInterface();" id="addIfBtn">Add</button>
453                         <label>Interfaces</label>
454                 </div>
455                 <select class="listcontent" id="interfaces" size="18" onchange="interfaceSelectionChanged();" name="interfaceName">
456                 <c:set var="generatelifcecycleifactebtnDisabled" value=""></c:set>
457                 <c:set var="URI_LIFECYCLE_INTERFACE" value="<%=URI_LIFECYCLE_INTERFACE%>"></c:set>
458                 <!-- ${URI_LIFECYCLE_INTERFACE} -->
459                 <c:forEach var="iface" varStatus="count" items="${it.listOfAllEntityIdsAsList}">
460                         <c:set var="selected" value=""></c:set>
461                         <c:if test="${count.index == 0}">
462                                 <c:set var="selected" value=" selected=\"selected\""></c:set>
463                         </c:if>
464                         <c:if test="${iface == URI_LIFECYCLE_INTERFACE}">
465                                 <c:set var="generatelifcecycleifactebtnDisabled" value=" disabled=\"disabled\""></c:set>
466                         </c:if>
467                         <option value="${iface}"${selected}>${iface}</option>
468                 </c:forEach>
469                 </select>
470                 <button id="generateiabtn" class="btn btn-default btn-xs" data-toggle="modal" data-target="#generateiamodal">Generate Implementation Artifact</button>
471                 <button id="generatelifecycleifacetn" class="btn btn-default btn-xs" onclick="generateLifeCycleInterface();"${generatelifcecycleifactebtnDisabled}>Generate lifecycle interface</button>
472         </div>
473
474         <div class="col-xs-4 middlebox bordered">
475                 <div class="listheading">
476                         <button class="rightbutton btn btn-danger btn-xs" type="button" onclick="deleteOperation();" id="removeOpBtn">Remove</button>
477                         <button class="rightbutton btn btn-primary btn-xs" type="button" onclick="createOperation();" id="addOpBtn">Add</button>
478                         <label>Operations</label>
479                 </div>
480                 <select class="listcontent" id="operations" size="18" onchange="operationSelectionChanged();">
481                 </select>
482         </div>
483
484         <div class="col-xs-4 bordered">
485                 <p:parametersInput baseURL="getOperationURL()"></p:parametersInput>
486                 <br /><br />
487                 <p:parametersOutput baseURL="getOperationURL()"></p:parametersOutput>
488         </div>
489 </div>