1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   *
12   *
13   */
14  
15  package com.liferay.portal.configuration;
16  
17  import com.germinus.easyconf.AggregatedProperties;
18  import com.germinus.easyconf.ComponentConfiguration;
19  import com.germinus.easyconf.ComponentProperties;
20  import com.germinus.easyconf.Conventions;
21  import com.germinus.easyconf.EasyConf;
22  
23  import com.liferay.portal.kernel.configuration.Filter;
24  import com.liferay.portal.kernel.log.Log;
25  import com.liferay.portal.kernel.log.LogFactoryUtil;
26  import com.liferay.portal.kernel.util.PropertiesUtil;
27  import com.liferay.portal.kernel.util.StringBundler;
28  import com.liferay.portal.kernel.util.StringPool;
29  import com.liferay.portal.kernel.util.StringUtil;
30  import com.liferay.portal.kernel.util.Validator;
31  import com.liferay.portal.model.Company;
32  import com.liferay.portal.model.CompanyConstants;
33  import com.liferay.portal.service.CompanyLocalServiceUtil;
34  
35  import java.io.FileWriter;
36  import java.io.Writer;
37  
38  import java.lang.reflect.Field;
39  
40  import java.net.URI;
41  import java.net.URISyntaxException;
42  import java.net.URL;
43  
44  import java.util.HashSet;
45  import java.util.Iterator;
46  import java.util.List;
47  import java.util.Map;
48  import java.util.Properties;
49  import java.util.Set;
50  
51  import org.apache.commons.configuration.CompositeConfiguration;
52  import org.apache.commons.configuration.Configuration;
53  import org.apache.commons.configuration.MapConfiguration;
54  
55  /**
56   * <a href="ConfigurationImpl.java.html"><b><i>View Source</i></b></a>
57   *
58   * @author Brian Wing Shun Chan
59   */
60  public class ConfigurationImpl
61      implements com.liferay.portal.kernel.configuration.Configuration {
62  
63      public ConfigurationImpl(ClassLoader classLoader, String name) {
64          this(classLoader, name, CompanyConstants.SYSTEM);
65      }
66  
67      public ConfigurationImpl(
68          ClassLoader classLoader, String name, long companyId) {
69  
70          try {
71              URL url = classLoader.getResource(
72                  name + Conventions.PROPERTIES_EXTENSION);
73  
74              if ((url != null) && url.getProtocol().equals("file")) {
75                  String basePath = url.getPath();
76  
77                  int pos = name.lastIndexOf(
78                      StringPool.SLASH + name + Conventions.PROPERTIES_EXTENSION);
79  
80                  if (pos != -1) {
81                      basePath = basePath.substring(0, pos);
82                  }
83  
84                  Properties properties = new Properties();
85  
86                  properties.load(url.openStream());
87  
88                  if (!properties.containsKey("base.path")) {
89                      String fileName = StringUtil.replace(
90                          url.getFile(), "%20", StringPool.SPACE);
91  
92                      Writer writer = new FileWriter(fileName, true);
93  
94                      StringBundler sb = new StringBundler(4);
95  
96                      sb.append(StringPool.OS_EOL);
97                      sb.append(StringPool.OS_EOL);
98                      sb.append("base.path=");
99                      sb.append(basePath);
100 
101                     writer.write(sb.toString());
102 
103                     writer.close();
104                 }
105             }
106         }
107         catch (Exception e) {
108             _log.error(e, e);
109         }
110 
111         String webId = null;
112 
113         if (companyId > CompanyConstants.SYSTEM) {
114             try {
115                 Company company = CompanyLocalServiceUtil.getCompanyById(
116                     companyId);
117 
118                 webId = company.getWebId();
119             }
120             catch (Exception e) {
121                 _log.error(e, e);
122             }
123         }
124 
125         if (webId != null) {
126             _componentConfiguration = EasyConf.getConfiguration(
127                 webId, getFileName(classLoader, name));
128         }
129         else {
130             _componentConfiguration = EasyConf.getConfiguration(
131                 getFileName(classLoader, name));
132         }
133 
134         printSources(companyId, webId);
135     }
136 
137     public void addProperties(Properties properties) {
138         try {
139             ComponentProperties componentProperties =
140                 _componentConfiguration.getProperties();
141 
142             AggregatedProperties aggregatedProperties =
143                 (AggregatedProperties)componentProperties.toConfiguration();
144 
145             Field field1 = CompositeConfiguration.class.getDeclaredField(
146                 "configList");
147 
148             field1.setAccessible(true);
149 
150             // Add to configList of base conf
151 
152             List<Configuration> configurations =
153                 (List<Configuration>)field1.get(aggregatedProperties);
154 
155             MapConfiguration newConfiguration =
156                 new MapConfiguration(properties);
157 
158             configurations.add(0, newConfiguration);
159 
160             // Add to configList of AggregatedProperties itself
161 
162             Field field2 = aggregatedProperties.getClass().getDeclaredField(
163                 "baseConf");
164 
165             field2.setAccessible(true);
166 
167             CompositeConfiguration compositeConfiguration =
168                 (CompositeConfiguration)field2.get(aggregatedProperties);
169 
170             configurations = (List<Configuration>)field1.get(
171                 compositeConfiguration);
172 
173             configurations.add(0, newConfiguration);
174         }
175         catch (Exception e) {
176             _log.error("The properties could not be added", e);
177         }
178     }
179 
180     public boolean contains(String key) {
181         return getComponentProperties().containsKey(key);
182     }
183 
184     public String get(String key) {
185         if (_PRINT_DUPLICATE_CALLS_TO_GET) {
186             if (_keys.contains(key)) {
187                 System.out.println("Duplicate call to get " + key);
188             }
189             else {
190                 _keys.add(key);
191             }
192         }
193 
194         return getComponentProperties().getString(key);
195     }
196 
197     public String get(String key, Filter filter) {
198         return getComponentProperties().getString(
199             key, getEasyConfFilter(filter));
200     }
201 
202     public String[] getArray(String key) {
203         String[] array = getComponentProperties().getStringArray(key);
204 
205         if (array == null) {
206             return new String[0];
207         }
208         else if (array.length > 0) {
209 
210             // Commons Configuration parses an empty property into a String
211             // array with one String containing one space. It also leaves a
212             // trailing array member if you set a property in more than one
213             // line.
214 
215             if (Validator.isNull(array[array.length - 1])) {
216                 String[] subArray = new String[array.length - 1];
217 
218                 System.arraycopy(array, 0, subArray, 0, subArray.length);
219 
220                 array = subArray;
221             }
222         }
223 
224         return array;
225     }
226 
227     public String[] getArray(String key, Filter filter) {
228         return getComponentProperties().getStringArray(
229             key, getEasyConfFilter(filter));
230     }
231 
232     public Properties getProperties() {
233 
234         // For some strange reason, componentProperties.getProperties() returns
235         // values with spaces after commas. So a property setting of "xyz=1,2,3"
236         // actually returns "xyz=1, 2, 3". This can break applications that
237         // don't expect that extra space. However, getting the property value
238         // directly through componentProperties returns the correct value. This
239         // method fixes the weird behavior by returing properties with the
240         // correct values.
241 
242         Properties properties = new Properties();
243 
244         ComponentProperties componentProperties = getComponentProperties();
245 
246         Iterator<Map.Entry<Object, Object>> itr =
247             componentProperties.getProperties().entrySet().iterator();
248 
249         while (itr.hasNext()) {
250             Map.Entry<Object, Object> entry = itr.next();
251 
252             String key = (String)entry.getKey();
253             String value = (String)entry.getValue();
254 
255             properties.setProperty(key, value);
256         }
257 
258         return properties;
259     }
260 
261     public Properties getProperties(String prefix, boolean removePrefix) {
262         Properties allProperties = getProperties();
263 
264         return PropertiesUtil.getProperties(
265             allProperties, prefix, removePrefix);
266     }
267 
268     public void removeProperties(Properties properties) {
269         try {
270             ComponentProperties componentProperties =
271                 _componentConfiguration.getProperties();
272 
273             AggregatedProperties aggregatedProperties =
274                 (AggregatedProperties)componentProperties.toConfiguration();
275 
276             Field field1 = aggregatedProperties.getClass().getDeclaredField(
277                 "baseConf");
278 
279             field1.setAccessible(true);
280 
281             CompositeConfiguration compositeConfiguration =
282                 (CompositeConfiguration)field1.get(aggregatedProperties);
283 
284             Field field2 = CompositeConfiguration.class.getDeclaredField(
285                 "configList");
286 
287             field2.setAccessible(true);
288 
289             List<Configuration> configurations =
290                 (List<Configuration>)field2.get(compositeConfiguration);
291 
292             Iterator<Configuration> itr = configurations.iterator();
293 
294             while (itr.hasNext()) {
295                 Configuration configuration = itr.next();
296 
297                 if (!(configuration instanceof MapConfiguration)) {
298                     return;
299                 }
300 
301                 MapConfiguration mapConfiguration =
302                     (MapConfiguration)configuration;
303 
304                 if (mapConfiguration.getMap() == properties) {
305                     itr.remove();
306 
307                     aggregatedProperties.removeConfiguration(configuration);
308                 }
309             }
310         }
311         catch (Exception e) {
312             _log.error("The properties could not be removed", e);
313         }
314     }
315 
316     public void set(String key, String value) {
317         getComponentProperties().setProperty(key, value);
318     }
319 
320     protected ComponentProperties getComponentProperties() {
321         return _componentConfiguration.getProperties();
322     }
323 
324     protected com.germinus.easyconf.Filter getEasyConfFilter(Filter filter) {
325         com.germinus.easyconf.Filter easyConfFilter =
326             com.germinus.easyconf.Filter.by(filter.getSelectors());
327 
328         if (filter.getVariables() != null) {
329             easyConfFilter.setVariables(filter.getVariables());
330         }
331 
332         return easyConfFilter;
333     }
334 
335     protected String getFileName(ClassLoader classLoader, String name) {
336         URL url = classLoader.getResource(name + ".properties");
337 
338         // If the resource is located inside of a JAR, then EasyConf needs the
339         // "jar:file:" prefix appended to the path. Use URL.toExternalForm() to
340         // achieve that. When running under JBoss, the protocol returned is
341         // "vfsfile" or "vfszip". When running under OC4J, the protocol returned
342         // is "code-source". When running under WebLogic, the protocol returned
343         // is "zip". When running under WebSphere, the protocol returned is
344         // "wsjar".
345 
346         String protocol = url.getProtocol();
347 
348         if (protocol.equals("code-source") || protocol.equals("jar") ||
349             protocol.equals("vfsfile") || protocol.equals("vfszip") ||
350             protocol.equals("wsjar") || protocol.equals("zip")) {
351 
352             name = url.toExternalForm();
353         }
354         else {
355             try {
356                 name = new URI(url.getPath()).getPath();
357             }
358             catch (URISyntaxException urise) {
359                 name = url.getFile();
360             }
361         }
362 
363         int pos = name.lastIndexOf(".properties");
364 
365         if (pos != -1) {
366             name = name.substring(0, pos);
367         }
368 
369         return name;
370     }
371 
372     protected void printSources(long companyId, String webId) {
373         List<String> sources = getComponentProperties().getLoadedSources();
374 
375         for (int i = sources.size() - 1; i >= 0; i--) {
376             String source = sources.get(i);
377 
378             if (_printedSources.contains(source)) {
379                 continue;
380             }
381 
382             _printedSources.add(source);
383 
384             String info = "Loading " + source;
385 
386             if (companyId > CompanyConstants.SYSTEM) {
387                 info +=
388                     " for {companyId=" + companyId + ", webId=" + webId + "}";
389             }
390 
391             System.out.println(info);
392         }
393     }
394 
395     private static final boolean _PRINT_DUPLICATE_CALLS_TO_GET = false;
396 
397     private static Log _log = LogFactoryUtil.getLog(ConfigurationImpl.class);
398 
399     private ComponentConfiguration _componentConfiguration;
400     private Set<String> _keys = new HashSet<String>();
401     private Set<String> _printedSources = new HashSet<String>();
402 
403 }