Properties Management =================================================================================== .. only:: html .. contents:: Table of Contents :depth: 3 :local: Overview -------------------------------------------------------------------------------- This section explains how to manage properties. Value that needs to be managed as properties can be classified into following two categories. .. tabularcolumns:: |p{0.10\linewidth}|p{0.20\linewidth}|p{0.35\linewidth}|p{0.35\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 20 35 35 * - Sr. No. - Classification - Description - Example * - 1. - Environment dependent setting - The setting needs to be changed according to the environment on which the application is running. It depends on non-functional requirements such as system configuration. - * Database connection information (connection URL, connection user, password, etc) * Destination of the file storage (directory path etc) * more ... * - 2. - Application settings - The settings that can be customize the application behavior. It depends on functional requirements. - * Password valid days * Reservation period days * more ... .. note:: In this guideline, it is recommended to manage these settings as properties (properties file). If an application is mechanized such a way that acquires setting from the properties, there is no need to re-build the application even if there is any changes in these values. Therefore it is possible to release the tested application on production environment. About how to release the tested application, refer to ":doc:`../Appendix/EnvironmentIndependency`". .. tip:: Values that are managed as properties can be acquired from JVM system properties (-D option) or OS environment variables. About access order, refer to ":ref:`PropertiesManagementHowToUse`". | Values that are managed as properties can be used at the following two locations. * Bean definition file * Java classes managed by DI container | .. _PropertiesManagementHowToUse: How to use -------------------------------------------------------------------------------- .. _technical-details_label: About properties file definition ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | Properties file values in Java class and bean definition file can be accessed by defining ```` tag in bean definition file. | ```` tag reads the group of specified properties files | and can fetch values for properties files key \ ``xxx``\ specified in \ ``${xxx}``\ format in ``@Value`` annotation or bean definition files. .. note:: When specified in \ ``${xxx:defaultValue}``\ format and when key \ ``xxx``\ is not set in properties file, \ ``defaultValue``\ is used. | See the method below for defining a properties file **bean definition file** - applicationContext.xml - spring-mvc.xml .. code-block:: xml .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - Sr. No. - Description * - | (1) - | In location, set the resource location path. | Multiple paths separated by comma can be specified in location attribute. | By performing above settings, read properties file under META-INF/spring directory of class path. | Once these settings are done, just add the properties file under META-INF/spring. | For details on location value, see \ `Reference `_\ . .. note:: \ ````\ needs to be defined in both ``applicationContext.xml`` and ``spring-mvc.xml``. | Properties are accessed in the following order by default. #. System properties of active JVM #. Environment variables #. Application definition properties | As per default setting, properties file defined in application is searched and read after all environment related properties (JVM system properties and environment variables) are read. | Read sequence can be changed by setting local-override attribute of ```` tag to true. | By performing these settings, the properties defined in application are enabled with higher priority. **bean definition file** .. code-block:: xml .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - Sr. No. - Description * - | (1) - | Access properties in the following order when local-override attribute is set to true. | 1. Application definition properties | 2. System properties of active JVM | 3. Environment variables | .. note:: Normally the above settings are sufficient. When multiple ```` tags are specified, read order can be defined by setting order attribute value. **bean definition file** .. code-block:: xml .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - Sr. No. - Description * - | (1) - | By setting the order attribute to a value which is less than (2), properties file corresponding to location attribute is read before (2). | When a key overlapping with the key in properties file read in (2) exists, value fetched in (1) is given preference. | By setting ignore-unresolvable attribute to true, error which occurs when key exists only in properties file of (2) can be prevented. * - | (2) - | By setting the order attribute to value greater than (1), properties file corresponding to location attribute is read after (1). | When a key overlapping with the key in properties file read in (1) exists, value fetched in (1) is set. | By setting ignore-unresolvable attribute to true, error which occurs when key exists only in properties file of (1) can be prevented. | .. _bean-definition-file_label: Using properties in bean definition file ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | See the example below of datasource configuration file. | In the following example, it is assumed that properties file definition ( ```` ) is specified. | Basically, property value can be set by setting properties file key in bean definition file using ``${}`` placeholder. **Properties file** .. code-block:: properties database.url=jdbc:postgresql://localhost:5432/shopping database.password=postgres database.username=postgres database.driverClassName=org.postgresql.Driver | **bean definition file** .. code-block:: xml | .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - Sr. No. - Description * - | (1) - | By setting ``${database.driverClassName}``, the value for read properties file key \ ``database.driverClassName``\ gets substituted. * - | (2) - | By setting ``${database.url}``, the value for read properties file key \ ``database.url``\ gets substituted. * - | (3) - | By setting ``${database.username}``, the value for read properties file key \ ``database.username``\ gets substituted. * - | (4) - | By setting ``${database.password}``, the value for read properties file key \ ``database.password``\ gets substituted. | As a result of reading the properties file key, the values are replaced as follows: .. code-block:: xml | Using properties in Java class ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | It is possible to use properties in Java class by specifying ``@Value`` annotation in the field wherein properties values are to be stored. | To use ``@Value`` annotation, the corresponding object needs to be stored in DI container of Spring. | In the following example, it is assumed that properties file definition ( ```` ) is specified. | External reference is possible by adding ``@Value`` annotation to variables and setting properties file key in value using ``${}`` placeholder. **Properties file** .. code-block:: properties item.upload.title=list of update file item.upload.dir=file:/tmp/upload item.upload.maxUpdateFileNum=10 **Java class** .. code-block:: java @Value("${item.upload.title}") // (1) private String uploadTitle; @Value("${item.upload.dir}") // (2) private Resource uploadDir; @Value("${item.upload.maxUpdateFileNum}") // (3) private int maxUpdateFileNum; // Getters and setters omitted .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - Sr. No. - Description * - | (1) - | By setting ``${item.upload.title}`` to ``@Value`` annotation value, the value for read properties file key \ ``item.upload.title``\ gets substituted. | ``uploadTitle`` is substituted by "list of update file" in String class. * - | (2) - | By setting ``${item.upload.dir}`` to ``@Value`` annotation value, the value for read properties file key \ ``item.upload.dir``\ gets substituted. | \ ``org.springframework.core.io.Resource``\ object created with initial value "/tmp/upload" is stored in ``uploadDir``. * - | (3) - | By setting ``${item.upload.maxUpdateFileNum}`` to ``@Value`` annotation value, the value for read properties file key \ ``item.upload.maxUpdateFileNum``\ gets substituted. | ``maxUpdateFileNum`` is substituted by 10. .. warning:: There could be cases wherein properties values are to be used in static methods of Utility classes etc.; however properties value cannot be fetched using \ ``@Value``\ annotation in classes for which bean definition is not done. In this case, it is recommended to create Helper class with ``@Component`` annotation and to fetch properties values using \ ``@Value``\ annotation. (This class needs to be included in the component-scan scope.) Classes in which values from properties file is to be used, should not be made Utility classes. | How to extend -------------------------------------------------------------------------------- Extension of method for fetching properties values is explained below. This can be achieved by extending ``org.springframework.context.support.PropertySourcesPlaceholderConfigurer`` class. The example below illustrates a case wherein encrypted properties file is used. | Decrypting encrypted values and using them ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | To strengthen security, properties file needs to be encrypted in some cases. | The example below illustrates decryption of encrypted properties values. (No specific encrypting and decrypting methods are mentioned.) **bean definition file** - applicationContext.xml - spring-mvc.xml .. code-block:: xml .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - Sr. No. - Description * - | (1) - | Define the extended PropertySourcesPlaceholderConfigurer instead of ````\. ````\ tag should be deleted. * - | (2) - | Set "locations" in name attribute of property tag and specify the path of the properties file to be read, in value attribute. | The method of specifying path of the properties file to be read is same as :ref:`technical-details_label`. **Java class** - Extended PropertySourcesPlaceholderConfigurer .. code-block:: java public class EncryptedPropertySourcesPlaceholderConfigurer extends PropertySourcesPlaceholderConfigurer { // (1) @Override protected void doProcessProperties( ConfigurableListableBeanFactory beanFactoryToProcess, StringValueResolver valueResolver) { // (2) super.doProcessProperties(beanFactoryToProcess, new EncryptedValueResolver(valueResolver)); // (3) } } .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - Sr. No. - Description * - | (1) - | Inherited PropertySourcesPlaceholderConfigurer, should extend ``org.springframework.context.support.PropertySourcesPlaceholderConfigurer`` class. * - | (2) - | Override ``doProcessProperties`` method of ``org.springframework.context.support.PropertySourcesPlaceholderConfigurer`` class. * - | (3) - | Call ``doProcessProperties`` of parent class; however, use valueResolver( ``EncryptedValueResolver`` ) ``valueResolver`` wherein ``valueResolver`` is implemented independently. | In ``EncryptedValueResolver`` class, decrypt when encrypted values of properties file are fetched. | - EncryptedValueResolver.java .. code-block:: java public class EncryptedValueResolver implements StringValueResolver { // (1) private final StringValueResolver valueResolver; EncryptedValueResolver(StringValueResolver stringValueResolver) { // (2) this.valueResolver = stringValueResolver; } @Override public String resolveStringValue(String strVal) { // (3) // Values obtained from the property file to the naming // as seen with the encryption target String value = valueResolver.resolveStringValue(strVal); // (4) // Target messages only, implement coding if (value.startsWith("Encrypted:")) { // (5) value = value.substring(10); // (6) // omitted decryption } return value; } } .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - Sr. No. - Description * - | (1) - | Inherited ``EncryptedValueResolver`` should implement ``org.springframework.util.StringValueResolver``. * - | (2) - | When ``EncryptedValueResolver`` class is created in constructor, set ``StringValueResolver`` inherited from ``EncryptedPropertySourcesPlaceholderConfigurer``. * - | (3) - | Override ``resolveStringValue`` method of ``org.springframework.util.StringValueResolver``. | If the values fetched from properties file are encrypted, these must be decrypted in ``resolveStringValue`` method. | The process mentioned in steps (5) and (6) is just an example, the process differs depending on type of implementation. * - | (4) - | The value is being fetched by specifying key as an argument of ``resolveStringValue`` method of ``StringValueResolver`` set in constructor. This value is defined in properties file. * - | (5) - | Check whether values of properties file are encrypted. The method to determine whether the values are encrypted differs depending on type of implementation. | Here, the value can be considered encrypted if it starts with "Encrypted:". | If the values are encrypted, decrypt them in step (6) and if they are not encrypted, return them as is. * - | (6) - | Encrypted values of properties file are being decrypted. (No specific decryption process is mentioned.) | Decryption method differs depending on type of implementation. - Helper to fetch properties .. code-block:: java @Value("${encrypted.property.string}") // (1) private String testString; @Value("${encrypted.property.int}") // (2) private int testInt; @Value("${encrypted.property.integer}") // (3) private Integer testInteger; @Value("${encrypted.property.file}") // (4) private File testFile; // Getters and setters omitted .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - Sr. No. - Description * - | (1) - | By setting ``${encrypted.property.string}`` to ``@Value`` annotation value, the value for read properties file key \ ``encrypted.property.string``\ is decrypted and then substituted. | Value decrypted in String class is substituted in ``testString``. * - | (2) - | By setting ``${encrypted.property.int}`` to ``@Value`` annotation value, the value for read properties file key \ ``encrypted.property.int``\ is decrypted and then substituted. | Value decrypted in integer type is substituted in ``testInt``. * - | (3) - | By setting ``${encrypted.property.integer}`` to ``@Value`` annotation value, the value for read properties file key \ ``encrypted.property.integer``\ is decrypted and then substituted. | Value decrypted in Integer class is substituted in ``testInteger``. * - | (4) - | By setting ``${encrypted.property.file}`` to ``@Value`` annotation value, the value for read properties file key \ ``encrypted.property.file``\ is decrypted and then substituted. | In ``testFile``, File object is stored as initial value which is created using the decrypted value (auto conversion). **Properties file** The values encrypted as properties values are prefixed with "Encrypted:" to indicate that they are encrypted. Although one can view the contents of properties file, but cannot understand them as the values are encrypted. .. code-block:: properties encrypted.property.string=Encrypted:ZlpbQRJRWlNAU1FGV0ASRVteXhJQVxJXXFFAS0JGV1Yc encrypted.property.int=Encrypted:AwI= encrypted.property.integer=Encrypted:AwICAgI= encrypted.property.file=Encrypted:YkBdQldARkt/U1xTVVdfV1xGHFpGX14= .. raw:: latex \newpage