Skip to content

Commit ce6e889

Browse files
committed
Merge grace-plugin-events into the framework
2 parents e49b141 + f58421b commit ce6e889

9 files changed

Lines changed: 255 additions & 0 deletions

File tree

grace-plugin-events/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
## grails-plugin-events
2+

grace-plugin-events/app/.gitkeep

Whitespace-only changes.

grace-plugin-events/build.gradle

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
dependencies {
2+
api "org.graceframework:grace-core"
3+
api project(":grace-events-core")
4+
api project(":grace-events-spring")
5+
api project(":grace-events-transform")
6+
7+
api("org.springframework.boot:spring-boot-autoconfigure")
8+
annotationProcessor("org.springframework.boot:spring-boot-autoconfigure-processor")
9+
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
10+
}
11+
12+
jar {
13+
enabled = true
14+
archiveClassifier.set('plugin')
15+
includeEmptyDirs = false
16+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright 2015 original authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.grails.events.spring
17+
18+
import grails.events.bus.EventBus
19+
import grails.util.GrailsNameUtils
20+
import groovy.transform.CompileStatic
21+
import org.springframework.beans.BeansException
22+
import org.springframework.context.ApplicationContext
23+
import org.springframework.context.ApplicationContextAware
24+
import org.springframework.context.ApplicationEvent
25+
import org.springframework.context.ApplicationListener
26+
import org.springframework.context.event.ContextClosedEvent
27+
import org.springframework.context.support.GenericApplicationContext
28+
import java.util.concurrent.ConcurrentHashMap
29+
30+
31+
/**
32+
* Translates Spring Events into Reactor events
33+
*
34+
* @author Graeme Rocher
35+
* @since 3.0.8
36+
*/
37+
@CompileStatic
38+
class SpringEventTranslator implements ApplicationListener, ApplicationContextAware {
39+
40+
public static final String GDM_EVENT_PACKAGE = 'org.grails.datastore'
41+
public static final String EVENT_SUFFIX = "Event"
42+
public static final String SPRING_PACKAGE = "org.springframework"
43+
44+
private Map<Class, String> eventClassToName = new ConcurrentHashMap<Class, String>().withDefault { Class eventClass ->
45+
def clsName = eventClass.name
46+
def logicalName = GrailsNameUtils.getLogicalPropertyName(clsName, EVENT_SUFFIX)
47+
if(clsName.startsWith(GDM_EVENT_PACKAGE)) {
48+
return "gorm:${logicalName}".toString()
49+
}
50+
else if(clsName.startsWith(SPRING_PACKAGE)) {
51+
return "spring:${logicalName}".toString()
52+
}
53+
else {
54+
return "grails:${logicalName}".toString()
55+
}
56+
}
57+
58+
59+
private final EventBus eventBus
60+
61+
SpringEventTranslator(EventBus eventBus) {
62+
this.eventBus = eventBus
63+
}
64+
65+
void onApplicationEvent(ApplicationEvent event) {
66+
def eventName = eventClassToName[event.getClass()]
67+
68+
if(eventBus.isActive()) {
69+
// don't relay context closed events because Reactor would have been shutdown
70+
if(!(event instanceof ContextClosedEvent)) {
71+
eventBus.notify(eventName, event)
72+
}
73+
}
74+
}
75+
76+
@Override
77+
void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
78+
((GenericApplicationContext)applicationContext).addApplicationListener(this)
79+
}
80+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright 2014-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.grails.plugins.events
17+
18+
import grails.plugins.Plugin
19+
20+
/**
21+
* A plugin that integrates Reactor into Grails
22+
*
23+
* @author Graeme Rocher
24+
* @since 3.0
25+
*/
26+
class EventBusGrailsPlugin extends Plugin {
27+
28+
def grailsVersion = "2023.0.0 > *"
29+
def description = 'Grace Events Plugin'
30+
def documentation = "https://graceframework.org/grace-events/7.0.x/"
31+
def license = "APACHE"
32+
def issueManagement = [system: "Github Issues", url: "https://github.com/graceframework/grace-events"]
33+
def scm = [url: "https://github.com/graceframework/grace-events"]
34+
35+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.grails.plugins.events;
17+
18+
import org.springframework.beans.factory.ObjectProvider;
19+
import org.springframework.boot.autoconfigure.AutoConfiguration;
20+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
21+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
22+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
23+
import org.springframework.context.ApplicationContext;
24+
import org.springframework.context.annotation.Bean;
25+
26+
import grails.events.bus.EventBus;
27+
import org.grails.events.bus.spring.EventBusFactoryBean;
28+
import org.grails.events.gorm.GormDispatcherRegistrar;
29+
import org.grails.events.spring.SpringEventTranslator;
30+
31+
/**
32+
* {@link EnableAutoConfiguration Auto-configuration} for Events.
33+
*
34+
* @author Michael Yan
35+
* @since 6.1
36+
*/
37+
@AutoConfiguration
38+
public class EventsAutoConfiguration {
39+
40+
@Bean
41+
@ConditionalOnMissingBean
42+
public EventBus eventBus(ObjectProvider<ApplicationContext> applicationContext) throws Exception {
43+
EventBusFactoryBean factoryBean = new EventBusFactoryBean();
44+
applicationContext.ifAvailable(factoryBean::setApplicationContext);
45+
return factoryBean.getObject();
46+
}
47+
48+
@Bean
49+
@ConditionalOnMissingBean
50+
public GormDispatcherRegistrar gormDispatchEventRegistrar(EventBus eventBus) {
51+
return new GormDispatcherRegistrar(eventBus);
52+
}
53+
54+
@Bean
55+
@ConditionalOnMissingBean
56+
@ConditionalOnProperty(name = "grails.events.spring", havingValue = "true")
57+
public SpringEventTranslator springEventTranslator(EventBus eventBus) {
58+
return new SpringEventTranslator(eventBus);
59+
}
60+
61+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"groups": [],
3+
"properties": [
4+
{
5+
"name": "grails.events.spring",
6+
"type": "java.lang.Boolean",
7+
"description": "Whether enable spring events translation.",
8+
"defaultValue": false
9+
}
10+
],
11+
"hints": []
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
org.grails.plugins.events.EventsAutoConfiguration
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package grails.events
2+
3+
import grails.events.bus.EventBus
4+
import org.grails.events.spring.SpringEventTranslator
5+
import org.springframework.context.event.ContextStartedEvent
6+
import org.springframework.context.support.GenericApplicationContext
7+
import spock.lang.Specification
8+
9+
/*
10+
* Copyright 2014 original authors
11+
*
12+
* Licensed under the Apache License, Version 2.0 (the "License");
13+
* you may not use this file except in compliance with the License.
14+
* You may obtain a copy of the License at
15+
*
16+
* http://www.apache.org/licenses/LICENSE-2.0
17+
*
18+
* Unless required by applicable law or agreed to in writing, software
19+
* distributed under the License is distributed on an "AS IS" BASIS,
20+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21+
* See the License for the specific language governing permissions and
22+
* limitations under the License.
23+
*/
24+
25+
/**
26+
* @author graemerocher
27+
*/
28+
class SpringEventTranslatorSpec extends Specification {
29+
30+
void "Test event translator translates Spring events"() {
31+
setup:
32+
33+
34+
def eventBus = Mock(EventBus)
35+
eventBus.isActive() >> true
36+
def translator = new SpringEventTranslator(eventBus)
37+
38+
when:"A Spring event occurs"
39+
40+
def ctx = new GenericApplicationContext()
41+
translator.onApplicationEvent(new ContextStartedEvent(ctx))
42+
43+
then:"The event bus is notified"
44+
1 * eventBus.notify("spring:contextStarted", _)
45+
46+
}
47+
48+
}

0 commit comments

Comments
 (0)