1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.configuration;
24  
25  import com.germinus.easyconf.AggregatedProperties;
26  import com.germinus.easyconf.ComponentConfiguration;
27  import com.germinus.easyconf.ComponentProperties;
28  import com.germinus.easyconf.EasyConf;
29  
30  import com.liferay.portal.kernel.configuration.Filter;
31  import com.liferay.portal.kernel.log.Log;
32  import com.liferay.portal.kernel.log.LogFactoryUtil;
33  import com.liferay.portal.kernel.util.Validator;
34  
35  import java.lang.reflect.Field;
36  
37  import java.net.URI;
38  import java.net.URISyntaxException;
39  import java.net.URL;
40  
41  import java.util.Enumeration;
42  import java.util.HashSet;
43  import java.util.Iterator;
44  import java.util.List;
45  import java.util.Map;
46  import java.util.Properties;
47  import java.util.Set;
48  
49  import org.apache.commons.configuration.CompositeConfiguration;
50  import org.apache.commons.configuration.Configuration;
51  import org.apache.commons.configuration.MapConfiguration;
52  
53  /**
54   * <a href="ConfigurationImpl.java.html"><b><i>View Source</i></b></a>
55   *
56   * @author Brian Wing Shun Chan
57   *
58   */
59  public class ConfigurationImpl
60      implements com.liferay.portal.kernel.configuration.Configuration {
61  
62      public ConfigurationImpl(ClassLoader classLoader, String name) {
63          _componentConfiguration = EasyConf.getConfiguration(
64              getFileName(classLoader, name));
65  
66          printSources();
67      }
68  
69      public void addProperties(Properties properties) {
70          try {
71              ComponentProperties componentProperties =
72                  _componentConfiguration.getProperties();
73  
74              AggregatedProperties aggregatedProperties =
75                  (AggregatedProperties)componentProperties.toConfiguration();
76  
77              Field field1 = CompositeConfiguration.class.getDeclaredField(
78                  "configList");
79  
80              field1.setAccessible(true);
81  
82              // Add to configList of base conf
83  
84              List<Configuration> configurations =
85                  (List<Configuration>)field1.get(aggregatedProperties);
86  
87              MapConfiguration newConfiguration =
88                  new MapConfiguration(properties);
89  
90              configurations.add(0, newConfiguration);
91  
92              // Add to configList of AggregatedProperties itself
93  
94              Field field2 = aggregatedProperties.getClass().getDeclaredField(
95                  "baseConf");
96  
97              field2.setAccessible(true);
98  
99              CompositeConfiguration compositeConfiguration =
100                 (CompositeConfiguration)field2.get(aggregatedProperties);
101 
102             configurations = (List<Configuration>)field1.get(
103                 compositeConfiguration);
104 
105             configurations.add(0, newConfiguration);
106         }
107         catch (Exception e) {
108             _log.error("The properties could not be added", e);
109         }
110     }
111 
112     public boolean contains(String key) {
113         return getComponentProperties().containsKey(key);
114     }
115 
116     public String get(String key) {
117         if (_PRINT_DUPLICATE_CALLS_TO_GET) {
118             if (_keys.contains(key)) {
119                 System.out.println("Duplicate call to get " + key);
120             }
121             else {
122                 _keys.add(key);
123             }
124         }
125 
126         return getComponentProperties().getString(key);
127     }
128 
129     public String get(String key, Filter filter) {
130         return getComponentProperties().getString(
131             key, getEasyConfFilter(filter));
132     }
133 
134     public String[] getArray(String key) {
135         String[] array = getComponentProperties().getStringArray(key);
136 
137         if (array == null) {
138             return new String[0];
139         }
140         else if (array.length > 0) {
141 
142             // Commons Configuration parses an empty property into a String
143             // array with one String containing one space. It also leaves a
144             // trailing array member if you set a property in more than one
145             // line.
146 
147             if (Validator.isNull(array[array.length - 1])) {
148                 String[] subArray = new String[array.length - 1];
149 
150                 System.arraycopy(array, 0, subArray, 0, subArray.length);
151 
152                 array = subArray;
153             }
154         }
155 
156         return array;
157     }
158 
159     public String[] getArray(String key, Filter filter) {
160         return getComponentProperties().getStringArray(
161             key, getEasyConfFilter(filter));
162     }
163 
164     public Properties getProperties() {
165 
166         // For some strange reason, componentProperties.getProperties() returns
167         // values with spaces after commas. So a property setting of "xyz=1,2,3"
168         // actually returns "xyz=1, 2, 3". This can break applications that
169         // don't expect that extra space. However, getting the property value
170         // directly through componentProperties returns the correct value. This
171         // method fixes the weird behavior by returing properties with the
172         // correct values.
173 
174         Properties properties = new Properties();
175 
176         ComponentProperties componentProperties = getComponentProperties();
177 
178         Iterator<Map.Entry<Object, Object>> itr =
179             componentProperties.getProperties().entrySet().iterator();
180 
181         while (itr.hasNext()) {
182             Map.Entry<Object, Object> entry = itr.next();
183 
184             String key = (String)entry.getKey();
185             String value = (String)entry.getValue();
186 
187             properties.setProperty(key, value);
188         }
189 
190         return properties;
191     }
192 
193     public Properties getProperties(String prefix, boolean removePrefix) {
194         Properties subProperties = new Properties();
195 
196         Properties allProperties = getProperties();
197 
198         Enumeration<String> enu =
199             (Enumeration<String>)allProperties.propertyNames();
200 
201         while (enu.hasMoreElements()) {
202             String key = enu.nextElement();
203 
204             if (key.startsWith(prefix)) {
205                 String value = allProperties.getProperty(key);
206 
207                 if (removePrefix) {
208                     key = key.substring(prefix.length());
209                 }
210 
211                 subProperties.setProperty(key, value);
212             }
213         }
214 
215         return subProperties;
216     }
217 
218     public void removeProperties(Properties properties) {
219         try {
220             ComponentProperties componentProperties =
221                 _componentConfiguration.getProperties();
222 
223             AggregatedProperties aggregatedProperties =
224                 (AggregatedProperties)componentProperties.toConfiguration();
225 
226             Field field1 = aggregatedProperties.getClass().getDeclaredField(
227                 "baseConf");
228 
229             field1.setAccessible(true);
230 
231             CompositeConfiguration compositeConfiguration =
232                 (CompositeConfiguration)field1.get(aggregatedProperties);
233 
234             Field field2 = CompositeConfiguration.class.getDeclaredField(
235                 "configList");
236 
237             field2.setAccessible(true);
238 
239             List<Configuration> configurations =
240                 (List<Configuration>)field2.get(compositeConfiguration);
241 
242             Iterator<Configuration> itr = configurations.iterator();
243 
244             while (itr.hasNext()) {
245                 Configuration configuration = itr.next();
246 
247                 if (!(configuration instanceof MapConfiguration)) {
248                     return;
249                 }
250 
251                 MapConfiguration mapConfiguration =
252                     (MapConfiguration)configuration;
253 
254                 if (mapConfiguration.getMap() == properties) {
255                     itr.remove();
256 
257                     aggregatedProperties.removeConfiguration(configuration);
258                 }
259             }
260         }
261         catch (Exception e) {
262             _log.error("The properties could not be removed", e);
263         }
264     }
265 
266     public void set(String key, String value) {
267         getComponentProperties().setProperty(key, value);
268     }
269 
270     protected ComponentProperties getComponentProperties() {
271         return _componentConfiguration.getProperties();
272     }
273 
274     protected com.germinus.easyconf.Filter getEasyConfFilter(Filter filter) {
275         com.germinus.easyconf.Filter easyConfFilter =
276             com.germinus.easyconf.Filter.by(filter.getSelectors());
277 
278         if (filter.getVariables() != null) {
279             easyConfFilter.setVariables(filter.getVariables());
280         }
281 
282         return easyConfFilter;
283     }
284 
285     protected String getFileName(ClassLoader classLoader, String name) {
286         URL url = classLoader.getResource(name + ".properties");
287 
288         // If the resource is located inside of a JAR, then EasyConf needs the
289         // "jar:file:" prefix appended to the path. Use URL.toExternalForm() to
290         // achieve that. When running under WebLogic, the protocol returned is
291         // "zip". When running under WebSphere, the protocol returned is
292         // "wsjar".
293 
294         String protocol = url.getProtocol();
295 
296         if (protocol.equals("jar") || protocol.equals("vfszip") ||
297             protocol.equals("wsjar") || protocol.equals("zip")) {
298 
299             name = url.toExternalForm();
300         }
301         else {
302             try {
303                 name = new URI(url.getPath()).getPath();
304             }
305             catch (URISyntaxException urise) {
306                 name = url.getFile();
307             }
308         }
309 
310         int pos = name.lastIndexOf(".properties");
311 
312         if (pos != -1) {
313             name = name.substring(0, pos);
314         }
315 
316         return name;
317     }
318 
319     protected void printSources() {
320         List<String> sources = getComponentProperties().getLoadedSources();
321 
322         for (int i = sources.size() - 1; i >= 0; i--) {
323             String source = sources.get(i);
324 
325             System.out.println("Loading " + source);
326         }
327     }
328 
329     private static final boolean _PRINT_DUPLICATE_CALLS_TO_GET = false;
330 
331     private static Log _log = LogFactoryUtil.getLog(ConfigurationImpl.class);
332 
333     private ComponentConfiguration _componentConfiguration;
334     private Set<String> _keys = new HashSet<String>();
335 
336 }