1   /**
2    * Copyright (c) 2000-2008 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.util.Validator;
32  
33  import java.lang.reflect.Field;
34  
35  import java.net.URI;
36  import java.net.URISyntaxException;
37  import java.net.URL;
38  
39  import java.util.HashSet;
40  import java.util.Iterator;
41  import java.util.List;
42  import java.util.Map;
43  import java.util.Properties;
44  import java.util.Set;
45  
46  import org.apache.commons.configuration.CompositeConfiguration;
47  import org.apache.commons.configuration.Configuration;
48  import org.apache.commons.configuration.MapConfiguration;
49  import org.apache.commons.logging.Log;
50  import org.apache.commons.logging.LogFactory;
51  
52  /**
53   * <a href="ConfigurationImpl.java.html"><b><i>View Source</i></b></a>
54   *
55   * @author Brian Wing Shun Chan
56   *
57   */
58  public class ConfigurationImpl
59      implements com.liferay.portal.kernel.configuration.Configuration {
60  
61      public ConfigurationImpl(ClassLoader classLoader, String name) {
62          _componentConfiguration = EasyConf.getConfiguration(
63              getFileName(classLoader, name));
64  
65          printSources();
66      }
67  
68      public void addProperties(Properties properties) {
69          try {
70              ComponentProperties componentProperties =
71                  _componentConfiguration.getProperties();
72  
73              AggregatedProperties aggregatedProperties =
74                  (AggregatedProperties)componentProperties.toConfiguration();
75  
76              Field field1 = CompositeConfiguration.class.getDeclaredField(
77                  "configList");
78  
79              field1.setAccessible(true);
80  
81              // Add to configList of base conf
82  
83              List<Configuration> configurations =
84                  (List<Configuration>)field1.get(aggregatedProperties);
85  
86              MapConfiguration newConfiguration =
87                  new MapConfiguration(properties);
88  
89              configurations.add(0, newConfiguration);
90  
91              // Add to configList of AggregatedProperties itself
92  
93              Field field2 = aggregatedProperties.getClass().getDeclaredField(
94                  "baseConf");
95  
96              field2.setAccessible(true);
97  
98              CompositeConfiguration compositeConfiguration =
99                  (CompositeConfiguration)field2.get(aggregatedProperties);
100 
101             configurations = (List<Configuration>)field1.get(
102                 compositeConfiguration);
103 
104             configurations.add(0, newConfiguration);
105         }
106         catch (Exception e) {
107             _log.error("The properties could not be added", e);
108         }
109     }
110 
111     public boolean contains(String key) {
112         return getComponentProperties().containsKey(key);
113     }
114 
115     public String get(String key) {
116         if (_PRINT_DUPLICATE_CALLS_TO_GET) {
117             if (_keys.contains(key)) {
118                 System.out.println("Duplicate call to get " + key);
119             }
120             else {
121                 _keys.add(key);
122             }
123         }
124 
125         return getComponentProperties().getString(key);
126     }
127 
128     public String get(String key, Filter filter) {
129         return getComponentProperties().getString(
130             key, getEasyConfFilter(filter));
131     }
132 
133     public String[] getArray(String key) {
134         String[] array = getComponentProperties().getStringArray(key);
135 
136         if (array == null) {
137             return new String[0];
138         }
139         else if (array.length > 0) {
140 
141             // Commons Configuration parses an empty property into a String
142             // array with one String containing one space. It also leaves a
143             // trailing array member if you set a property in more than one
144             // line.
145 
146             if (Validator.isNull(array[array.length - 1])) {
147                 String[] subArray = new String[array.length - 1];
148 
149                 System.arraycopy(array, 0, subArray, 0, subArray.length);
150 
151                 array = subArray;
152             }
153         }
154 
155         return array;
156     }
157 
158     public String[] getArray(String key, Filter filter) {
159         return getComponentProperties().getStringArray(
160             key, getEasyConfFilter(filter));
161     }
162 
163     public Properties getProperties() {
164 
165         // For some strange reason, componentProperties.getProperties() returns
166         // values with spaces after commas. So a property setting of "xyz=1,2,3"
167         // actually returns "xyz=1, 2, 3". This can break applications that
168         // don't expect that extra space. However, getting the property value
169         // directly through componentProperties returns the correct value. This
170         // method fixes the weird behavior by returing properties with the
171         // correct values.
172 
173         Properties properties = new Properties();
174 
175         ComponentProperties componentProperties = getComponentProperties();
176 
177         Iterator<Map.Entry<Object, Object>> itr =
178             componentProperties.getProperties().entrySet().iterator();
179 
180         while (itr.hasNext()) {
181             Map.Entry<Object, Object> entry = itr.next();
182 
183             String key = (String)entry.getKey();
184             String value = (String)entry.getValue();
185 
186             properties.setProperty(key, value);
187         }
188 
189         return properties;
190     }
191 
192     public void removeProperties(Properties properties) {
193         try {
194             ComponentProperties componentProperties =
195                 _componentConfiguration.getProperties();
196 
197             AggregatedProperties aggregatedProperties =
198                 (AggregatedProperties)componentProperties.toConfiguration();
199 
200             Field field1 = aggregatedProperties.getClass().getDeclaredField(
201                 "baseConf");
202 
203             field1.setAccessible(true);
204 
205             CompositeConfiguration compositeConfiguration =
206                 (CompositeConfiguration)field1.get(aggregatedProperties);
207 
208             Field field2 = CompositeConfiguration.class.getDeclaredField(
209                 "configList");
210 
211             field2.setAccessible(true);
212 
213             List<Configuration> configurations =
214                 (List<Configuration>)field2.get(compositeConfiguration);
215 
216             Iterator<Configuration> itr = configurations.iterator();
217 
218             while (itr.hasNext()) {
219                 Configuration configuration = itr.next();
220 
221                 if (!(configuration instanceof MapConfiguration)) {
222                     return;
223                 }
224 
225                 MapConfiguration mapConfiguration =
226                     (MapConfiguration)configuration;
227 
228                 if (mapConfiguration.getMap() == properties) {
229                     itr.remove();
230 
231                     aggregatedProperties.removeConfiguration(configuration);
232                 }
233             }
234         }
235         catch (Exception e) {
236             _log.error("The properties could not be removed", e);
237         }
238     }
239 
240     public void set(String key, String value) {
241         getComponentProperties().setProperty(key, value);
242     }
243 
244     protected ComponentProperties getComponentProperties() {
245         return _componentConfiguration.getProperties();
246     }
247 
248     protected com.germinus.easyconf.Filter getEasyConfFilter(Filter filter) {
249         com.germinus.easyconf.Filter easyConfFilter =
250             com.germinus.easyconf.Filter.by(filter.getSelectors());
251 
252         if (filter.getVariables() != null) {
253             easyConfFilter.setVariables(filter.getVariables());
254         }
255 
256         return easyConfFilter;
257     }
258 
259     protected String getFileName(ClassLoader classLoader, String name) {
260         URL url = classLoader.getResource(name + ".properties");
261 
262         // If the resource is located inside of a JAR, then EasyConf needs the
263         // "jar:file:" prefix appended to the path. Use URL.toExternalForm() to
264         // achieve that. When running under WebLogic, the protocol returned is
265         // "zip". When running under WebSphere, the protocol returned is
266         // "wsjar".
267 
268         String protocol = url.getProtocol();
269 
270         if (protocol.equals("jar") || protocol.equals("wsjar") ||
271             protocol.equals("zip")) {
272 
273             name = url.toExternalForm();
274         }
275         else {
276             try {
277                 name = new URI(url.getPath()).getPath();
278             }
279             catch (URISyntaxException urise) {
280                 name = url.getFile();
281             }
282         }
283 
284         int pos = name.lastIndexOf(".properties");
285 
286         if (pos != -1) {
287             name = name.substring(0, pos);
288         }
289 
290         return name;
291     }
292 
293     protected void printSources() {
294         List<String> sources = getComponentProperties().getLoadedSources();
295 
296         for (int i = sources.size() - 1; i >= 0; i--) {
297             String source = sources.get(i);
298 
299             System.out.println("Loading " + source);
300         }
301     }
302 
303     private static final boolean _PRINT_DUPLICATE_CALLS_TO_GET = false;
304 
305     private static Log _log = LogFactory.getLog(ConfigurationImpl.class);
306 
307     private ComponentConfiguration _componentConfiguration;
308     private Set<String> _keys = new HashSet<String>();
309 
310 }