/*************************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.packagematerial; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.thoughtworks.go.plugin.access.common.handler.JSONResultMessageHandler; import com.thoughtworks.go.plugin.api.config.Property; import com.thoughtworks.go.plugin.api.material.packagerepository.PackageConfiguration; import com.thoughtworks.go.plugin.api.material.packagerepository.PackageMaterialProperty; import com.thoughtworks.go.plugin.api.material.packagerepository.PackageRevision; import com.thoughtworks.go.plugin.api.material.packagerepository.RepositoryConfiguration; import com.thoughtworks.go.plugin.api.response.Result; import com.thoughtworks.go.plugin.api.response.validation.ValidationResult; import org.apache.commons.lang.StringUtils; import java.text.SimpleDateFormat; import java.util.*; import static java.lang.String.format; import static org.apache.commons.lang.StringUtils.isEmpty; public class JsonMessageHandler1_0 implements JsonMessageHandler { private static final String DATE_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; private final JSONResultMessageHandler jsonResultMessageHandler; public JsonMessageHandler1_0() { jsonResultMessageHandler = new JSONResultMessageHandler(); } @Override public RepositoryConfiguration responseMessageForRepositoryConfiguration(String responseBody) { try { RepositoryConfiguration repositoryConfiguration = new RepositoryConfiguration(); Map<String, Map> configurations; try { configurations = parseResponseToMap(responseBody); } catch (Exception e) { throw new RuntimeException("Repository configuration should be returned as a map"); } if (configurations == null || configurations.isEmpty()) { throw new RuntimeException("Empty response body"); } for (String key : configurations.keySet()) { if (isEmpty(key)) { throw new RuntimeException("Repository configuration key cannot be empty"); } if (!(configurations.get(key) instanceof Map)) { throw new RuntimeException(format("Repository configuration properties for key '%s' should be represented as a Map", key)); } repositoryConfiguration.add(toPackageMaterialProperty(key, configurations.get(key))); } return repositoryConfiguration; } catch (Exception e) { throw new RuntimeException(format("Unable to de-serialize json response. %s", e.getMessage())); } } @Override public String requestMessageForIsRepositoryConfigurationValid(RepositoryConfiguration repositoryConfiguration) { Map configuredValues = new LinkedHashMap(); configuredValues.put("repository-configuration", jsonResultMessageHandler.configurationToMap(repositoryConfiguration)); return toJsonString(configuredValues); } @Override public ValidationResult responseMessageForIsRepositoryConfigurationValid(String responseBody) { return jsonResultMessageHandler.toValidationResult(responseBody); } @Override public String requestMessageForCheckConnectionToRepository(RepositoryConfiguration repositoryConfiguration) { Map configuredValues = new LinkedHashMap(); configuredValues.put("repository-configuration", jsonResultMessageHandler.configurationToMap(repositoryConfiguration)); return toJsonString(configuredValues); } @Override public Result responseMessageForCheckConnectionToRepository(String responseBody) { return jsonResultMessageHandler.toResult(responseBody); } @Override public PackageConfiguration responseMessageForPackageConfiguration(String responseBody) { try { PackageConfiguration packageConfiguration = new PackageConfiguration(); Map<String, Map> configurations; try { configurations = parseResponseToMap(responseBody); } catch (Exception e) { throw new RuntimeException("Package configuration should be returned as a map"); } if (configurations == null || configurations.isEmpty()) { throw new RuntimeException("Empty response body"); } for (String key : configurations.keySet()) { if (isEmpty(key)) { throw new RuntimeException("Package configuration key cannot be empty"); } if (!(configurations.get(key) instanceof Map)) { throw new RuntimeException(format("Package configuration properties for key '%s' should be represented as a Map", key)); } packageConfiguration.add(toPackageMaterialProperty(key, configurations.get(key))); } return packageConfiguration; } catch (RuntimeException e) { throw new RuntimeException(format("Unable to de-serialize json response. %s", e.getMessage())); } } @Override public String requestMessageForIsPackageConfigurationValid(PackageConfiguration packageConfiguration, RepositoryConfiguration repositoryConfiguration) { Map configuredValues = new LinkedHashMap(); configuredValues.put("repository-configuration", jsonResultMessageHandler.configurationToMap(repositoryConfiguration)); configuredValues.put("package-configuration", jsonResultMessageHandler.configurationToMap(packageConfiguration)); return toJsonString(configuredValues); } @Override public ValidationResult responseMessageForIsPackageConfigurationValid(String responseBody) { return jsonResultMessageHandler.toValidationResult(responseBody); } @Override public String requestMessageForCheckConnectionToPackage(PackageConfiguration packageConfiguration, RepositoryConfiguration repositoryConfiguration) { Map configuredValues = new LinkedHashMap(); configuredValues.put("repository-configuration", jsonResultMessageHandler.configurationToMap(repositoryConfiguration)); configuredValues.put("package-configuration", jsonResultMessageHandler.configurationToMap(packageConfiguration)); return toJsonString(configuredValues); } @Override public Result responseMessageForCheckConnectionToPackage(String responseBody) { return jsonResultMessageHandler.toResult(responseBody); } @Override public String requestMessageForLatestRevision(PackageConfiguration packageConfiguration, RepositoryConfiguration repositoryConfiguration) { Map configuredValues = new LinkedHashMap(); configuredValues.put("repository-configuration", jsonResultMessageHandler.configurationToMap(repositoryConfiguration)); configuredValues.put("package-configuration", jsonResultMessageHandler.configurationToMap(packageConfiguration)); return toJsonString(configuredValues); } @Override public PackageRevision responseMessageForLatestRevision(String responseBody) { PackageRevision packageRevision = toPackageRevision(responseBody); if (packageRevision == null) { throw new RuntimeException("Empty response body"); } else return packageRevision; } @Override public String requestMessageForLatestRevisionSince(PackageConfiguration packageConfiguration, RepositoryConfiguration repositoryConfiguration, PackageRevision previousRevision) { Map configuredValues = new LinkedHashMap(); configuredValues.put("repository-configuration", jsonResultMessageHandler.configurationToMap(repositoryConfiguration)); configuredValues.put("package-configuration", jsonResultMessageHandler.configurationToMap(packageConfiguration)); configuredValues.put("previous-revision", packageRevisionToMap(previousRevision)); return toJsonString(configuredValues); } @Override public PackageRevision responseMessageForLatestRevisionSince(String responseBody) { return toPackageRevision(responseBody); } private List<Map> parseResponseToList(String responseBody) { return (List<Map>) new GsonBuilder().create().fromJson(responseBody, Object.class); } private Map parseResponseToMap(String responseBody) { return (Map) new GsonBuilder().create().fromJson(responseBody, Object.class); } private static String toJsonString(Object object) { Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); return gson.toJson(object); } private PackageMaterialProperty toPackageMaterialProperty(String key, Map configuration) { List<String> errors = new ArrayList<>(); String defaultValue = null; try { defaultValue = (String) configuration.get("default-value"); } catch (Exception e) { errors.add(format("'default-value' property for key '%s' should be of type string", key)); } Boolean partOfIdentity = null; try { partOfIdentity = (Boolean) configuration.get("part-of-identity"); } catch (Exception e) { errors.add(format("'part-of-identity' property for key '%s' should be of type boolean", key)); } Boolean isSecure = null; try { isSecure = (Boolean) configuration.get("secure"); } catch (Exception e) { errors.add(format("'secure' property for key '%s' should be of type boolean", key)); } Boolean required = null; try { required = (Boolean) configuration.get("required"); } catch (Exception e) { errors.add(format("'required' property for key '%s' should be of type boolean", key)); } String displayName = null; try { displayName = (String) configuration.get("display-name"); } catch (Exception e) { errors.add(format("'display-name' property for key '%s' should be of type string", key)); } Integer displayOrder = null; try { displayOrder = configuration.get("display-order") == null ? null : Integer.parseInt((String) configuration.get("display-order")); } catch (Exception e) { errors.add(format("'display-order' property for key '%s' should be of type integer", key)); } if (!errors.isEmpty()) { throw new RuntimeException(StringUtils.join(errors, ", ")); } PackageMaterialProperty packageMaterialProperty = new PackageMaterialProperty(key); if (!isEmpty(defaultValue)) { packageMaterialProperty.withDefault(defaultValue); } if (partOfIdentity != null) { packageMaterialProperty.with(Property.PART_OF_IDENTITY, partOfIdentity); } if (isSecure != null) { packageMaterialProperty.with(Property.SECURE, isSecure); } if (required != null) { packageMaterialProperty.with(Property.REQUIRED, required); } if (!isEmpty(displayName)) { packageMaterialProperty.with(Property.DISPLAY_NAME, displayName); } if (displayOrder != null) { packageMaterialProperty.with(Property.DISPLAY_ORDER, displayOrder); } return packageMaterialProperty; } PackageRevision toPackageRevision(String responseBody) { try { Map map; try { map = parseResponseToMap(responseBody); } catch (Exception e) { throw new RuntimeException("Package revision should be returned as a map"); } if (map == null || map.isEmpty()) { return null; } String revision; try { revision = (String) map.get("revision"); } catch (Exception e) { throw new RuntimeException("Package revision should be of type string"); } String revisionComment; try { revisionComment = (String) map.get("revisionComment"); } catch (Exception e) { throw new RuntimeException("Package revision comment should be of type string"); } String user; try { user = (String) map.get("user"); } catch (Exception e) { throw new RuntimeException("Package revision user should be of type string"); } String trackbackUrl; try { trackbackUrl = (String) map.get("trackbackUrl"); } catch (Exception e) { throw new RuntimeException("Package revision trackbackUrl should be of type string"); } Date timestamp; try { String timestampString = (String) map.get("timestamp"); timestamp = new SimpleDateFormat(DATE_PATTERN).parse(timestampString); } catch (Exception e) { throw new RuntimeException("Package revision timestamp should be of type string with format yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); } Map data = (Map) map.get("data"); PackageRevision packageRevision = new PackageRevision(revision, timestamp, user, revisionComment, trackbackUrl, data); return packageRevision; } catch (Exception e) { throw new RuntimeException(format("Unable to de-serialize json response. %s", e.getMessage())); } } private Map packageRevisionToMap(PackageRevision packageRevision) { Map map = new LinkedHashMap(); map.put("revision", packageRevision.getRevision()); map.put("timestamp", new SimpleDateFormat(DATE_PATTERN).format(packageRevision.getTimestamp())); map.put("data", packageRevision.getData()); return map; } }