1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.datadictionary;
17
18 import no.geosoft.cc.io.FileListener;
19 import no.geosoft.cc.io.FileMonitor;
20 import org.apache.commons.lang.StringUtils;
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23 import org.kuali.rice.core.api.config.property.ConfigurationService;
24 import org.kuali.rice.krad.service.KRADServiceLocator;
25 import org.kuali.rice.krad.uif.util.UifBeanFactoryPostProcessor;
26 import org.springframework.beans.BeansException;
27 import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
28 import org.springframework.context.ApplicationContext;
29 import org.springframework.context.ApplicationContextAware;
30 import org.springframework.context.ApplicationListener;
31 import org.springframework.context.ConfigurableApplicationContext;
32 import org.springframework.context.event.ContextClosedEvent;
33 import org.springframework.core.io.FileSystemResource;
34 import org.springframework.core.io.InputStreamResource;
35 import org.springframework.core.io.Resource;
36
37 import java.io.File;
38 import java.io.InputStream;
39 import java.net.URL;
40 import java.util.ArrayList;
41 import java.util.List;
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 public class ReloadingDataDictionary extends DataDictionary implements FileListener, URLMonitor.URLContentChangedListener, ApplicationContextAware {
62 private static final Log LOG = LogFactory.getLog(DataDictionary.class);
63
64 private static final String CLASS_DIR_CONFIG_PARM = "reload.data.dictionary.classes.dir";
65 private static final String SOURCE_DIR_CONFIG_PARM = "reload.data.dictionary.source.dir";
66 private static final String INTERVAL_CONFIG_PARM = "reload.data.dictionary.interval";
67
68 private URLMonitor dictionaryUrlMonitor;
69
70
71 public ReloadingDataDictionary() {
72 super();
73 }
74
75
76
77
78
79
80
81 @Override
82 public void parseDataDictionaryConfigurationFiles(boolean allowConcurrentValidation) {
83 ConfigurationService configurationService = KRADServiceLocator.getKualiConfigurationService();
84
85
86 String classesDir = configurationService.getPropertyValueAsString(CLASS_DIR_CONFIG_PARM);
87
88
89 String sourceDir = configurationService.getPropertyValueAsString(SOURCE_DIR_CONFIG_PARM);
90
91
92 int reloadInterval = Integer.parseInt(configurationService.getPropertyValueAsString(INTERVAL_CONFIG_PARM));
93
94 FileMonitor dictionaryFileMonitor = new FileMonitor(reloadInterval);
95
96 dictionaryUrlMonitor = new URLMonitor(reloadInterval);
97 dictionaryUrlMonitor.addListener(this);
98
99
100
101 List<String> configLocations = new ArrayList<String>(configFileLocations);
102
103 super.parseDataDictionaryConfigurationFiles(allowConcurrentValidation);
104 for (String configLocation : configLocations) {
105 Resource classFileResource = getFileResource(configLocation);
106 try {
107 if (classFileResource.getURI().toString().startsWith("jar:")) {
108 LOG.debug("Monitoring dictionary file at URI: " + classFileResource.getURI().toString());
109 dictionaryUrlMonitor.addURI(classFileResource.getURL());
110 } else {
111 String filePathClassesDir = classFileResource.getFile().getAbsolutePath();
112 String sourceFilePath = StringUtils.replace(filePathClassesDir, classesDir, sourceDir);
113 File dictionaryFile = new File(filePathClassesDir);
114 if (dictionaryFile.exists()) {
115 LOG.debug("Monitoring dictionary file: " + dictionaryFile.getName());
116 dictionaryFileMonitor.addFile(dictionaryFile);
117 }
118 }
119 }
120 catch (Exception e) {
121 LOG.info("Exception in picking up dictionary file for monitoring: " + e.getMessage(), e);
122 }
123 }
124
125
126 dictionaryFileMonitor.addListener(this);
127 }
128
129
130
131
132
133
134
135
136 @Override
137 public void fileChanged(File file) {
138 LOG.info("reloading dictionary configuration for " + file.getName());
139 try {
140 Resource resource = new FileSystemResource(file);
141 xmlReader.loadBeanDefinitions(resource);
142
143 UifBeanFactoryPostProcessor factoryPostProcessor = new UifBeanFactoryPostProcessor();
144 factoryPostProcessor.postProcessBeanFactory(ddBeans);
145
146
147 ddIndex.run();
148 }
149 catch (Exception e) {
150 LOG.info("Exception in dictionary hot deploy: " + e.getMessage(), e);
151 }
152 }
153
154 public void urlContentChanged(final URL url) {
155 LOG.info("reloading dictionary configuration for " + url.toString());
156 try {
157 InputStream urlStream = url.openStream();
158 InputStreamResource resource = new InputStreamResource(urlStream);
159
160 int originalValidationMode = xmlReader.getValidationMode();
161 xmlReader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_XSD);
162 xmlReader.loadBeanDefinitions(resource);
163 xmlReader.setValidationMode(originalValidationMode);
164
165 UifBeanFactoryPostProcessor factoryPostProcessor = new UifBeanFactoryPostProcessor();
166 factoryPostProcessor.postProcessBeanFactory(ddBeans);
167
168
169 ddIndex.run();
170 }
171 catch (Exception e) {
172 LOG.info("Exception in dictionary hot deploy: " + e.getMessage(), e);
173 }
174 }
175
176 @Override
177 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
178
179 if (applicationContext instanceof ConfigurableApplicationContext) {
180 ConfigurableApplicationContext context = (ConfigurableApplicationContext) applicationContext;
181 context.addApplicationListener(new ApplicationListener<ContextClosedEvent>() {
182 @Override
183 public void onApplicationEvent(ContextClosedEvent e) {
184 LOG.info("Context '" + e.getApplicationContext().getDisplayName() + "' closed, shutting down URLMonitor scheduler");
185 dictionaryUrlMonitor.shutdownScheduler();
186 }
187 });
188 }
189 }
190 }