diff --git a/.gitignore b/.gitignore index b0bb852..9a03c6e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ #Idea Files .idea *.iml +*.ipr *.class target @@ -9,3 +10,8 @@ target *.jar *.war *.ear + +#Eclipse files +.project +.settings +.classpath diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index 59d1de1..249422f 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,14 @@ * [Project Structure](#project-structure) * [Property File Creation](#property-file-creation) * [Property Class Creation](#property-class-creation) - * [Property Class Initialisation](#property-class-initialisation) + * [Property Class Initialization](#property-class-initialiszation) * [System Properties Overriding](#system-properties-overriding) * [Properties Priorities](#properties-priority) + * [Create Multi File Configuration][create-multi-file-configuration] + * [Own Property-Provider][creation-custom-property-provider] * [Property Loader Extension](#property-loader-extension) * [Conversion Data Types](#conversion-data-types) - * [Creating Specific Converter][creation-specific-converter] + * [Creating Specific Converter][creation-custom-converter] В тестах часто приходится работать с переменными окружения. Причем в зависимости от этих переменных поведение тестов может меняться. Для работы с properties-файлами мы разработали несложную обертку. @@ -24,7 +26,7 @@ ru.yandex.qatools.properties properties-loader - 1.3-SNAPSHOT + 1.4 ``` @@ -109,7 +111,7 @@ public class ProxyProperties { } ``` -### Property Class Initialisation +### Property Class Initialization В конструкторе класса `ProxyProperties` вызывается статический метод `PropertyLoader.populate(this)`, который инициализирует поля класса из файла `proxy.properties` @@ -142,6 +144,22 @@ assertThat(proxyProperties.getHost(), equatlTo(3133)); - значения переменных из property-файла. Средний приоритет. - объявленные значения переменных. Наименьший приоритет. +Если по какой-то причине вам не нравится существующий приоритет или принцип инициалиции объектов, +то вы можете переопределить его следуя примеру [Загрузка кофигураций в зависимости от окружения (частный метод)][create-multi-file-configuration] +или воспользовавшись мануалом по созданию [Cобственного загрузчика пропертей][creation-custom-property-provider]. + +Уже доступен провайдер, позволяющий превращать пути вида +```java +@Resource.Classpath("${system.file.name}.path.${map.scope.value}.properties") +``` +в реальные пути. Подключить его можно аннотацией + +```java +@With(MapOrSyspropPathReplacerProvider.class) +``` +Подробнее по применению в [тесте][custom-provider-test] + + ## Property Loader Extension ### Conversion Data Types @@ -186,6 +204,9 @@ private URI aURI; Если вам по какой-то причине не хватает этих типов, то вы всегда можете сделать и использовать свой конвертер. О том, как это можно использовать нужно почтитать в статье -["Создание собственного конвертера"][creation-specific-converter] +["Создание собственного конвертера"][creation-custom-converter] -[creation-specific-converter]: https://github.com/yandex-qatools/properties/blob/master/properties-loader/src/site/creation-specific-converter.ru.md +[custom-provider-test]: https://github.com/yandex-qatools/properties/blob/master/properties-loader/src/test/java/ru/yandex/qatools/properties/CustomPropertyProviderTest.java +[creation-custom-converter]: https://github.com/yandex-qatools/properties/blob/master/properties-loader/src/site/creation-custom-converter.ru.md +[create-multi-file-configuration]: https://github.com/yandex-qatools/properties/blob/master/properties-loader/src/site/create-multi-file-configuration.ru.md +[creation-custom-property-provider]: https://github.com/yandex-qatools/properties/blob/master/properties-loader/src/site/creation-custom-property-provider.ru.md diff --git a/pom.xml b/pom.xml index 5afab30..9e66358 100644 --- a/pom.xml +++ b/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 @@ -11,7 +10,7 @@ ru.yandex.qatools.properties properties - 1.3-SNAPSHOT + 1.5-SNAPSHOT Yandex @@ -45,7 +44,7 @@ https://github.com/yandex-qatools/properties scm:git:git@github.com:yandex-qatools/properties.git - scm:git:git@github.com:yandex-qatools/proeprties.git + scm:git:git@github.com:yandex-qatools/properties.git @@ -60,54 +59,26 @@ eroshenkoam@yandex-team.ru Yandex + + lanwen + Merkushev Kirill + lanwen@yandex-team.ru + Yandex + - - org.apache.maven.plugins - maven-release-plugin - 2.4 - - true - - org.apache.maven.plugins maven-compiler-plugin 2.5.1 - 1.6 - 1.6 + 1.7 + 1.7 - - org.apache.maven.plugins - maven-source-plugin - 2.2 - - - attach-sources - - jar - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.7 - - - aggregate - - aggregate-jar - - - - - \ No newline at end of file + diff --git a/properties-loader/pom.xml b/properties-loader/pom.xml index 76a06fc..9e5f8b0 100644 --- a/properties-loader/pom.xml +++ b/properties-loader/pom.xml @@ -1,10 +1,9 @@ - + properties ru.yandex.qatools.properties - 1.3-SNAPSHOT + 1.5-SNAPSHOT 4.0.0 diff --git a/properties-loader/releasenotes/1.4-releasenotes.ru.md b/properties-loader/releasenotes/1.4-releasenotes.ru.md new file mode 100644 index 0000000..f272082 --- /dev/null +++ b/properties-loader/releasenotes/1.4-releasenotes.ru.md @@ -0,0 +1,17 @@ +# 1.4 Release Notes + +## [Pull Req #5](https://github.com/yandex-qatools/properties/pull/5) Use property provider to provide interface for load props +Теперь, можно легко переопределить последовательность наполнения бина значениями переменных окружения. + +~~~ java +@Resource.Classpath("file.${system.scope.value}.properties") +@With(SyspropPathReplacerProvider.class) +public class UseSystemReplacerProviderProperty { +... +~~~ + +[Подробнее](https://github.com/yandex-qatools/properties/blob/master/properties-loader/src/site/creation-custom-property-provider.ru.md) + +## [Pull Req #12](https://github.com/yandex-qatools/properties/pull/12) Update java verison to 1.7 + +Теперь используемая версия java в проекте - **1.7** \ No newline at end of file diff --git a/properties-loader/src/main/java/ru/yandex/qatools/properties/PropertyLoader.java b/properties-loader/src/main/java/ru/yandex/qatools/properties/PropertyLoader.java index de7cc77..9010864 100644 --- a/properties-loader/src/main/java/ru/yandex/qatools/properties/PropertyLoader.java +++ b/properties-loader/src/main/java/ru/yandex/qatools/properties/PropertyLoader.java @@ -1,14 +1,15 @@ package ru.yandex.qatools.properties; -import ru.yandex.qatools.properties.annotations.Resource; +import ru.yandex.qatools.properties.annotations.With; import ru.yandex.qatools.properties.decorators.DefaultFieldDecorator; import ru.yandex.qatools.properties.decorators.FieldDecorator; +import ru.yandex.qatools.properties.exeptions.PropertyLoaderException; +import ru.yandex.qatools.properties.providers.DefaultPropertyProvider; +import ru.yandex.qatools.properties.providers.PropertyProvider; import java.lang.reflect.Field; import java.util.Properties; -import static ru.yandex.qatools.properties.utils.PropertiesUtils.readProperties; - /** * User: eroshenkoam * Date: 11/13/12, 12:53 PM @@ -19,11 +20,13 @@ private PropertyLoader() { } public static void populate(T bean) { - populate(bean, loadProperties(bean.getClass())); + populate(bean, new Properties()); } public static void populate(T bean, Properties properties) { - populate(bean, new DefaultFieldDecorator(properties)); + PropertyProvider provider = instantiatePropertyProvider(bean); + Properties completed = provider.provide(bean, properties); + populate(bean, new DefaultFieldDecorator(completed)); } public static void populate(T bean, FieldDecorator decorator) { @@ -43,26 +46,28 @@ private static void initFields(FieldDecorator decorator, Object bean, Class c field.setAccessible(true); field.set(bean, value); } catch (IllegalAccessException e) { - throw new RuntimeException(e); + throw new PropertyLoaderException( + String.format("Can not set bean <%s> field <%s> value", bean, field), + e); } } } } - private static Properties loadProperties(Class clazz) { - Properties result = new Properties(); - if (clazz.isAnnotationPresent(Resource.Classpath.class)) { - String path = clazz.getAnnotation(Resource.Classpath.class).value(); - result.putAll(readProperties(ClassLoader.getSystemResourceAsStream(path))); - } - - if (clazz.isAnnotationPresent(Resource.File.class)) { - String path = clazz.getAnnotation(Resource.File.class).value(); - result.putAll(readProperties(new java.io.File(path))); + private static PropertyProvider instantiatePropertyProvider(T bean) { + Class clazz = bean.getClass(); + if (clazz.isAnnotationPresent(With.class)) { + try { + return clazz.getAnnotation(With.class).value().newInstance(); + } catch (InstantiationException e) { + throw new PropertyLoaderException("Can't create instance property provider in class " + + bean.getClass().getName(), e); + } catch (IllegalAccessException e) { + throw new PropertyLoaderException("Can't load property provider in class " + + bean.getClass().getName(), e); + } } - - result.putAll(System.getProperties()); - return result; + return new DefaultPropertyProvider(); } diff --git a/properties-loader/src/main/java/ru/yandex/qatools/properties/annotations/Property.java b/properties-loader/src/main/java/ru/yandex/qatools/properties/annotations/Property.java index 5816658..b3b1675 100644 --- a/properties-loader/src/main/java/ru/yandex/qatools/properties/annotations/Property.java +++ b/properties-loader/src/main/java/ru/yandex/qatools/properties/annotations/Property.java @@ -11,5 +11,5 @@ @Target({java.lang.annotation.ElementType.FIELD}) public @interface Property { - public String value(); + String value(); } diff --git a/properties-loader/src/main/java/ru/yandex/qatools/properties/annotations/Use.java b/properties-loader/src/main/java/ru/yandex/qatools/properties/annotations/Use.java index 733dfef..f81332f 100644 --- a/properties-loader/src/main/java/ru/yandex/qatools/properties/annotations/Use.java +++ b/properties-loader/src/main/java/ru/yandex/qatools/properties/annotations/Use.java @@ -13,5 +13,5 @@ @Target({java.lang.annotation.ElementType.FIELD}) public @interface Use { - public Class value(); + Class value(); } diff --git a/properties-loader/src/main/java/ru/yandex/qatools/properties/annotations/With.java b/properties-loader/src/main/java/ru/yandex/qatools/properties/annotations/With.java new file mode 100644 index 0000000..3548202 --- /dev/null +++ b/properties-loader/src/main/java/ru/yandex/qatools/properties/annotations/With.java @@ -0,0 +1,18 @@ +package ru.yandex.qatools.properties.annotations; + +import ru.yandex.qatools.properties.providers.PropertyProvider; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * User: lanwen + * Date: 17.07.13 + * Time: 17:28 + */ +@Retention(java.lang.annotation.RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface With { + Class value(); +} diff --git a/properties-loader/src/main/java/ru/yandex/qatools/properties/converters/URIConverter.java b/properties-loader/src/main/java/ru/yandex/qatools/properties/converters/URIConverter.java index 94364ac..8ff0d82 100644 --- a/properties-loader/src/main/java/ru/yandex/qatools/properties/converters/URIConverter.java +++ b/properties-loader/src/main/java/ru/yandex/qatools/properties/converters/URIConverter.java @@ -11,7 +11,7 @@ public class URIConverter extends AbstractConverter { @Override - protected Object convertToType(Class aClass, Object o) throws Throwable { + protected Object convertToType(Class aClass, Object o) { return URI.create(o.toString()); } diff --git a/properties-loader/src/main/java/ru/yandex/qatools/properties/decorators/DefaultFieldDecorator.java b/properties-loader/src/main/java/ru/yandex/qatools/properties/decorators/DefaultFieldDecorator.java index f3d94b1..ac11108 100644 --- a/properties-loader/src/main/java/ru/yandex/qatools/properties/decorators/DefaultFieldDecorator.java +++ b/properties-loader/src/main/java/ru/yandex/qatools/properties/decorators/DefaultFieldDecorator.java @@ -53,7 +53,6 @@ public Object decorate(Field field) { try { return converter.convert(field.getType(), properties.getProperty(key)); } catch (ConversionException e) { - System.out.println(e); return null; } } @@ -70,7 +69,7 @@ private Converter createNewInstanceFromUseAnnotations(Field field) { try { return field.getAnnotation(Use.class).value().newInstance(); } catch (Exception e) { - throw new RuntimeException(e); + return null; } } } diff --git a/properties-loader/src/main/java/ru/yandex/qatools/properties/decorators/FieldDecorator.java b/properties-loader/src/main/java/ru/yandex/qatools/properties/decorators/FieldDecorator.java index a857ae7..97ad81c 100644 --- a/properties-loader/src/main/java/ru/yandex/qatools/properties/decorators/FieldDecorator.java +++ b/properties-loader/src/main/java/ru/yandex/qatools/properties/decorators/FieldDecorator.java @@ -1,7 +1,6 @@ package ru.yandex.qatools.properties.decorators; import java.lang.reflect.Field; -import java.util.Properties; /** * User: eroshenkoam @@ -9,5 +8,5 @@ */ public interface FieldDecorator { - public Object decorate(Field field); + Object decorate(Field field); } diff --git a/properties-loader/src/main/java/ru/yandex/qatools/properties/exeptions/PropertyLoaderException.java b/properties-loader/src/main/java/ru/yandex/qatools/properties/exeptions/PropertyLoaderException.java new file mode 100644 index 0000000..21a8897 --- /dev/null +++ b/properties-loader/src/main/java/ru/yandex/qatools/properties/exeptions/PropertyLoaderException.java @@ -0,0 +1,12 @@ +package ru.yandex.qatools.properties.exeptions; + +/** + * @author Artem Eroshenko eroshenkoam + * 5/31/13, 7:03 PM + */ +public class PropertyLoaderException extends RuntimeException { + + public PropertyLoaderException(String message, Throwable e) { + super(message, e); + } +} diff --git a/properties-loader/src/main/java/ru/yandex/qatools/properties/providers/DefaultPropertyProvider.java b/properties-loader/src/main/java/ru/yandex/qatools/properties/providers/DefaultPropertyProvider.java new file mode 100644 index 0000000..a5c0ada --- /dev/null +++ b/properties-loader/src/main/java/ru/yandex/qatools/properties/providers/DefaultPropertyProvider.java @@ -0,0 +1,61 @@ +package ru.yandex.qatools.properties.providers; + +import ru.yandex.qatools.properties.annotations.Resource; + +import java.lang.annotation.Annotation; +import java.util.Properties; + +import static ru.yandex.qatools.properties.utils.PropertiesUtils.readProperties; + + +/** + * User: lanwen + * Date: 17.07.13 + * Time: 17:28 + */ +public class DefaultPropertyProvider implements PropertyProvider { + @Override + public Properties provide(T bean, Properties properties) { + Class clazz = bean.getClass(); + + if (have(clazz, Resource.Classpath.class)) { + String path = classpath(clazz, properties); + properties.putAll(readProperties(getClassLoader().getSystemResourceAsStream(path))); + } + + if (have(clazz, Resource.File.class)) { + String path = filepath(clazz, properties); + properties.putAll(readProperties(new java.io.File(path))); + } + + properties.putAll(System.getProperties()); + return properties; + } + + + protected boolean have(Class clazz, Class anno) { + return clazz.isAnnotationPresent(anno); + } + + protected String filepath(Class clazz, Properties properties) { + return clazz.getAnnotation(Resource.File.class).value(); + } + + protected String classpath(Class clazz, Properties properties) { + return clazz.getAnnotation(Resource.Classpath.class).value(); + } + + private ClassLoader getClassLoader() { + ClassLoader classLoader = null; + try { + classLoader = Thread.currentThread().getContextClassLoader(); + } catch (SecurityException e) { + // do nothing + } finally { + if (classLoader == null) { + return ClassLoader.getSystemClassLoader(); + } + return classLoader; + } + } +} diff --git a/properties-loader/src/main/java/ru/yandex/qatools/properties/providers/MapOrSyspropPathReplacerProvider.java b/properties-loader/src/main/java/ru/yandex/qatools/properties/providers/MapOrSyspropPathReplacerProvider.java new file mode 100644 index 0000000..4a1e38b --- /dev/null +++ b/properties-loader/src/main/java/ru/yandex/qatools/properties/providers/MapOrSyspropPathReplacerProvider.java @@ -0,0 +1,47 @@ +package ru.yandex.qatools.properties.providers; + +import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * User: lanwen + * Date: 17.07.13 + * Time: 19:58 + */ +public class MapOrSyspropPathReplacerProvider extends DefaultPropertyProvider { + public static final String MAP_PROP_KEY_PATTERN = "\\$\\{map\\.([^\\}]*)\\}"; + public static final String SYS_PROP_KEY_PATTERN = "\\$\\{system\\.([^\\}]*)\\}"; + + @Override + public String filepath(Class clazz, Properties properties) { + String filepath = super.filepath(clazz, properties); + String mapreplaced = replaceWithMapProps(filepath, properties); + return replaceWithSystemProps(mapreplaced); + } + + @Override + public String classpath(Class clazz, Properties properties) { + String classpath = super.classpath(clazz, properties); + String mapreplaced = replaceWithMapProps(classpath, properties); + return replaceWithSystemProps(mapreplaced); + } + + private String replaceWithMapProps(String path, Properties properties) { + Matcher matcher = Pattern.compile(MAP_PROP_KEY_PATTERN).matcher(path); + String replaced = path; + while (matcher.find()) { + replaced = replaced.replace(matcher.group(0), properties.getProperty(matcher.group(1), "")); + } + return replaced; + } + + private String replaceWithSystemProps(String path) { + Matcher matcher = Pattern.compile(SYS_PROP_KEY_PATTERN).matcher(path); + String replaced = path; + while (matcher.find()) { + replaced = replaced.replace(matcher.group(0), System.getProperty(matcher.group(1), "")); + } + return replaced; + } +} diff --git a/properties-loader/src/main/java/ru/yandex/qatools/properties/providers/PropertyProvider.java b/properties-loader/src/main/java/ru/yandex/qatools/properties/providers/PropertyProvider.java new file mode 100644 index 0000000..99b6f6b --- /dev/null +++ b/properties-loader/src/main/java/ru/yandex/qatools/properties/providers/PropertyProvider.java @@ -0,0 +1,12 @@ +package ru.yandex.qatools.properties.providers; + +import java.util.Properties; + +/** + * User: lanwen + * Date: 17.07.13 + * Time: 15:45 + */ +public interface PropertyProvider { + Properties provide(T bean, Properties properties); +} diff --git a/properties-loader/src/main/java/ru/yandex/qatools/properties/utils/PropertiesUtils.java b/properties-loader/src/main/java/ru/yandex/qatools/properties/utils/PropertiesUtils.java index 83cc8f2..64ea5ea 100644 --- a/properties-loader/src/main/java/ru/yandex/qatools/properties/utils/PropertiesUtils.java +++ b/properties-loader/src/main/java/ru/yandex/qatools/properties/utils/PropertiesUtils.java @@ -1,6 +1,7 @@ package ru.yandex.qatools.properties.utils; import java.io.*; +import java.nio.charset.Charset; import java.util.Properties; /** @@ -24,7 +25,7 @@ public static Properties readProperties(InputStream inputStream) { if (inputStream == null) { return new Properties(); } else { - return readProperties(new InputStreamReader(inputStream)); + return readProperties(new InputStreamReader(inputStream, Charset.defaultCharset())); } } diff --git a/properties-loader/src/site/create-multi-file-configuration.ru.md b/properties-loader/src/site/create-multi-file-configuration.ru.md new file mode 100644 index 0000000..47bdf9a --- /dev/null +++ b/properties-loader/src/site/create-multi-file-configuration.ru.md @@ -0,0 +1,63 @@ +# Загрузка кофигураций в зависимости от окружения + +Иногда необходимо подключать различные файлы конфигураций для тестирования на разных тестовых средах. +Допустим нам нужны разные пользователи для авторизации в тестах. + +Создадим проперти-файл для тестового окружения 'testing.properties': +```properties +user = Ivan +password = chelovek-divan +``` +и для предпродакшн окружения 'preprod.properties': +```properties +user = Oleg +password = chelovek-strateg +``` + +Создадим класс-обёртку, работающий с этими данными: +```java +public class UserProperties { + @Property("user") + private String user = "defaultUser"; + + @Property("password") + private String password = "defaultPassword"; +} +``` + +Для того, чтобы проперти автоматически подгружались при создании этого класса, нужно добавить конструктор: +```java + public UserProperties() { + PropertyLoader.populate(this); + } +``` + +Осталось научить наш класс работать с разными файлами. Загружать проперти из одного файла очень просто - достаточно +добавить аннотацию @Resource.Classpath в которой указать имя этого файла: +```java +@Resource.Classpath("testing.properties") +public class UserProperties { +``` + +Метод PropertyLoader.populate может принимать на вход Properties, которыми нужно заполнить наш бин. По дефолту, +PropertyLoader ищет аннотации @Resource.Classpath, @Resource.File, а так же считывает свойства из переменных окружения. +Нам остётся написать метод, который будет возвращать Properties, считаный из нужного нам файла: +```java + private static Properties loadProperties() { + Properties result = new Properties(); + String filePath = System.getProperty("property.file"); + if (filePath != null) { + result.putAll(readProperties(ClassLoader.getSystemResourceAsStream(filePath))); + } + return result; + } +``` + +и передать этот метод в загрузчик в конструкторе нашего класса: +```java + public UserProperties() { + PropertyLoader.populate(this, loadProperties()); + } +``` + +Полный пример реализации можно посмотреть в тесте LoadPropertiesDependsOnSystemPropertyTest. diff --git a/properties-loader/src/site/creation-specific-converter.ru.md b/properties-loader/src/site/creation-custom-converter.ru.md similarity index 95% rename from properties-loader/src/site/creation-specific-converter.ru.md rename to properties-loader/src/site/creation-custom-converter.ru.md index 4e22a34..f366594 100644 --- a/properties-loader/src/site/creation-specific-converter.ru.md +++ b/properties-loader/src/site/creation-custom-converter.ru.md @@ -37,7 +37,7 @@ public class ServersProperties { ``` Если попробовать инициализировать этот класс, то вы увидите эксепшен. Чтобы использование списка стало возможным, -необходимо зарегистрировать создать свой конвертер и зарегистрировать его. +необходимо создать свой конвертер и зарегистрировать его. ## Имплементация интерфейса org.apache.commons.beanutils.Converter @@ -89,4 +89,4 @@ public class ServersProperties { } ``` -Таким образом можно переопределять существующие конвертеры и добавлять новые. \ No newline at end of file +Таким образом можно переопределять существующие конвертеры и добавлять новые. diff --git a/properties-loader/src/site/creation-custom-property-provider.ru.md b/properties-loader/src/site/creation-custom-property-provider.ru.md new file mode 100644 index 0000000..b013659 --- /dev/null +++ b/properties-loader/src/site/creation-custom-property-provider.ru.md @@ -0,0 +1,121 @@ +## Переопределение способа загрузки пропертей + +*since 1.4* + +Статья решает проблему, описанную в [Загрузка кофигураций в зависимости от окружения (передача предустановленных пропертей)][create-multi-file-configuration], +но в более общем виде, позволяя аккуратно вынести грязную работу в отдельный класс, +предоставив неограниченные возможности манипуляций с пропертями. + +Начальные данные: +- есть необходимость загружать разные файлы пропертей в зависимости от некоторых условий, +- путь может формироваться на лету по шаблону, используя в одном месте системные проперти, а в другом переменные из кода, +- задействует это сразу множество классов-пропертей, +- вдруг может понадобиться возможность игнорирования системных пропертей. + +Стратегия загрузки пропертей реализуется при помощи классов-имплементаций для ``PropertyProvider``, у которого нужно реализовать +метод `` Properties provide(T bean, Properties properties)``. Куда на вход соответственно передается бин пропертей и `Map` из +предустановленного набора пар ключ-значение. + +Когда в конструкторе класса пропертей делается ``PropertyLoader.populate(this);`` или ``PropertyLoader.populate(this, someProperties);``, +у класса ищется аннотация ``@With`` со значением проперти-провайдера. В случае, если такой аннотации нет, используется дефолтный провайдер, +который ищет аннотации ``@Resource.Classpath``, ``@Resource.File`` и берет путь загрузки по их значению, а так же считывает свойства из переменных окружения. + +Все что описано дальше, уже реализовано в классе ``MapOrSyspropPathReplacerProvider``, который можно подключать и превращать пути +вида +```java +@Resource.Classpath("${system.file.name}.path.${map.scope.value}.properties") +``` +в реальные пути к файлам пропертей. О том, как создать свой механизм, на примере этого класса - ниже. + +Попробуем реализовать возможность формирования пути файла при помощи переменных окружения, указывая место куда нужно вставить значение прямо в пути файла. +Например, нужно считывать значение системной проперти *scope.value* и добавлять ее после имени файла с пропертями. +Тогда укажем путь считывания в виде значения аннотации ``@Resource.Classpath("file.${system.scope.value}.properties")``. +Теперь, нужно искать в этом пути все строки вида `${system.*}` и заменять их на значение. + +У ``DefaultPropertyProvider`` есть специальный метод получения пути из аннотации. Создадим наследника, в котором переопределим этот метод. + +```java +public class SyspropPathReplacerProvider extends DefaultPropertyProvider { + + public static final String SYS_PROP_KEY_PATTERN = "\\$\\{system\\.([^\\}]*)\\}"; + + @Override + public String classpath(Class clazz, Properties properties) { + return replaceWithSystemProps(super.classpath(clazz, properties)); + } + + private String replaceWithSystemProps(String path) { + Matcher matcher = Pattern.compile(SYS_PROP_KEY_PATTERN).matcher(path); + while (matcher.find()) { + path = path.replace(matcher.group(0), System.getProperty(matcher.group(1), "")); + } + return path; + } +} +``` + +Реализация элементарна - пробегаем по строке пути, попутно заменяя по регулярному выражению все что требуется. + +Теперь, подключив к классу пропертей этот провайдер, можно динамически формировать путь, просто указав куда нужно вставить значение. + +```java +@Resource.Classpath("file.${system.scope.value}.properties") +@With(SyspropPathReplacerProvider.class) +public class UseSystemReplacerProviderProperty { + + public UseSystemReplacerProviderProperty() { + PropertyLoader.populate(this); + } + + @Property("property") + private String property = "undefined"; + + public String getProperty() { + return property; + } +} +``` + +Похожим образом, можно сделать возможность формирования пути прямо в коде, не используя переменных окружения. +Для этого нам понадобится метод ``PropertyLoader.populate(this, someProperties);``. Properties - это наследник ``Map``, +поэтому мы можем сразу передать туда необходимые ключи, которые будут доступны в провайдере. +Код пропертей будет выглядеть примерно так: + +```java +@Resource.Classpath("file.${map.scope.value}.properties") +@With(MapPathReplacerProvider.class) +public class UseMapReplacerProviderProperty { + + public UseMapReplacerProviderProperty(String scope) { + Properties map = new Properties(); + map.put("scope.value", scope); + PropertyLoader.populate(this, map); + } + + ... + +``` + +Тогда код провайдера изменится следующим образом: + +```java + @Override + public String classpath(Class clazz, Properties properties) { + return replaceWithMapProps(super.classpath(clazz, properties), properties); + } + + private String replaceWithMapProps(String path, Properties properties) { + Matcher matcher = Pattern.compile(MAP_PROP_KEY_PATTERN).matcher(path); + while (matcher.find()) { + path = path.replace(matcher.group(0), properties.getProperty(matcher.group(1), "")); + } + return path; + } +``` + +Соответственно вызов конструктора с нужным параметром и определит имя файла. +Рабочие примеры кода можно посмотреть в тесте ``CustomPropertyProviderTest`` + +[create-multi-file-configuration]: https://github.com/yandex-qatools/properties/blob/master/properties-loader/src/site/create-multi-file-configuration.ru.md + + diff --git a/properties-loader/src/test/java/ru/yandex/qatools/properties/CustomPropertyProviderTest.java b/properties-loader/src/test/java/ru/yandex/qatools/properties/CustomPropertyProviderTest.java new file mode 100644 index 0000000..fead88a --- /dev/null +++ b/properties-loader/src/test/java/ru/yandex/qatools/properties/CustomPropertyProviderTest.java @@ -0,0 +1,78 @@ +package ru.yandex.qatools.properties; + +import org.junit.BeforeClass; +import org.junit.Test; +import ru.yandex.qatools.properties.testdata.UseMapReplacerProviderProperty; +import ru.yandex.qatools.properties.testdata.UseSystemReplacerProviderProperty; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; + +/** + * User: lanwen + * Date: 17.07.13 + * Time: 20:17 + */ +public class CustomPropertyProviderTest { + + @BeforeClass + public static void clear() throws Exception { + System.clearProperty("property"); + } + + @Test + public void loadDefaults() { + System.clearProperty("file.name"); + System.clearProperty("scope.value"); + UseSystemReplacerProviderProperty mfp = new UseSystemReplacerProviderProperty(); + assertThat(mfp.getProperty(), equalTo("undefined")); + } + + @Test + public void loadTestingProperty() { + System.setProperty("file.name", "first"); + System.setProperty("scope.value", "testing"); + UseSystemReplacerProviderProperty mfp = new UseSystemReplacerProviderProperty(); + assertThat(mfp.getProperty(), equalTo("testing")); + } + + @Test + public void loadProductionProperty() { + System.setProperty("file.name", "second"); + System.setProperty("scope.value", "production"); + UseSystemReplacerProviderProperty mfp = new UseSystemReplacerProviderProperty(); + assertThat(mfp.getProperty(), equalTo("production")); + } + + @Test + public void noFileLoadDefaults() { + UseMapReplacerProviderProperty mfp = new UseMapReplacerProviderProperty("third", "beta"); + assertThat(mfp.getProperty(), equalTo("undefined")); + } + + @Test + public void loadTestingPropertyWithMap() { + UseMapReplacerProviderProperty mfp = new UseMapReplacerProviderProperty("first", "testing"); + assertThat(mfp.getProperty(), equalTo("testing")); + } + + @Test + public void loadProductionPropertyWithMap() { + UseMapReplacerProviderProperty mfp = new UseMapReplacerProviderProperty("second", "production"); + assertThat(mfp.getProperty(), equalTo("production")); + } + + @Test + public void loadTestingPropertyBothWithMapAndSysprops() { + System.setProperty("file.name", "first"); + UseMapOrSyspropReplacerProviderProperty mfp = new UseMapOrSyspropReplacerProviderProperty("testing"); + assertThat(mfp.getProperty(), equalTo("testing")); + } + + @Test + public void loadProductionPropertyBothWithMapAndSysprops() { + System.setProperty("file.name", "second"); + UseMapOrSyspropReplacerProviderProperty mfp = new UseMapOrSyspropReplacerProviderProperty("production"); + assertThat(mfp.getProperty(), equalTo("production")); + } +} diff --git a/properties-loader/src/test/java/ru/yandex/qatools/properties/LoadPropertiesDependsOnSystemPropertyTest.java b/properties-loader/src/test/java/ru/yandex/qatools/properties/LoadPropertiesDependsOnSystemPropertyTest.java new file mode 100644 index 0000000..d7e8c7e --- /dev/null +++ b/properties-loader/src/test/java/ru/yandex/qatools/properties/LoadPropertiesDependsOnSystemPropertyTest.java @@ -0,0 +1,42 @@ +package ru.yandex.qatools.properties; + +import org.junit.BeforeClass; +import org.junit.Test; +import ru.yandex.qatools.properties.testdata.MultiFileProperty; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; + +/** + * @author artkoshelev + */ +public class LoadPropertiesDependsOnSystemPropertyTest { + + + @BeforeClass + public static void clear() throws Exception { + System.clearProperty("property"); + } + + @Test + public void loadDefaults() { + System.clearProperty("property.file"); + MultiFileProperty mfp = new MultiFileProperty(); + assertThat(mfp.getProperty(), equalTo("undefined")); + } + + @Test + public void loadPublicProperty() { + System.setProperty("property.file", "public.properties"); + MultiFileProperty mfp = new MultiFileProperty(); + assertThat(mfp.getProperty(), equalTo("public")); + } + + @Test + public void loadPrivateProperty() { + System.setProperty("property.file", "private.properties"); + MultiFileProperty mfp = new MultiFileProperty(); + assertThat(mfp.getProperty(), equalTo("private")); + } + +} diff --git a/properties-loader/src/test/java/ru/yandex/qatools/properties/OverrideDefaultsFromFilePropertiesTest.java b/properties-loader/src/test/java/ru/yandex/qatools/properties/OverrideDefaultsFromFilePropertiesTest.java index 7e4bcb8..14b0e12 100644 --- a/properties-loader/src/test/java/ru/yandex/qatools/properties/OverrideDefaultsFromFilePropertiesTest.java +++ b/properties-loader/src/test/java/ru/yandex/qatools/properties/OverrideDefaultsFromFilePropertiesTest.java @@ -1,17 +1,17 @@ package ru.yandex.qatools.properties; -import org.apache.commons.beanutils.ConvertUtils; -import org.junit.BeforeClass; -import org.junit.Test; -import ru.yandex.qatools.properties.testdata.ProxyProperties; -import ru.yandex.qatools.properties.testdata.ProxyPropertiesFactory; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.junit.Assert.assertThat; import java.io.File; import java.io.FileReader; import java.util.Properties; -import static org.hamcrest.core.IsEqual.equalTo; -import static org.junit.Assert.assertThat; +import org.junit.BeforeClass; +import org.junit.Test; + +import ru.yandex.qatools.properties.testdata.ProxyProperties; +import ru.yandex.qatools.properties.testdata.ProxyPropertiesFactory; /** * @author Artem Eroshenko eroshenkoam diff --git a/properties-loader/src/test/java/ru/yandex/qatools/properties/OverrideDefaultsFromSystemPropertiesTest.java b/properties-loader/src/test/java/ru/yandex/qatools/properties/OverrideDefaultsFromSystemPropertiesTest.java index b284b85..b342eb7 100644 --- a/properties-loader/src/test/java/ru/yandex/qatools/properties/OverrideDefaultsFromSystemPropertiesTest.java +++ b/properties-loader/src/test/java/ru/yandex/qatools/properties/OverrideDefaultsFromSystemPropertiesTest.java @@ -1,16 +1,15 @@ package ru.yandex.qatools.properties; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.junit.Assert.assertThat; + import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; + import ru.yandex.qatools.properties.testdata.ProxyProperties; import ru.yandex.qatools.properties.testdata.ProxyPropertiesFactory; -import java.util.Properties; - -import static org.hamcrest.core.IsEqual.equalTo; -import static org.junit.Assert.assertThat; - /** * @author Artem Eroshenko eroshenkoam * 3/24/13, 12:33 AM diff --git a/properties-loader/src/test/java/ru/yandex/qatools/properties/UseMapOrSyspropReplacerProviderProperty.java b/properties-loader/src/test/java/ru/yandex/qatools/properties/UseMapOrSyspropReplacerProviderProperty.java new file mode 100644 index 0000000..91173b3 --- /dev/null +++ b/properties-loader/src/test/java/ru/yandex/qatools/properties/UseMapOrSyspropReplacerProviderProperty.java @@ -0,0 +1,29 @@ +package ru.yandex.qatools.properties; + +import ru.yandex.qatools.properties.annotations.Property; +import ru.yandex.qatools.properties.annotations.Resource; +import ru.yandex.qatools.properties.annotations.With; +import ru.yandex.qatools.properties.providers.MapOrSyspropPathReplacerProvider; + +import java.util.Properties; + +/** + * @author artkoshelev + */ +@Resource.Classpath("${system.file.name}.path.${map.scope.value}.properties") +@With(MapOrSyspropPathReplacerProvider.class) +public class UseMapOrSyspropReplacerProviderProperty { + + public UseMapOrSyspropReplacerProviderProperty(String scope) { + Properties map = new Properties(); + map.put("scope.value", scope); + PropertyLoader.populate(this, map); + } + + @Property("property") + private String property = "undefined"; + + public String getProperty() { + return property; + } +} \ No newline at end of file diff --git a/properties-loader/src/test/java/ru/yandex/qatools/properties/testdata/MapPathReplacerProvider.java b/properties-loader/src/test/java/ru/yandex/qatools/properties/testdata/MapPathReplacerProvider.java new file mode 100644 index 0000000..8e54fb2 --- /dev/null +++ b/properties-loader/src/test/java/ru/yandex/qatools/properties/testdata/MapPathReplacerProvider.java @@ -0,0 +1,37 @@ +package ru.yandex.qatools.properties.testdata; + +import ru.yandex.qatools.properties.providers.DefaultPropertyProvider; + +import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * User: lanwen + * Date: 17.07.13 + * Time: 19:58 + */ +public class MapPathReplacerProvider extends DefaultPropertyProvider { + public static final String MAP_PROP_KEY_PATTERN = "\\$\\{map\\.([^\\}]*)\\}"; + + @Override + public String filepath(Class clazz, Properties properties) { + return replaceWithMapProps(super.filepath(clazz, properties), properties); + } + + @Override + public String classpath(Class clazz, Properties properties) { + return replaceWithMapProps(super.classpath(clazz, properties), properties); + } + + + private String replaceWithMapProps(String path, Properties properties) { + Matcher matcher = Pattern.compile(MAP_PROP_KEY_PATTERN).matcher(path); + String replaced = path; + while (matcher.find()) { + replaced = replaced.replace(matcher.group(0), properties.getProperty(matcher.group(1), "")); + } + return replaced; + } + +} diff --git a/properties-loader/src/test/java/ru/yandex/qatools/properties/testdata/MultiFileProperty.java b/properties-loader/src/test/java/ru/yandex/qatools/properties/testdata/MultiFileProperty.java new file mode 100644 index 0000000..604367b --- /dev/null +++ b/properties-loader/src/test/java/ru/yandex/qatools/properties/testdata/MultiFileProperty.java @@ -0,0 +1,36 @@ +package ru.yandex.qatools.properties.testdata; + +import static ru.yandex.qatools.properties.utils.PropertiesUtils.readProperties; + +import java.util.Properties; + +import ru.yandex.qatools.properties.PropertyLoader; +import ru.yandex.qatools.properties.annotations.Property; + +/** + * + * @author artkoshelev + * + */ +public class MultiFileProperty { + + public MultiFileProperty() { + PropertyLoader.populate(this, loadProperties()); + } + + @Property("property") + private String property = "undefined"; + + public String getProperty() { + return property; + } + + private static Properties loadProperties() { + Properties result = new Properties(); + String filePath = System.getProperty("property.file"); + if (filePath != null) { + result.putAll(readProperties(ClassLoader.getSystemResourceAsStream(filePath))); + } + return result; + } +} \ No newline at end of file diff --git a/properties-loader/src/test/java/ru/yandex/qatools/properties/testdata/PropertiesWithCustomConverter.java b/properties-loader/src/test/java/ru/yandex/qatools/properties/testdata/PropertiesWithCustomConverter.java index 124d649..6975eb9 100644 --- a/properties-loader/src/test/java/ru/yandex/qatools/properties/testdata/PropertiesWithCustomConverter.java +++ b/properties-loader/src/test/java/ru/yandex/qatools/properties/testdata/PropertiesWithCustomConverter.java @@ -1,14 +1,20 @@ package ru.yandex.qatools.properties.testdata; +import ru.yandex.qatools.properties.PropertyLoader; import ru.yandex.qatools.properties.annotations.Property; +import ru.yandex.qatools.properties.annotations.Resource; import ru.yandex.qatools.properties.annotations.Use; +import java.util.Properties; + /** * @author Artem Eroshenko eroshenkoam * 5/13/13, 8:14 PM */ +@Resource.Classpath("${proeprty.load}.property") public class PropertiesWithCustomConverter { + @Property("field") @Use(UpperCaseStringConverter.class) public String field; diff --git a/properties-loader/src/test/java/ru/yandex/qatools/properties/testdata/SyspropPathReplacerProvider.java b/properties-loader/src/test/java/ru/yandex/qatools/properties/testdata/SyspropPathReplacerProvider.java new file mode 100644 index 0000000..c023665 --- /dev/null +++ b/properties-loader/src/test/java/ru/yandex/qatools/properties/testdata/SyspropPathReplacerProvider.java @@ -0,0 +1,34 @@ +package ru.yandex.qatools.properties.testdata; + +import ru.yandex.qatools.properties.providers.DefaultPropertyProvider; + +import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * User: lanwen + * Date: 17.07.13 + * Time: 19:58 + */ +public class SyspropPathReplacerProvider extends DefaultPropertyProvider { + public static final String SYS_PROP_KEY_PATTERN = "\\$\\{system\\.([^\\}]*)\\}"; + + @Override + public String filepath(Class clazz, Properties properties) { + return replaceWithSystemProps(super.filepath(clazz, properties)); + } + + @Override + public String classpath(Class clazz, Properties properties) { + return replaceWithSystemProps(super.classpath(clazz, properties)); + } + private String replaceWithSystemProps(String path) { + Matcher matcher = Pattern.compile(SYS_PROP_KEY_PATTERN).matcher(path); + String replaced = path; + while (matcher.find()) { + replaced = replaced.replace(matcher.group(0), System.getProperty(matcher.group(1), "")); + } + return replaced; + } +} diff --git a/properties-loader/src/test/java/ru/yandex/qatools/properties/testdata/UseMapReplacerProviderProperty.java b/properties-loader/src/test/java/ru/yandex/qatools/properties/testdata/UseMapReplacerProviderProperty.java new file mode 100644 index 0000000..0607a64 --- /dev/null +++ b/properties-loader/src/test/java/ru/yandex/qatools/properties/testdata/UseMapReplacerProviderProperty.java @@ -0,0 +1,30 @@ +package ru.yandex.qatools.properties.testdata; + +import ru.yandex.qatools.properties.PropertyLoader; +import ru.yandex.qatools.properties.annotations.Property; +import ru.yandex.qatools.properties.annotations.Resource; +import ru.yandex.qatools.properties.annotations.With; + +import java.util.Properties; + +/** + * @author artkoshelev + */ +@Resource.Classpath("${map.file.name}.path.${map.scope.value}.properties") +@With(MapPathReplacerProvider.class) +public class UseMapReplacerProviderProperty { + + public UseMapReplacerProviderProperty(String name, String scope) { + Properties map = new Properties(); + map.put("file.name", name); + map.put("scope.value", scope); + PropertyLoader.populate(this, map); + } + + @Property("property") + private String property = "undefined"; + + public String getProperty() { + return property; + } +} \ No newline at end of file diff --git a/properties-loader/src/test/java/ru/yandex/qatools/properties/testdata/UseSystemReplacerProviderProperty.java b/properties-loader/src/test/java/ru/yandex/qatools/properties/testdata/UseSystemReplacerProviderProperty.java new file mode 100644 index 0000000..b61567a --- /dev/null +++ b/properties-loader/src/test/java/ru/yandex/qatools/properties/testdata/UseSystemReplacerProviderProperty.java @@ -0,0 +1,31 @@ +package ru.yandex.qatools.properties.testdata; + +import ru.yandex.qatools.properties.PropertyLoader; +import ru.yandex.qatools.properties.annotations.Property; +import ru.yandex.qatools.properties.annotations.Resource; +import ru.yandex.qatools.properties.annotations.With; + +import java.util.Properties; + +import static ru.yandex.qatools.properties.utils.PropertiesUtils.readProperties; + +/** + * + * @author artkoshelev + * + */ +@Resource.Classpath("${system.file.name}.path.${system.scope.value}.properties") +@With(SyspropPathReplacerProvider.class) +public class UseSystemReplacerProviderProperty { + + public UseSystemReplacerProviderProperty() { + PropertyLoader.populate(this); + } + + @Property("property") + private String property = "undefined"; + + public String getProperty() { + return property; + } +} \ No newline at end of file diff --git a/properties-loader/src/test/resources/first.path.testing.properties b/properties-loader/src/test/resources/first.path.testing.properties new file mode 100644 index 0000000..719f536 --- /dev/null +++ b/properties-loader/src/test/resources/first.path.testing.properties @@ -0,0 +1 @@ +property = testing \ No newline at end of file diff --git a/properties-loader/src/test/resources/private.properties b/properties-loader/src/test/resources/private.properties new file mode 100644 index 0000000..e0b418b --- /dev/null +++ b/properties-loader/src/test/resources/private.properties @@ -0,0 +1 @@ +property = private \ No newline at end of file diff --git a/properties-loader/src/test/resources/public.properties b/properties-loader/src/test/resources/public.properties new file mode 100644 index 0000000..cc9b0ef --- /dev/null +++ b/properties-loader/src/test/resources/public.properties @@ -0,0 +1 @@ +property = public \ No newline at end of file diff --git a/properties-loader/src/test/resources/second.path.production.properties b/properties-loader/src/test/resources/second.path.production.properties new file mode 100644 index 0000000..5598c6d --- /dev/null +++ b/properties-loader/src/test/resources/second.path.production.properties @@ -0,0 +1 @@ +property = production \ No newline at end of file