package alien4cloud.repository.services; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.UUID; import java.util.stream.Collectors; import javax.annotation.Resource; import org.apache.commons.lang3.StringUtils; import org.elasticsearch.index.query.QueryBuilders; import org.springframework.stereotype.Component; import com.google.common.collect.Maps; import alien4cloud.component.repository.IArtifactResolver; import alien4cloud.component.repository.IConfigurableArtifactResolver; import alien4cloud.component.repository.IConfigurableArtifactResolverFactory; import alien4cloud.dao.IGenericSearchDAO; import alien4cloud.dao.model.FacetedSearchResult; import alien4cloud.exception.AlreadyExistException; import alien4cloud.exception.NotFoundException; import alien4cloud.model.repository.Repository; import alien4cloud.plugin.Plugin; import alien4cloud.plugin.PluginManager; import alien4cloud.plugin.model.PluginComponent; import alien4cloud.repository.model.RepositoryPluginComponent; import alien4cloud.repository.model.ValidationResult; import alien4cloud.rest.model.FilteredSearchRequest; import alien4cloud.rest.utils.JsonUtil; import lombok.extern.slf4j.Slf4j; @Component @Slf4j public class RepositoryService { @Resource(name = "alien-es-dao") private IGenericSearchDAO alienDAO; @Resource private ConfigurableResolverRegistry configurableResolverRegistry; @Resource private ResolverRegistry resolverRegistry; @Resource private PluginManager pluginManager; private Map<String, IConfigurableArtifactResolver> registeredResolvers = Maps.newConcurrentMap(); public void initialize() { // We won't have millions of configured repositories for all the platform List<Repository> repositories = alienDAO.customFindAll(Repository.class, QueryBuilders.matchAllQuery()); if (repositories != null) { for (Repository repository : repositories) { Plugin plugin = alienDAO.findById(Plugin.class, repository.getPluginId()); if (plugin.isEnabled()) { try { createConfiguredResolver(repository.getId(), repository.getConfiguration(), repository.getPluginId()); } catch (Exception e) { log.error("Could not enable repository " + repository.getName() + " of type " + repository.getRepositoryType() + " for plugin " + repository.getPluginId(), e); } } else { // TODO Later when the user has re-enabled the plugin must re-initialize this log.info("Don't enable resolver as the plugin {} with name {} is not enabled ", plugin.getId(), plugin.getDescriptor().getName()); } } } } public void unloadAllResolvers() { registeredResolvers.clear(); } /** * Try to resolve an artifact from all configured resolver plugins and repositories * * @param artifactReference reference of the artifact inside the repository * @param repositoryURL the repository's URL * @param repositoryType the type of the repository * @param credentials the credentials to retrieve the artifact * @return the artifact's path downloaded locally, null if artifact cannot be resolved */ public String resolveArtifact(String artifactReference, String repositoryURL, String repositoryType, Map<String, Object> credentials) { for (IConfigurableArtifactResolver configurableArtifactResolver : registeredResolvers.values()) { String resolvedArtifact = configurableArtifactResolver.resolveArtifact(artifactReference, repositoryURL, repositoryType, credentials); if (resolvedArtifact != null) { return resolvedArtifact; } } for (Map<String, IArtifactResolver> resolverMap : resolverRegistry.getInstancesByPlugins().values()) { for (IArtifactResolver resolver : resolverMap.values()) { String resolvedArtifact = resolver.resolveArtifact(artifactReference, repositoryURL, repositoryType, credentials); if (resolvedArtifact != null) { return resolvedArtifact; } } } return null; } public String getRepositoryUrl(Repository repository) { IConfigurableArtifactResolver resolver = registeredResolvers.get(repository.getId()); return resolver.getConfigurationUrl(); } public boolean canResolveArtifact(String artifactReference, String repositoryURL, String repositoryType, Map<String, Object> credentials) { for (IConfigurableArtifactResolver configurableArtifactResolver : registeredResolvers.values()) { ValidationResult validationResult = configurableArtifactResolver.canHandleArtifact(artifactReference, repositoryURL, repositoryType, credentials); if (validationResult.equals(ValidationResult.SUCCESS)) { return true; } } for (Map<String, IArtifactResolver> resolverMap : resolverRegistry.getInstancesByPlugins().values()) { for (IArtifactResolver resolver : resolverMap.values()) { ValidationResult validationResult = resolver.canHandleArtifact(artifactReference, repositoryURL, repositoryType, credentials); if (validationResult.equals(ValidationResult.SUCCESS)) { return true; } } } return false; } public FacetedSearchResult search(FilteredSearchRequest searchRequest) { return alienDAO.facetedSearch(Repository.class, searchRequest.getQuery(), searchRequest.getFilters(), null, searchRequest.getFrom(), searchRequest.getSize()); } public List<RepositoryPluginComponent> listPluginComponents() { List<RepositoryPluginComponent> repositoryPluginComponents = new ArrayList<>(); List<PluginComponent> pluginComponents = pluginManager.getPluginComponents(IArtifactResolver.class.getSimpleName()); repositoryPluginComponents.addAll(pluginComponents.stream().map( pluginComponent -> new RepositoryPluginComponent(pluginComponent, getResolverFactoryOrFail(pluginComponent.getPluginId()).getResolverType())) .collect(Collectors.toList())); return repositoryPluginComponents; } private IConfigurableArtifactResolverFactory getResolverFactoryOrFail(String pluginId) { IConfigurableArtifactResolverFactory configurableArtifactResolverFactory = configurableResolverRegistry.getSinglePluginBean(pluginId); if (configurableArtifactResolverFactory == null) { throw new NotFoundException("Plugin " + pluginId + " is not found or is not enabled"); } return configurableArtifactResolverFactory; } public Class<?> getRepositoryConfigurationType(String pluginId) { return getResolverFactoryOrFail(pluginId).getResolverConfigurationType(); } private void createConfiguredResolver(String repositoryId, Object configuration, String pluginId) { IConfigurableArtifactResolverFactory configurableArtifactResolverFactory = getResolverFactoryOrFail(pluginId); IConfigurableArtifactResolver configurableArtifactResolver = configurableArtifactResolverFactory.newInstance(); configurableArtifactResolver.setConfiguration(JsonUtil.toObject(configuration, configurableArtifactResolverFactory.getResolverConfigurationType())); registeredResolvers.put(repositoryId, configurableArtifactResolver); } public String createRepositoryConfiguration(String name, String pluginId, Object configuration) { String id = UUID.randomUUID().toString(); Repository repository = new Repository(id, name, pluginId, getResolverFactoryOrFail(pluginId).getResolverType(), configuration); createConfiguredResolver(id, configuration, pluginId); ensureNameUnicityAndSave(repository, null); return id; } public void updateRepository(Repository updated, String oldName, boolean updateConfiguration) { ensureNameUnicityAndSave(updated, oldName); if (updateConfiguration) { if (registeredResolvers.containsKey(updated.getId())) { IConfigurableArtifactResolverFactory resolverFactory = getResolverFactoryOrFail(updated.getPluginId()); IConfigurableArtifactResolver resolver = registeredResolvers.get(updated.getId()); resolver.setConfiguration(JsonUtil.toObject(updated.getConfiguration(), resolverFactory.getResolverConfigurationType())); } } else { log.warn("Repository not found with id [" + updated.getId() + "] and name [" + updated.getName() + "]"); } } public Repository getOrFail(String id) { Repository repository = alienDAO.findById(Repository.class, id); if (repository == null) { throw new NotFoundException("Repository [" + id + "] cannot be found"); } return repository; } public void delete(String id) { alienDAO.delete(Repository.class, id); registeredResolvers.remove(id); } private synchronized void ensureNameUnicityAndSave(Repository repository, String oldName) { if (StringUtils.isBlank(oldName) || !Objects.equals(repository.getName(), oldName)) { // check that the orchestrator doesn't already exists if (alienDAO.count(Repository.class, QueryBuilders.termQuery("name", repository.getName())) > 0) { throw new AlreadyExistException("a repository with the given name already exists."); } } alienDAO.save(repository); } }