/* * Copyright 2014 Bernd Vogt and others. * * 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 org.sourcepit.b2.model.builder.util; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static org.sourcepit.common.utils.path.PathMatcher.parsePackagePatterns; import java.util.ArrayList; import java.util.List; import javax.inject.Named; import org.osgi.framework.Version; import org.sourcepit.b2.model.module.AbstractReference; import org.sourcepit.b2.model.module.FeatureInclude; import org.sourcepit.b2.model.module.ModuleModelFactory; import org.sourcepit.b2.model.module.PluginInclude; import org.sourcepit.b2.model.module.RuledReference; import org.sourcepit.b2.model.module.StrictReference; import org.sourcepit.b2.model.module.VersionMatchRule; import org.sourcepit.common.utils.path.PathMatcher; import org.sourcepit.common.utils.props.PropertiesSource; import com.google.common.base.Function; import com.google.common.base.Strings; @Named public class DefaultConverter implements SitesConverter, BasicConverter, FeaturesConverter, ProductsConverter { public boolean isSkipInterpolator(PropertiesSource moduleProperties) { return moduleProperties.getBoolean("b2.skipInterpolator", false); } public boolean isSkipGenerator(PropertiesSource moduleProperties) { return moduleProperties.getBoolean("b2.skipGenerator", false); } public List<String> getAssemblyNames(PropertiesSource moduleProperties) { final List<String> assemblies = new ArrayList<String>(); final String rawAssemblies = moduleProperties.get("b2.assemblies"); if (rawAssemblies != null) { for (String rawAssembly : rawAssemblies.split(",")) { final String assembly = rawAssembly.trim(); if (assembly.length() > 0 && !assemblies.contains(assembly)) { assemblies.add(assembly); } } } return assemblies; } public String getAssemblyClassifier(PropertiesSource properties, String assemblyName) { if (assemblyName == null || assemblyName.length() == 0) { throw new IllegalArgumentException("assemblyName must not be empty."); } // TODO assert result is valid id return properties.get(assemblyKey(assemblyName, "classifier"), toValidId(assemblyName)); } public AggregatorMode getAggregatorMode(PropertiesSource moduleProperties, String assemblyName) { final String literal = get(moduleProperties, assemblyKey(assemblyName, "aggregator.mode"), b2Key("aggregator.mode")); return literal == null ? AggregatorMode.OFF : AggregatorMode.valueOf(literal.toUpperCase()); } public PathMatcher getAggregatorFeatureMatcherForAssembly(PropertiesSource moduleProperties, String assemblyName) { final String patterns = moduleProperties.get(assemblyKey(assemblyName, "aggregator.featuresFilter"), "**"); return PathMatcher.parse(patterns, ".", ","); } public PathMatcher getFeatureMatcherForAssembly(PropertiesSource moduleProperties, String assemblyName) { final String patterns = moduleProperties.get(assemblyKey(assemblyName, "featuresFilter"), "**"); return PathMatcher.parse(patterns, ".", ","); } public PathMatcher getPluginMatcherForAssembly(PropertiesSource moduleProperties, String assemblyName) { final String patterns = moduleProperties.get(assemblyKey(assemblyName, "pluginsFilter"), "!**"); return PathMatcher.parse(patterns, ".", ","); } public List<FeatureInclude> getIncludedFeaturesForAssembly(PropertiesSource moduleProperties, String assemblyName) { final String key = "includedFeatures"; final String rawIncludes = get(moduleProperties, assemblyKey(assemblyName, key), assemblyKey(null, key), b2Key(key)); return toFeatureIncludeList(rawIncludes); } public List<PluginInclude> getIncludedPluginsForAssembly(PropertiesSource moduleProperties, String assemblyName) { final String key = "includedPlugins"; final String rawIncludes = get(moduleProperties, assemblyKey(assemblyName, key), assemblyKey(null, key), b2Key(key)); return toPluginIncludeList(rawIncludes); } public List<RuledReference> getRequiredFeaturesForAssembly(PropertiesSource moduleProperties, String assemblyName) { final String key = "requiredFeatures"; final String rawIncludes = get(moduleProperties, assemblyKey(assemblyName, key), assemblyKey(null, key), b2Key(key)); return toRuledReferenceList(rawIncludes, GREATER_OR_EQUAL); } public List<RuledReference> getRequiredPluginsForAssembly(PropertiesSource moduleProperties, String assemblyName) { final String key = "requiredPlugins"; final String rawIncludes = get(moduleProperties, assemblyKey(assemblyName, key), assemblyKey(null, key), b2Key(key)); return toRuledReferenceList(rawIncludes, GREATER_OR_EQUAL); } public String getFacetClassifier(PropertiesSource properties, String facetName) { if (facetName == null || facetName.length() == 0) { throw new IllegalArgumentException("facetName must not be empty."); } // TODO assert result is valid id return properties.get(facetKey(facetName, "classifier"), toValidId(facetName)); } public PathMatcher getPluginMatcherForFacet(PropertiesSource moduleProperties, String facetName) { final String patterns = moduleProperties.get(facetKey(facetName, "pluginsFilter"), "**"); return PathMatcher.parse(patterns, ".", ","); } public List<FeatureInclude> getIncludedFeaturesForFacet(PropertiesSource moduleProperties, String facetName, boolean isSource) { final String key = isSource ? "includedSourceFeatures" : "includedFeatures"; final String rawIncludes = get(moduleProperties, facetKey(facetName, key), facetKey(null, key), b2Key(key)); return toFeatureIncludeList(rawIncludes); } private List<FeatureInclude> toFeatureIncludeList(final String rawIncludes) { final List<FeatureInclude> result = new ArrayList<FeatureInclude>(); if (rawIncludes != null) { for (String rawInclude : rawIncludes.split(",")) { final String include = rawInclude.trim(); if (include.length() > 0) { result.add(toFeatureInclude(include)); } } } return result; } public List<PluginInclude> getIncludedPluginsForFacet(PropertiesSource moduleProperties, String facetName, boolean isSource) { final String key = isSource ? "includedSourcePlugins" : "includedPlugins"; final String rawIncludes = get(moduleProperties, facetKey(facetName, key), facetKey(null, key), b2Key(key)); return toPluginIncludeList(rawIncludes); } private List<PluginInclude> toPluginIncludeList(final String rawIncludes) { final List<PluginInclude> result = new ArrayList<PluginInclude>(); if (rawIncludes != null) { for (String rawInclude : rawIncludes.split(",")) { final String include = rawInclude.trim(); if (include.length() > 0) { result.add(toPluginInclude(include)); } } } return result; } private List<StrictReference> toStrictReferenceList(final String rawIncludes) { final List<StrictReference> result = new ArrayList<StrictReference>(); if (rawIncludes != null) { for (String rawInclude : rawIncludes.split(",")) { final String include = rawInclude.trim(); if (include.length() > 0) { result.add(toStrictReference(include)); } } } return result; } public List<RuledReference> getRequiredFeaturesForFacet(PropertiesSource moduleProperties, String facetName, boolean isSource) { final String key = isSource ? "requiredSourceFeatures" : "requiredFeatures"; final String requirements = get(moduleProperties, facetKey(facetName, key), facetKey(null, key), b2Key(key)); return toRuledReferenceList(requirements, GREATER_OR_EQUAL); } public List<RuledReference> getRequiredPluginsForFacet(PropertiesSource moduleProperties, String facetName, boolean isSource) { final String key = isSource ? "requiredSourcePlugins" : "requiredPlugins"; final String requirements = get(moduleProperties, facetKey(facetName, key), facetKey(null, key), b2Key(key)); return toRuledReferenceList(requirements, GREATER_OR_EQUAL); } private static final Function<String, VersionMatchRule> GREATER_OR_EQUAL = new Function<String, VersionMatchRule>() { @Override public VersionMatchRule apply(String input) { return VersionMatchRule.GREATER_OR_EQUAL; } }; private static List<RuledReference> toRuledReferenceList(String rawRequirements, Function<String, VersionMatchRule> defaultVersionMatchRule) { final List<RuledReference> result = new ArrayList<RuledReference>(); // foo.feature:1.0.0:compatible, if (rawRequirements != null) { for (String rawRequirement : rawRequirements.split(",")) { final String requirement = rawRequirement.trim(); if (requirement.length() > 0) { result.add(toRuledReference(requirement, defaultVersionMatchRule)); } } } return result; } private static RuledReference toRuledReference(String string, Function<String, VersionMatchRule> defaultVersionMatchRule) { final RuledReference ref = ModuleModelFactory.eINSTANCE.createRuledReference(); final String[] segments = string.split(":"); if (segments.length < 1 || segments.length > 3) { throw new IllegalArgumentException(string + " is not a valid requirement specification"); } parseAndSetIdAndVersion(string, ref, segments); if (segments.length > 2) { final String ruleString = segments[2].trim(); final VersionMatchRule rule = VersionMatchRule.get(ruleString); if (rule == null) { throw new IllegalArgumentException("'" + ruleString + "' in " + string + " is not a valid version matching rule"); } ref.setVersionMatchRule(rule); } else { if (!ref.isSetVersion()) // force set { ref.setVersion("0.0.0"); } ref.setVersionMatchRule(defaultVersionMatchRule.apply(ref.getId())); } return ref; } private static void parseAndSetIdAndVersion(String reference, final AbstractReference ref, final String[] segments) { // TODO assert is valid ref.setId(segments[0].trim()); if (segments.length > 1) { final String versionString = segments[1].trim(); try { new Version(versionString); } catch (IllegalArgumentException e) { throw new IllegalArgumentException("'" + versionString + "' in " + reference + " is not a valid version"); } ref.setVersion(versionString); } } private static FeatureInclude toFeatureInclude(String include) { // foo:1.0.0:optional final FeatureInclude inc = ModuleModelFactory.eINSTANCE.createFeatureInclude(); final String[] segments = include.split(":"); if (segments.length < 1 || segments.length > 3) { throw new IllegalArgumentException(include + " is not a valid feature include specification"); } parseAndSetIdAndVersion(include, inc, segments); if (segments.length > 2) { final String optionalString = segments[2].trim(); if (!"optional".equals(optionalString)) { throw new IllegalArgumentException("'" + optionalString + "' in " + include + " must be 'optional' or missing"); } inc.setOptional(true); } return inc; } private static PluginInclude toPluginInclude(String include) { // foo:1.0.0:unpack final PluginInclude inc = ModuleModelFactory.eINSTANCE.createPluginInclude(); final String[] segments = include.split(":"); if (segments.length < 1 || segments.length > 3) { throw new IllegalArgumentException(include + " is not a valid plugin include specification"); } parseAndSetIdAndVersion(include, inc, segments); inc.setUnpack(false); if (segments.length > 2) { final String optionalString = segments[2].trim(); if (!"unpack".equals(optionalString)) { throw new IllegalArgumentException("'" + optionalString + "' in " + include + " must be 'optional' or missing"); } inc.setUnpack(true); } return inc; } private static StrictReference toStrictReference(String include) { // foo:1.0.0 final StrictReference ref = ModuleModelFactory.eINSTANCE.createStrictReference(); final String[] segments = include.split(":"); if (segments.length < 1 || segments.length > 2) { throw new IllegalArgumentException(include + " is not a valid reference specification"); } parseAndSetIdAndVersion(include, ref, segments); return ref; } private static String assemblyKey(String assemblyName, String key) { if (Strings.isNullOrEmpty(assemblyName)) { return b2Key("assemblies." + key); } return b2Key("assemblies." + assemblyName + "." + key); } private static String facetKey(String facetName, String key) { if (Strings.isNullOrEmpty(facetName)) { return b2Key("facets." + key); } return b2Key("facets." + facetName + "." + key); } private static String b2Key(String key) { return "b2." + key; } private static String get(PropertiesSource moduleProperties, String... keys) { for (String key : keys) { final String value = moduleProperties.get(key); if (value != null) { return value; } } return null; } @Override public String getFeatureIdForAssembly(PropertiesSource moduleProperties, String assemblyName, String moduleId) { String featureId = moduleProperties.get(assemblyKey(assemblyName, "featureId")); if (featureId == null) { final String classifier = getAssemblyClassifier(moduleProperties, assemblyName); featureId = getFeatureId(moduleProperties, moduleId, classifier, false); } return featureId; } @Override public String getFeatureIdForFacet(PropertiesSource moduleProperties, String facetName, String moduleId, boolean isSource) { String featureId = moduleProperties.get(facetKey(facetName, isSource ? "sourceFeatureId" : "featureId")); if (featureId == null) { final String classifier = getFacetClassifier(moduleProperties, facetName); featureId = getFeatureId(moduleProperties, moduleId, classifier, isSource); } return featureId; } private String getFeatureId(PropertiesSource properties, String moduleId, String classifier, boolean isSource) { final StringBuilder sb = new StringBuilder(); if (classifier != null) { sb.append(classifier); } if (isSource) { if (sb.length() > 0) { sb.append('.'); } sb.append(properties.get("b2.featuresSourceClassifier", "sources")); } return idOfProject(moduleId, sb.toString(), properties.get("b2.featuresAppendix", "feature")); } public boolean isSkipBrandingPlugins(PropertiesSource properties) { return properties.getBoolean("b2.skipBrandingPlugins", false); } @Override public String getBrandingPluginIdForAssembly(PropertiesSource moduleProperties, String assemblyName, String moduleId) { String pluginId = moduleProperties.get(assemblyKey(assemblyName, "brandingPluginId")); if (pluginId == null) { final String classifier = getAssemblyClassifier(moduleProperties, assemblyName); pluginId = getBrandingPluginId(moduleProperties, moduleId, classifier, false); } return pluginId; } @Override public String getBrandingPluginIdForFacet(PropertiesSource moduleProperties, String facetName, String moduleId, boolean isSource) { String pluginId = moduleProperties.get(facetKey(facetName, isSource ? "sourceBrandingPluginId" : "brandingPluginId")); if (pluginId == null) { final String classifier = getFacetClassifier(moduleProperties, facetName); pluginId = getBrandingPluginId(moduleProperties, moduleId, classifier, isSource); } return pluginId; } private String getBrandingPluginId(PropertiesSource properties, String moduleId, String classifier, boolean isSource) { final StringBuilder sb = new StringBuilder(); if (classifier != null) { sb.append(classifier); } if (isSource) { if (sb.length() > 0) { sb.append('.'); } sb.append(properties.get("b2.featuresSourceClassifier", "sources")); } return idOfProject(moduleId, sb.toString(), properties.get("b2.brandingPluginsAppendix", "branding")); } public String getSourcePluginId(PropertiesSource moduleProperties, String pluginId) { final StringBuilder sb = new StringBuilder(); sb.append(pluginId); if (sb.length() > 0) { sb.append('.'); sb.append(moduleProperties.get("b2.pluginsSourceClassifier", "source")); } return sb.toString(); } public List<String> getAssemblyCategories(PropertiesSource moduleProperties, String assemblyName) { final String rawCategories = getRawAssemblyCategories(moduleProperties, assemblyName); final List<String> categories = new ArrayList<String>(); if (rawCategories != null) { for (String rawAssembly : rawCategories.split(",")) { final String assembly = rawAssembly.trim(); if (assembly.length() > 0 && !categories.contains(assembly)) { categories.add(assembly); } } } return categories; } private String getRawAssemblyCategories(PropertiesSource moduleProperties, String assemblyName) { String rawCategories = get(moduleProperties, assemblyKey(assemblyName, "categories"), assemblyKey(null, "categories")); if (rawCategories == null) { rawCategories = "assembled, included"; } return rawCategories; } public PathMatcher getAssemblySiteFeatureMatcher(PropertiesSource moduleProperties, String assemblyName) { String filterPatterns = get(moduleProperties, assemblyKey(assemblyName, "siteFeaturesFilter"), assemblyKey(null, "siteFeaturesFilter")); if (Strings.isNullOrEmpty(filterPatterns)) { filterPatterns = "**"; } return PathMatcher.parsePackagePatterns(filterPatterns); } public PathMatcher getAssemblyCategoryFeatureMatcher(PropertiesSource moduleProperties, String moduleId, String assemblyName, String category) { String defaultFilter; if ("included".equals(category)) { final String assemblyClassifier = getAssemblyClassifier(moduleProperties, assemblyName); defaultFilter = "**,!" + getFeatureId(moduleProperties, moduleId, assemblyClassifier, false); } else if ("assembled".equals(category)) { final String assemblyClassifier = getAssemblyClassifier(moduleProperties, assemblyName); defaultFilter = getFeatureId(moduleProperties, moduleId, assemblyClassifier, false); } else { defaultFilter = "**"; } final String filter = moduleProperties.get(assemblyKey(assemblyName, "categories." + category + ".filter"), defaultFilter); return PathMatcher.parsePackagePatterns(filter); } public String getSiteIdForAssembly(PropertiesSource moduleProperties, String moduleId, String assemblyName) { String siteId = moduleProperties.get(assemblyKey(assemblyName, "siteId")); if (siteId == null) { siteId = idOfProject(moduleId, getAssemblyClassifier(moduleProperties, assemblyName), moduleProperties.get("b2.sitesAppendix", "site")); } return siteId; } private static String idOfProject(String moduleId, String classifier, String appendix) { final StringBuilder sb = new StringBuilder(); sb.append(moduleId); if (classifier != null && classifier.length() > 0) { sb.append('.'); sb.append(classifier); } if (appendix != null && appendix.length() > 0) { sb.append("."); sb.append(appendix); } return sb.toString(); } protected static String toValidId(String string) { // TODO assert not empty return toJavaIdentifier(string.toLowerCase()); } /** * Converts the specified string into a valid Java identifier. All illegal characters are replaced by underscores. * * @param aString <i>(required)</i>. The string must contain at least one character. * @return <i>(required)</i>. */ private static String toJavaIdentifier(String aString) { if (aString.length() == 0) { return "_"; } final StringBuilder res = new StringBuilder(); int idx = 0; char c = aString.charAt(idx); if (Character.isJavaIdentifierStart(c)) { res.append(c); idx++; } else if (Character.isJavaIdentifierPart(c)) { res.append('_'); } while (idx < aString.length()) { c = aString.charAt(idx++); res.append(Character.isJavaIdentifierPart(c) || c == '.' ? c : '_'); } return res.toString(); } public String getModuleVersion(PropertiesSource moduleProperties) { return moduleProperties.get("b2.moduleVersion", "0.1.0.qualifier"); } public String getNameSpace(PropertiesSource moduleProperties) { return moduleProperties.get("b2.moduleNameSpace", "b2.module"); } @Override public PathMatcher getResourceMatcherForProduct(PropertiesSource moduleProperties, String productId) { String patterns = get(moduleProperties, productKey(productId, "resources"), productKey(null, "resources")); if (patterns == null) { patterns = "!**"; } return PathMatcher.parse(patterns, "/", ","); } @Override public VersionMatchRule getDefaultVersionMatchRuleForProduct(PropertiesSource moduleProperties, String productId) { final String key = "defaultVersionMatchRule"; final String defaultVersionMatchRule = get(moduleProperties, productKey(productId, key), productKey(null, key)); final VersionMatchRule rule = VersionMatchRule.get(defaultVersionMatchRule); checkNotNull(rule); return rule; } @Override public List<RuledReference> getIncludedFeaturesForProduct(final PropertiesSource moduleProperties, final String productId, final VersionMatchRule defaultVersionMatchRule) { final String key = "features"; final String rawIncludes = get(moduleProperties, productKey(productId, key), productKey(null, key)); return toRuledReferenceList(rawIncludes, new Function<String, VersionMatchRule>() { @Override public VersionMatchRule apply(String featureId) { return getVersionMatchRuleForProductInclude(moduleProperties, productId, featureId, defaultVersionMatchRule); } }); } @Override public List<RuledReference> getIncludedPluginsForProduct(final PropertiesSource moduleProperties, final String productId, final VersionMatchRule defaultVersionMatchRule) { final String key = "plugins"; final String rawIncludes = get(moduleProperties, productKey(productId, key), productKey(null, key)); return toRuledReferenceList(rawIncludes, new Function<String, VersionMatchRule>() { @Override public VersionMatchRule apply(String pluginId) { return getVersionMatchRuleForProductInclude(moduleProperties, productId, pluginId, defaultVersionMatchRule); } }); } @Override public VersionMatchRule getVersionMatchRuleForProductInclude(PropertiesSource moduleProperties, String productId, String featureOrPluginId, VersionMatchRule defaultVersionMatchRule) { final String key = "versionMatchRules"; final String rawRules = get(moduleProperties, productKey(productId, key), productKey(null, key)); if (rawRules != null) { for (String mapping : rawRules.split(";")) { final String[] patternToRule = mapping.split("="); checkState(patternToRule.length == 2, "Invalid mapping %s", mapping); if (parsePackagePatterns(patternToRule[0].trim()).isMatch(featureOrPluginId)) { final String literal = patternToRule[1].trim(); final VersionMatchRule rule = VersionMatchRule.get(literal); checkNotNull(rule, "Invalid version match rule %s", literal); return rule; } } } return defaultVersionMatchRule; } public List<String> getUpdateSitesForProduct(PropertiesSource moduleProperties, String productId) { final String key = "sites"; final String rawSites = get(moduleProperties, productKey(productId, key), productKey(null, key)); final List<String> sites = new ArrayList<String>(); if (rawSites != null) { for (String rawInclude : rawSites.split(",")) { final String site = rawInclude.trim(); if (site.length() > 0) { sites.add(site); } } } return sites; } private static String productKey(String productId, String key) { if (Strings.isNullOrEmpty(productId)) { return b2Key("products." + key); } return b2Key("products." + productId + "." + key); } }