View Javadoc

1   /**
2    * Copyright 2005-2013 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.service.impl;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.apache.commons.logging.Log;
20  import org.apache.commons.logging.LogFactory;
21  import org.apache.log4j.Logger;
22  import org.kuali.rice.core.api.config.property.ConfigContext;
23  import org.kuali.rice.core.api.config.property.ConfigurationService;
24  import org.kuali.rice.core.api.util.Truth;
25  import org.kuali.rice.kns.web.struts.action.KualiPropertyMessageResources;
26  import org.kuali.rice.kns.web.struts.action.KualiPropertyMessageResourcesFactory;
27  import org.kuali.rice.krad.exception.DuplicateKeyException;
28  import org.kuali.rice.krad.exception.PropertiesException;
29  
30  import java.io.IOException;
31  import java.io.InputStream;
32  import java.net.URL;
33  import java.util.Collections;
34  import java.util.Iterator;
35  import java.util.Map;
36  import java.util.Properties;
37  
38  /**
39   * ConfigurationService implementation which is a thin wrapper over the core Config object, and which
40   * merges in Kuali message resource properties.
41   */
42  public class ConfigurationServiceImpl implements ConfigurationService {
43      private final PropertyHolder propertyHolder = new PropertyHolder();
44  
45      /**
46       * Harcoding the configFileName, by request.
47       */
48      public ConfigurationServiceImpl() {
49          this.propertyHolder.getHeldProperties().putAll(ConfigContext.getCurrentContextConfig().getProperties());
50  
51          KualiPropertyMessageResourcesFactory propertyMessageFactory = new KualiPropertyMessageResourcesFactory();
52  
53          // create default KualiPropertyMessageResources
54          KualiPropertyMessageResources messageResources =
55                  (KualiPropertyMessageResources) propertyMessageFactory.createResources("");
56  
57          //Add Kuali Properties to property holder
58          this.propertyHolder.getHeldProperties().putAll(messageResources.getKualiProperties(null));
59      }
60  
61      /**
62       * @see org.kuali.rice.core.api.config.property.ConfigurationService#getPropertyValueAsString(java.lang.String)
63       */
64      @Override
65      public String getPropertyValueAsString(String key) {
66          if (key == null) {
67              throw new IllegalArgumentException("invalid (null) key");
68          }
69  
70          return this.propertyHolder.getProperty(key);
71      }
72  
73      /**
74       * @see org.kuali.rice.core.api.config.property.ConfigurationService#getPropertyValueAsBoolean(java.lang.String)
75       */
76      @Override
77      public boolean getPropertyValueAsBoolean(String key) {
78          if (key == null) {
79              throw new IllegalArgumentException("invalid (null) key");
80          }
81          String property = this.propertyHolder.getProperty(key);
82          Boolean b = Truth.strToBooleanIgnoreCase(property);
83          if (b == null) {
84              return false;
85          }
86          return b;
87      }
88  
89      /**
90       * @see org.kuali.rice.core.api.config.property.ConfigurationService#getAllProperties()
91       */
92      @Override
93      public Map<String, String> getAllProperties() {
94          return (Map) Collections.unmodifiableMap(propertyHolder.getHeldProperties());
95      }
96  
97      /**
98       * This is an interface for a source for properties
99       *
100      *
101      */
102     static interface PropertySource {
103         /**
104          * @return Properties loaded from this PropertySource
105          * @throws org.kuali.rice.krad.exception.PropertiesException if there's a problem loading the properties
106          */
107         public Properties loadProperties();
108     }
109 
110     /**
111      * This class is a Property container. It is able to load properties from various property-sources.
112      *
113      *
114      */
115     static class PropertyHolder {
116         private static Logger LOG = Logger.getLogger(PropertyHolder.class);
117 
118         Properties heldProperties;
119 
120         /**
121          * Default constructor.
122          */
123         public PropertyHolder() {
124             this.heldProperties = new Properties();
125         }
126 
127 
128         /**
129          * @return true if this container currently has no properties
130          */
131         public boolean isEmpty() {
132             return this.heldProperties.isEmpty();
133         }
134 
135         /**
136          * @param key
137          * @return true if a property with the given key exists in this container
138          * @throws IllegalArgumentException if the given key is null
139          */
140         public boolean containsKey(String key) {
141             validateKey(key);
142 
143             return this.heldProperties.containsKey(key);
144         }
145 
146         /**
147          * @param key
148          * @return the current value of the property with the given key, or null if no property exists with that key
149          * @throws IllegalArgumentException if the given key is null
150          */
151         public String getProperty(String key) {
152             validateKey(key);
153 
154             return this.heldProperties.getProperty(key);
155         }
156 
157 
158         /**
159          * Associates the given value with the given key
160          *
161          * @param key
162          * @param value
163          * @throws IllegalArgumentException if the given key is null
164          * @throws IllegalArgumentException if the given value is null
165          * @throws org.kuali.rice.krad.exception.DuplicateKeyException if a property with the given key already exists
166          */
167         public void setProperty(String key, String value) {
168         setProperty(null, key, value);
169         }
170 
171         /**
172          * Associates the given value with the given key
173          *
174          * @param source
175          * @param key
176          * @param value
177          * @throws IllegalArgumentException if the given key is null
178          * @throws IllegalArgumentException if the given value is null
179          * @throws org.kuali.rice.krad.exception.DuplicateKeyException if a property with the given key already exists
180          */
181         public void setProperty(PropertySource source, String key, String value) {
182             validateKey(key);
183             validateValue(value);
184 
185             if (containsKey(key)) {
186                 if (source != null && source instanceof FilePropertySource && ((FilePropertySource)source).isAllowOverrides()) {
187                     LOG.info("Duplicate Key: Override is enabled [key=" + key + ", new value=" + value + ", old value=" + this.heldProperties.getProperty(key) + "]");
188                 } else {
189                     throw new DuplicateKeyException("duplicate key '" + key + "'");
190                 }
191             }
192             this.heldProperties.setProperty(key, value);
193         }
194 
195         /**
196          * Removes the property with the given key from this container
197          *
198          * @param key
199          * @throws IllegalArgumentException if the given key is null
200          */
201         public void clearProperty(String key) {
202             validateKey(key);
203 
204             this.heldProperties.remove(key);
205         }
206 
207 
208         /**
209          * Copies all name,value pairs from the given PropertySource instance into this container.
210          *
211          * @param source
212          * @throws IllegalStateException if the source is invalid (improperly initialized)
213          * @throws org.kuali.rice.krad.exception.DuplicateKeyException the first time a given property has the same key as an existing property
214          * @throws org.kuali.rice.krad.exception.PropertiesException if unable to load properties from the given source
215          */
216         public void loadProperties(PropertySource source) {
217             if (source == null) {
218                 throw new IllegalArgumentException("invalid (null) source");
219             }
220 
221             Properties newProperties = source.loadProperties();
222 
223             for (Iterator i = newProperties.keySet().iterator(); i.hasNext();) {
224                 String key = (String) i.next();
225                 setProperty(source, key, newProperties.getProperty(key));
226             }
227         }
228 
229         /**
230          * Removes all properties from this container.
231          */
232         public void clearProperties() {
233             this.heldProperties.clear();
234         }
235 
236 
237         /**
238          * @return iterator over the keys of all properties in this container
239          */
240         public Iterator getKeys() {
241             return this.heldProperties.keySet().iterator();
242         }
243 
244 
245         /**
246          * @param key
247          * @throws IllegalArgumentException if the given key is null
248          */
249         private void validateKey(String key) {
250             if (key == null) {
251                 throw new IllegalArgumentException("invalid (null) key");
252             }
253         }
254 
255         /**
256          * @param value
257          * @throws IllegalArgumentException if the given value is null
258          */
259         private void validateValue(String value) {
260             if (value == null) {
261                 throw new IllegalArgumentException("invalid (null) value");
262             }
263         }
264 
265 
266         public Properties getHeldProperties() {
267             return heldProperties;
268         }
269 
270 
271         public void setHeldProperties(Properties heldProperties) {
272             this.heldProperties = heldProperties;
273         }
274     }
275 
276     /**
277      * This class is used to obtain properties from a properites file.
278      *
279      *
280      */
281     static class FilePropertySource implements PropertySource {
282         private static Log log = LogFactory.getLog(FilePropertySource.class);
283 
284 
285         private String fileName;
286         private boolean allowOverrides;
287 
288         /**
289          * Set source fileName.
290          *
291          * @param fileName
292          */
293         public void setFileName(String fileName) {
294             this.fileName = fileName;
295         }
296 
297         /**
298          * @return source fileName
299          */
300         public String getFileName() {
301             return this.fileName;
302         }
303 
304         public boolean isAllowOverrides() {
305             return this.allowOverrides;
306         }
307 
308         public void setAllowOverrides(boolean allowOverrides) {
309             this.allowOverrides = allowOverrides;
310         }
311 
312         /**
313          * Attempts to load properties from a properties file which has the current fileName and is located on the classpath.
314          *
315          * @see org.kuali.rice.krad.service.impl.ConfigurationServiceImpl.PropertySource#loadProperties()
316          * @throws IllegalStateException if the fileName is null or empty
317          */
318         public Properties loadProperties() {
319             if (StringUtils.isBlank(getFileName())) {
320                 throw new IllegalStateException("invalid (blank) fileName");
321             }
322 
323             Properties properties = new Properties();
324 
325             ClassLoader loader = Thread.currentThread().getContextClassLoader();
326             URL url = loader.getResource(getFileName());
327             if (url == null) {
328                 throw new PropertiesException("unable to locate properties file '" + getFileName() + "'");
329             }
330 
331             InputStream in = null;
332 
333             try {
334                 in = url.openStream();
335                 properties.load(in);
336             }
337             catch (IOException e) {
338                 throw new PropertiesException("error loading from properties file '" + getFileName() + "'", e);
339             }
340             finally {
341                 if (in != null) {
342                     try {
343                         in.close();
344                     }
345                     catch (IOException e) {
346                         log.error("caught exception closing InputStream: " + e);
347                     }
348 
349                 }
350             }
351 
352             return properties;
353         }
354 
355     }
356 }