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