Add ProjectGeneratedEvent

Replace `ProjectGenerationListener` by an event that is thrown via the
regular `ApplicationEventPublisher`. This allows any arbitrary bean to
listen to the event without the need of implementing an interface.

Closes gh-184
This commit is contained in:
Stephane Nicoll 2016-01-29 16:38:33 +01:00
parent b443a08370
commit b1352ca264
6 changed files with 84 additions and 58 deletions

View File

@ -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.
@ -83,9 +83,7 @@ class InitializrAutoConfiguration {
@Bean
@ConditionalOnMissingBean
ProjectGenerator projectGenerator() {
def generator = new ProjectGenerator()
generator.listeners << metricsListener()
generator
new ProjectGenerator()
}
@Bean

View File

@ -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.
@ -17,17 +17,26 @@
package io.spring.initializr.generator
/**
* Interface to be implemented by components that need to be aware of project generation
* related events.
* Event fired when a new project has been generated successfully.
*
* @author Stephane Nicoll
* @since 1.0
*/
public interface ProjectGenerationListener {
class ProjectGeneratedEvent {
/**
* Invoked when a project has been generated for the specified {@link ProjectRequest}.
* The {@link ProjectRequest} used to generate the project.
*/
void onGeneratedProject(ProjectRequest request)
final ProjectRequest projectRequest
/**
* The timestamp at which the project was generated
*/
final long timestamp
ProjectGeneratedEvent(ProjectRequest projectRequest) {
this.projectRequest = projectRequest
this.timestamp = System.currentTimeMillis()
}
}

View File

@ -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,16 +18,17 @@ package io.spring.initializr.generator
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.actuate.metrics.CounterService
import org.springframework.context.event.EventListener
import org.springframework.util.StringUtils
/**
* A {@link ProjectGenerationListener} implementation that uses a {@link CounterService}
* to update various project related metrics.
* A {@link ProjectGeneratedEvent} listener that uses a {@link CounterService} to update
* various project related metrics.
*
* @author Stephane Nicoll
* @since 1.0
*/
class ProjectGenerationMetricsListener implements ProjectGenerationListener {
class ProjectGenerationMetricsListener {
private final CounterService counterService
@ -36,8 +37,9 @@ class ProjectGenerationMetricsListener implements ProjectGenerationListener {
this.counterService = counterService
}
@Override
void onGeneratedProject(ProjectRequest request) {
@EventListener
void onGeneratedProject(ProjectGeneratedEvent event) {
def request = event.projectRequest
increment(key('requests')) // Total number of requests
handleDependencies(request)
handleType(request)

View File

@ -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.
@ -23,6 +23,7 @@ import io.spring.initializr.util.Version
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.context.ApplicationEventPublisher
import org.springframework.util.Assert
import static io.spring.initializr.util.GroovyTemplate.template
@ -41,6 +42,9 @@ class ProjectGenerator {
private static final VERSION_1_3_0_M1 = Version.parse('1.3.0.M1')
@Autowired
ApplicationEventPublisher eventPublisher
@Autowired
InitializrMetadataProvider metadataProvider
@ -50,8 +54,6 @@ class ProjectGenerator {
@Value('${TMPDIR:.}')
String tmpdir
final Set<ProjectGenerationListener> listeners = []
private transient Map<String, List<File>> temporaryFiles = [:]
/**
@ -60,7 +62,7 @@ class ProjectGenerator {
byte[] generateMavenPom(ProjectRequest request) {
def model = initializeModel(request)
def content = doGenerateMavenPom(model)
invokeListeners(request)
publishProjectGeneratedEvent(request)
content
}
@ -70,7 +72,7 @@ class ProjectGenerator {
byte[] generateGradleBuild(ProjectRequest request) {
def model = initializeModel(request)
def content = doGenerateGradleBuild(model)
invokeListeners(request)
publishProjectGeneratedEvent(request)
content
}
@ -131,7 +133,7 @@ class ProjectGenerator {
new File(dir, 'src/main/resources/templates').mkdirs()
new File(dir, 'src/main/resources/static').mkdirs()
}
invokeListeners(request)
publishProjectGeneratedEvent(request)
rootDir
}
@ -164,10 +166,9 @@ class ProjectGenerator {
}
}
private void invokeListeners(ProjectRequest request) {
listeners.each {
it.onGeneratedProject(request)
}
private void publishProjectGeneratedEvent(ProjectRequest request) {
ProjectGeneratedEvent event = new ProjectGeneratedEvent(request)
eventPublisher.publishEvent(event)
}
protected Map initializeModel(ProjectRequest request) {

View File

@ -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.
@ -47,7 +47,7 @@ class ProjectGenerationMetricsListenerTests {
void projectGenerationCount() {
def request = initialize()
request.resolve(metadata)
listener.onGeneratedProject(request)
fireEvent(request)
metricsAssert.hasValue(1, 'initializr.requests')
}
@ -56,7 +56,7 @@ class ProjectGenerationMetricsListenerTests {
def request = initialize()
request.style << 'security' << 'spring-data'
request.resolve(metadata)
listener.onGeneratedProject(request)
fireEvent(request)
metricsAssert.hasValue(1, 'initializr.dependency.security',
'initializr.dependency.spring-data')
}
@ -65,7 +65,7 @@ class ProjectGenerationMetricsListenerTests {
void noDependencies() {
def request = initialize()
request.resolve(metadata)
listener.onGeneratedProject(request)
fireEvent(request)
metricsAssert.hasNoValue('initializr.dependency.')
}
@ -75,7 +75,7 @@ class ProjectGenerationMetricsListenerTests {
request.style << 'spring-data'
request.packaging = 'war'
request.resolve(metadata)
listener.onGeneratedProject(request)
fireEvent(request)
metricsAssert.hasValue(1, 'initializr.dependency.web',
'initializr.dependency.spring-data')
}
@ -91,7 +91,7 @@ class ProjectGenerationMetricsListenerTests {
request.initialize(metadata)
request.style << 'foo-old'
request.resolve(metadata)
listener.onGeneratedProject(request)
fireEvent(request)
metricsAssert.hasValue(1, 'initializr.dependency.foo') // standard id is used
}
@ -99,7 +99,7 @@ class ProjectGenerationMetricsListenerTests {
void defaultType() {
def request = initialize()
request.resolve(metadata)
listener.onGeneratedProject(request)
fireEvent(request)
metricsAssert.hasValue(1, 'initializr.type.maven-project')
}
@ -108,7 +108,7 @@ class ProjectGenerationMetricsListenerTests {
def request = initialize()
request.type = 'gradle-build'
request.resolve(metadata)
listener.onGeneratedProject(request)
fireEvent(request)
metricsAssert.hasValue(1, 'initializr.type.gradle-build')
}
@ -116,7 +116,7 @@ class ProjectGenerationMetricsListenerTests {
void defaultPackaging() {
def request = initialize()
request.resolve(metadata)
listener.onGeneratedProject(request)
fireEvent(request)
metricsAssert.hasValue(1, 'initializr.packaging.jar')
}
@ -125,7 +125,7 @@ class ProjectGenerationMetricsListenerTests {
def request = initialize()
request.packaging = 'war'
request.resolve(metadata)
listener.onGeneratedProject(request)
fireEvent(request)
metricsAssert.hasValue(1, 'initializr.packaging.war')
}
@ -133,7 +133,7 @@ class ProjectGenerationMetricsListenerTests {
void defaultJavaVersion() {
def request = initialize()
request.resolve(metadata)
listener.onGeneratedProject(request)
fireEvent(request)
metricsAssert.hasValue(1, 'initializr.java_version.1_8')
}
@ -142,7 +142,7 @@ class ProjectGenerationMetricsListenerTests {
def request = initialize()
request.javaVersion = '1.7'
request.resolve(metadata)
listener.onGeneratedProject(request)
fireEvent(request)
metricsAssert.hasValue(1, 'initializr.java_version.1_7')
}
@ -150,7 +150,7 @@ class ProjectGenerationMetricsListenerTests {
void defaultLanguage() {
def request = initialize()
request.resolve(metadata)
listener.onGeneratedProject(request)
fireEvent(request)
metricsAssert.hasValue(1, 'initializr.language.java')
}
@ -159,7 +159,7 @@ class ProjectGenerationMetricsListenerTests {
def request = initialize()
request.language = 'groovy'
request.resolve(metadata)
listener.onGeneratedProject(request)
fireEvent(request)
metricsAssert.hasValue(1, 'initializr.language.groovy')
}
@ -167,7 +167,7 @@ class ProjectGenerationMetricsListenerTests {
void defaultBootVersion() {
def request = initialize()
request.resolve(metadata)
listener.onGeneratedProject(request)
fireEvent(request)
metricsAssert.hasValue(1, 'initializr.boot_version.1_2_3_RELEASE')
}
@ -176,7 +176,7 @@ class ProjectGenerationMetricsListenerTests {
def request = initialize()
request.bootVersion = '1.0.2.RELEASE'
request.resolve(metadata)
listener.onGeneratedProject(request)
fireEvent(request)
metricsAssert.hasValue(1, 'initializr.boot_version.1_0_2_RELEASE')
}
@ -191,7 +191,7 @@ class ProjectGenerationMetricsListenerTests {
request.bootVersion = '1.0.2.RELEASE'
request.resolve(metadata)
listener.onGeneratedProject(request)
fireEvent(request)
metricsAssert.hasValue(1, 'initializr.requests',
'initializr.dependency.web', 'initializr.dependency.security',
'initializr.type.gradle-project', 'initializr.packaging.jar',
@ -204,20 +204,24 @@ class ProjectGenerationMetricsListenerTests {
def request = initialize()
request.style << 'security' << 'spring-data'
request.resolve(metadata)
listener.onGeneratedProject(request)
fireEvent(request)
metricsAssert.hasValue(1, 'initializr.requests',
'initializr.dependency.security', 'initializr.dependency.spring-data')
def anotherRequest = initialize()
anotherRequest.style << 'web' << 'spring-data'
anotherRequest.resolve(metadata)
listener.onGeneratedProject(anotherRequest)
fireEvent(anotherRequest)
metricsAssert.hasValue(2, 'initializr.dependency.spring-data',
'initializr.dependency.spring-data')
metricsAssert.hasValue(1, 'initializr.dependency.web',
'initializr.dependency.security')
}
private fireEvent(ProjectRequest projectRequest) {
listener.onGeneratedProject(new ProjectGeneratedEvent(projectRequest))
}
private ProjectRequest initialize() {
def request = new ProjectRequest()
request.initialize(metadata)

View File

@ -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.
@ -28,12 +28,15 @@ import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import org.mockito.ArgumentMatcher
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.context.ApplicationEventPublisher
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Configuration
import static org.mockito.Matchers.argThat
import static org.mockito.Mockito.mock
import static org.mockito.Mockito.times
import static org.mockito.Mockito.verify
@ -48,44 +51,38 @@ class ProjectGeneratorTests {
private final ProjectGenerator projectGenerator = new ProjectGenerator()
private final ApplicationEventPublisher eventPublisher = mock(ApplicationEventPublisher)
@Before
void setup() {
def metadata = InitializrMetadataTestBuilder.withDefaults()
.addDependencyGroup('test', 'web', 'security', 'data-jpa', 'aop', 'batch', 'integration').build()
applyMetadata(metadata)
projectGenerator.eventPublisher = eventPublisher
projectGenerator.tmpdir = folder.newFolder().absolutePath
}
@Test
void defaultMavenPom() {
def listener = mock(ProjectGenerationListener)
projectGenerator.listeners << listener
def request = createProjectRequest('web')
generateMavenPom(request).hasNoRepository()
.hasSpringBootStarterDependency('web')
verify(listener, times(1)).onGeneratedProject(request)
verify(eventPublisher, times(1)).publishEvent(argThat(new EventMatcher(request)))
}
@Test
void defaultGradleBuild() {
def listener = mock(ProjectGenerationListener)
projectGenerator.listeners << listener
def request = createProjectRequest('web')
generateGradleBuild(request)
verify(listener, times(1)).onGeneratedProject(request)
verify(eventPublisher, times(1)).publishEvent(argThat(new EventMatcher(request)))
}
@Test
void defaultProject() {
def listener = mock(ProjectGenerationListener)
projectGenerator.listeners << listener
def request = createProjectRequest('web')
generateProject(request).isJavaProject().isMavenProject().pomAssert()
.hasNoRepository().hasSpringBootStarterDependency('web')
verify(listener, times(1)).onGeneratedProject(request)
verify(eventPublisher, times(1)).publishEvent(argThat(new EventMatcher(request)))
}
@Test
@ -558,4 +555,19 @@ class ProjectGeneratorTests {
}
}
private static class EventMatcher extends ArgumentMatcher<ProjectGeneratedEvent> {
private final ProjectRequest request
EventMatcher(ProjectRequest request) {
this.request = request
}
@Override
boolean matches(Object argument) {
ProjectGeneratedEvent event = (ProjectGeneratedEvent) argument
return request.equals(event.getProjectRequest())
}
}
}