/* * 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.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import com.fasterxml.jackson.databind.ObjectMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.Resource; import org.springframework.util.StreamUtils; import org.springframework.util.StringUtils; /** * Builder for {@link InitializrMetadata}. Allows to read metadata from any arbitrary * resource, including remote URLs. * * @author Stephane Nicoll * @see InitializrMetadataCustomizer */ public class InitializrMetadataBuilder { private final List<InitializrMetadataCustomizer> customizers = new ArrayList<>(); private final InitializrConfiguration configuration; private InitializrMetadataBuilder(InitializrConfiguration configuration) { this.configuration = configuration; } /** * Create a builder instance from the specified {@link InitializrProperties}. * Initialize the configuration to use. * @see #withInitializrProperties(InitializrProperties) */ public static InitializrMetadataBuilder fromInitializrProperties( InitializrProperties configuration) { return new InitializrMetadataBuilder(configuration) .withInitializrProperties(configuration); } /** * Create an empty builder instance with a default {@link InitializrConfiguration} */ public static InitializrMetadataBuilder create() { return new InitializrMetadataBuilder(new InitializrConfiguration()); } /** * Add a {@link InitializrProperties} to be merged with other content. Merges the * settings only and not the configuration. * @see #withInitializrProperties(InitializrProperties, boolean) */ public InitializrMetadataBuilder withInitializrProperties( InitializrProperties properties) { return withInitializrProperties(properties, false); } /** * Add a {@link InitializrProperties} to be merged with other content. * @param properties the settings to merge onto this instance * @param mergeConfiguration specify if service configuration should be merged as well */ public InitializrMetadataBuilder withInitializrProperties( InitializrProperties properties, boolean mergeConfiguration) { if (mergeConfiguration) { this.configuration.merge(properties); } return withCustomizer(new InitializerPropertiesCustomizer(properties)); } /** * Add a {@link InitializrMetadata} to be merged with other content. * @param resource a resource to a json document describing the metadata to include */ public InitializrMetadataBuilder withInitializrMetadata(Resource resource) { return withCustomizer(new ResourceInitializrMetadataCustomizer(resource)); } /** * Add a {@link InitializrMetadataCustomizer}. customizers are invoked in their order * of addition. * @see InitializrMetadataCustomizer */ public InitializrMetadataBuilder withCustomizer( InitializrMetadataCustomizer customizer) { customizers.add(customizer); return this; } /** * Build a {@link InitializrMetadata} based on the state of this builder. */ public InitializrMetadata build() { InitializrConfiguration config = this.configuration != null ? this.configuration : new InitializrConfiguration(); InitializrMetadata metadata = createInstance(config); for (InitializrMetadataCustomizer customizer : customizers) { customizer.customize(metadata); } applyDefaults(metadata); metadata.validate(); return metadata; } /** * Creates an empty instance based on the specified {@link InitializrConfiguration} */ protected InitializrMetadata createInstance(InitializrConfiguration configuration) { return new InitializrMetadata(configuration); } /** * Apply defaults to capabilities that have no value. */ protected void applyDefaults(InitializrMetadata metadata) { if (!StringUtils.hasText(metadata.getName().getContent())) { metadata.getName().setContent("demo"); } if (!StringUtils.hasText(metadata.getDescription().getContent())) { metadata.getDescription().setContent("Demo project for Spring Boot"); } if (!StringUtils.hasText(metadata.getGroupId().getContent())) { metadata.getGroupId().setContent("com.example"); } if (!StringUtils.hasText(metadata.getVersion().getContent())) { metadata.getVersion().setContent("0.0.1-SNAPSHOT"); } } private static class InitializerPropertiesCustomizer implements InitializrMetadataCustomizer { private final InitializrProperties properties; InitializerPropertiesCustomizer(InitializrProperties properties) { this.properties = properties; } @Override public void customize(InitializrMetadata metadata) { metadata.getDependencies().merge(properties.getDependencies()); metadata.getTypes().merge(properties.getTypes()); metadata.getBootVersions().merge(properties.getBootVersions()); metadata.getPackagings().merge(properties.getPackagings()); metadata.getJavaVersions().merge(properties.getJavaVersions()); metadata.getLanguages().merge(properties.getLanguages()); properties.getGroupId().apply(metadata.getGroupId()); properties.getArtifactId().apply(metadata.getArtifactId()); properties.getVersion().apply(metadata.getVersion()); properties.getName().apply(metadata.getName()); properties.getDescription().apply(metadata.getDescription()); properties.getPackageName().apply(metadata.getPackageName()); } } private static class ResourceInitializrMetadataCustomizer implements InitializrMetadataCustomizer { private static final Logger log = LoggerFactory.getLogger( InitializrMetadataBuilder.ResourceInitializrMetadataCustomizer.class); private static final Charset UTF_8 = Charset.forName("UTF-8"); private final Resource resource; ResourceInitializrMetadataCustomizer(Resource resource) { this.resource = resource; } @Override public void customize(InitializrMetadata metadata) { log.info("Loading initializr metadata from " + resource); try { String content = StreamUtils.copyToString(resource.getInputStream(), UTF_8); ObjectMapper objectMapper = new ObjectMapper(); InitializrMetadata anotherMetadata = objectMapper.readValue(content, InitializrMetadata.class); metadata.merge(anotherMetadata); } catch (Exception e) { throw new IllegalStateException("Cannot merge", e); } } } }