001/**
002 * Copyright 2005-2017 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.ksb.messaging.quartz;
017
018import org.kuali.rice.core.api.config.ConfigurationException;
019import org.kuali.rice.core.api.config.property.ConfigContext;
020import org.kuali.rice.ksb.service.KSBServiceLocator;
021import org.kuali.rice.ksb.util.KSBConstants;
022import org.quartz.Scheduler;
023import org.quartz.SchedulerException;
024import org.quartz.SchedulerFactory;
025import org.springframework.scheduling.quartz.SchedulerFactoryBean;
026import org.springframework.transaction.PlatformTransactionManager;
027
028import javax.sql.DataSource;
029import javax.transaction.TransactionManager;
030
031/**
032 * An implementation of the Quartz SchedulerFactoryBean which uses a database-backed quartz if the useQuartzDatabase property
033 * is set.
034 * 
035 * @author Kuali Rice Team (rice.collab@kuali.org)
036 */
037public class KSBSchedulerFactoryBean extends SchedulerFactoryBean {
038
039    private PlatformTransactionManager jtaTransactionManager;
040    private TransactionManager transactionManager;
041    private DataSource dataSource;
042    private DataSource nonTransactionalDataSource;
043    private boolean transactionManagerSet = false;
044    private boolean nonTransactionalDataSourceSet = false;
045    private boolean nonTransactionalDataSourceNull = true;
046    private boolean dataSourceSet = false;
047    private boolean schedulerInjected = false;
048    
049    @Override
050    protected Scheduler createScheduler(SchedulerFactory schedulerFactory, String schedulerName) throws SchedulerException {
051        if (ConfigContext.getCurrentContextConfig().getObject(KSBConstants.Config.INJECTED_EXCEPTION_MESSAGE_SCHEDULER_KEY) != null) {
052            try {
053                    schedulerInjected = true;
054                Scheduler scheduler = (Scheduler) ConfigContext.getCurrentContextConfig().getObject(KSBConstants.Config.INJECTED_EXCEPTION_MESSAGE_SCHEDULER_KEY);
055                scheduler.getListenerManager().addJobListener( new MessageServiceExecutorJobListener());
056
057                return scheduler;
058            } catch (Exception e) {
059                throw new ConfigurationException(e);
060            }
061        }
062        return super.createScheduler(schedulerFactory, schedulerName);
063    }
064
065    @Override
066    public void afterPropertiesSet() throws Exception {
067
068        boolean useQuartzDatabase = new Boolean(ConfigContext.getCurrentContextConfig().getProperty(KSBConstants.Config.USE_QUARTZ_DATABASE));
069        if (useQuartzDatabase && !schedulerInjected) {
070            // require a transaction manager
071            if (jtaTransactionManager == null) {
072                throw new ConfigurationException("No jta transaction manager was configured for the KSB Quartz Scheduler");
073            }
074            setTransactionManager(jtaTransactionManager);
075            if (!nonTransactionalDataSourceSet) {
076                // since transaction manager is required... require a non transactional datasource
077                nonTransactionalDataSource = KSBServiceLocator.getMessageNonTransactionalDataSource();
078                if (nonTransactionalDataSource == null) {
079                        throw new ConfigurationException("No non-transactional data source was found but is required for the KSB Quartz Scheduler");
080                }
081                super.setNonTransactionalDataSource(nonTransactionalDataSource);
082            }
083            if (!dataSourceSet) {
084                dataSource = KSBServiceLocator.getMessageDataSource();
085            }
086            super.setDataSource(dataSource);
087            if (transactionManagerSet && nonTransactionalDataSourceNull) {
088                throw new ConfigurationException("A valid transaction manager was set but no non-transactional data source was found");
089            }
090        }
091        super.afterPropertiesSet();
092    }
093    
094    /**
095     * This overridden method is used simply to keep track of whether the transactionManager property has been set
096     * 
097     * @see org.springframework.scheduling.quartz.SchedulerFactoryBean#setTransactionManager(org.springframework.transaction.PlatformTransactionManager)
098     */
099    @Override
100    public void setTransactionManager(PlatformTransactionManager jtaTransactionManager) {
101        transactionManagerSet = jtaTransactionManager != null;
102        this.jtaTransactionManager = jtaTransactionManager;
103    }
104    
105    /**
106     * This overridden method is used to keep track of whether the non transactional data source is null
107     * 
108     * @see org.springframework.scheduling.quartz.SchedulerFactoryBean#setNonTransactionalDataSource(javax.sql.DataSource)
109     */
110    @Override
111    public void setNonTransactionalDataSource(DataSource nonTransactionalDataSource) {
112        nonTransactionalDataSourceSet = true;
113        nonTransactionalDataSourceNull = (nonTransactionalDataSource == null);
114        this.nonTransactionalDataSource = nonTransactionalDataSource;
115    }
116    
117    @Override
118    public void setDataSource(DataSource dataSource) {
119        dataSourceSet = true;
120        this.dataSource = dataSource;
121    }
122}