View Javadoc
1   /**
2    * Copyright 2005-2014 The Kuali Foundation
3    *
4    * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
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.kuali.rice.krad.config;
17  
18  import org.kuali.rice.core.api.config.module.RunMode;
19  import org.kuali.rice.core.api.config.property.ConfigContext;
20  import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
21  import org.kuali.rice.core.framework.config.module.ModuleConfigurer;
22  import org.kuali.rice.krad.service.DataDictionaryService;
23  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
24  import org.kuali.rice.krad.util.KRADConstants;
25  import org.springframework.context.ApplicationEvent;
26  import org.springframework.context.ApplicationListener;
27  import org.springframework.context.event.ContextRefreshedEvent;
28  import org.springframework.context.event.SmartApplicationListener;
29  
30  import javax.sql.DataSource;
31  import java.util.ArrayList;
32  import java.util.Arrays;
33  import java.util.List;
34  import java.util.concurrent.Executors;
35  import java.util.concurrent.ScheduledExecutorService;
36  import java.util.concurrent.TimeUnit;
37  
38  /**
39   * Rice module configurer for KRAD
40   *
41   * @author Kuali Rice Team (rice.collab@kuali.org)
42   */
43  public class KRADConfigurer extends ModuleConfigurer implements SmartApplicationListener {
44  
45      private DataSource applicationDataSource;
46  
47      private boolean includeKnsSpringBeans;
48  
49      private static final String KRAD_SPRING_BEANS_PATH = "classpath:org/kuali/rice/krad/config/KRADSpringBeans.xml";
50      private static final String KNS_SPRING_BEANS_PATH = "classpath:org/kuali/rice/kns/config/KNSSpringBeans.xml";
51  
52      public KRADConfigurer() {
53          // TODO really the constant value should be "krad" but there's some work to do in order to make
54          // that really work, see KULRICE-6532
55          super(KRADConstants.KR_MODULE_NAME);
56          setValidRunModes(Arrays.asList(RunMode.LOCAL));
57          setIncludeKnsSpringBeans(true);
58      }
59  
60      @Override
61      public void addAdditonalToConfig() {
62          // export the state of KNS enablement to the global config
63          ConfigContext.getCurrentContextConfig().putProperty(KRADConstants.Config.KNS_ENABLED, Boolean.valueOf(isIncludeKnsSpringBeans()).toString());
64          configureDataSource();
65      }
66  
67      @Override
68      public List<String> getPrimarySpringFiles() {
69          LOG.info("KRADConfigurer:getPrimarySpringFiles: getRunMode => " + getRunMode());
70          final List<String> springFileLocations = new ArrayList<String>();
71          springFileLocations.add(KRAD_SPRING_BEANS_PATH);
72  
73          if (isIncludeKnsSpringBeans()) {
74              springFileLocations.add(KNS_SPRING_BEANS_PATH);
75          }
76  
77          return springFileLocations;
78      }
79  
80      @Override
81      public void onApplicationEvent(ApplicationEvent applicationEvent) {
82          if (applicationEvent instanceof ContextRefreshedEvent) {
83              loadDataDictionary();
84              publishDataDictionaryComponents();
85          }
86      }
87  
88      @Override
89      public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) {
90          return true;
91      }
92  
93      @Override
94      public boolean supportsSourceType(Class<?> aClass) {
95          return true;
96      }
97  
98      @Override
99      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 }