/*
* Copyright 2017 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.
*/
package com.thoughtworks.go.server.service.materials;
import com.thoughtworks.go.config.ConfigTag;
import com.thoughtworks.go.config.Validatable;
import com.thoughtworks.go.config.commands.EntityConfigUpdateCommand;
import com.thoughtworks.go.config.exceptions.GoConfigInvalidException;
import com.thoughtworks.go.config.update.CreatePackageConfigCommand;
import com.thoughtworks.go.config.update.DeletePackageConfigCommand;
import com.thoughtworks.go.config.update.ErrorCollector;
import com.thoughtworks.go.config.update.UpdatePackageConfigCommand;
import com.thoughtworks.go.domain.ConfigErrors;
import com.thoughtworks.go.domain.config.Configuration;
import com.thoughtworks.go.domain.config.ConfigurationProperty;
import com.thoughtworks.go.domain.packagerepository.PackageDefinition;
import com.thoughtworks.go.domain.packagerepository.PackageRepository;
import com.thoughtworks.go.i18n.LocalizedMessage;
import com.thoughtworks.go.i18n.Localizer;
import com.thoughtworks.go.plugin.access.packagematerial.PackageRepositoryExtension;
import com.thoughtworks.go.plugin.access.packagematerial.PackageConfiguration;
import com.thoughtworks.go.plugin.access.packagematerial.PackageMetadataStore;
import com.thoughtworks.go.plugin.api.material.packagerepository.PackageMaterialProperty;
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.ValidationError;
import com.thoughtworks.go.plugin.api.response.validation.ValidationResult;
import com.thoughtworks.go.server.domain.Username;
import com.thoughtworks.go.server.service.EntityHashingService;
import com.thoughtworks.go.server.service.GoConfigService;
import com.thoughtworks.go.server.service.result.HttpLocalizedOperationResult;
import com.thoughtworks.go.server.service.result.LocalizedOperationResult;
import com.thoughtworks.go.util.StringUtil;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@Service
public class PackageDefinitionService {
private final Localizer localizer;
private EntityHashingService entityHashingService;
private GoConfigService goConfigService;
PackageRepositoryExtension packageRepositoryExtension;
public static final Logger LOGGER = Logger.getLogger(PackageDefinitionService.class);
@Autowired
public PackageDefinitionService(PackageRepositoryExtension packageRepositoryExtension, Localizer localizer, EntityHashingService entityHashingService, GoConfigService goConfigService) {
this.packageRepositoryExtension = packageRepositoryExtension;
this.localizer = localizer;
this.entityHashingService = entityHashingService;
this.goConfigService = goConfigService;
}
public void performPluginValidationsFor(final PackageDefinition packageDefinition) {
String pluginId = packageDefinition.getRepository().getPluginConfiguration().getId();
ValidationResult validationResult = packageRepositoryExtension.isPackageConfigurationValid(pluginId, buildPackageConfigurations(packageDefinition), buildRepositoryConfigurations(packageDefinition.getRepository()));
for (ValidationError error : validationResult.getErrors()) {
packageDefinition.addConfigurationErrorFor(error.getKey(), error.getMessage());
}
for (ConfigurationProperty configurationProperty : packageDefinition.getConfiguration()) {
String key = configurationProperty.getConfigurationKey().getName();
if (PackageMetadataStore.getInstance().hasOption(packageDefinition.getRepository().getPluginConfiguration().getId(), key, PackageConfiguration.REQUIRED)) {
if (configurationProperty.getValue().isEmpty() && configurationProperty.doesNotHaveErrorsAgainstConfigurationValue()) {
configurationProperty.addErrorAgainstConfigurationValue(localizer.localize("MANDATORY_CONFIGURATION_FIELD_WITH_NAME", configurationProperty.getConfigurationKey().getName()));
}
}
}
}
public boolean validatePackageConfiguration(final PackageDefinition packageDefinition) {
String pluginId = packageDefinition.getRepository().getPluginConfiguration().getId();
if (!packageDefinition.getRepository().doesPluginExist()) {
throw new RuntimeException(String.format("Plugin with id '%s' is not found.", pluginId));
}
ValidationResult validationResult = packageRepositoryExtension.isPackageConfigurationValid(pluginId, buildPackageConfigurations(packageDefinition), buildRepositoryConfigurations(packageDefinition.getRepository()));
addErrorsToConfiguration(validationResult, packageDefinition);
return validationResult.isSuccessful();
}
private void addErrorsToConfiguration(ValidationResult validationResult, PackageDefinition packageDefinition) {
for (ValidationError validationError : validationResult.getErrors()) {
ConfigurationProperty property = packageDefinition.getConfiguration().getProperty(validationError.getKey());
if (property != null) {
property.addError(validationError.getKey(), validationError.getMessage());
} else {
String validationErrorKey = StringUtil.isBlank(validationError.getKey()) ? PackageDefinition.CONFIGURATION : validationError.getKey();
packageDefinition.addError(validationErrorKey, validationError.getMessage());
}
}
}
private HashMap<String, List<String>> fieldErrors(Validatable subject, String filedErrorPrefix) {
HashMap<String, List<String>> filedErrors = new HashMap<>();
ErrorCollector.collectFieldErrors(filedErrors, filedErrorPrefix, subject);
return filedErrors;
}
private List<String> globalErrors(List<ConfigErrors> allErrorsExceptSubject) {
ArrayList<String> globalErrors = new ArrayList<>();
ErrorCollector.collectGlobalErrors(globalErrors, allErrorsExceptSubject);
return globalErrors;
}
public void checkConnection(final PackageDefinition packageDefinition, final LocalizedOperationResult result) {
try {
String pluginId = packageDefinition.getRepository().getPluginConfiguration().getId();
Result checkConnectionResult = packageRepositoryExtension.checkConnectionToPackage(pluginId, buildPackageConfigurations(packageDefinition), buildRepositoryConfigurations(packageDefinition.getRepository()));
String messages = checkConnectionResult.getMessagesForDisplay();
if (!checkConnectionResult.isSuccessful()) {
result.connectionError(LocalizedMessage.string("PACKAGE_CHECK_FAILED", messages));
return;
}
result.setMessage(LocalizedMessage.string("PACKAGE_CHECK_OK", messages));
return;
} catch (Exception e) {
result.internalServerError(LocalizedMessage.string("PACKAGE_CHECK_FAILED", e.getMessage()));
}
}
private RepositoryConfiguration buildRepositoryConfigurations(PackageRepository packageRepository) {
RepositoryConfiguration repositoryConfiguration = new RepositoryConfiguration();
populateConfiguration(packageRepository.getConfiguration(), repositoryConfiguration);
return repositoryConfiguration;
}
private void update(Username username, PackageDefinition packageDeinition, HttpLocalizedOperationResult result, EntityConfigUpdateCommand command) {
try {
goConfigService.updateConfig(command, username);
} catch (Exception e) {
if (e instanceof GoConfigInvalidException && !result.hasMessage()) {
result.unprocessableEntity(LocalizedMessage.string("ENTITY_CONFIG_VALIDATION_FAILED", packageDeinition.getClass().getAnnotation(ConfigTag.class).value(), packageDeinition.getId(), e.getMessage()));
} else {
if (!result.hasMessage()) {
LOGGER.error(e.getMessage(), e);
result.internalServerError(LocalizedMessage.string("SAVE_FAILED_WITH_REASON", "An error occurred while saving the package config. Please check the logs for more information."));
}
}
}
}
public PackageDefinition find(String packageId) {
return goConfigService.findPackage(packageId);
}
public List<PackageDefinition> getPackages() {
return goConfigService.getPackages();
}
public void deletePackage(PackageDefinition packageDefinition, Username username, HttpLocalizedOperationResult result) {
DeletePackageConfigCommand command = new DeletePackageConfigCommand(goConfigService, packageDefinition, username, result);
update(username, packageDefinition, result, command);
if (result.isSuccessful()) {
result.setMessage(LocalizedMessage.string("RESOURCE_DELETE_SUCCESSFUL", "package definition", packageDefinition.getId()));
}
}
public void createPackage(PackageDefinition packageDefinition, String repositoryId, Username username, HttpLocalizedOperationResult result) {
CreatePackageConfigCommand command = new CreatePackageConfigCommand(goConfigService, packageDefinition, repositoryId, username, result, this);
update(username, packageDefinition, result, command);
}
public void updatePackage(String oldPackageId, PackageDefinition newPackage, String md5, Username username, HttpLocalizedOperationResult result) {
UpdatePackageConfigCommand command = new UpdatePackageConfigCommand(goConfigService, oldPackageId, newPackage, username, md5, this.entityHashingService, result, this);
update(username, this.find(oldPackageId), result, command);
}
private com.thoughtworks.go.plugin.api.material.packagerepository.PackageConfiguration buildPackageConfigurations(PackageDefinition packageDefinition) {
com.thoughtworks.go.plugin.api.material.packagerepository.PackageConfiguration packageConfiguration = new com.thoughtworks.go.plugin.api.material.packagerepository.PackageConfiguration();
populateConfiguration(packageDefinition.getConfiguration(), packageConfiguration);
return packageConfiguration;
}
private void populateConfiguration(Configuration configuration, com.thoughtworks.go.plugin.api.config.Configuration pluginConfiguration) {
for (ConfigurationProperty configurationProperty : configuration) {
pluginConfiguration.add(new PackageMaterialProperty(configurationProperty.getConfigurationKey().getName(), configurationProperty.getValue()));
}
}
}