/* * Copyright 2012-2017 the original author or authors. * * 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 io.spring.initializr.metadata; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import io.spring.initializr.util.InvalidVersionException; import io.spring.initializr.util.Version; import io.spring.initializr.util.VersionParser; import io.spring.initializr.util.VersionProperty; import io.spring.initializr.util.VersionRange; /** * Define a Bill Of Materials to be represented in the generated project if a dependency * refers to it. * * @author Stephane Nicoll */ @JsonInclude(JsonInclude.Include.NON_DEFAULT) public class BillOfMaterials { private String groupId; private String artifactId; private String version; private VersionProperty versionProperty; private Integer order = Integer.MAX_VALUE; private List<String> additionalBoms = new ArrayList<>(); private List<String> repositories = new ArrayList<>(); private final List<Mapping> mappings = new ArrayList<>(); public BillOfMaterials() { } private BillOfMaterials(String groupId, String artifactId) { this(groupId, artifactId, null); } private BillOfMaterials(String groupId, String artifactId, String version) { this.groupId = groupId; this.artifactId = artifactId; this.version = version; } public String getGroupId() { return groupId; } public void setGroupId(String groupId) { this.groupId = groupId; } public String getArtifactId() { return artifactId; } public void setArtifactId(String artifactId) { this.artifactId = artifactId; } /** * Return the version of the BOM. Can be {@code null} if it is provided via a mapping. */ public String getVersion() { return version; } public void setVersion(String version) { this.version = version; } /** * Return the {@link VersionProperty} to use to externalize the version of the BOM. * When this is set, a version property is automatically added rather than setting * the version in the bom declaration itself. */ public VersionProperty getVersionProperty() { return versionProperty; } public void setVersionProperty(VersionProperty versionProperty) { this.versionProperty = versionProperty; } public void setVersionProperty(String versionPropertyName) { setVersionProperty(new VersionProperty(versionPropertyName)); } /** * Return the relative order of this BOM where lower values have higher priority. The * default value is {@code Integer.MAX_VALUE}, indicating lowest priority. The Spring * Boot dependencies bom has an order of 100. */ public Integer getOrder() { return order; } public void setOrder(Integer order) { this.order = order; } /** * Return the BOM(s) that should be automatically included if this BOM is required. * Can be {@code null} if it is provided via a mapping. */ public List<String> getAdditionalBoms() { return additionalBoms; } public void setAdditionalBoms(List<String> additionalBoms) { this.additionalBoms = additionalBoms; } /** * Return the repositories that are required if this BOM is required. Can be * {@code null} if it is provided via a mapping. */ public List<String> getRepositories() { return repositories; } public void setRepositories(List<String> repositories) { this.repositories = repositories; } public List<Mapping> getMappings() { return mappings; } public void validate() { if (version == null && mappings.isEmpty()) { throw new InvalidInitializrMetadataException( "No version available for " + this); } updateVersionRange(VersionParser.DEFAULT); } public void updateVersionRange(VersionParser versionParser) { mappings.forEach(it -> { try { it.range = versionParser.parseRange(it.versionRange); } catch (InvalidVersionException ex) { throw new InvalidInitializrMetadataException( "Invalid version range " + it.versionRange + " for " + this, ex); } }); } /** * Resolve this instance according to the specified Spring Boot {@link Version}. * Return a {@link BillOfMaterials} instance that holds the version, repositories and * additional BOMs to use, if any. */ public BillOfMaterials resolve(Version bootVersion) { if (mappings.isEmpty()) { return this; } for (Mapping mapping : mappings) { if (mapping.range.match(bootVersion)) { BillOfMaterials resolvedBom = new BillOfMaterials(groupId, artifactId, mapping.version); resolvedBom.setVersionProperty(versionProperty); resolvedBom.setOrder(order); resolvedBom.repositories.addAll(!mapping.repositories.isEmpty() ? mapping.repositories : repositories); resolvedBom.additionalBoms.addAll(!mapping.additionalBoms.isEmpty() ? mapping.additionalBoms : additionalBoms); return resolvedBom; } } throw new IllegalStateException( "No suitable mapping was found for " + this + " and version " + bootVersion); } @Override public String toString() { return "BillOfMaterials [" + (groupId != null ? "groupId=" + groupId + ", " : "") + (artifactId != null ? "artifactId=" + artifactId + ", " : "") + (version != null ? "version=" + version + ", " : "") + (versionProperty != null ? "versionProperty=" + versionProperty + ", " : "") + (order != null ? "order=" + order + ", " : "") + (additionalBoms != null ? "additionalBoms=" + additionalBoms + ", " : "") + (repositories != null ? "repositories=" + repositories : "") + "]"; } public static class Mapping { private String versionRange; private String version; private List<String> repositories = new ArrayList<>(); private List<String> additionalBoms = new ArrayList<>(); @JsonIgnore private VersionRange range; public Mapping() { } private Mapping(String range, String version, String... repositories) { this.versionRange = range; this.version = version; this.repositories.addAll(Arrays.asList(repositories)); } public String determineVersionRangeRequirement() { return range.toString(); } public static Mapping create(String range, String version) { return new Mapping(range, version); } public static Mapping create(String range, String version, String... repositories) { return new Mapping(range, version, repositories); } public String getVersionRange() { return versionRange; } public String getVersion() { return version; } public List<String> getRepositories() { return repositories; } public List<String> getAdditionalBoms() { return additionalBoms; } public VersionRange getRange() { return range; } public void setVersionRange(String versionRange) { this.versionRange = versionRange; } public void setVersion(String version) { this.version = version; } public void setRepositories(List<String> repositories) { this.repositories = repositories; } public void setAdditionalBoms(List<String> additionalBoms) { this.additionalBoms = additionalBoms; } public void setRange(VersionRange range) { this.range = range; } @Override public String toString() { return "Mapping [" + (versionRange != null ? "versionRange=" + versionRange + ", " : "") + (version != null ? "version=" + version + ", " : "") + (repositories != null ? "repositories=" + repositories + ", " : "") + (additionalBoms != null ? "additionalBoms=" + additionalBoms + ", " : "") + (range != null ? "range=" + range : "") + "]"; } } public static BillOfMaterials create(String groupId, String artifactId) { return new BillOfMaterials(groupId, artifactId); } public static BillOfMaterials create(String groupId, String artifactId, String version) { return new BillOfMaterials(groupId, artifactId, version); } }