sbglasius commented on code in PR #16185: URL: https://github.com/apache/grails-core/pull/16185#discussion_r3832580330
########## grails-quartz/src/main/groovy/quartz/QuartzGrailsPlugin.groovy: ########## @@ -0,0 +1,363 @@ +/* + * Copyright 2015-2025 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 quartz + +import grails.plugins.Plugin +import grails.plugins.quartz.CustomTriggerFactoryBean +import grails.plugins.quartz.GrailsJobClass +import grails.plugins.quartz.GrailsJobFactory +import grails.plugins.quartz.JobArtefactHandler +import grails.plugins.quartz.JobDetailFactoryBean +import grails.plugins.quartz.cleanup.JdbcCleanup +import grails.plugins.quartz.listeners.ExceptionPrinterJobListener +import grails.plugins.quartz.listeners.SessionBinderJobListener +import groovy.util.logging.Slf4j +import org.quartz.JobDetail +import org.quartz.JobKey +import org.quartz.ListenerManager +import org.quartz.Scheduler +import org.quartz.Trigger +import org.quartz.TriggerKey +import org.quartz.impl.matchers.GroupMatcher +import org.quartz.impl.matchers.KeyMatcher +import org.springframework.beans.factory.config.MethodInvokingFactoryBean +import org.springframework.context.ApplicationContext +import org.springframework.scheduling.quartz.SchedulerFactoryBean + +@Slf4j +class QuartzGrailsPlugin extends Plugin { + + def grailsVersion = '7.0.0-SNAPSHOT > *' + def watchedResources = 'file:./grails-app/jobs/**/*Job.groovy' + def title = 'Quartz' + def author = 'Jeff Brown' + def description = 'Adds Quartz job scheduling features' + def profiles = ['web'] + List loadAfter = ['hibernate3', 'hibernate4', 'hibernate5', 'services'] + def documentation = 'https://apache.github.io/grails-quartz/latest/' + def license = 'APACHE' + def issueManagement = [ system: 'Github Issues', url: 'https://github.com/apache/grails-quartz/issues' ] + + // Any additional developers beyond the author specified above. + def developers = [ + [name: 'Sergey Nebolsin', email: '[email protected]'], + [name: 'Graeme Rocher', email: '[email protected]'], + [name: 'Ryan Vanderwerf', email: '[email protected]'], + [name: 'Vitalii Samolovskikh', email: '[email protected]'] + ] + + // Online location of the plugin's browsable source code. + def scm = [url: 'https://github.com/apache/grails-quartz'] + + Closure doWithSpring() { + { -> + Properties properties = loadQuartzProperties() + + boolean hasHibernate = hasHibernate(manager) + def hasJdbcStore = properties['org.quartz.jdbcStore']?.toBoolean() + if (hasJdbcStore == null) { + hasJdbcStore = true + } Review Comment: use `properties.getProperty('org.quartz.jdbcStor', true).toBoolean()` for default value ########## grails-quartz/src/main/groovy/quartz/QuartzGrailsPlugin.groovy: ########## @@ -0,0 +1,363 @@ +/* + * Copyright 2015-2025 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 quartz + +import grails.plugins.Plugin +import grails.plugins.quartz.CustomTriggerFactoryBean +import grails.plugins.quartz.GrailsJobClass +import grails.plugins.quartz.GrailsJobFactory +import grails.plugins.quartz.JobArtefactHandler +import grails.plugins.quartz.JobDetailFactoryBean +import grails.plugins.quartz.cleanup.JdbcCleanup +import grails.plugins.quartz.listeners.ExceptionPrinterJobListener +import grails.plugins.quartz.listeners.SessionBinderJobListener +import groovy.util.logging.Slf4j +import org.quartz.JobDetail +import org.quartz.JobKey +import org.quartz.ListenerManager +import org.quartz.Scheduler +import org.quartz.Trigger +import org.quartz.TriggerKey +import org.quartz.impl.matchers.GroupMatcher +import org.quartz.impl.matchers.KeyMatcher +import org.springframework.beans.factory.config.MethodInvokingFactoryBean +import org.springframework.context.ApplicationContext +import org.springframework.scheduling.quartz.SchedulerFactoryBean + +@Slf4j +class QuartzGrailsPlugin extends Plugin { + + def grailsVersion = '7.0.0-SNAPSHOT > *' + def watchedResources = 'file:./grails-app/jobs/**/*Job.groovy' + def title = 'Quartz' + def author = 'Jeff Brown' + def description = 'Adds Quartz job scheduling features' + def profiles = ['web'] + List loadAfter = ['hibernate3', 'hibernate4', 'hibernate5', 'services'] + def documentation = 'https://apache.github.io/grails-quartz/latest/' + def license = 'APACHE' + def issueManagement = [ system: 'Github Issues', url: 'https://github.com/apache/grails-quartz/issues' ] + + // Any additional developers beyond the author specified above. + def developers = [ + [name: 'Sergey Nebolsin', email: '[email protected]'], + [name: 'Graeme Rocher', email: '[email protected]'], + [name: 'Ryan Vanderwerf', email: '[email protected]'], + [name: 'Vitalii Samolovskikh', email: '[email protected]'] + ] + + // Online location of the plugin's browsable source code. + def scm = [url: 'https://github.com/apache/grails-quartz'] + + Closure doWithSpring() { + { -> + Properties properties = loadQuartzProperties() + + boolean hasHibernate = hasHibernate(manager) + def hasJdbcStore = properties['org.quartz.jdbcStore']?.toBoolean() + if (hasJdbcStore == null) { + hasJdbcStore = true Review Comment: The jdbcStore fallbacks default to true when unset (`?.toBoolean()` yields null, then the guard assigns true) in doWithSpring, configureScheduler and scheduleJob, contradicting the documented default of false. An app that overrides the quartz config block without a jdbcStore key (so plugin.yml's false is not in effect) gets a JDBC job store wired to the `dataSource` and `transactionManager` beans, and startup fails against a database with no QRTZ_* tables. ########## grails-quartz/src/main/groovy/quartz/QuartzGrailsPlugin.groovy: ########## @@ -0,0 +1,363 @@ +/* + * Copyright 2015-2025 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 quartz + +import grails.plugins.Plugin +import grails.plugins.quartz.CustomTriggerFactoryBean +import grails.plugins.quartz.GrailsJobClass +import grails.plugins.quartz.GrailsJobFactory +import grails.plugins.quartz.JobArtefactHandler +import grails.plugins.quartz.JobDetailFactoryBean +import grails.plugins.quartz.cleanup.JdbcCleanup +import grails.plugins.quartz.listeners.ExceptionPrinterJobListener +import grails.plugins.quartz.listeners.SessionBinderJobListener +import groovy.util.logging.Slf4j +import org.quartz.JobDetail +import org.quartz.JobKey +import org.quartz.ListenerManager +import org.quartz.Scheduler +import org.quartz.Trigger +import org.quartz.TriggerKey +import org.quartz.impl.matchers.GroupMatcher +import org.quartz.impl.matchers.KeyMatcher +import org.springframework.beans.factory.config.MethodInvokingFactoryBean +import org.springframework.context.ApplicationContext +import org.springframework.scheduling.quartz.SchedulerFactoryBean + +@Slf4j +class QuartzGrailsPlugin extends Plugin { + + def grailsVersion = '7.0.0-SNAPSHOT > *' + def watchedResources = 'file:./grails-app/jobs/**/*Job.groovy' + def title = 'Quartz' + def author = 'Jeff Brown' + def description = 'Adds Quartz job scheduling features' + def profiles = ['web'] + List loadAfter = ['hibernate3', 'hibernate4', 'hibernate5', 'services'] + def documentation = 'https://apache.github.io/grails-quartz/latest/' + def license = 'APACHE' + def issueManagement = [ system: 'Github Issues', url: 'https://github.com/apache/grails-quartz/issues' ] + + // Any additional developers beyond the author specified above. + def developers = [ + [name: 'Sergey Nebolsin', email: '[email protected]'], + [name: 'Graeme Rocher', email: '[email protected]'], + [name: 'Ryan Vanderwerf', email: '[email protected]'], + [name: 'Vitalii Samolovskikh', email: '[email protected]'] + ] + + // Online location of the plugin's browsable source code. + def scm = [url: 'https://github.com/apache/grails-quartz'] + + Closure doWithSpring() { + { -> + Properties properties = loadQuartzProperties() + + boolean hasHibernate = hasHibernate(manager) + def hasJdbcStore = properties['org.quartz.jdbcStore']?.toBoolean() + if (hasJdbcStore == null) { + hasJdbcStore = true + } + + def pluginEnabled = properties['org.quartz.pluginEnabled']?.toBoolean() + if (pluginEnabled == null) { + pluginEnabled = true + } + + if (pluginEnabled) { + def purgeTables = properties['org.quartz.purgeQuartzTablesOnStartup']?.toBoolean() + + if (purgeTables == null) { + purgeTables = false + } + + if (hasJdbcStore && hasHibernate && purgeTables) { + purgeTablesBean(JdbcCleanup) { bean -> + dataSource = ref(properties['org.quartz.jdbcStoreDataSource'] ?: 'dataSource') + bean.autowire = 'byName' + } + } + // Configure job beans + grailsApplication.jobClasses.each { GrailsJobClass jobClass -> + configureJobBeans.delegate = delegate + configureJobBeans(jobClass, hasHibernate) + } + + // Configure the session listener if there is the Hibernate is configured + if (hasHibernate) { + log.debug('Registering hibernate SessionBinderJobListener') + + // register SessionBinderJobListener to bind Hibernate Session to each Job's thread + "${SessionBinderJobListener.NAME}"(SessionBinderJobListener) { bean -> + bean.autowire = 'byName' + } + } + + // register global ExceptionPrinterJobListener which will log exceptions occured + // during job's execution + "${ExceptionPrinterJobListener.NAME}"(ExceptionPrinterJobListener) + + // Configure the job factory to create job instances on executions. + quartzJobFactory(GrailsJobFactory) + + // Configure Scheduler + configureScheduler.delegate = delegate + configureScheduler() + } + } + } + + /** + * Configure job beans. + */ + def configureJobBeans = { GrailsJobClass jobClass, boolean hasHibernate = true -> + def fullName = jobClass.fullName + + try { + "${fullName}Class"(MethodInvokingFactoryBean) { + targetObject = ref('grailsApplication', false) + targetMethod = 'getArtefact' + arguments = [JobArtefactHandler.TYPE, jobClass.fullName] + } + + "${fullName}"(ref("${fullName}Class")) { bean -> + bean.factoryMethod = 'newInstance' + bean.autowire = 'byName' + bean.scope = 'prototype' + } + } catch (Exception e) { + log.error("Error declaring ${fullName}Detail bean in context", e) + } + } + + /** + * Loads the quartz stanza from the grails configuration and turns it into a + * flattened Properties object suitable for use by the Quartz SchedulerFactoryBean. + * @return Quartz properties as defined in the Grails Configuration object + */ + def loadQuartzProperties() { + Properties quartzProperties = new Properties() + if (config.get('quartz')) { + // Convert to a properties file adding a prefix to each property + ConfigObject configObject = new ConfigObject() + configObject.putAll(config.get('quartz') ?: [:]) + quartzProperties << configObject.toProperties('org.quartz') + } + quartzProperties + } + + def configureScheduler = { -> + Properties properties = loadQuartzProperties() + quartzScheduler(SchedulerFactoryBean) { bean -> + quartzProperties = properties + // The bean name is used by the factory bean as the scheduler name so you must explicitly set it if + // you want a name different from the bean name. + if (quartzProperties['org.quartz.scheduler.instanceName']) { + schedulerName = properties['org.quartz.scheduler.instanceName'] + } + + // delay scheduler startup to after-bootstrap stage + if (quartzProperties['org.quartz.autoStartup']) { + autoStartup = false // we dont want to auto startup this bean as this bean autostartup is not grails aware. + } + // Store + def hasJdbcStore = quartzProperties['org.quartz.jdbcStore']?.toBoolean() + if (hasJdbcStore == null) { + hasJdbcStore = true + } + if (hasJdbcStore) { + dataSource = ref(quartzProperties['org.quartz.jdbcStoreDataSource'] ?: 'dataSource') + transactionManager = ref('transactionManager') + } + if (quartzProperties['org.quartz.waitForJobsToCompleteOnShutdown']) { + waitForJobsToCompleteOnShutdown = quartzProperties['org.quartz.waitForJobsToCompleteOnShutdown']?.toBoolean() + } + if (quartzProperties['org.quartz.exposeSchedulerInRepository']) { + exposeSchedulerInRepository = quartzProperties['org.quartz.exposeSchedulerInRepository']?.toBoolean() + } + + jobFactory = quartzJobFactory + + // Global listeners on each job. + globalJobListeners = [ref(ExceptionPrinterJobListener.NAME)] + } + } + + void onChange(Map<String, Object> event) { + def pluginEnabled = properties['org.quartz.pluginEnabled']?.toBoolean() Review Comment: Missing loading properties? ``` Properties properties = loadQuartzProperties() ``` ########## grails-quartz/src/main/groovy/quartz/QuartzGrailsPlugin.groovy: ########## @@ -0,0 +1,363 @@ +/* + * Copyright 2015-2025 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 quartz + +import grails.plugins.Plugin +import grails.plugins.quartz.CustomTriggerFactoryBean +import grails.plugins.quartz.GrailsJobClass +import grails.plugins.quartz.GrailsJobFactory +import grails.plugins.quartz.JobArtefactHandler +import grails.plugins.quartz.JobDetailFactoryBean +import grails.plugins.quartz.cleanup.JdbcCleanup +import grails.plugins.quartz.listeners.ExceptionPrinterJobListener +import grails.plugins.quartz.listeners.SessionBinderJobListener +import groovy.util.logging.Slf4j +import org.quartz.JobDetail +import org.quartz.JobKey +import org.quartz.ListenerManager +import org.quartz.Scheduler +import org.quartz.Trigger +import org.quartz.TriggerKey +import org.quartz.impl.matchers.GroupMatcher +import org.quartz.impl.matchers.KeyMatcher +import org.springframework.beans.factory.config.MethodInvokingFactoryBean +import org.springframework.context.ApplicationContext +import org.springframework.scheduling.quartz.SchedulerFactoryBean + +@Slf4j +class QuartzGrailsPlugin extends Plugin { + + def grailsVersion = '7.0.0-SNAPSHOT > *' + def watchedResources = 'file:./grails-app/jobs/**/*Job.groovy' + def title = 'Quartz' + def author = 'Jeff Brown' + def description = 'Adds Quartz job scheduling features' + def profiles = ['web'] + List loadAfter = ['hibernate3', 'hibernate4', 'hibernate5', 'services'] + def documentation = 'https://apache.github.io/grails-quartz/latest/' + def license = 'APACHE' + def issueManagement = [ system: 'Github Issues', url: 'https://github.com/apache/grails-quartz/issues' ] + + // Any additional developers beyond the author specified above. + def developers = [ + [name: 'Sergey Nebolsin', email: '[email protected]'], + [name: 'Graeme Rocher', email: '[email protected]'], + [name: 'Ryan Vanderwerf', email: '[email protected]'], + [name: 'Vitalii Samolovskikh', email: '[email protected]'] + ] + + // Online location of the plugin's browsable source code. + def scm = [url: 'https://github.com/apache/grails-quartz'] + + Closure doWithSpring() { + { -> + Properties properties = loadQuartzProperties() + + boolean hasHibernate = hasHibernate(manager) + def hasJdbcStore = properties['org.quartz.jdbcStore']?.toBoolean() + if (hasJdbcStore == null) { + hasJdbcStore = true + } + + def pluginEnabled = properties['org.quartz.pluginEnabled']?.toBoolean() + if (pluginEnabled == null) { + pluginEnabled = true + } Review Comment: Used several places, perhaps a method ``` boolean getPluginEnabled() { grailsApplication.config.getProperty('quartz.pluginEnabled', Boolean, true) } -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
