/*************************GO-LICENSE-START********************************* * Copyright 2014 ThoughtWorks, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *************************GO-LICENSE-END***********************************/ package com.thoughtworks.go.plugin.access.pluggabletask; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.thoughtworks.go.plugin.api.config.Property; import com.thoughtworks.go.plugin.api.response.execution.ExecutionResult; import com.thoughtworks.go.plugin.api.response.validation.ValidationError; import com.thoughtworks.go.plugin.api.response.validation.ValidationResult; import com.thoughtworks.go.plugin.api.task.TaskConfig; import com.thoughtworks.go.plugin.api.task.TaskConfigProperty; import com.thoughtworks.go.plugin.api.task.TaskExecutionContext; import com.thoughtworks.go.plugin.api.task.TaskView; import com.thoughtworks.go.util.ListUtil; import com.thoughtworks.go.util.StringUtil; import org.apache.log4j.Logger; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; public class JsonBasedTaskExtensionHandler_V1 implements JsonBasedTaskExtensionHandler { public static final String VERSION = "1.0"; private static final Logger LOGGER = Logger.getLogger(JsonBasedTaskExtensionHandler_V1.class); @Override public String version() { return VERSION; } @Override public String convertTaskConfigToJson(TaskConfig taskConfig) { return new Gson().toJson(configPropertiesAsMap(taskConfig)); } @Override public TaskConfig convertJsonToTaskConfig(String configJson) { final TaskConfig taskConfig = new TaskConfig(); ArrayList<String> exceptions = new ArrayList<>(); try { Map<String, Object> configMap = (Map) new GsonBuilder().create().fromJson(configJson, Object.class); if (configMap.isEmpty()) { exceptions.add("The Json for Task Config cannot be empty"); } for (Map.Entry<String, Object> entry : configMap.entrySet()) { TaskConfigProperty property = new TaskConfigProperty(entry.getKey(), null); property.with(Property.REQUIRED, true); Map propertyValue = (Map) entry.getValue(); if (propertyValue != null) { if (propertyValue.containsKey("default-value")) { if (!(propertyValue.get("default-value") instanceof String)) { exceptions.add(String.format("Key: '%s' - The Json for Task Config should contain a not-null 'default-value' of type String", entry.getKey())); } else { property.withDefault((String) propertyValue.get("default-value")); } } if (propertyValue.containsKey("display-name")) { if (!(propertyValue.get("display-name") instanceof String)) { exceptions.add(String.format("Key: '%s' - 'display-name' should be of type String", entry.getKey())); } else { property.with(Property.DISPLAY_NAME, (String) propertyValue.get("display-name")); } } if (propertyValue.containsKey("display-order")) { if (!(propertyValue.get("display-order") instanceof String && StringUtil.isInteger((String) propertyValue.get("display-order")))) { exceptions.add(String.format("Key: '%s' - 'display-order' should be a String containing a numerical value", entry.getKey())); } else { property.with(Property.DISPLAY_ORDER, Integer.parseInt((String) propertyValue.get("display-order"))); } } if (propertyValue.containsKey("secure")) { if (!(propertyValue.get("secure") instanceof Boolean)) { exceptions.add(String.format("Key: '%s' - The Json for Task Config should contain a 'secure' field of type Boolean", entry.getKey())); } else { property.with(Property.SECURE, (Boolean) propertyValue.get("secure")); } } if (propertyValue.containsKey("required")) { if (!(propertyValue.get("required") instanceof Boolean)) { exceptions.add(String.format("Key: '%s' - The Json for Task Config should contain a 'required' field of type Boolean", entry.getKey())); } else { property.with(Property.REQUIRED, (Boolean) propertyValue.get("required")); } } } taskConfig.add(property); } if (!exceptions.isEmpty()) { throw new RuntimeException(ListUtil.join(exceptions)); } return taskConfig; } catch (Exception e) { LOGGER.error(String.format("Error occurred while converting the Json to Task Config. Error: %s. The Json received was '%s'.", e.getMessage(), configJson)); throw new RuntimeException(String.format("Error occurred while converting the Json to Task Config. Error: %s.", e.getMessage())); } } @Override public ValidationResult toValidationResult(String responseBody) { ValidationResult validationResult = new ValidationResult(); ArrayList<String> exceptions = new ArrayList<>(); try { Map result = (Map) new GsonBuilder().create().fromJson(responseBody, Object.class); if (result == null) return validationResult; final Map<String, Object> errors = (Map<String, Object>) result.get("errors"); if (errors != null) { for (Map.Entry<String, Object> entry : errors.entrySet()) { if (!(entry.getValue() instanceof String)) { exceptions.add(String.format("Key: '%s' - The Json for Validation Request must contain a not-null error message of type String", entry.getKey())); } else { validationResult.addError(new ValidationError(entry.getKey(), entry.getValue().toString())); } } } if (!exceptions.isEmpty()) { throw new RuntimeException(ListUtil.join(exceptions)); } return validationResult; } catch (Exception e) { LOGGER.error(String.format("Error occurred while converting the Json to Validation Result. Error: %s. The Json received was '%s'.", e.getMessage(), responseBody)); throw new RuntimeException(String.format("Error occurred while converting the Json to Validation Result. Error: %s.", e.getMessage())); } } @Override public TaskView toTaskView(String responseBody) { ArrayList<String> exceptions = new ArrayList<>(); try { final Map map = (Map) new GsonBuilder().create().fromJson(responseBody, Object.class); if (map.isEmpty()) { exceptions.add("The Json for Task View cannot be empty"); } else { if (!(map.containsKey("displayValue") && map.get("displayValue") instanceof String)) { exceptions.add("The Json for Task View must contain a not-null 'displayValue' of type String"); } if (!(map.containsKey("template") && map.get("template") instanceof String)) { exceptions.add("The Json for Task View must contain a not-null 'template' of type String"); } } if (!exceptions.isEmpty()) { throw new RuntimeException(ListUtil.join(exceptions)); } return new TaskView() { @Override public String displayValue() { return (String) map.get("displayValue"); } @Override public String template() { return (String) map.get("template"); } }; } catch (Exception e) { LOGGER.error(String.format("Error occurred while converting the Json to Task View. Error: %s. The Json received was '%s'.", e.getMessage(), responseBody)); throw new RuntimeException(String.format("Error occurred while converting the Json to Task View. Error: %s.", e.getMessage())); } } @Override public ExecutionResult toExecutionResult(String responseBody) { ExecutionResult executionResult = new ExecutionResult(); ArrayList<String> exceptions = new ArrayList<>(); try { Map result = (Map) new GsonBuilder().create().fromJson(responseBody, Object.class); if (!(result.containsKey("success") && result.get("success") instanceof Boolean)) { exceptions.add("The Json for Execution Result must contain a not-null 'success' field of type Boolean"); } if (result.containsKey("message") && (!(result.get("message") instanceof String))) { exceptions.add("If the 'message' key is present in the Json for Execution Result, it must contain a not-null message of type String"); } if (!exceptions.isEmpty()) { throw new RuntimeException(ListUtil.join(exceptions)); } if ((Boolean) result.get("success")) { executionResult.withSuccessMessages((String) result.get("message")); } else { executionResult.withErrorMessages((String) result.get("message")); } return executionResult; } catch (Exception e) { LOGGER.error(String.format("Error occurred while converting the Json to Execution Result. Error: %s. The Json received was '%s'.", e.getMessage(), responseBody)); throw new RuntimeException(String.format("Error occurred while converting the Json to Execution Result. Error: %s.", e.getMessage())); } } @Override public String getTaskExecutionBody(TaskConfig config, TaskExecutionContext taskExecutionContext) { Map requestBody = new HashMap(); Map contextMap = new HashMap(); contextMap.put("environmentVariables", taskExecutionContext.environment().asMap()); contextMap.put("workingDirectory", taskExecutionContext.workingDir()); requestBody.put("context", contextMap); requestBody.put("config", configPropertiesAsMap(config)); return new Gson().toJson(requestBody); } private Map configPropertiesAsMap(TaskConfig taskConfig) { HashMap properties = new HashMap(); for (Property property : taskConfig.list()) { final HashMap propertyValue = new HashMap(); propertyValue.put("value", property.getValue()); propertyValue.put("secure", property.getOption(Property.SECURE)); propertyValue.put("required", property.getOption(Property.REQUIRED)); properties.put(property.getKey(), propertyValue); } return properties; } }