001/** 002 * Copyright 2005-2018 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.krad.config; 017 018import org.kuali.rice.core.api.config.module.RunMode; 019import org.kuali.rice.core.api.config.property.ConfigContext; 020import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader; 021import org.kuali.rice.core.framework.config.module.ModuleConfigurer; 022import org.kuali.rice.krad.service.DataDictionaryService; 023import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 024import org.kuali.rice.krad.util.KRADConstants; 025import org.springframework.context.ApplicationEvent; 026import org.springframework.context.ApplicationListener; 027import org.springframework.context.event.ContextRefreshedEvent; 028import org.springframework.context.event.SmartApplicationListener; 029 030import javax.sql.DataSource; 031import java.util.ArrayList; 032import java.util.Arrays; 033import java.util.List; 034import java.util.concurrent.Executors; 035import java.util.concurrent.ScheduledExecutorService; 036import java.util.concurrent.TimeUnit; 037 038/** 039 * Rice module configurer for KRAD 040 * 041 * @author Kuali Rice Team (rice.collab@kuali.org) 042 */ 043public class KRADConfigurer extends ModuleConfigurer implements SmartApplicationListener { 044 045 private DataSource applicationDataSource; 046 047 private boolean includeKnsSpringBeans; 048 049 private static final String KRAD_SPRING_BEANS_PATH = "classpath:org/kuali/rice/krad/config/KRADSpringBeans.xml"; 050 private static final String KNS_SPRING_BEANS_PATH = "classpath:org/kuali/rice/kns/config/KNSSpringBeans.xml"; 051 052 public KRADConfigurer() { 053 // TODO really the constant value should be "krad" but there's some work to do in order to make 054 // that really work, see KULRICE-6532 055 super(KRADConstants.KR_MODULE_NAME); 056 setValidRunModes(Arrays.asList(RunMode.LOCAL)); 057 setIncludeKnsSpringBeans(true); 058 } 059 060 @Override 061 public void addAdditonalToConfig() { 062 // export the state of KNS enablement to the global config 063 ConfigContext.getCurrentContextConfig().putProperty(KRADConstants.Config.KNS_ENABLED, Boolean.valueOf(isIncludeKnsSpringBeans()).toString()); 064 configureDataSource(); 065 } 066 067 @Override 068 public List<String> getPrimarySpringFiles() { 069 LOG.info("KRADConfigurer:getPrimarySpringFiles: getRunMode => " + getRunMode()); 070 final List<String> springFileLocations = new ArrayList<String>(); 071 springFileLocations.add(KRAD_SPRING_BEANS_PATH); 072 073 if (isIncludeKnsSpringBeans()) { 074 springFileLocations.add(KNS_SPRING_BEANS_PATH); 075 } 076 077 return springFileLocations; 078 } 079 080 @Override 081 public void onApplicationEvent(ApplicationEvent applicationEvent) { 082 if (applicationEvent instanceof ContextRefreshedEvent) { 083 loadDataDictionary(); 084 publishDataDictionaryComponents(); 085 } 086 } 087 088 @Override 089 public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) { 090 return true; 091 } 092 093 @Override 094 public boolean supportsSourceType(Class<?> aClass) { 095 return true; 096 } 097 098 @Override 099 public int getOrder() { 100 // return a lower value which will give the data dictionary indexing higher precedence since DD indexing should 101 // be started as soon as it can be 102 return -1000; 103 } 104 105 /** 106 * Used to "poke" the Data Dictionary again after the Spring Context is initialized. This is to 107 * allow for modules loaded with KualiModule after the KNS has already been initialized to work. 108 * 109 * Also initializes the DateTimeService 110 */ 111 protected void loadDataDictionary() { 112 if (isLoadDataDictionary()) { 113 LOG.info("KRAD Configurer - Loading DD"); 114 DataDictionaryService dds = KRADServiceLocatorWeb.getDataDictionaryService(); 115 if (dds == null) { 116 dds = (DataDictionaryService) GlobalResourceLoader.getService( 117 KRADServiceLocatorWeb.DATA_DICTIONARY_SERVICE); 118 } 119 dds.getDataDictionary().parseDataDictionaryConfigurationFiles(false); 120 121 if (isValidateDataDictionary()) { 122 LOG.info("KRAD Configurer - Validating DD"); 123 dds.getDataDictionary().validateDD(isValidateDataDictionaryEboReferences()); 124 } 125 126 // KULRICE-4513 After the Data Dictionary is loaded and validated, perform Data Dictionary bean overrides. 127 dds.getDataDictionary().performBeanOverrides(); 128 } 129 } 130 131 protected void publishDataDictionaryComponents() { 132 if (isComponentPublishingEnabled()) { 133 long delay = getComponentPublishingDelay(); 134 LOG.info("Publishing of Data Dictionary components is enabled, scheduling publish after " + delay + " millisecond delay"); 135 ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); 136 try { 137 scheduler.schedule(new Runnable() { 138 @Override 139 public void run() { 140 long start = System.currentTimeMillis(); 141 LOG.info("Executing scheduled Data Dictionary component publishing..."); 142 try { 143 KRADServiceLocatorWeb.getDataDictionaryComponentPublisherService().publishAllComponents(); 144 } catch (RuntimeException e) { 145 LOG.error("Failed to publish data dictionary components.", e); 146 throw e; 147 } finally { 148 long end = System.currentTimeMillis(); 149 LOG.info("... finished scheduled execution of Data Dictionary component publishing. Took " + (end-start) + " milliseconds"); 150 } 151 } 152 }, delay, TimeUnit.MILLISECONDS); 153 } finally { 154 scheduler.shutdown(); 155 } 156 } 157 } 158 159 @Override 160 public boolean hasWebInterface() { 161 return true; 162 } 163 164 /** 165 * Returns true - KNS UI should always be included. 166 * 167 * @see org.kuali.rice.core.framework.config.module.ModuleConfigurer#shouldRenderWebInterface() 168 */ 169 @Override 170 public boolean shouldRenderWebInterface() { 171 return true; 172 } 173 174 public boolean isLoadDataDictionary() { 175 return ConfigContext.getCurrentContextConfig().getBooleanProperty("load.data.dictionary", true); 176 } 177 178 public boolean isValidateDataDictionary() { 179 return ConfigContext.getCurrentContextConfig().getBooleanProperty("validate.data.dictionary", false); 180 } 181 182 public boolean isValidateDataDictionaryEboReferences() { 183 return ConfigContext.getCurrentContextConfig().getBooleanProperty("validate.data.dictionary.ebo.references", 184 false); 185 } 186 187 public boolean isComponentPublishingEnabled() { 188 return ConfigContext.getCurrentContextConfig().getBooleanProperty( 189 KRADConstants.Config.COMPONENT_PUBLISHING_ENABLED, false); 190 } 191 192 public long getComponentPublishingDelay() { 193 return ConfigContext.getCurrentContextConfig().getNumericProperty(KRADConstants.Config.COMPONENT_PUBLISHING_DELAY, 0); 194 } 195 196 /** 197 * Used to "poke" the Data Dictionary again after the Spring Context is initialized. This is to 198 * allow for modules loaded with KualiModule after the KNS has already been initialized to work. 199 * 200 * Also initializes the DateTimeService 201 */ 202 protected void configureDataSource() { 203 if (getApplicationDataSource() != null) { 204 ConfigContext.getCurrentContextConfig().putObject(KRADConstants.KRAD_APPLICATION_DATASOURCE, 205 getApplicationDataSource()); 206 } 207 } 208 209 public DataSource getApplicationDataSource() { 210 return this.applicationDataSource; 211 } 212 213 public void setApplicationDataSource(DataSource applicationDataSource) { 214 this.applicationDataSource = applicationDataSource; 215 } 216 217 /** 218 * Indicates whether the legacy KNS module should be included which will include 219 * the KNS spring beans file 220 * 221 * @return boolean true if kns should be supported, false if not 222 */ 223 public boolean isIncludeKnsSpringBeans() { 224 return includeKnsSpringBeans; 225 } 226 227 /** 228 * Setter for the include kns support indicator 229 * 230 * @param includeKnsSpringBeans 231 */ 232 public void setIncludeKnsSpringBeans(boolean includeKnsSpringBeans) { 233 this.includeKnsSpringBeans = includeKnsSpringBeans; 234 } 235}