com.fasterxml.jackson.core
jackson-core
@@ -234,4 +239,4 @@
-
\ No newline at end of file
+
diff --git a/initializr/src/main/groovy/io/spring/initializr/config/InitializrMetricsExporterAutoConfiguration.groovy b/initializr/src/main/groovy/io/spring/initializr/config/InitializrMetricsExporterAutoConfiguration.groovy
new file mode 100644
index 00000000..1101d0f2
--- /dev/null
+++ b/initializr/src/main/groovy/io/spring/initializr/config/InitializrMetricsExporterAutoConfiguration.groovy
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2014-2015 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.config
+
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.actuate.metrics.export.Exporter
+import org.springframework.boot.actuate.metrics.export.MetricCopyExporter
+import org.springframework.boot.actuate.metrics.repository.InMemoryMetricRepository
+import org.springframework.boot.actuate.metrics.repository.MetricRepository
+import org.springframework.boot.actuate.metrics.repository.redis.RedisMetricRepository
+import org.springframework.boot.actuate.metrics.writer.MetricWriter
+import org.springframework.boot.autoconfigure.AutoConfigureAfter
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
+import org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration
+import org.springframework.boot.context.properties.EnableConfigurationProperties
+import org.springframework.context.ApplicationContext
+import org.springframework.context.annotation.Bean
+import org.springframework.context.annotation.Configuration
+import org.springframework.context.annotation.Primary
+import org.springframework.data.redis.connection.RedisConnectionFactory
+import org.springframework.scheduling.annotation.EnableScheduling
+import org.springframework.scheduling.annotation.Scheduled
+import org.springframework.util.ObjectUtils
+
+/**
+ * {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
+ * Auto-configuration} to export the metrics of an initializr instnace.
+ *
+ * @author Dave Syer
+ * @since 1.0
+ */
+@Configuration
+@ConditionalOnBean(RedisConnectionFactory)
+@ConditionalOnProperty(value = 'spring.metrics.export.enabled')
+@EnableScheduling
+@EnableConfigurationProperties(MetricsProperties)
+@AutoConfigureAfter(value = RedisAutoConfiguration,
+ name = "org.springframework.boot.actuate.autoconfigure.MetricExportAutoConfiguration")
+class InitializrMetricsExporterAutoConfiguration {
+
+ @Autowired
+ RedisConnectionFactory connectionFactory
+
+ @Autowired
+ MetricsProperties metrics
+
+ @Autowired
+ ApplicationContext context
+
+ @Bean
+ // @ExportMetricWriter // Add this when upgrading to Boot 1.3
+ MetricWriter writer() {
+ new RedisMetricRepository(connectionFactory,
+ metrics.prefix + metrics.getId(context.getId()) + '.'
+ + ObjectUtils.getIdentityHexString(context) + '.',
+ metrics.key)
+ }
+
+ // Remove this when upgrading to Boot 1.3
+ @Bean
+ @ConditionalOnMissingClass(name = 'org.springframework.boot.actuate.autoconfigure.ActuatorMetricWriter')
+ @Primary
+ MetricRepository reader() {
+ new InMemoryMetricRepository()
+ }
+
+ // Remove this when upgrading to Boot 1.3
+ @Bean
+ @ConditionalOnMissingClass(name = 'org.springframework.boot.actuate.autoconfigure.ActuatorMetricWriter')
+ Exporter exporter(InMemoryMetricRepository reader) {
+ new MetricCopyExporter(reader, writer()) {
+ @Override
+ @Scheduled(fixedRateString = '${spring.metrics.export.default.delayMillis:5000}')
+ void export() {
+ super.export()
+ }
+ }
+ }
+
+}
diff --git a/initializr/src/main/groovy/io/spring/initializr/config/MetricsProperties.groovy b/initializr/src/main/groovy/io/spring/initializr/config/MetricsProperties.groovy
new file mode 100644
index 00000000..54828a15
--- /dev/null
+++ b/initializr/src/main/groovy/io/spring/initializr/config/MetricsProperties.groovy
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2014-2015 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.config
+
+import org.springframework.beans.factory.annotation.Value
+import org.springframework.boot.context.properties.ConfigurationProperties
+
+/**
+ * Metrics-related configuration.
+ *
+ * @author Dave Syer
+ * @since 1.0
+ */
+@ConfigurationProperties('initializr.metrics')
+class MetricsProperties {
+
+ /**
+ * Prefix for redis keys holding metrics in data store.
+ */
+ String prefix = 'spring.metrics.collector.'
+
+ /**
+ * Redis key holding index to metrics keys in data store.
+ */
+ String key = 'keys.spring.metrics.collector'
+
+ /**
+ * Identifier for application in metrics keys. Keys will be exported in the form
+ * '[id].[hex].[name]' (where '[id]' is this value, '[hex]' is unique per application
+ * context, and '[name]' is the "natural" name for the metric.
+ */
+ @Value('${spring.application.name:${vcap.application.name:application}}')
+ String id
+
+ /**
+ * The rate (in milliseconds) at which metrics are exported to Redis. If the value is
+ * <=0 then the export is disabled.
+ */
+ @Value('${spring.metrics.export.default.delayMillis:5000}')
+ long rateMillis = 5000L
+
+ String getPrefix() {
+ if (prefix.endsWith('.')) {
+ return prefix
+ }
+ prefix + '.'
+ }
+
+ String getId(String defaultValue) {
+ if (id) return id
+ defaultValue
+ }
+}
diff --git a/initializr/src/main/groovy/io/spring/initializr/metadata/InitializrConfiguration.groovy b/initializr/src/main/groovy/io/spring/initializr/metadata/InitializrConfiguration.groovy
index 94300fa0..3d0acbdb 100644
--- a/initializr/src/main/groovy/io/spring/initializr/metadata/InitializrConfiguration.groovy
+++ b/initializr/src/main/groovy/io/spring/initializr/metadata/InitializrConfiguration.groovy
@@ -30,7 +30,7 @@ class InitializrConfiguration {
}
/**
- * Generate a suitable application mame based on the specified name. If no suitable
+ * Generate a suitable application name based on the specified name. If no suitable
* application name can be generated from the specified {@code name}, the
* {@link Env#fallbackApplicationName} is used instead.
* No suitable application name can be generated if the name is {@code null} or
diff --git a/initializr/src/main/groovy/io/spring/initializr/metadata/InitializrProperties.groovy b/initializr/src/main/groovy/io/spring/initializr/metadata/InitializrProperties.groovy
index 47b09946..f9b9df30 100644
--- a/initializr/src/main/groovy/io/spring/initializr/metadata/InitializrProperties.groovy
+++ b/initializr/src/main/groovy/io/spring/initializr/metadata/InitializrProperties.groovy
@@ -26,7 +26,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties
* @author Stephane Nicoll
* @since 1.0
*/
-@ConfigurationProperties(prefix = 'initializr', ignoreUnknownFields = false)
+@ConfigurationProperties(prefix = 'initializr')
class InitializrProperties extends InitializrConfiguration {
@JsonIgnore
diff --git a/initializr/src/main/resources/META-INF/spring.factories b/initializr/src/main/resources/META-INF/spring.factories
index a6629e17..6c786bad 100644
--- a/initializr/src/main/resources/META-INF/spring.factories
+++ b/initializr/src/main/resources/META-INF/spring.factories
@@ -1 +1,3 @@
-org.springframework.boot.autoconfigure.EnableAutoConfiguration=io.spring.initializr.config.InitializrAutoConfiguration
\ No newline at end of file
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+io.spring.initializr.config.InitializrAutoConfiguration,\
+io.spring.initializr.config.InitializrMetricsExporterAutoConfiguration
\ No newline at end of file
diff --git a/initializr/src/test/groovy/io/spring/initializr/metrics/MetricsExportTests.groovy b/initializr/src/test/groovy/io/spring/initializr/metrics/MetricsExportTests.groovy
new file mode 100644
index 00000000..4e72087c
--- /dev/null
+++ b/initializr/src/test/groovy/io/spring/initializr/metrics/MetricsExportTests.groovy
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2014-2015 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.metrics
+
+import io.spring.initializr.generator.ProjectGenerationMetricsListener
+import io.spring.initializr.generator.ProjectRequest
+import io.spring.initializr.metadata.InitializrMetadata
+import io.spring.initializr.metadata.InitializrMetadataProvider
+import io.spring.initializr.test.OfflineInitializrMetadataProvider
+import io.spring.initializr.test.RedisRunning
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.beans.factory.annotation.Qualifier
+import org.springframework.boot.actuate.metrics.repository.redis.RedisMetricRepository
+import org.springframework.boot.actuate.metrics.writer.MetricWriter
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration
+import org.springframework.boot.test.IntegrationTest
+import org.springframework.boot.test.SpringApplicationConfiguration
+import org.springframework.context.annotation.Bean
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner
+
+import static org.junit.Assert.assertTrue
+
+/**
+ * @author Dave Syer
+ */
+@RunWith(SpringJUnit4ClassRunner)
+@SpringApplicationConfiguration(classes = Config)
+@IntegrationTest(['spring.metrics.export.default.delayMillis:500',
+ 'spring.metrics.export.enabled:true',
+ 'initializr.metrics.prefix:test.prefix', 'initializr.metrics.key:key.test'])
+public class MetricsExportTests {
+
+ @Rule
+ public RedisRunning running = new RedisRunning()
+
+ @Autowired
+ ProjectGenerationMetricsListener listener
+
+ @Autowired
+ @Qualifier("writer")
+ MetricWriter writer
+
+ RedisMetricRepository repository
+
+ @Before
+ void init() {
+ repository = (RedisMetricRepository) writer
+ repository.findAll().each {
+ repository.reset(it.name)
+ }
+ assertTrue("Metrics not empty", repository.findAll().size() == 0)
+ }
+
+ @Test
+ void exportAndCheckMetricsExist() {
+ listener.onGeneratedProject(new ProjectRequest())
+ Thread.sleep(1000L)
+ assertTrue("No metrics exported", repository.findAll().size() > 0)
+ }
+
+ @EnableAutoConfiguration
+ static class Config {
+
+ @Bean
+ InitializrMetadataProvider initializrMetadataProvider(InitializrMetadata metadata) {
+ new OfflineInitializrMetadataProvider(metadata)
+ }
+ }
+}
diff --git a/initializr/src/test/groovy/io/spring/initializr/test/OfflineInitializrMetadataProvider.groovy b/initializr/src/test/groovy/io/spring/initializr/test/OfflineInitializrMetadataProvider.groovy
new file mode 100644
index 00000000..4497ecec
--- /dev/null
+++ b/initializr/src/test/groovy/io/spring/initializr/test/OfflineInitializrMetadataProvider.groovy
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2012-2015 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.test
+
+import io.spring.initializr.metadata.DefaultMetadataElement
+import io.spring.initializr.metadata.InitializrMetadata
+import io.spring.initializr.support.DefaultInitializrMetadataProvider
+
+/**
+ * A {@link DefaultInitializrMetadataProvider} that does not attempt to
+ * use the network to refresh its configuration.
+ *
+ * @author Stephane Nicoll
+ * @since 1.0
+ */
+class OfflineInitializrMetadataProvider extends DefaultInitializrMetadataProvider {
+
+ OfflineInitializrMetadataProvider(InitializrMetadata metadata) {
+ super(metadata)
+ }
+
+ @Override
+ protected List fetchBootVersions() {
+ null // Disable metadata fetching from spring.io
+ }
+}
diff --git a/initializr/src/test/groovy/io/spring/initializr/test/RedisRunning.groovy b/initializr/src/test/groovy/io/spring/initializr/test/RedisRunning.groovy
new file mode 100644
index 00000000..978f7020
--- /dev/null
+++ b/initializr/src/test/groovy/io/spring/initializr/test/RedisRunning.groovy
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2014-2015 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.test
+
+import org.junit.Assume
+import org.junit.rules.TestWatcher
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+import org.springframework.data.redis.connection.jedis.JedisConnectionFactory
+
+/**
+ * A {@link org.junit.rules.TestRule} that validates Redis is available.
+ *
+ * @author Dave Syer
+ * @since 1.0
+ */
+class RedisRunning extends TestWatcher {
+
+ JedisConnectionFactory connectionFactory;
+
+ @Override
+ Statement apply(Statement base, Description description) {
+ if (connectionFactory == null) {
+ connectionFactory = new JedisConnectionFactory()
+ connectionFactory.afterPropertiesSet()
+ }
+ try {
+ connectionFactory.connection
+ } catch (Exception e) {
+ Assume.assumeNoException('Cannot connect to Redis (so skipping tests)', e)
+ }
+ super.apply(base, description)
+ }
+
+}
diff --git a/initializr/src/test/groovy/io/spring/initializr/web/AbstractInitializrControllerIntegrationTests.groovy b/initializr/src/test/groovy/io/spring/initializr/web/AbstractInitializrControllerIntegrationTests.groovy
index d2bcf146..38f09b49 100644
--- a/initializr/src/test/groovy/io/spring/initializr/web/AbstractInitializrControllerIntegrationTests.groovy
+++ b/initializr/src/test/groovy/io/spring/initializr/web/AbstractInitializrControllerIntegrationTests.groovy
@@ -19,10 +19,9 @@ package io.spring.initializr.web
import java.nio.charset.Charset
import io.spring.initializr.mapper.InitializrMetadataVersion
-import io.spring.initializr.metadata.DefaultMetadataElement
import io.spring.initializr.metadata.InitializrMetadata
-import io.spring.initializr.support.DefaultInitializrMetadataProvider
import io.spring.initializr.metadata.InitializrMetadataProvider
+import io.spring.initializr.test.OfflineInitializrMetadataProvider
import io.spring.initializr.test.ProjectAssert
import org.json.JSONObject
import org.junit.Rule
@@ -85,7 +84,7 @@ abstract class AbstractInitializrControllerIntegrationTests {
*/
protected void validateContentType(ResponseEntity response, MediaType expected) {
def actual = response.headers.getContentType()
- assertTrue "Non compatible media-type, expected $expected, got $actual" ,
+ assertTrue "Non compatible media-type, expected $expected, got $actual",
actual.isCompatibleWith(expected)
assertEquals 'All text content should be UTF-8 encoded',
'UTF-8', actual.getParameter('charset')
@@ -93,7 +92,7 @@ abstract class AbstractInitializrControllerIntegrationTests {
protected void validateMetadata(ResponseEntity response, MediaType mediaType,
- String version, JSONCompareMode compareMode) {
+ String version, JSONCompareMode compareMode) {
validateContentType(response, mediaType)
def json = new JSONObject(response.body)
def expected = readMetadataJson(version)
@@ -147,7 +146,7 @@ abstract class AbstractInitializrControllerIntegrationTests {
}
protected ResponseEntity execute(String contextPath, Class responseType,
- String userAgentHeader, String... acceptHeaders) {
+ String userAgentHeader, String... acceptHeaders) {
HttpHeaders headers = new HttpHeaders();
if (userAgentHeader) {
headers.set("User-Agent", userAgentHeader);
@@ -217,12 +216,7 @@ abstract class AbstractInitializrControllerIntegrationTests {
@Bean
InitializrMetadataProvider initializrMetadataProvider(InitializrMetadata metadata) {
- new DefaultInitializrMetadataProvider(metadata) {
- @Override
- protected List fetchBootVersions() {
- null // Disable metadata fetching from spring.io
- }
- }
+ new OfflineInitializrMetadataProvider(metadata)
}
}