diff --git a/initializr-generator/src/main/groovy/io/spring/initializr/generator/CommandLineHelpGenerator.groovy b/initializr-generator/src/main/groovy/io/spring/initializr/generator/CommandLineHelpGenerator.groovy index cab3f2e2..8f211f0f 100644 --- a/initializr-generator/src/main/groovy/io/spring/initializr/generator/CommandLineHelpGenerator.groovy +++ b/initializr-generator/src/main/groovy/io/spring/initializr/generator/CommandLineHelpGenerator.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2016 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. @@ -18,10 +18,9 @@ package io.spring.initializr.generator import io.spring.initializr.metadata.InitializrMetadata import io.spring.initializr.metadata.Type +import io.spring.initializr.util.GroovyTemplate import io.spring.initializr.util.VersionRange -import static io.spring.initializr.util.GroovyTemplate.template - /** * Generate help pages for command-line clients. * @@ -39,6 +38,12 @@ class CommandLineHelpGenerator { =========|_|==============|___/=/_/_/_/ ''' + private final GroovyTemplate template + + CommandLineHelpGenerator(GroovyTemplate template) { + this.template = template + } + /** * Generate the capabilities of the service as a generic plain text * document. Used when no particular agent was detected. @@ -46,7 +51,7 @@ class CommandLineHelpGenerator { String generateGenericCapabilities(InitializrMetadata metadata, String serviceUrl) { def model = initializeCommandLineModel(metadata, serviceUrl) model['hasExamples'] = false - template 'cli-capabilities.txt', model + template.process 'cli-capabilities.txt', model } /** @@ -55,9 +60,9 @@ class CommandLineHelpGenerator { */ String generateCurlCapabilities(InitializrMetadata metadata, String serviceUrl) { def model = initializeCommandLineModel(metadata, serviceUrl) - model['examples'] = template 'curl-examples.txt', model + model['examples'] = template.process 'curl-examples.txt', model model['hasExamples'] = true - template 'cli-capabilities.txt', model + template.process 'cli-capabilities.txt', model } /** @@ -66,9 +71,9 @@ class CommandLineHelpGenerator { */ String generateHttpieCapabilities(InitializrMetadata metadata, String serviceUrl) { def model = initializeCommandLineModel(metadata, serviceUrl) - model['examples'] = template 'httpie-examples.txt', model + model['examples'] = template.process 'httpie-examples.txt', model model['hasExamples'] = true - template 'cli-capabilities.txt', model + template.process 'cli-capabilities.txt', model } /** @@ -78,7 +83,7 @@ class CommandLineHelpGenerator { String generateSpringBootCliCapabilities(InitializrMetadata metadata, String serviceUrl) { def model = initializeSpringBootCliModel(metadata, serviceUrl) model['hasExamples'] = false - template('boot-cli-capabilities.txt', model) + template.process('boot-cli-capabilities.txt', model) } protected Map initializeCommandLineModel(InitializrMetadata metadata, serviceUrl) { diff --git a/initializr-generator/src/main/groovy/io/spring/initializr/generator/ProjectGenerator.groovy b/initializr-generator/src/main/groovy/io/spring/initializr/generator/ProjectGenerator.groovy index 1a71acf1..97bdb0e3 100644 --- a/initializr-generator/src/main/groovy/io/spring/initializr/generator/ProjectGenerator.groovy +++ b/initializr-generator/src/main/groovy/io/spring/initializr/generator/ProjectGenerator.groovy @@ -20,6 +20,7 @@ import groovy.util.logging.Slf4j import io.spring.initializr.InitializrException import io.spring.initializr.metadata.Dependency import io.spring.initializr.metadata.InitializrMetadataProvider +import io.spring.initializr.util.GroovyTemplate import io.spring.initializr.util.Version import org.springframework.beans.factory.annotation.Autowired @@ -28,7 +29,6 @@ import org.springframework.context.ApplicationEventPublisher import org.springframework.util.Assert import static io.spring.initializr.metadata.InitializrConfiguration.Env.Maven.ParentPom -import static io.spring.initializr.util.GroovyTemplate.template /** * Generate a project based on the configured metadata. @@ -58,6 +58,9 @@ class ProjectGenerator { @Autowired ProjectRequestResolver requestResolver + @Autowired + GroovyTemplate groovyTemplate = new GroovyTemplate() + @Autowired ProjectResourceLocator projectResourceLocator = new ProjectResourceLocator() @@ -321,12 +324,12 @@ class ProjectGenerator { } private byte[] doGenerateMavenPom(Map model) { - template 'starter-pom.xml', model + groovyTemplate.process 'starter-pom.xml', model } private byte[] doGenerateGradleBuild(Map model) { - template 'starter-build.gradle', model + groovyTemplate.process 'starter-build.gradle', model } private void writeGradleWrapper(File dir) { @@ -384,7 +387,7 @@ class ProjectGenerator { def write(File target, String templateName, def model) { def tmpl = templateName.endsWith('.groovy') ? templateName + '.tmpl' : templateName - def body = template tmpl, model + def body = groovyTemplate.process tmpl, model target.write(body) } diff --git a/initializr-generator/src/main/groovy/io/spring/initializr/util/GroovyTemplate.groovy b/initializr-generator/src/main/groovy/io/spring/initializr/util/GroovyTemplate.groovy index 923a8854..97850088 100644 --- a/initializr-generator/src/main/groovy/io/spring/initializr/util/GroovyTemplate.groovy +++ b/initializr-generator/src/main/groovy/io/spring/initializr/util/GroovyTemplate.groovy @@ -16,36 +16,52 @@ package io.spring.initializr.util +import java.util.concurrent.ConcurrentMap + import groovy.text.GStringTemplateEngine import groovy.text.Template import groovy.text.TemplateEngine import org.codehaus.groovy.control.CompilationFailedException +import org.springframework.util.ConcurrentReferenceHashMap + /** * @author Dave Syer * @since 1.0 */ class GroovyTemplate { - // This is a copy/paste from GroovyTemplate in spring-boot-cli. We should migrate - // to Spring's native support available in 4.1 + boolean cache = true - static String template(String name, Map model) throws IOException, - CompilationFailedException, ClassNotFoundException { - template(new GStringTemplateEngine(), name, model) + private final TemplateEngine engine + private final ConcurrentMap templateCaches = new ConcurrentReferenceHashMap<>() + + GroovyTemplate(TemplateEngine engine) { + this.engine = engine } - static String template(TemplateEngine engine, String name, Map model) + GroovyTemplate() { + this(new GStringTemplateEngine()) + } + + String process(String name, Map model) throws IOException, CompilationFailedException, ClassNotFoundException { - def writable = getTemplate(engine, name).make(model) + def template = getTemplate(name) + def writable = template.make(model) def result = new StringWriter() writable.writeTo(result) result.toString() } - static Template getTemplate(TemplateEngine engine, String name) + Template getTemplate(String name) throws CompilationFailedException, ClassNotFoundException, IOException { + if (cache) { + return this.templateCaches.computeIfAbsent(name, { n -> loadTemplate(n) }) + } + return loadTemplate(name) + } + protected Template loadTemplate(String name) { def file = new File("templates", name) if (file.exists()) { return engine.createTemplate(file) @@ -59,4 +75,5 @@ class GroovyTemplate { return engine.createTemplate(name) } + } diff --git a/initializr-generator/src/test/groovy/io/spring/initializr/generator/CommandLineHelpGeneratorTests.groovy b/initializr-generator/src/test/groovy/io/spring/initializr/generator/CommandLineHelpGeneratorTests.groovy index 3baa3eb7..e0398995 100644 --- a/initializr-generator/src/test/groovy/io/spring/initializr/generator/CommandLineHelpGeneratorTests.groovy +++ b/initializr-generator/src/test/groovy/io/spring/initializr/generator/CommandLineHelpGeneratorTests.groovy @@ -19,6 +19,7 @@ package io.spring.initializr.generator import io.spring.initializr.metadata.Dependency import io.spring.initializr.metadata.Type import io.spring.initializr.test.metadata.InitializrMetadataTestBuilder +import io.spring.initializr.util.GroovyTemplate import org.junit.Test import static org.hamcrest.CoreMatchers.containsString @@ -30,7 +31,7 @@ import static org.junit.Assert.assertThat */ class CommandLineHelpGeneratorTests { - private CommandLineHelpGenerator generator = new CommandLineHelpGenerator() + private CommandLineHelpGenerator generator = new CommandLineHelpGenerator(new GroovyTemplate()) @Test void generateGenericCapabilities() { diff --git a/initializr-service/src/main/groovy/io/spring/initializr/service/InitializrService.groovy b/initializr-service/src/main/groovy/io/spring/initializr/service/InitializrService.groovy index 3eb01540..f6167fd7 100644 --- a/initializr-service/src/main/groovy/io/spring/initializr/service/InitializrService.groovy +++ b/initializr-service/src/main/groovy/io/spring/initializr/service/InitializrService.groovy @@ -18,6 +18,8 @@ package io.spring.initializr.service import java.util.concurrent.Executor +import io.spring.initializr.metadata.InitializrMetadataProvider +import io.spring.initializr.util.GroovyTemplate import io.spring.initializr.web.project.LegacyStsController import org.springframework.boot.SpringApplication @@ -44,8 +46,9 @@ class InitializrService { @Bean @SuppressWarnings("deprecation") - LegacyStsController legacyStsController() { - new LegacyStsController() + LegacyStsController legacyStsController(InitializrMetadataProvider metadataProvider, + GroovyTemplate groovyTemplate) { + new LegacyStsController(metadataProvider, groovyTemplate) } @Configuration diff --git a/initializr-web/src/main/groovy/io/spring/initializr/web/autoconfigure/InitializrAutoConfiguration.groovy b/initializr-web/src/main/groovy/io/spring/initializr/web/autoconfigure/InitializrAutoConfiguration.groovy index 2f17b7db..eeebc312 100644 --- a/initializr-web/src/main/groovy/io/spring/initializr/web/autoconfigure/InitializrAutoConfiguration.groovy +++ b/initializr-web/src/main/groovy/io/spring/initializr/web/autoconfigure/InitializrAutoConfiguration.groovy @@ -27,6 +27,7 @@ import io.spring.initializr.metadata.DependencyMetadataProvider import io.spring.initializr.metadata.InitializrMetadataBuilder import io.spring.initializr.metadata.InitializrMetadataProvider import io.spring.initializr.metadata.InitializrProperties +import io.spring.initializr.util.GroovyTemplate import io.spring.initializr.web.project.MainController import io.spring.initializr.web.support.DefaultDependencyMetadataProvider import io.spring.initializr.web.support.DefaultInitializrMetadataProvider @@ -34,6 +35,7 @@ import io.spring.initializr.web.ui.UiController import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean +import org.springframework.boot.bind.RelaxedPropertyResolver import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.cache.Cache import org.springframework.cache.CacheManager @@ -43,6 +45,7 @@ import org.springframework.cache.concurrent.ConcurrentMapCache import org.springframework.cache.support.SimpleCacheManager import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration +import org.springframework.core.env.Environment import org.springframework.web.client.RestTemplate /** @@ -72,8 +75,11 @@ class InitializrAutoConfiguration { @Bean @ConditionalOnMissingBean - MainController initializrMainController() { - new MainController() + MainController initializrMainController(InitializrMetadataProvider metadataProvider, + GroovyTemplate groovyTemplate, + ProjectGenerator projectGenerator, + DependencyMetadataProvider dependencyMetadataProvider) { + new MainController(metadataProvider, groovyTemplate, projectGenerator, dependencyMetadataProvider) } @Bean @@ -88,6 +94,16 @@ class InitializrAutoConfiguration { new ProjectGenerator() } + @Bean + @ConditionalOnMissingBean + GroovyTemplate groovyTemplate(Environment environment) { + def resolver = new RelaxedPropertyResolver(environment, 'spring.groovy.template.') + boolean cache = resolver.getProperty('cache', Boolean.class, true) + def groovyTemplate = new GroovyTemplate() + groovyTemplate.cache = cache + groovyTemplate + } + @Bean @ConditionalOnMissingBean ProjectRequestResolver projectRequestResolver() { diff --git a/initializr-web/src/main/groovy/io/spring/initializr/web/project/AbstractInitializrController.groovy b/initializr-web/src/main/groovy/io/spring/initializr/web/project/AbstractInitializrController.groovy index e44632f1..ea89253e 100644 --- a/initializr-web/src/main/groovy/io/spring/initializr/web/project/AbstractInitializrController.groovy +++ b/initializr-web/src/main/groovy/io/spring/initializr/web/project/AbstractInitializrController.groovy @@ -21,14 +21,12 @@ import javax.servlet.http.HttpServletResponse import io.spring.initializr.generator.InvalidProjectRequestException import io.spring.initializr.metadata.InitializrMetadataProvider +import io.spring.initializr.util.GroovyTemplate -import org.springframework.beans.factory.annotation.Autowired import org.springframework.http.HttpStatus import org.springframework.web.bind.annotation.ExceptionHandler import org.springframework.web.servlet.support.ServletUriComponentsBuilder -import static io.spring.initializr.util.GroovyTemplate.template - /** * A base controller that uses a {@link InitializrMetadataProvider} * @@ -37,11 +35,16 @@ import static io.spring.initializr.util.GroovyTemplate.template */ abstract class AbstractInitializrController { - @Autowired - protected InitializrMetadataProvider metadataProvider - + protected final InitializrMetadataProvider metadataProvider + private final GroovyTemplate groovyTemplate private boolean forceSsl + protected AbstractInitializrController(InitializrMetadataProvider metadataProvider, + GroovyTemplate groovyTemplate) { + this.metadataProvider = metadataProvider + this.groovyTemplate = groovyTemplate + } + @PostConstruct void initialize() { forceSsl = metadataProvider.get().configuration.env.forceSsl @@ -74,7 +77,7 @@ abstract class AbstractInitializrController { // Google analytics support model['trackingCode'] = metadata.configuration.env.googleAnalyticsTrackingCode - template templatePath, model + groovyTemplate.process templatePath, model } /** diff --git a/initializr-web/src/main/groovy/io/spring/initializr/web/project/LegacyStsController.groovy b/initializr-web/src/main/groovy/io/spring/initializr/web/project/LegacyStsController.groovy index 385d1f89..a5dfdaaa 100644 --- a/initializr-web/src/main/groovy/io/spring/initializr/web/project/LegacyStsController.groovy +++ b/initializr-web/src/main/groovy/io/spring/initializr/web/project/LegacyStsController.groovy @@ -16,6 +16,9 @@ package io.spring.initializr.web.project +import io.spring.initializr.metadata.InitializrMetadataProvider +import io.spring.initializr.util.GroovyTemplate + import org.springframework.stereotype.Controller import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.ResponseBody @@ -30,6 +33,10 @@ import org.springframework.web.bind.annotation.ResponseBody @Deprecated class LegacyStsController extends AbstractInitializrController { + LegacyStsController(InitializrMetadataProvider metadataProvider, GroovyTemplate groovyTemplate) { + super(metadataProvider, groovyTemplate) + } + @RequestMapping(value = '/sts', produces = 'text/html') @ResponseBody String stsHome() { diff --git a/initializr-web/src/main/groovy/io/spring/initializr/web/project/MainController.groovy b/initializr-web/src/main/groovy/io/spring/initializr/web/project/MainController.groovy index f1905175..c36283ec 100644 --- a/initializr-web/src/main/groovy/io/spring/initializr/web/project/MainController.groovy +++ b/initializr-web/src/main/groovy/io/spring/initializr/web/project/MainController.groovy @@ -24,7 +24,9 @@ import io.spring.initializr.generator.BasicProjectRequest import io.spring.initializr.generator.CommandLineHelpGenerator import io.spring.initializr.generator.ProjectGenerator import io.spring.initializr.generator.ProjectRequest +import io.spring.initializr.metadata.InitializrMetadataProvider import io.spring.initializr.util.Agent +import io.spring.initializr.util.GroovyTemplate import io.spring.initializr.web.mapper.DependencyMetadataV21JsonMapper import io.spring.initializr.web.mapper.InitializrMetadataJsonMapper import io.spring.initializr.web.mapper.InitializrMetadataV21JsonMapper @@ -67,14 +69,17 @@ class MainController extends AbstractInitializrController { static final MediaType HAL_JSON_CONTENT_TYPE = MediaType.parseMediaType('application/hal+json') - @Autowired - private ProjectGenerator projectGenerator - - @Autowired - private DependencyMetadataProvider dependencyMetadataProvider - - private CommandLineHelpGenerator commandLineHelpGenerator = new CommandLineHelpGenerator() + private final ProjectGenerator projectGenerator + private final DependencyMetadataProvider dependencyMetadataProvider + private final CommandLineHelpGenerator commandLineHelpGenerator + MainController(InitializrMetadataProvider metadataProvider, GroovyTemplate groovyTemplate, + ProjectGenerator projectGenerator, DependencyMetadataProvider dependencyMetadataProvider) { + super(metadataProvider, groovyTemplate) + this.projectGenerator = projectGenerator + this.dependencyMetadataProvider = dependencyMetadataProvider + this.commandLineHelpGenerator = new CommandLineHelpGenerator(groovyTemplate) + } @ModelAttribute BasicProjectRequest projectRequest(@RequestHeader Map headers) {