diff options
author | Dirk Fauth | 2020-10-13 09:18:39 +0000 |
---|---|---|
committer | Dirk Fauth | 2020-10-13 09:18:39 +0000 |
commit | d6ad7e69fc0131d0f5a3f2f3476945642b164e33 (patch) | |
tree | 18f787a4ec8e974d80b06d8168d1a4b605abb062 | |
parent | 4e5b2bc9f1f71ff8e3ecd1f23bde9f5432361d19 (diff) | |
download | org.eclipse.app4mc.cloud-d6ad7e69fc0131d0f5a3f2f3476945642b164e33.tar.gz org.eclipse.app4mc.cloud-d6ad7e69fc0131d0f5a3f2f3476945642b164e33.tar.xz org.eclipse.app4mc.cloud-d6ad7e69fc0131d0f5a3f2f3476945642b164e33.zip |
Added handling of configuration parameter
Change-Id: I1f8b52c321528ddd40a1b9079234017665cae64e
Signed-off-by: Dirk Fauth <Dirk.Fauth@de.bosch.com>
8 files changed, 318 insertions, 49 deletions
diff --git a/manager/pom.xml b/manager/pom.xml index bec8421..52b57cf 100644 --- a/manager/pom.xml +++ b/manager/pom.xml @@ -62,7 +62,7 @@ <dependency> <groupId>com.konghq</groupId> <artifactId>unirest-java</artifactId> - <version>3.7.04</version> + <version>3.11.01</version> </dependency> <dependency> diff --git a/manager/src/main/java/org/eclipse/app4mc/cloud/manager/ServiceConfiguration.java b/manager/src/main/java/org/eclipse/app4mc/cloud/manager/ServiceConfiguration.java new file mode 100644 index 0000000..1f21f09 --- /dev/null +++ b/manager/src/main/java/org/eclipse/app4mc/cloud/manager/ServiceConfiguration.java @@ -0,0 +1,39 @@ +/********************************************************************************* + * Copyright (c) 2020 Robert Bosch GmbH and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Robert Bosch GmbH - initial API and implementation + ******************************************************************************** + */ +package org.eclipse.app4mc.cloud.manager; + +import java.util.ArrayList; +import java.util.List; + +public class ServiceConfiguration { + + private final String serviceName; + private ArrayList<ServiceConfigurationParameter> parameter = new ArrayList<>(); + + public ServiceConfiguration(String serviceName) { + this.serviceName = serviceName; + } + + public String getServiceName() { + return serviceName; + } + + public void addParameter(ServiceConfigurationParameter param) { + this.parameter.add(param); + } + + public List<ServiceConfigurationParameter> getParameterList() { + return this.parameter; + } +} diff --git a/manager/src/main/java/org/eclipse/app4mc/cloud/manager/ServiceConfigurationParameter.java b/manager/src/main/java/org/eclipse/app4mc/cloud/manager/ServiceConfigurationParameter.java new file mode 100644 index 0000000..a96ebbf --- /dev/null +++ b/manager/src/main/java/org/eclipse/app4mc/cloud/manager/ServiceConfigurationParameter.java @@ -0,0 +1,85 @@ +/********************************************************************************* + * Copyright (c) 2020 Robert Bosch GmbH and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Robert Bosch GmbH - initial API and implementation + ******************************************************************************** + */ +package org.eclipse.app4mc.cloud.manager; + +import java.util.ArrayList; +import java.util.List; + +public class ServiceConfigurationParameter { + + private String name; + private String key; + private String value; + private String type; + private String cardinality = "single"; + private boolean mandatory = false; + private List<String> possibleValues = new ArrayList<>(); + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getCardinality() { + return cardinality; + } + + public void setCardinality(String cardinality) { + this.cardinality = cardinality; + } + + public boolean isMandatory() { + return mandatory; + } + + public void setMandatory(boolean mandatory) { + this.mandatory = mandatory; + } + + public List<String> getPossibleValues() { + return possibleValues; + } + + public void setPossibleValues(List<String> possibleValues) { + this.possibleValues = possibleValues; + } + +} diff --git a/manager/src/main/java/org/eclipse/app4mc/cloud/manager/WorkflowController.java b/manager/src/main/java/org/eclipse/app4mc/cloud/manager/WorkflowController.java index 8766f29..efa796f 100644 --- a/manager/src/main/java/org/eclipse/app4mc/cloud/manager/WorkflowController.java +++ b/manager/src/main/java/org/eclipse/app4mc/cloud/manager/WorkflowController.java @@ -20,7 +20,9 @@ import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; import org.apache.http.HttpStatus; import org.eclipse.app4mc.cloud.manager.administration.CloudServiceDefinition; @@ -47,6 +49,7 @@ import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder; import kong.unirest.HttpResponse; +import kong.unirest.MultipartBody; import kong.unirest.Unirest; @Controller @@ -65,28 +68,6 @@ public class WorkflowController { @GetMapping("/workflow") public String workflow(Model model) { - - // TODO move this to a configuration resource mechanism - CloudServiceDefinition csd = this.cloudServiceDefinitions.stream() - .filter(sd -> sd.getName().equals("Validation")) - .findFirst() - .orElse(null); - - List<?> allProfiles = new ArrayList<>(); - if (csd != null) { - try { - String baseUrl = csd.getBaseUrl(); - if (!baseUrl.endsWith("/")) { - baseUrl += "/"; - } - allProfiles = Unirest.get(baseUrl + "profiles").asJson().getBody().getArray().toList(); - } catch (Exception e) { - // do nothing, we will handle configurations in a different way in the future - } - } - - model.addAttribute("allProfiles", allProfiles); - // render the form view return "workflow"; } @@ -104,8 +85,65 @@ public class WorkflowController { ws.addSelectedService(selected); - // TODO init service configuration - + if ("Validation".equals(selected)) { + // TODO general: check if the selected service has a configuration URL + // TODO build configuration based on provided service configuration + CloudServiceDefinition csd = this.cloudServiceDefinitions.stream() + .filter(sd -> sd.getName().equals("Validation")) + .findFirst() + .orElse(null); + + if (csd != null) { + List<String> allProfiles = new ArrayList<>(); + try { + String baseUrl = csd.getBaseUrl(); + if (!baseUrl.endsWith("/")) { + baseUrl += "/"; + } + List<?> jsonResult = Unirest.get(baseUrl + "profiles").asJson().getBody().getArray().toList(); + allProfiles = jsonResult.stream().map(Object::toString).collect(Collectors.toList()); + } catch (Exception e) { + // do nothing, we will handle configurations in a different way in the future + } + + if (allProfiles != null && !allProfiles.isEmpty()) { + ServiceConfiguration config = new ServiceConfiguration(selected); + + ServiceConfigurationParameter validationProfiles = new ServiceConfigurationParameter(); + validationProfiles.setName("Validation profiles"); + validationProfiles.setKey("profiles"); + validationProfiles.setType("String"); + validationProfiles.setCardinality("multiple"); + validationProfiles.setPossibleValues(allProfiles); + config.addParameter(validationProfiles); + + ws.addConfiguration(selected, config); + } + } + } else if ("RTC Analysis".equals(selected)) { + ServiceConfiguration config = new ServiceConfiguration(selected); + + ServiceConfigurationParameter ascPriorities = new ServiceConfigurationParameter(); + ascPriorities.setName("Ascending priorities"); + ascPriorities.setKey("analysis-ascending-priorities"); + ascPriorities.setType("boolean"); + config.addParameter(ascPriorities); + + ServiceConfigurationParameter enableFlows = new ServiceConfigurationParameter(); + enableFlows.setName("Include flow analysis"); + enableFlows.setKey("analysis-enable-flows"); + enableFlows.setType("boolean"); + config.addParameter(enableFlows); + + ServiceConfigurationParameter timeUnit = new ServiceConfigurationParameter(); + timeUnit.setName("Time unit"); + timeUnit.setKey("analysis-time-unit"); + timeUnit.setType("String"); + timeUnit.setPossibleValues(Arrays.asList("s", "ms", "us", "ns")); + config.addParameter(timeUnit); + + ws.addConfiguration(selected, config); + } // render the form view return "workflow"; @@ -118,6 +156,8 @@ public class WorkflowController { ws.removeSelectedService(selected); + ws.removeConfiguration(selected); + // render the form view return "workflow"; } @@ -149,12 +189,13 @@ public class WorkflowController { @PostMapping("/workflow") public String handleFileUpload( @RequestParam("file") MultipartFile file, - @RequestParam(name = "profiles", required = false) String[] validationProfiles, Model model, @ModelAttribute WorkflowStatus ws) { if (ws == null) { ws = new WorkflowStatus(); + } else { + ws.clearResults(); } final WorkflowStatus workflowStatus = ws; @@ -249,9 +290,28 @@ public class WorkflowController { } // upload to service - HttpResponse<?> uploadResponse = Unirest.post(baseUrl) + MultipartBody multipartBody = Unirest.post(baseUrl) .field("file", Files.newInputStream(inputFile), originalFilename) - .asEmpty(); + .field("values", Arrays.asList("value1", "value2")); + + ServiceConfiguration config = workflowStatus.getConfiguration(serviceName); + if (config != null) { + config.getParameterList().forEach(param -> { + if (!StringUtils.isEmpty(param.getValue())) { + if ("multiple".equals(param.getCardinality())) { + // TODO remove query string once equinox multipart is fixed + multipartBody.queryString(param.getKey(), Arrays.asList(param.getValue().split(","))); + multipartBody.field(param.getKey(), Arrays.asList(param.getValue().split(","))); + } else { + // TODO remove query string once equinox multipart is fixed + multipartBody.queryString(param.getKey(), param.getValue()); + multipartBody.field(param.getKey(), param.getValue()); + } + } + }); + } + + HttpResponse<?> uploadResponse = multipartBody.asEmpty(); // extract status link from result String statusUrl = null; @@ -396,7 +456,8 @@ public class WorkflowController { "serveFile", workflowStatus.getUuid(), "_" + serviceName.toLowerCase(), - migrationError.getFileName().toString()).build().toUri().toString()); + migrationError.getFileName().toString(), + null).build().toUri().toString()); // extract delete deleteUrl = getUrlFromLink(errorResponse.getHeaders().get("Link"), "delete", baseUrl); diff --git a/manager/src/main/java/org/eclipse/app4mc/cloud/manager/WorkflowStatus.java b/manager/src/main/java/org/eclipse/app4mc/cloud/manager/WorkflowStatus.java index 1e7eae3..1f972ae 100644 --- a/manager/src/main/java/org/eclipse/app4mc/cloud/manager/WorkflowStatus.java +++ b/manager/src/main/java/org/eclipse/app4mc/cloud/manager/WorkflowStatus.java @@ -21,6 +21,7 @@ public class WorkflowStatus { private String uuid; private ArrayList<String> selectedServices = new ArrayList<>(); + private HashMap<String, ServiceConfiguration> serviceConfigurations = new LinkedHashMap<>(); private ArrayList<String> messages = new ArrayList<>(); private ArrayList<String> errors = new ArrayList<>(); private HashMap<String, String> results = new LinkedHashMap<>(); @@ -45,6 +46,22 @@ public class WorkflowStatus { this.selectedServices.remove(service); } + public ServiceConfiguration getConfiguration(String key) { + return this.serviceConfigurations.get(key); + } + + public HashMap<String, ServiceConfiguration> getConfigurations() { + return this.serviceConfigurations; + } + + public void addConfiguration(String key, ServiceConfiguration config) { + this.serviceConfigurations.put(key, config); + } + + public void removeConfiguration(String key) { + this.serviceConfigurations.remove(key); + } + public ArrayList<String> getMessages() { return messages; } @@ -69,8 +86,15 @@ public class WorkflowStatus { this.results.put(key, resultFile); } + public void clearResults() { + this.messages.clear(); + this.errors.clear(); + this.results.clear(); + } + public void clear() { this.selectedServices.clear(); + this.serviceConfigurations.clear(); this.messages.clear(); this.errors.clear(); this.results.clear(); diff --git a/manager/src/main/resources/templates/selectedServices.html b/manager/src/main/resources/templates/selectedServices.html index 71058a5..60fc357 100644 --- a/manager/src/main/resources/templates/selectedServices.html +++ b/manager/src/main/resources/templates/selectedServices.html @@ -5,7 +5,7 @@ </head> <body> - <div th:fragment="servicesList" id="selectedServices"> + <div th:fragment="servicesList" id="selectedServices" th:object="${workflowStatus}"> <ul class="list-group"> <li th:each="selected : ${workflowStatus.selectedServices}" class="list-group-item d-flex justify-content-between"> <p class="p-0 m-0 flex-grow-1" th:text="${selected}">Service</p> @@ -21,6 +21,50 @@ th:selected="${service.name == selected}"> </option> </select><br> + + <div th:if="not *{configurations.isEmpty()}"> + <div th:each="config : *{configurations}" class="mb-3"> + <h4 th:text="${config.key + ' Configuration'}">Config</h4> + <div th:each="parameter, parameterStatus : ${config.value.parameterList}"> + <!-- multiple possible values + cardinality multiple = checkboxes --> + <div th:if="${parameter.cardinality == 'multiple' and parameter.possibleValues.size() > 1}"> + <label th:text="${parameter.name}">Label</label> + <div th:each="pv : ${parameter.possibleValues}" class="form-check"> + <input + class="form-check-input" + type="checkbox" + th:field="*{configurations[__${config.key}__].parameterList[__${parameterStatus.index}__].value}" + th:value="${pv}"> + <label class="form-check-label" th:text="${pv}">Profile</label> + </div> + </div> + <!-- multiple possible values + cardinality single = combobox --> + <div th:if="${parameter.cardinality == 'single' and parameter.possibleValues.size() > 1}"> + <label th:text="${parameter.name}">Label</label> + <select + class="custom-select" + th:field="*{configurations[__${config.key}__].parameterList[__${parameterStatus.index}__].value}"> + <option value=""></option> + <option + th:each="pv : ${parameter.possibleValues}" + th:text="${pv}" + th:value="${pv}"> + </option> + </select> + </div> + <!-- single boolean value --> + <div th:if="${parameter.cardinality == 'single' and parameter.type == 'boolean'}" class="form-check"> + <input + class="form-check-input" + type="checkbox" + th:field="*{configurations[__${config.key}__].parameterList[__${parameterStatus.index}__].value}" + value="true"> + <label class="form-check-label" th:text="${parameter.name}" th:for="${parameter.key}">Label</label> + </div> + </div> + </div> + </div> + </div> </body> </html> diff --git a/manager/src/main/resources/templates/workflow.html b/manager/src/main/resources/templates/workflow.html index fdb7fef..08100a5 100644 --- a/manager/src/main/resources/templates/workflow.html +++ b/manager/src/main/resources/templates/workflow.html @@ -61,7 +61,7 @@ $(document).ready(function(){ </div> </div> - <form method="POST" enctype="multipart/form-data" action="/workflow"> + <form method="POST" enctype="multipart/form-data" action="/workflow" th:object="${workflowStatus}"> <div class="form-row mb-3"> <div class="custom-file"> <input type="file" class="custom-file-input" id="customFile" name="file"> @@ -85,19 +85,6 @@ $(document).ready(function(){ </div> </div> </div> - <table> - <tr th:if="${allProfiles != null and not allProfiles.isEmpty()}"> - <td valign="top">Select validations to perform:</td> - <td> - <ul> - <li th:each="profile : ${allProfiles}"> - <input type="checkbox" name="profiles" th:value="${profile}" /> - <label th:text="${profile}">Amalthea</label> - </li> - </ul> - </td> - </tr> - </table> <div class="form-row"> <div class="col text-center"> <input type="submit" value="Start workflow" class="btn btn-primary mt-2"/> diff --git a/org.eclipse.app4mc.validation.cloud/org.eclipse.app4mc.validation.cloud.http/src/org/eclipse/app4mc/validation/cloud/http/ValidationServlet.java b/org.eclipse.app4mc.validation.cloud/org.eclipse.app4mc.validation.cloud.http/src/org/eclipse/app4mc/validation/cloud/http/ValidationServlet.java index 82c54e8..8d02b69 100644 --- a/org.eclipse.app4mc.validation.cloud/org.eclipse.app4mc.validation.cloud.http/src/org/eclipse/app4mc/validation/cloud/http/ValidationServlet.java +++ b/org.eclipse.app4mc.validation.cloud/org.eclipse.app4mc.validation.cloud.http/src/org/eclipse/app4mc/validation/cloud/http/ValidationServlet.java @@ -13,16 +13,19 @@ */ package org.eclipse.app4mc.validation.cloud.http; +import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; import java.io.PrintWriter; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; @@ -141,6 +144,8 @@ public class ValidationServlet extends HttpServlet { ServletContext context = getServletContext(); Map<String, String> registry = getRegistry(context); registry.put(uuid, PROGRESS_MARKER); + + List<String> selectedProfiles = getSelectedProfiles(request); // trigger asynchronous processing executor.execute(() -> { @@ -155,10 +160,6 @@ public class ValidationServlet extends HttpServlet { return; } - // get profile selection out of request - String[] profiles = request.getParameterValues("profiles"); - List<String> selectedProfiles = profiles != null ? Arrays.asList(profiles) : Arrays.asList("Amalthea Standard Validations"); - // get selected profiles from profile manager List<Class<? extends IProfile>> profileList = manager.getRegisteredValidationProfiles().values().stream() .filter(profile -> selectedProfiles.contains(profile.getName())) @@ -214,6 +215,34 @@ public class ValidationServlet extends HttpServlet { return; } + private List<String> getSelectedProfiles(HttpServletRequest request) throws IOException, ServletException { + + // first check if the profiles are sent as query parameter + String[] profiles = request.getParameterValues("profiles"); + if (profiles != null) { + return Arrays.asList(profiles); + } else { + // check if the profiles are sent as post parameter in the multipart request + List<String> collected = new ArrayList<>(); + for (Part supportPart : request.getParts()) { + if (supportPart.getName().equals("profiles")) { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(supportPart.getInputStream()))) { + List<String> collect = reader.lines().collect(Collectors.toList()); + if (collect != null && !collect.isEmpty()) { + collected.addAll(collect); + } + } + } + } + if (!collected.isEmpty()) { + return collected; + } + } + + // neither query parameter nor multipart post parameter found, return default + return Arrays.asList("Amalthea Standard Validations"); + } + // GET /app4mc/validation/profiles // GET /app4mc/validation/{id} // GET /app4mc/validation/{id}/download @@ -222,7 +251,7 @@ public class ValidationServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - + response.addHeader("Link", "<" + request.getRequestURL() + ">;rel=\"self\""); String[] splitPath = validatePath(request.getPathInfo()); |