001/**
002 * Copyright 2005-2016 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.addJobListener(new MessageServiceExecutorJobListener());
056                return scheduler;
057            } catch (Exception e) {
058                throw new ConfigurationException(e);
059            }
060        }
061        return super.createScheduler(schedulerFactory, schedulerName);
062    }
063
064    @Override
065    public void afterPropertiesSet() throws Exception {
066
067        boolean useQuartzDatabase = new Boolean(ConfigContext.getCurrentContextConfig().getProperty(KSBConstants.Config.USE_QUARTZ_DATABASE));
068        if (useQuartzDatabase && !schedulerInjected) {
069            // require a transaction manager
070            if (jtaTransactionManager == null) {
071                throw new ConfigurationException("No jta transaction manager was configured for the KSB Quartz Scheduler");
072            }
073            setTransactionManager(jtaTransactionManager);
074            if (!nonTransactionalDataSourceSet) {
075                // since transaction manager is required... require a non transactional datasource
076                nonTransactionalDataSource = KSBServiceLocator.getMessageNonTransactionalDataSource();
077                if (nonTransactionalDataSource == null) {
078                        throw new ConfigurationException("No non-transactional data source was found but is required for the KSB Quartz Scheduler");
079                }
080                super.setNonTransactionalDataSource(nonTransactionalDataSource);
081            }
082            if (!dataSourceSet) {
083                dataSource = KSBServiceLocator.getMessageDataSource();
084            }
085            super.setDataSource(dataSource);
086            if (transactionManagerSet && nonTransactionalDataSourceNull) {
087                throw new ConfigurationException("A valid transaction manager was set but no non-transactional data source was found");
088            }
089        }
090        super.afterPropertiesSet();
091    }
092    
093    /**
094     * This overridden method is used simply to keep track of whether the transactionManager property has been set
095     * 
096     * @see org.springframework.scheduling.quartz.SchedulerFactoryBean#setTransactionManager(org.springframework.transaction.PlatformTransactionManager)
097     */
098    @Override
099    public void setTransactionManager(PlatformTransactionManager jtaTransactionManager) {
100        transactionManagerSet = jtaTransactionManager != null;
101        this.jtaTransactionManager = jtaTransactionManager;
102    }
103    
104    /**
105     * This overridden method is used to keep track of whether the non transactional data source is null
106     * 
107     * @see org.springframework.scheduling.quartz.SchedulerFactoryBean#setNonTransactionalDataSource(javax.sql.DataSource)
108     */
109    @Override
110    public void setNonTransactionalDataSource(DataSource nonTransactionalDataSource) {
111        nonTransactionalDataSourceSet = true;
112        nonTransactionalDataSourceNull = (nonTransactionalDataSource == null);
113        this.nonTransactionalDataSource = nonTransactionalDataSource;
114    }
115    
116    @Override
117    public void setDataSource(DataSource dataSource) {
118        dataSourceSet = true;
119        this.dataSource = dataSource;
120    }
121}