View Javadoc

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 }