/* * Copyright 2016 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.domain.packagerepository; import java.io.Serializable; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import javax.annotation.PostConstruct; import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; import com.thoughtworks.go.config.ConfigAttribute; import com.thoughtworks.go.config.ConfigSubtag; import com.thoughtworks.go.config.ConfigTag; import com.thoughtworks.go.config.Validatable; import com.thoughtworks.go.config.ValidationContext; import com.thoughtworks.go.config.builder.ConfigurationPropertyBuilder; import com.thoughtworks.go.config.validation.NameTypeValidator; import com.thoughtworks.go.domain.ConfigErrors; import com.thoughtworks.go.domain.ConfigurationDisplayUtil; import com.thoughtworks.go.domain.config.PluginConfiguration; import com.thoughtworks.go.domain.config.Configuration; import com.thoughtworks.go.domain.config.ConfigurationProperty; import com.thoughtworks.go.domain.config.SecureKeyInfoProvider; import com.thoughtworks.go.plugin.api.config.Property; import com.thoughtworks.go.plugin.api.material.packagerepository.RepositoryConfiguration; import com.thoughtworks.go.util.StringUtil; import com.thoughtworks.go.plugin.access.packagematerial.AbstractMetaDataStore; import com.thoughtworks.go.plugin.access.packagematerial.RepositoryMetadataStore; import com.thoughtworks.go.plugin.access.packagematerial.PackageConfiguration; import com.thoughtworks.go.plugin.access.packagematerial.PackageConfigurations; import static java.lang.String.format; import static org.apache.commons.lang.StringUtils.isBlank; import static org.apache.commons.lang.StringUtils.isEmpty; @ConfigTag("repository") public class PackageRepository implements Serializable, Validatable { @ConfigAttribute(value = "id", allowNull = true) private String id; @ConfigAttribute(value = "name", allowNull = false) private String name; @Expose @SerializedName("plugin") @ConfigSubtag private PluginConfiguration pluginConfiguration = new PluginConfiguration(); @Expose @SerializedName("config") @ConfigSubtag private Configuration configuration = new Configuration(); @ConfigSubtag private transient Packages packages = new Packages(); private ConfigErrors errors = new ConfigErrors(); public static final String NAME = "name"; public static final String REPO_ID = "repoId"; public static final String PLUGIN_CONFIGURATION = "pluginConfiguration"; public static final String CONFIGURATION = "repoConfiguration"; public PackageRepository() { } //used in tests public PackageRepository(String repoId, String name, PluginConfiguration pluginConfiguration, Configuration configurationProperties) { this.id = repoId; this.name = name; this.pluginConfiguration = pluginConfiguration; this.configuration = configurationProperties; } public String getId() { return id; } //used in erb as it cannot access id attribute as it treats 'id' as keyword public String getRepoId() { return getId(); } public void setId(String id) { this.id = id; } public String getName() { return name; } public PluginConfiguration getPluginConfiguration() { return pluginConfiguration; } public void setPluginConfiguration(PluginConfiguration pluginConfiguration) { this.pluginConfiguration = pluginConfiguration; } public void setName(String name) { this.name = name; } public Configuration getConfiguration() { return configuration; } public void setConfiguration(Configuration configuration) { this.configuration = configuration; } public void addConfigurations(List<ConfigurationProperty> configurations) { ConfigurationPropertyBuilder builder = new ConfigurationPropertyBuilder(); for (ConfigurationProperty property : configurations) { RepositoryConfiguration repositoryMetadata = RepositoryMetadataStore.getInstance().getRepositoryMetadata(pluginConfiguration.getId()); if (isValidPluginConfiguration(property.getConfigKeyName(), repositoryMetadata)) { configuration.add(builder.create(property.getConfigKeyName(), property.getConfigValue(), property.getEncryptedValue(), repositoryPropertyFor(property.getConfigKeyName(), repositoryMetadata).getOption(Property.SECURE))); } else { configuration.add(property); } } } private boolean isValidPluginConfiguration(String configKeyName, RepositoryConfiguration repositoryMetadata) { return doesPluginExist() && repositoryPropertyFor(configKeyName, repositoryMetadata) != null; } private Property repositoryPropertyFor(String configKey, RepositoryConfiguration repositoryMetadata) { return repositoryMetadata.get(configKey); } public Packages getPackages() { return packages; } public void setPackages(Packages packages) { this.packages = packages; } public void addPackage(PackageDefinition pkg) { packages.add(pkg); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } PackageRepository that = (PackageRepository) o; if (configuration != null ? !configuration.equals(that.configuration) : that.configuration != null) { return false; } if (id != null ? !id.equals(that.id) : that.id != null) { return false; } if (name != null ? !name.equals(that.name) : that.name != null) { return false; } if (packages != null ? !packages.equals(that.packages) : that.packages != null) { return false; } if (pluginConfiguration != null ? !pluginConfiguration.equals(that.pluginConfiguration) : that.pluginConfiguration != null) { return false; } return true; } @Override public int hashCode() { int result = id != null ? id.hashCode() : 0; result = 31 * result + (name != null ? name.hashCode() : 0); result = 31 * result + (pluginConfiguration != null ? pluginConfiguration.hashCode() : 0); result = 31 * result + (configuration != null ? configuration.hashCode() : 0); result = 31 * result + (packages != null ? packages.hashCode() : 0); return result; } @Override public void validate(ValidationContext validationContext) { if (isBlank(name)) { errors().add(NAME, "Please provide name"); } else if (new NameTypeValidator().isNameInvalid(name)) { errors().add(NAME, NameTypeValidator.errorMessage("PackageRepository", name)); } configuration.validateUniqueness(String.format("Repository '%s'", name)); } @Override public ConfigErrors errors() { return errors; } @Override public void addError(String fieldName, String message) { errors.add(fieldName, message); } @PostConstruct public void setRepositoryReferenceOnPackages() { for (PackageDefinition packageDefinition : packages) { packageDefinition.setRepository(this); } } public String getConfigForDisplay() { String pluginId = pluginConfiguration.getId(); AbstractMetaDataStore metadataStore = RepositoryMetadataStore.getInstance(); List<ConfigurationProperty> propertiesToBeUsedForDisplay = ConfigurationDisplayUtil.getConfigurationPropertiesToBeUsedForDisplay(metadataStore, pluginId, configuration); String prefix = metadataStore.hasPlugin(pluginId) ? "" : "WARNING! Plugin missing for "; return prefix + "Repository: " + configuration.forDisplay(propertiesToBeUsedForDisplay); } public boolean doesPluginExist(){ return RepositoryMetadataStore.getInstance().hasPlugin(pluginConfiguration.getId()); } @PostConstruct public void applyPackagePluginMetadata() { String pluginId = pluginConfiguration.getId(); for (ConfigurationProperty configurationProperty : configuration) { RepositoryMetadataStore repositoryMetadataStore = RepositoryMetadataStore.getInstance(); if (repositoryMetadataStore.getMetadata(pluginId) != null) { boolean isSecureProperty = repositoryMetadataStore.hasOption(pluginId, configurationProperty.getConfigurationKey().getName(), PackageConfiguration.SECURE); configurationProperty.handleSecureValueConfiguration(isSecureProperty); } } for (PackageDefinition packageDefinition : packages) { packageDefinition.applyPackagePluginMetadata(pluginId); } } public void setConfigAttributes(Object attributes) { Map attributesMap = (Map) attributes; if (attributesMap.containsKey(NAME)) { name = ((String) attributesMap.get(NAME)); } if (attributesMap.containsKey(REPO_ID)) { id = ((String) attributesMap.get(REPO_ID)); } if (attributesMap.containsKey(PLUGIN_CONFIGURATION)) { pluginConfiguration.setConfigAttributes(attributesMap.get(PLUGIN_CONFIGURATION)); } if (attributesMap.containsKey(Configuration.CONFIGURATION)) { configuration.clear(); configuration.setConfigAttributes(attributesMap.get(Configuration.CONFIGURATION), getSecureKeyInfoProvider()); } } private SecureKeyInfoProvider getSecureKeyInfoProvider() { final RepositoryMetadataStore repositoryMetadataStore = RepositoryMetadataStore.getInstance(); final PackageConfigurations metadata = repositoryMetadataStore.getMetadata(pluginConfiguration.getId()); if(metadata==null){ return null; } return new SecureKeyInfoProvider() { @Override public boolean isSecure(String key) { PackageConfiguration packageConfiguration = metadata.get(key); return packageConfiguration.getOption(PackageConfiguration.SECURE); } }; } public void addConfigurationErrorFor(String key, String message) { configuration.addErrorFor(key, message); } public boolean isNew() { return isEmpty(id); } public PackageDefinition findPackage(String packageId) { return packages.find(packageId); } public void clearEmptyConfigurations() { configuration.clearEmptyConfigurations(); } public void removePackage(String packageId) { PackageDefinition entryToBeDeleted = null; for (PackageDefinition packageDefinition : packages) { if (packageDefinition.getId().equals(packageId)) { entryToBeDeleted = packageDefinition; } } if (entryToBeDeleted == null) { throw new RuntimeException(format("Could not find package with id:[%s]", packageId)); } packages.remove(entryToBeDeleted); } public PackageDefinition findOrCreatePackageDefinition(Map attributes) { if (attributes.get("packageId") != null) { return findPackage((String) attributes.get("packageId")); } PackageDefinition packageDefinition = new PackageDefinition(); packageDefinition.setRepository(this); packageDefinition.setConfigAttributes(attributes.get("package_definition")); return packageDefinition; } public void validateNameUniqueness(HashMap<String, PackageRepository> nameMap) { if (name == null) { return; } String errorMessageForDuplicateName = String.format("You have defined multiple repositories called '%s'. Repository names are case-insensitive and must be unique.", name); PackageRepository repoWithSameFieldValue = nameMap.get(name.toLowerCase()); if (repoWithSameFieldValue == null) { nameMap.put(name.toLowerCase(), this); } else { repoWithSameFieldValue.addError(NAME, errorMessageForDuplicateName); addError(NAME, errorMessageForDuplicateName); } } @PostConstruct public void ensureIdExists() { if (StringUtil.isBlank(getId())) { setId(UUID.randomUUID().toString()); } } }