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 }