All Downloads are FREE. Search and download functionalities are using the official Maven repository.

brooklyn.entity.drivers.downloads.DownloadProducerFromProperties Maven / Gradle / Ivy

There is a newer version: 0.7.0-M1
Show newest version
package brooklyn.entity.drivers.downloads;

import static com.google.common.base.Preconditions.checkNotNull;

import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import brooklyn.config.StringConfigMap;
import brooklyn.entity.Entity;
import brooklyn.entity.basic.Attributes;
import brooklyn.entity.drivers.EntityDriver;
import brooklyn.entity.drivers.downloads.DownloadResolverManager.DownloadRequirement;
import brooklyn.entity.drivers.downloads.DownloadResolverManager.DownloadTargets;
import brooklyn.util.text.Strings;

import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
 * Based on the contents of brooklyn properties, sets up rules for resolving where to
 * download artifacts from, for installing entities. 
 * 
 * By default, these rules override the DOWNLOAD_URL defined on the entities in code.
 * Global properties can be specified that apply to all entities. Entity-specific properties
 * can also be specified (which override the global properties for that entity type).
 * 
 * Below is an example of realistic configuration for an enterprise who have an in-house 
 * repository that must be used for everything, rather than going out to the public internet. 
 * 
 * {@code
 * // FIXME Check format for including addonname- only if addonname is non-null?
 * // FIXME Use this in a testng test case
 * brooklyn.downloads.all.url=http://downloads.acme.com/brookyn/repository/${simpletype}/${simpletype}-${addon?? addon-}${version}.${fileSuffix!.tar.gz}
 * }
 * 
* * To illustrate the features and variations one can use, below is an example of global * properties that can be specified. The semicolon-separated list of URLs will be tried in-order * until one succeeds. The fallback url says to use that if all other URLs fail (or no others are * specified). *
 * {@code
 * brooklyn.downloads.all.url=http://myurl1/${simpletype}-${version}.tar.gz; http://myurl2/${simpletype}-${version}.tar.gz
 * brooklyn.downloads.all.fallbackurl=http://myurl3/${simpletype}-${version}.tar.gz
 * }
 * 
* * Similarly, entity-specific properties can be defined. All "global properties" will also apply * to this entity type, unless explicitly overridden. *
 * {@code
 * brooklyn.downloads.entity.tomcatserver.url=http://mytomcaturl1/tomcat-${version}.tar.gz
 * brooklyn.downloads.entity.tomcatserver.fallbackurl=http://myurl2/tomcat-${version}.tar.gz
 * }
 * 
* * Downloads for entity-specific add-ons can also be defined. All "global properties" will also apply * to this entity type, unless explicitly overridden. *
 * {@code
 * brooklyn.downloads.entity.nginxcontroller.addon.stickymodule.url=http://myurl1/nginx-stickymodule-${version}.tar.gz
 * brooklyn.downloads.entity.nginxcontroller.addon.stickymodule.fallbackurl=http://myurl2/nginx-stickymodule-${version}.tar.gz
 * }
 * 
* * If no explicit URLs are supplied, then by default it will use the DOWNLOAD_URL attribute * of the entity (if supplied), followed by the fallbackurl if that fails. * * A URL can be a "template", where things of the form ${version} will be substituted for the value * of "version" provided for that entity. The freemarker template engine is used to convert URLs * (see rules = generateRules(); BasicDownloadTargets.Builder result = BasicDownloadTargets.builder(); for (Rule rule : rules) { if (rule.matches(downloadRequirement.getEntityDriver(), downloadRequirement.getAddonName())) { result.addAll(rule.resolve(downloadRequirement)); } } return result.build(); } /** * Produces a set of URL-generating rules, based on the brooklyn properties. These * rules will be applied in-order until one of them returns a non-empty result. */ private List generateRules() { List result = Lists.newArrayList(); Map subconfig = filterAndStripPrefix(config.asMapWithStringKeys(), DOWNLOAD_CONF_PREFIX); // If exists, use things like: // brooklyn.downloads.all.fallbackurl=... // brooklyn.downloads.all.url=... // But only if not overridden by more entity-specify value Map forall = filterAndStripPrefix(subconfig, "all."); String fallbackUrlForAll = forall.get("fallbackurl"); String urlForAll = forall.get("url"); // If exists, use things like: // brooklyn.downloads.entity.JBoss7Server.url=... Map forSpecificEntities = filterAndStripPrefix(subconfig, "entity."); Map> splitBySpecificEntity = splitByPrefix(forSpecificEntities); for (Map.Entry> entry : splitBySpecificEntity.entrySet()) { String entityType = entry.getKey(); Map forentity = entry.getValue(); String urlForEntity = forentity.get("url"); if (urlForEntity == null) urlForEntity = urlForAll; String fallbackUrlForEntity = forentity.get("fallbackurl"); if (fallbackUrlForEntity == null) fallbackUrlForEntity = fallbackUrlForAll; result.add(new EntitySpecificRule(entityType, urlForEntity, fallbackUrlForEntity)); // If exists, use things like: // brooklyn.downloads.entity.nginxcontroller.addon.stickymodule.url=... Map forSpecificAddons = filterAndStripPrefix(forentity, "addon."); Map> splitBySpecificAddon = splitByPrefix(forSpecificAddons); for (Map.Entry> entry2 : splitBySpecificAddon.entrySet()) { String addonName = entry2.getKey(); Map foraddon = entry2.getValue(); String urlForAddon = foraddon.get("url"); if (urlForAddon == null) urlForAddon = urlForEntity; String fallbackUrlForAddon = foraddon.get("fallbackurl"); if (fallbackUrlForEntity == null) fallbackUrlForAddon = fallbackUrlForEntity; result.add(new EntityAddonSpecificRule(entityType, addonName, urlForAddon, fallbackUrlForAddon)); } } if (!forall.isEmpty()) { result.add(new UniversalRule(urlForAll, fallbackUrlForAll)); } return result; } /** * Returns a sub-map of config for keys that started with the given prefix, but where the returned * map's keys do not include the prefix. */ private static Map filterAndStripPrefix(Map config, String prefix) { Map result = Maps.newLinkedHashMap(); for (Map.Entry entry : config.entrySet()) { String key = entry.getKey(); if (key.startsWith(prefix)) { Object value = entry.getValue(); result.put(key.substring(prefix.length()), (value == null) ? null : value.toString()); } } return result; } /** * Splits the map up into multiple maps, using the key's prefix up to the first dot to * tell which map to include it in. This prefix is used as the key in the map-of-maps, and * is omitted in the contained map. * * For example, given [a.b:v1, a.c:v2, d.e:v3], it will return [ a:[b:v1, c:v2], d:[e:v3] ] */ private static Map> splitByPrefix(Map config) { Map> result = Maps.newLinkedHashMap(); for (Map.Entry entry : config.entrySet()) { String key = entry.getKey(); String keysuffix = key.substring(key.indexOf(".")+1); String keyprefix = key.substring(0, key.length()-keysuffix.length()-1); String value = entry.getValue(); Map submap = result.get(keyprefix); if (submap == null) { submap = Maps.newLinkedHashMap(); result.put(keyprefix, submap); } submap.put(keysuffix, value); } return result; } /** * Resolves the download url, given an EntityDriver, with the following rules: *
    *
  1. If url is not null, split and trim it on ";" and use *
  2. If url is null, retrive entity's Attributes.DOWNLOAD_URL and use if non-null *
  3. If fallbackUrl is not null, split and trim it on ";" and use *
      * * For each of the resulting Strings, transforms them (using freemarker syntax for * substitutions). Returns the list. */ private static abstract class Rule { private final String url; private final String fallbackUrl; Rule(String url, String fallbackUrl) { this.url = url; this.fallbackUrl = fallbackUrl; } abstract boolean matches(EntityDriver driver, String addon); DownloadTargets resolve(DownloadRequirement req) { EntityDriver driver = req.getEntityDriver(); List primaries = Lists.newArrayList(); List fallbacks = Lists.newArrayList(); if (Strings.isEmpty(url)) { String defaulturl = driver.getEntity().getAttribute(Attributes.DOWNLOAD_URL); if (defaulturl != null) primaries.add(defaulturl); } else { String[] parts = url.split(";"); for (String part : parts) { if (!part.isEmpty()) primaries.add(part.trim()); } } if (fallbackUrl != null) { String[] parts = fallbackUrl.split(";"); for (String part : parts) { if (!part.isEmpty()) fallbacks.add(part.trim()); } } BasicDownloadTargets.Builder result = BasicDownloadTargets.builder(); for (String baseurl : primaries) { result.addPrimary(DownloadSubstituters.substitute(req, baseurl)); } for (String baseurl : fallbacks) { result.addFallback(DownloadSubstituters.substitute(req, baseurl)); } return result.build(); } } /** * Rule for generating URLs that applies to all entities, if a more specific rule * did not exist or failed to find a match. */ private static class UniversalRule extends Rule { UniversalRule(String url, String fallbackUrl) { super(url, fallbackUrl); } @Override boolean matches(EntityDriver driver, String addon) { return true; } } /** * Rule for generating URLs that applies to only the entity of the given type. */ private static class EntitySpecificRule extends Rule { private final String entityType; EntitySpecificRule(String entityType, String url, String fallbackUrl) { super(url, fallbackUrl); this.entityType = checkNotNull(entityType, "entityType"); } @Override boolean matches(EntityDriver driver, String addon) { String actualType = driver.getEntity().getEntityType().getName(); String actualSimpleType = actualType.substring(actualType.lastIndexOf(".")+1); return addon == null && entityType.equalsIgnoreCase(actualSimpleType); } } /** * Rule for generating URLs that applies to only the entity of the given type. */ private static class EntityAddonSpecificRule extends Rule { private final String entityType; private final String addonName; EntityAddonSpecificRule(String entityType, String addonName, String url, String fallbackUrl) { super(url, fallbackUrl); this.entityType = checkNotNull(entityType, "entityType"); this.addonName = checkNotNull(addonName, "addonName"); } @Override boolean matches(EntityDriver driver, String addon) { String actualType = driver.getEntity().getEntityType().getName(); String actualSimpleType = actualType.substring(actualType.lastIndexOf(".")+1); return addonName.equals(addon) && entityType.equalsIgnoreCase(actualSimpleType); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy