/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.brooklyn.core.entity.drivers.downloads; import static com.google.common.base.Preconditions.checkNotNull; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.brooklyn.api.entity.drivers.EntityDriver; import org.apache.brooklyn.api.entity.drivers.downloads.DownloadResolver; import org.apache.brooklyn.api.entity.drivers.downloads.DownloadResolverManager; import org.apache.brooklyn.config.StringConfigMap; import org.apache.brooklyn.util.text.Strings; import com.google.common.base.Function; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.collect.Sets; public class BasicDownloadsManager implements DownloadResolverManager { private final List<Function<? super DownloadRequirement, ? extends DownloadTargets>> producers = Lists.newCopyOnWriteArrayList(); private final List<Function<? super DownloadRequirement, String>> filenameProducers = Lists.newCopyOnWriteArrayList(); /** * The default is (in-order) to: * <ol> * <li>Use the local repo, if any (defaulting to $HOME/.brooklyn/repository) * <li>Use brooklyn properties for any download overrides defined there (see {@link DownloadProducerFromProperties} * <li>Use the entity's Attributes.DOWNLOAD_URL * <li>Use the cloudsoft fallback repo * </ol> * @param config */ public static BasicDownloadsManager newDefault(StringConfigMap config) { BasicDownloadsManager result = new BasicDownloadsManager(); // In-order, will look up: local repo, overrides defined in the properties, and then // the entity's attribute to get the download URL DownloadProducerFromLocalRepo localRepoProducer = new DownloadProducerFromLocalRepo(config); DownloadProducerFromProperties propertiesProducer = new DownloadProducerFromProperties(config); DownloadProducerFromUrlAttribute attributeProducer = new DownloadProducerFromUrlAttribute(); DownloadProducerFromCloudsoftRepo cloudsoftRepoProducer = new DownloadProducerFromCloudsoftRepo(config); result.registerProducer(localRepoProducer); result.registerProducer(propertiesProducer); result.registerProducer(attributeProducer); result.registerProducer(cloudsoftRepoProducer); result.registerFilenameProducer(FilenameProducers.fromFilenameProperty()); result.registerFilenameProducer(FilenameProducers.firstPrimaryTargetOf(propertiesProducer)); result.registerFilenameProducer(FilenameProducers.firstPrimaryTargetOf(attributeProducer)); return result; } public static BasicDownloadsManager newEmpty() { return new BasicDownloadsManager(); } @Override public void registerPrimaryProducer(Function<? super DownloadRequirement, ? extends DownloadTargets> producer) { producers.add(0, checkNotNull(producer, "resolver")); } @Override public void registerProducer(Function<? super DownloadRequirement, ? extends DownloadTargets> producer) { producers.add(checkNotNull(producer, "resolver")); } @Override public void registerFilenameProducer(Function<? super DownloadRequirement, String> producer) { filenameProducers.add(checkNotNull(producer, "producer")); } @Override public DownloadResolver newDownloader(EntityDriver driver) { return newDownloader(new BasicDownloadRequirement(driver)); } @Override public DownloadResolver newDownloader(EntityDriver driver, Map<String, ?> properties) { return newDownloader(new BasicDownloadRequirement(driver, properties)); } @Override public DownloadResolver newDownloader(EntityDriver driver, String addonName, Map<String, ?> addonProperties) { return newDownloader(new BasicDownloadRequirement(driver, addonName, addonProperties)); } private DownloadResolver newDownloader(DownloadRequirement req) { // Infer filename String filename = null; for (Function<? super DownloadRequirement, String> filenameProducer : filenameProducers) { filename = filenameProducer.apply(req); if (!Strings.isBlank(filename)) break; } // If a filename-producer has given us the filename, then augment the DownloadRequirement with that // (so that local-repo substitutions etc can use that explicit filename) DownloadRequirement wrappedReq; if (filename == null) { wrappedReq = req; } else { wrappedReq = BasicDownloadRequirement.copy(req, ImmutableMap.of("filename", filename)); } // Get ordered download targets to be tried List<String> primaries = Lists.newArrayList(); List<String> fallbacks = Lists.newArrayList(); for (Function<? super DownloadRequirement, ? extends DownloadTargets> producer : producers) { DownloadTargets vals = producer.apply(wrappedReq); primaries.addAll(vals.getPrimaryLocations()); fallbacks.addAll(vals.getFallbackLocations()); if (!vals.canContinueResolving()) { break; } } Set<String> result = Sets.newLinkedHashSet(); result.addAll(primaries); result.addAll(fallbacks); if (result.isEmpty()) { throw new IllegalArgumentException("No downloads matched for "+req); } // If filename-producers didn't give any explicit filename, then infer from download results if (filename == null) { for (String target : result) { filename = FilenameProducers.inferFilename(target); if (!Strings.isBlank(filename)) break; } } if (Strings.isBlank(filename)) { throw new IllegalArgumentException("No filenames matched for "+req+" (targets "+result+")"); } // And return the result return new BasicDownloadResolver(result, filename); } }