1 package com.sourceforge.jpatterns.core.configuration;
2
3 import com.sourceforge.jpatterns.core.configuration.exceptions.JPInitializationException;
4 import com.zmicer.utils.InputArgumentUtils;
5 import com.zmicer.utils.StringUtils;
6 import org.apache.log4j.Logger;
7
8 import java.util.HashMap;
9 import java.util.Map;
10 import java.util.Set;
11
12 /**
13 * This class would store the properties per the key. The values are defined at the properties file of the JPatterns.
14 * <br/>
15 * The storage would be the Map, the initialization of the properties would be performed at this class (method #init).
16 * <br/>
17 * Please remember that the priority has custom properties files
18 * ({@link com.sourceforge.jpatterns.core.configuration.PropertiesManagerImpl#m_customBundle}),
19 * and then the default bundle is asked to provide the property:
20 * ({@link com.sourceforge.jpatterns.core.configuration.PropertiesManagerImpl#m_defaultBundle}).
21 * <br/>
22 * Please review properly the following Java Docs - it is important for understanding of the algorithm of working of the JPatterns
23 * configuration functionality.
24 * {@link com.sourceforge.jpatterns.core.configuration.PropertiesProvider.JPProperties.USE_ONLY_CUSTOM_FRAMEWORK_PROPERTIES}
25 *
26 * todo: [zmicer] think over the moving this functionality to the common utility/framework.
27 * <br/>
28 * <strong>Also important feature in the behaviour of this class is: it won't store the keys/values which define the implementations of the
29 * interfaces/abstract classes. It is done in the following way. We would check the values of the properties trying to instantiate the
30 * appropriate classes instances. If it is done succesfully - we would exclude such values.</strong>
31 *
32 * $Author:: zmicer $<br/>
33 * $Rev:: 67 $<br/> * $Date:: 2007-08-28 21:37:07 #$<br/>
34 * $Date:: 2007-08-28 21:37:07 #$<br/>
35 */
36 public class PropertiesProvider
37 {
38 /**
39 * Logger instance.
40 */
41 final public static Logger LOG = Logger.getLogger(PropertiesProvider.class);
42
43 /**
44 * The singleton instance of the property provider.
45 */
46 final private static PropertiesProvider PROVIDER = new PropertiesProvider();
47
48 /**
49 * Signs of the initialization took place.
50 */
51 private boolean m_isInitialized = false;
52
53 /**
54 * This map stores all the important properties we need (which values are the <code>Boolean</code> objects).
55 */
56 private Map<String, Boolean> m_booleanProperties = new HashMap<String, Boolean>();
57
58 /**
59 * This map stores all the important properties we need (which values are the <code>String</code> objects).
60 */
61 private Map<String, String> m_stringProperties = new HashMap<String, String>();
62
63 /**
64 * This interface stores the keys for necessary and important for the JPatterns properties.
65 * <br/>
66 * Please extend this interface with the values you would add to the properties files (default one). In the case new properties would
67 * be added to the custom framework properties - create your own interface somewhere else.
68 */
69 public interface JPProperties
70 {
71 /**
72 * If the custom properties would be found only its value would be used. Please be noticed that this property is very important
73 * as defines the behaviour of all the configuration sub-system. The following rule takes power with it. This property is seached
74 * at the both default and custom properties, the custom has the priority. The further loading of the props is done using its
75 * value.
76 * <br/>
77 * If both the properties files do not specify this property - we would use the custom ones if custom file presents and has these
78 * properties, otherwise the default values would be used.
79 */
80 String USE_ONLY_CUSTOM_FRAMEWORK_PROPERTIES = "jpatterns.configuration.props.use.only.custom.if.present";
81
82 /**
83 * this settings in the case its value is true defines that *custom* *framework* configuration would override all the *default*
84 * *framework* configuration (it won't be used at all) in the case this is false - when merging default and custom settings firstly
85 * default would be written to the result, and then all the settings from custom would override default one.
86 */
87 String USE_ONLY_CUSTOM_FRAMEWORK_XML = "jpatterns.configuration.xml.use.only.custom.framework.settings.if.present";
88
89 /**
90 * this settings in the case its value is true defines that *custom* *consumer* configuration would override all the *default*
91 * *consumer* configuration (it won't be used at all) in the case this is false - when merging default and custom settings firstly
92 * default would be written to the result, and then all the settings from custom would override default one.
93 * a. default consumer settings - appropriate xml files were found at the classpath and all the dirs of the classpath
94 * b. custom consumer configuration was provided by the properties framework configuration (it also could be provided as JVM
95 * parameter, in this case JVM value would have the sense of custom consumer config).
96 */
97 String USE_ONLY_CUSTOM_CONSUMER_XML = "jpatterns.configuration.xml.use.only.custom.consumer.settings.if.present";
98
99 /**
100 * Defines the depth for the validating/overriding the JPatterns configuration.
101 * <br/>
102 * the default value is
103 * <code>com.sourceforge.jpatterns.core.configuration.PropertiesProvider.OverridingDepths.OVERRIDING_LEVEL_SECTION</code>
104 *
105 */
106 String XML_CONFIG_OVERRIDING_DEPTH = "jpatterns.configuration.xml.overriding.depth";
107
108 /**
109 * <code>XML_CONFIG_CUSTOM_OVERRIDES_NOT_DEPENDING_ON_PRIORITY</code>
110 * <br/>
111 * Default value is <code>false</code>
112 */
113 String XML_CONFIG_CUSTOM_OVERRIDES_NOT_DEPENDING_ON_PRIORITY =
114 "jpatterns.configuration.xml.custom.overrides.not.depending.on.priorities";
115 }
116
117 /**
118 * This enum defines the depths we could use for the defining the overriding types.
119 * <br/>
120 * Consider the idea of the common stuff for the converting possible types of the properties files to the enum (check how it is done
121 * fore the castor - may be it is worth to use castor for it) - idea of <strong>Prosper</strong>!!!
122 * <br/>
123 * Please review the comments to the <strong>jpatterns.configuration.xml.overriding.depth</strong> property in the
124 * <strong>jpatterns.properties</strong> properties file.
125 */
126 public enum OverridingDepths
127 {
128 /**
129 * Says that it is incorrect case when the sections contains two section with identical pathes (scopes, section names, priorities).
130 */
131 OVERRIDING_LEVEL_SECTION,
132 /**
133 * Says it is correct case of existence of two section objects with identical path (scope, section name, priorities) - just because
134 * it is allowed to extend the existed sections items configuration by the additional items.
135 */
136 OVERRIDING_LEVEL_ITEM
137 }
138
139 /**
140 * Default public constructor
141 * <br/>
142 * Please be carefull in adding some initialization functionality at this constructor - this is singleton, and the call of the
143 * constructor is done at the static initialization level.
144 */
145 private PropertiesProvider()
146 {
147 super();
148 }
149
150 /**
151 * Init method - initializes the provided.
152 * todo [zmicer]: think over the adjustment here!!! we should initialize the objects just to check they are working
153 *
154 *
155 * @param manager the manager, entry point to the properties values.
156 * Can not be null (otherwise <code>IllegalArgumentException</code> would appear).
157 */
158 protected void init(final IPropertiesManager manager)
159 {
160 PROVIDER.m_isInitialized = false; //[Silent.codeChangies] value changed from true to false.
161 if (null == manager)
162 {
163 throw new IllegalArgumentException("IPropertiesManager can not be null.");
164 }
165 final Set<String> mergedKeys = manager.getMergedKeys();
166 if (null == mergedKeys || mergedKeys.isEmpty())
167 {
168 throw new JPInitializationException("The properties manager doesn't contain the bundles at all.");
169 }
170 for (final String key : mergedKeys)
171 {
172 final String value = manager.getBundle(key);
173 final Boolean boolValue = StringUtils.getBoolean(value);
174 if ((key.contains("I") && value.contains(key.substring(1)) && value.contains(".")))
175 {
176 continue;
177 }
178 if (null != boolValue)
179 {
180 m_booleanProperties.put(key, boolValue);
181 }
182 else
183 {
184 m_stringProperties.put(key, value);
185 }
186 }
187 PROVIDER.m_isInitialized = true;
188 }
189
190 /**
191 * Get instance of the PropertiesProvider.
192 * todo: [zmicer] seems to be not the best way (because IPropertiesProvider is passed.)
193 *
194 * @param manager is necessary for the initializing properties values (if they are initialized already - it is just skipped.)
195 * Can not be null (otherwise <code>IllegalArgumentException</code> would appear).
196 * @param reloadAnyWay says to reload the properties anyway. It could be used at the unit tests. In the normal life - it should
197 * be set to false;
198 *
199 * @return the PropertiesProvider instance.
200 */
201 public static PropertiesProvider getInstance(final IPropertiesManager manager, final boolean reloadAnyWay)
202 {
203 if (null == manager)
204 {
205 throw new IllegalArgumentException("IPropertiesManager can not be null.");
206 }
207 if (!PROVIDER.m_isInitialized || reloadAnyWay)
208 {
209 PROVIDER.init(manager);
210 }
211 return PROVIDER;
212 }
213
214 /**
215 * @param key The key to retrieve the appropriate value. Can not be null (otherwise <code>IllegalArgumentException</code> would appear).
216 * Please use the values of JPProperties (surely having the boolean sense).
217 *
218 * @return the boolean property.
219 */
220 public Boolean getBooleanProperty(final String key)
221 {
222 InputArgumentUtils.checkStrings(true, key);
223 checkIfInitialized();
224 return m_booleanProperties.get(key);
225 }
226
227 /**
228 * @param key The key to retrieve the appropriate value. Can not be null (otherwise <code>IllegalArgumentException</code> would appear).
229 * Please use the values of JPProperties (surely having the boolean sense).
230 *
231 * @return the String property.
232 */
233 public String getStringProperty(final String key)
234 {
235 InputArgumentUtils.checkStrings(true, key);
236 checkIfInitialized();
237 return m_stringProperties.get(key);
238 }
239
240 /**
241 * Check if the <code>PropertiesProvider</code> was iinitialized.
242 */
243 protected void checkIfInitialized()
244 {
245 if (!m_isInitialized)
246 {
247 throw new IllegalStateException("The propertis provider was not initialized.");
248 }
249 }
250 }