diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..707a647
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+*.jar
+*.war
+*.ear
+
+target
+.idea
+*.iml
+*.ipr
+*.iws
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..4f72ee0
--- /dev/null
+++ b/README.md
@@ -0,0 +1,41 @@
+# BeanLoader
+
+[![release](http://github-release-version.herokuapp.com/github/yandex-qatools/beanloader/release.svg?style=flat)](https://github.com/yandex-qatools/beanloader/releases/latest) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/ru.yandex.qatools.beanloader/beanloader/badge.svg?style=flat)](https://maven-badges.herokuapp.com/maven-central/ru.yandex.qatools.beanloader/beanloader)
+
+This small library provides an easy fluent API to load xml beans
+from different sources via JAXB, giving some of them higher priority
+than to the others.
+
+### Maven
+
+```xml
+
+ ru.yandex.qatools.beanloader
+ beanloader
+ 1.0-SNAPSHOT
+
+```
+
+### Usage
+
+```java
+import static ru.qatools.beanloader.BeanLoaderStrategies.*;
+import static ru.qatools.beanloader.BeanLoader.*;
+
+BeanLoader beanLoader = load(Bean.class)
+ .from(resource("bean.xml"))
+ .from(url("http://example.com?get-my-bean-dawg"))
+ .from(file("~/beans/bean.xml"))
+ .from(fileWithWatcher("/etc/beans/", "bean.xml"));
+
+// load bean iterating over the given strategies
+// until one of the returns a non-null bean
+Bean bean = beanLoader.getBean();
+makeSomeStuff(bean);
+
+// reload the bean, if reloads are specified for any strategy
+// returns the same object if no reloads are specified
+bean = beanLoader.getBean();
+makeAnotherStuff(bean);
+
+```
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..e1c004d
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,139 @@
+
+
+ 4.0.0
+
+
+ org.sonatype.oss
+ oss-parent
+ 7
+
+
+ ru.yandex.qatools.beanloader
+ beanloader
+ 1.0-SNAPSHOT
+ Yandex QATools BeanLoader
+
+
+ scm:git:git@github.com:yandex-qatools/beanloader.git
+ scm:git:git@github.com:yandex-qatools/beanloader.git
+ https://github.com/yandex-qatools/beanloader
+
+
+ https://github.com/yandex-qatools/beanloader
+
+
+ UTF-8
+ 1.7
+
+
+
+ Yandex
+ http://company.yandex.com
+
+
+
+
+ The Apache Software License, Version 2.0
+ http://www.apache.org/licenses/LICENSE-2.0.txt
+ repo
+
+
+
+
+ GitHub Issue Tracker
+ https://github.com/yandex-qatools/beanloader/issues
+
+
+
+ Jenkins
+ http://jenkins.qatools.ru/
+
+
+
+
+ innokenty
+ Innokenty Shuvalov
+ innokenty@yandex-team.ru
+ Yandex
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.0
+
+
+ ${java.version}
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 2.2.1
+
+
+ attach-sources
+
+ jar
+
+
+
+
+
+ org.codehaus.mojo
+ jaxb2-maven-plugin
+ 1.6
+
+
+ generate test bean
+
+ testXjc
+
+
+
+
+ ru.qatools.beanloader
+ src/test/resources
+
+
+
+
+
+
+
+ org.slf4j
+ slf4j-log4j12
+ 1.7.7
+
+
+ junit
+ junit
+ 4.11
+ test
+
+
+ org.hamcrest
+ hamcrest-all
+ 1.3
+ test
+
+
+ ru.yandex.qatools.matchers
+ matcher-decorators
+ 1.0
+ test
+
+
+ com.googlecode.lambdaj
+ lambdaj
+ 2.3.3
+ test
+
+
+
+
diff --git a/src/main/java/ru/qatools/beanloader/BeanLoader.java b/src/main/java/ru/qatools/beanloader/BeanLoader.java
new file mode 100644
index 0000000..165f68a
--- /dev/null
+++ b/src/main/java/ru/qatools/beanloader/BeanLoader.java
@@ -0,0 +1,40 @@
+package ru.qatools.beanloader;
+
+import ru.qatools.beanloader.internal.BeanLoadStrategy;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Innokenty Shuvalov innokenty@yandex-team.ru
+ */
+public class BeanLoader {
+
+ private final List strategies = new ArrayList<>();
+
+ private final Class beanClass;
+
+ private BeanLoader(Class beanClass) {
+ this.beanClass = beanClass;
+ }
+
+ public static BeanLoader load(Class beanClass) {
+ return new BeanLoader<>(beanClass);
+ }
+
+ public BeanLoader from(BeanLoadStrategy strategy) {
+ strategies.add(strategy);
+ return this;
+ }
+
+ public T getBean() {
+ for (BeanLoadStrategy strategy : strategies) {
+ @SuppressWarnings("unchecked")
+ T bean = (T) strategy.getBeanAs(beanClass);
+ if (bean != null) {
+ return bean;
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/ru/qatools/beanloader/BeanLoaderStrategies.java b/src/main/java/ru/qatools/beanloader/BeanLoaderStrategies.java
new file mode 100644
index 0000000..395a2b4
--- /dev/null
+++ b/src/main/java/ru/qatools/beanloader/BeanLoaderStrategies.java
@@ -0,0 +1,49 @@
+package ru.qatools.beanloader;
+
+import ru.qatools.beanloader.internal.*;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+ * @author Innokenty Shuvalov innokenty@yandex-team.ru
+ */
+public abstract class BeanLoaderStrategies {
+
+ public static FileLoadStrategy file(String filename) {
+ return file(filename, false);
+ }
+
+ public static FileLoadStrategy file(String filename, boolean reloadEveryTime) {
+ return file(new File(filename), reloadEveryTime);
+ }
+
+ public static FileLoadStrategy file(File file, boolean reloadEveryTime) {
+ return new FileLoadStrategy(file, reloadEveryTime);
+ }
+
+ public static FileWithWatcherLoadStrategy fileWithWatcher(String directoryToWatch, String fileToWatch) {
+ return new FileWithWatcherLoadStrategy(directoryToWatch, fileToWatch);
+ }
+
+ public static UrlLoadStrategy url(URL url) {
+ return url(url, false);
+ }
+
+ static BeanLoadStrategy url(String url) throws MalformedURLException {
+ return url(new URL(url));
+ }
+
+ static BeanLoadStrategy url(String url, boolean reloadEveryTime) throws MalformedURLException {
+ return url(new URL(url), reloadEveryTime);
+ }
+
+ public static UrlLoadStrategy url(URL url, boolean reloadEveryTime) {
+ return new UrlLoadStrategy(url, reloadEveryTime);
+ }
+
+ public static ResourceLoadStrategy resource(String resource) {
+ return new ResourceLoadStrategy(resource);
+ }
+}
diff --git a/src/main/java/ru/qatools/beanloader/internal/BeanLoadStrategy.java b/src/main/java/ru/qatools/beanloader/internal/BeanLoadStrategy.java
new file mode 100644
index 0000000..129443f
--- /dev/null
+++ b/src/main/java/ru/qatools/beanloader/internal/BeanLoadStrategy.java
@@ -0,0 +1,61 @@
+package ru.qatools.beanloader.internal;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.xml.bind.DataBindingException;
+
+/**
+ * This class could be generified but it is not. The purpose of that is
+ * to increase the 'fluency' of the {@link ru.qatools.beanloader.BeanLoader} API. Note that
+ * with the proper usage through BeanLoader this code can not lead to any
+ * ClassCastExceptions, although it is not fully generified and has class casts
+ * in the code. This is fine because the BeanLoader itself is generified properly.
+ *
+ * @author Innokenty Shuvalov innokenty@yandex-team.ru
+ */
+public abstract class BeanLoadStrategy {
+
+ protected final Logger logger = LoggerFactory.getLogger(getClass());
+
+ private Object bean;
+ private boolean loaded;
+
+ public Object getBeanAs(Class beanClass) {
+ if (!loaded || reloadEveryTime()) {
+ loadBean(beanClass);
+ }
+ return bean;
+ }
+
+ protected void loadBean(Class beanClass) {
+ loaded = true;
+ logger.trace("trying to load bean from " + getSourceDescription());
+ if (!canUnmarshal()) {
+ logger.trace("source does not exist, aborting");
+ return;
+ }
+
+ try {
+ logger.trace("source exists, trying to unmarshal");
+ bean = performUnmarshal(beanClass);
+ logger.trace("successfully unmarshalled");
+ } catch (DataBindingException e) {
+ logUnmarshallingException(e, getSourceDescription());
+ }
+ }
+
+ private void logUnmarshallingException(Exception e, String sourceDescription) {
+ if (logger.isDebugEnabled()) {
+ logger.error("exception caught while unmarshalling from " + sourceDescription, e);
+ } else {
+ logger.error(String.format("exception caught while unmarshalling from %s: %s",
+ sourceDescription, e.getMessage()));
+ }
+ }
+
+ protected abstract boolean canUnmarshal();
+ protected abstract boolean reloadEveryTime();
+ protected abstract Object performUnmarshal(Class beanClass);
+ protected abstract String getSourceDescription();
+}
diff --git a/src/main/java/ru/qatools/beanloader/internal/FileLoadStrategy.java b/src/main/java/ru/qatools/beanloader/internal/FileLoadStrategy.java
new file mode 100644
index 0000000..a74609b
--- /dev/null
+++ b/src/main/java/ru/qatools/beanloader/internal/FileLoadStrategy.java
@@ -0,0 +1,38 @@
+package ru.qatools.beanloader.internal;
+
+import javax.xml.bind.JAXB;
+import java.io.File;
+
+/**
+ * @author Innokenty Shuvalov innokenty@yandex-team.ru
+ */
+public class FileLoadStrategy extends BeanLoadStrategy {
+
+ private final File file;
+ private final boolean reload;
+
+ public FileLoadStrategy(File file, boolean reload) {
+ super();
+ this.file = file;
+ this.reload = reload;
+ }
+
+ @Override
+ protected boolean canUnmarshal() {
+ return file.exists();
+ }
+
+ protected boolean reloadEveryTime() {
+ return reload;
+ }
+
+ @Override
+ protected Object performUnmarshal(Class beanClass) {
+ return JAXB.unmarshal(file, beanClass);
+ }
+
+ @Override
+ protected String getSourceDescription() {
+ return "file '" + file.getPath() + "'";
+ }
+}
diff --git a/src/main/java/ru/qatools/beanloader/internal/FileWatcher.java b/src/main/java/ru/qatools/beanloader/internal/FileWatcher.java
new file mode 100644
index 0000000..38c552e
--- /dev/null
+++ b/src/main/java/ru/qatools/beanloader/internal/FileWatcher.java
@@ -0,0 +1,66 @@
+package ru.qatools.beanloader.internal;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.nio.file.*;
+
+/**
+ * @author Innokenty Shuvalov innokenty@yandex-team.ru
+ * @author Dmitry Baev charlie@yandex-team.ru
+ */
+public class FileWatcher implements Runnable {
+
+ private final Logger logger = LoggerFactory.getLogger(getClass());
+
+ private final BeanLoadStrategy loadStrategy;
+ private final Class beanClass;
+ private final String directory;
+ private final String file;
+
+ public FileWatcher(BeanLoadStrategy loadStrategy, Class beanClass,
+ String directory, String file) {
+ this.loadStrategy = loadStrategy;
+ this.beanClass = beanClass;
+ this.directory = directory;
+ this.file = file;
+ }
+
+ @Override
+ public void run() {
+ Path directory = Paths.get(this.directory);
+ try (WatchService service = FileSystems.getDefault().newWatchService()) {
+ directory.register(service, StandardWatchEventKinds.ENTRY_MODIFY);
+ watch(service);
+ } catch (IOException e) {
+ logger.error("Can't create watch service for directory " + this.directory, e);
+ } catch (InterruptedException e) {
+ logger.warn("oops, thread was interrupted");
+ }
+ }
+
+ private void watch(WatchService service) throws InterruptedException {
+ logger.info("Watching for changes in directory " + directory);
+ //noinspection all
+ while (true) {
+ WatchKey key = service.take();
+ handleKey(key);
+ key.reset();
+ }
+ }
+
+ private void handleKey(WatchKey key) {
+ for (WatchEvent event : key.pollEvents()) {
+ Path path = (Path) event.context();
+ if (path.toAbsolutePath().endsWith(file)) {
+ logger.info("file '" + file + "' changed");
+ invokeFileReload();
+ }
+ }
+ }
+
+ protected void invokeFileReload() {
+ loadStrategy.loadBean(beanClass);
+ }
+}
diff --git a/src/main/java/ru/qatools/beanloader/internal/FileWithWatcherLoadStrategy.java b/src/main/java/ru/qatools/beanloader/internal/FileWithWatcherLoadStrategy.java
new file mode 100644
index 0000000..e9e0f56
--- /dev/null
+++ b/src/main/java/ru/qatools/beanloader/internal/FileWithWatcherLoadStrategy.java
@@ -0,0 +1,47 @@
+package ru.qatools.beanloader.internal;
+
+import java.io.File;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * @author Innokenty Shuvalov innokenty@yandex-team.ru
+ */
+public class FileWithWatcherLoadStrategy extends FileLoadStrategy {
+
+ private final String directory;
+ private final String file;
+
+ private boolean fileWatcherInitialized;
+
+ private ExecutorService executor;
+
+ public FileWithWatcherLoadStrategy(String directory, String file) {
+ super(new File(directory, file), false);
+ this.directory = directory;
+ this.file = file;
+ }
+
+ @Override
+ protected synchronized void loadBean(Class beanClass) {
+ super.loadBean(beanClass);
+ if (!fileWatcherInitialized) {
+ initFileWatcher(beanClass);
+ fileWatcherInitialized = true;
+ }
+ }
+
+ private void initFileWatcher(Class beanClass) {
+ executor = Executors.newSingleThreadExecutor();
+ executor.execute(new FileWatcher(this, beanClass, directory, file));
+ executor.shutdown();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ super.finalize();
+ if (executor != null) {
+ executor.shutdownNow();
+ }
+ }
+}
diff --git a/src/main/java/ru/qatools/beanloader/internal/ResourceLoadStrategy.java b/src/main/java/ru/qatools/beanloader/internal/ResourceLoadStrategy.java
new file mode 100644
index 0000000..d93daaa
--- /dev/null
+++ b/src/main/java/ru/qatools/beanloader/internal/ResourceLoadStrategy.java
@@ -0,0 +1,19 @@
+package ru.qatools.beanloader.internal;
+
+/**
+ * @author Innokenty Shuvalov innokenty@yandex-team.ru
+ */
+public class ResourceLoadStrategy extends UrlLoadStrategy {
+
+ private final String resource;
+
+ public ResourceLoadStrategy(String resource) {
+ super(ResourceLoadStrategy.class.getClassLoader().getResource(resource), false);
+ this.resource = resource;
+ }
+
+ @Override
+ protected String getSourceDescription() {
+ return "resource '" + resource + "'";
+ }
+}
diff --git a/src/main/java/ru/qatools/beanloader/internal/UrlLoadStrategy.java b/src/main/java/ru/qatools/beanloader/internal/UrlLoadStrategy.java
new file mode 100644
index 0000000..1eafd3a
--- /dev/null
+++ b/src/main/java/ru/qatools/beanloader/internal/UrlLoadStrategy.java
@@ -0,0 +1,37 @@
+package ru.qatools.beanloader.internal;
+
+import javax.xml.bind.JAXB;
+import java.net.URL;
+
+/**
+ * @author Innokenty Shuvalov innokenty@yandex-team.ru
+ */
+public class UrlLoadStrategy extends BeanLoadStrategy {
+
+ protected final URL url;
+ private final boolean reload;
+
+ public UrlLoadStrategy(URL url, boolean reload) {
+ super();
+ this.url = url;
+ this.reload = reload;
+ }
+
+ protected boolean canUnmarshal() {
+ return url != null;
+ }
+
+ protected boolean reloadEveryTime() {
+ return reload;
+ }
+
+ @Override
+ protected Object performUnmarshal(Class beanClass) {
+ return JAXB.unmarshal(url, beanClass);
+ }
+
+ @Override
+ protected String getSourceDescription() {
+ return url.toString();
+ }
+}
diff --git a/src/test/java/ru/qatools/beanloader/BeanAssert.java b/src/test/java/ru/qatools/beanloader/BeanAssert.java
new file mode 100644
index 0000000..85d0cb8
--- /dev/null
+++ b/src/test/java/ru/qatools/beanloader/BeanAssert.java
@@ -0,0 +1,95 @@
+package ru.qatools.beanloader;
+
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+import ru.qatools.beanloader.internal.BeanLoadStrategy;
+
+import java.io.File;
+
+import static javax.xml.bind.JAXB.marshal;
+import static javax.xml.bind.JAXB.unmarshal;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.assertThat;
+import static ru.qatools.beanloader.BeanLoader.load;
+import static ru.yandex.qatools.matchers.decorators.MatcherDecorators.should;
+import static ru.yandex.qatools.matchers.decorators.MatcherDecorators.timeoutHasExpired;
+
+/**
+ * @author Innokenty Shuvalov innokenty@yandex-team.ru
+ */
+public class BeanAssert {
+
+ public static final String RESOURCES_DIR = "src/test/resources/";
+ public static final String BEAN_XML_NAME = "bean.xml";
+ public static final String BEAN_XML_PATH = RESOURCES_DIR + BEAN_XML_NAME;
+ public static final String BEAN_XML_URL = "file:" + BEAN_XML_PATH;
+ public static final File BEAN_XML_FILE = new File(BEAN_XML_PATH);
+
+ private final String actualValue = getActualValue();
+
+ private final BeanLoader loader;
+
+ public BeanAssert(BeanLoadStrategy strategy) {
+ this(load(Bean.class).from(strategy));
+ }
+
+ public BeanAssert(BeanLoader beanLoader) {
+ loader = beanLoader;
+ }
+
+ public static String getActualValue() {
+ return unmarshal(BEAN_XML_FILE, Bean.class).getValue();
+ }
+
+ public static void setActualValue(String value) {
+ setActualValue(value, BEAN_XML_FILE);
+ }
+
+ public static void setActualValue(String value, File file) {
+ Bean bean = new Bean();
+ bean.setValue(value);
+ marshal(bean, file);
+ }
+
+ public void isNull() {
+ assertThat(loader.getBean(), is(nullValue()));
+ }
+
+ public void valueIsEqualTo(String value) {
+ assertThat(loader.getBean().getValue(), equalTo(value));
+ }
+
+ public void valueIsEqualToActual() {
+ valueIsEqualTo(actualValue);
+ }
+
+ public void valueHasNotChanged() {
+ valueIsEqualToActual();
+ }
+
+ public void waitUntilValueIsEqualTo(String value) {
+ assertThat(loader, should(haveBeanWith(value))
+ .whileWaitingUntil(timeoutHasExpired(60000)));
+ }
+
+ private Matcher> haveBeanWith(final String value) {
+ return new TypeSafeMatcher>() {
+
+ @Override
+ protected boolean matchesSafely(BeanLoader item) {
+ return item.getBean().getValue().equals(value);
+ }
+
+ @Override
+ protected void describeMismatchSafely(BeanLoader item, Description description) {
+ description.appendText("bean with value = " + item.getBean().getValue());
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("bean with value = " + value);
+ }
+ };
+ }
+}
diff --git a/src/test/java/ru/qatools/beanloader/BeanChangingTest.java b/src/test/java/ru/qatools/beanloader/BeanChangingTest.java
new file mode 100644
index 0000000..d843862
--- /dev/null
+++ b/src/test/java/ru/qatools/beanloader/BeanChangingTest.java
@@ -0,0 +1,25 @@
+package ru.qatools.beanloader;
+
+import org.junit.After;
+import org.junit.Before;
+
+import static ru.qatools.beanloader.BeanAssert.getActualValue;
+import static ru.qatools.beanloader.BeanAssert.setActualValue;
+
+/**
+ * @author Innokenty Shuvalov innokenty@yandex-team.ru
+ */
+public abstract class BeanChangingTest {
+
+ private String actualValueAtTheBeginningOfTheTest;
+
+ @Before
+ public void setUp() throws Exception {
+ actualValueAtTheBeginningOfTheTest = getActualValue();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ setActualValue(actualValueAtTheBeginningOfTheTest);
+ }
+}
diff --git a/src/test/java/ru/qatools/beanloader/BeanLoaderTest.java b/src/test/java/ru/qatools/beanloader/BeanLoaderTest.java
new file mode 100644
index 0000000..bb248b9
--- /dev/null
+++ b/src/test/java/ru/qatools/beanloader/BeanLoaderTest.java
@@ -0,0 +1,61 @@
+package ru.qatools.beanloader;
+
+import org.junit.Test;
+
+import java.io.File;
+
+import static ru.qatools.beanloader.BeanAssert.*;
+import static ru.qatools.beanloader.BeanLoader.load;
+import static ru.qatools.beanloader.BeanLoaderStrategies.*;
+
+/**
+ * @author Innokenty Shuvalov innokenty@yandex-team.ru
+ */
+public class BeanLoaderTest {
+
+ @Test
+ public void testLoadFromTheFirstStrategy() {
+ BeanAssert assertBean = new BeanAssert(load(Bean.class)
+ .from(resource(BEAN_XML_NAME))
+ .from(file("non existing file")));
+ assertBean.valueIsEqualToActual();
+ assertBean.valueIsEqualToActual();
+ }
+
+ @Test
+ public void testLoadFromTheSecondStrategy() {
+ BeanAssert assertBean = new BeanAssert(load(Bean.class)
+ .from(resource("non existing resource"))
+ .from(file(BEAN_XML_PATH)));
+ assertBean.valueIsEqualToActual();
+ assertBean.valueIsEqualToActual();
+ }
+
+ @Test
+ public void testLoadWhenAllStrategiesFail() throws Exception {
+ BeanAssert assertBean = new BeanAssert(load(Bean.class)
+ .from(url("file:non existing file"))
+ .from(resource("non existing resource"))
+ .from(file("non existing file")));
+ assertBean.isNull();
+ assertBean.isNull();
+ }
+
+ @Test
+ public void testReloadFromDifferentStrategy() {
+ File anotherFile = new File(RESOURCES_DIR + "bean1.xml");
+
+ BeanAssert assertBean = new BeanAssert(load(Bean.class)
+ .from(file(anotherFile, true))
+ .from(resource(BEAN_XML_NAME)));
+ assertBean.valueIsEqualToActual();
+ assertBean.valueIsEqualToActual();
+
+ String anotherValue = "another value";
+ setActualValue(anotherValue, anotherFile);
+ anotherFile.deleteOnExit();
+
+ assertBean.valueIsEqualTo(anotherValue);
+ assertBean.valueIsEqualTo(anotherValue);
+ }
+}
diff --git a/src/test/java/ru/qatools/beanloader/FileWatcherTest.java b/src/test/java/ru/qatools/beanloader/FileWatcherTest.java
new file mode 100644
index 0000000..fd825a4
--- /dev/null
+++ b/src/test/java/ru/qatools/beanloader/FileWatcherTest.java
@@ -0,0 +1,54 @@
+package ru.qatools.beanloader;
+
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+import org.junit.Test;
+import ru.qatools.beanloader.internal.FileWatcher;
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static ru.qatools.beanloader.BeanAssert.*;
+import static ru.yandex.qatools.matchers.decorators.MatcherDecorators.should;
+import static ru.yandex.qatools.matchers.decorators.MatcherDecorators.timeoutHasExpired;
+
+/**
+ * @author Innokenty Shuvalov innokenty@yandex-team.ru
+ */
+public class FileWatcherTest extends BeanChangingTest {
+
+ @Test
+ public void testFileWatcher() throws Exception {
+ final AtomicBoolean unmarshalInvoked = new AtomicBoolean(false);
+ FileWatcher watcher = new FileWatcher(null, null, RESOURCES_DIR, BEAN_XML_NAME) {
+ @Override
+ protected void invokeFileReload() {
+ unmarshalInvoked.getAndSet(true);
+ }
+ };
+ Executors.newSingleThreadExecutor().submit(watcher);
+
+ Thread.sleep(1000);
+ assertFalse(unmarshalInvoked.get());
+ setActualValue("another " + getActualValue());
+ assertThat(unmarshalInvoked, should(beTrue())
+ .whileWaitingUntil(timeoutHasExpired(60000)));
+ }
+
+ private static Matcher beTrue() {
+ return new TypeSafeMatcher() {
+ @Override
+ protected boolean matchesSafely(AtomicBoolean item) {
+ return item.get();
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("");
+ }
+ };
+ }
+}
diff --git a/src/test/java/ru/qatools/beanloader/FileWithWatcherLoadStrategyTest.java b/src/test/java/ru/qatools/beanloader/FileWithWatcherLoadStrategyTest.java
new file mode 100644
index 0000000..999deaa
--- /dev/null
+++ b/src/test/java/ru/qatools/beanloader/FileWithWatcherLoadStrategyTest.java
@@ -0,0 +1,25 @@
+package ru.qatools.beanloader;
+
+import org.junit.Test;
+
+import static ru.qatools.beanloader.BeanAssert.*;
+import static ru.qatools.beanloader.BeanLoaderStrategies.fileWithWatcher;
+
+/**
+ * @author Innokenty Shuvalov innokenty@yandex-team.ru
+ */
+public class FileWithWatcherLoadStrategyTest extends BeanChangingTest {
+
+ @Test
+ public void testFileWatcher() throws Exception {
+ BeanAssert assertBean
+ = new BeanAssert(fileWithWatcher(RESOURCES_DIR, BEAN_XML_NAME));
+
+ assertBean.valueIsEqualToActual();
+ Thread.sleep(1000);
+ String newValue = "another " + getActualValue();
+ setActualValue(newValue);
+ assertBean.valueHasNotChanged();
+ assertBean.waitUntilValueIsEqualTo(newValue);
+ }
+}
diff --git a/src/test/java/ru/qatools/beanloader/LoadStrategiesTest.java b/src/test/java/ru/qatools/beanloader/LoadStrategiesTest.java
new file mode 100644
index 0000000..762d9a4
--- /dev/null
+++ b/src/test/java/ru/qatools/beanloader/LoadStrategiesTest.java
@@ -0,0 +1,79 @@
+package ru.qatools.beanloader;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import ru.qatools.beanloader.internal.*;
+
+import java.net.MalformedURLException;
+import java.util.Arrays;
+import java.util.Collection;
+
+import static ru.qatools.beanloader.BeanAssert.*;
+import static ru.qatools.beanloader.BeanLoaderStrategies.*;
+
+/**
+ * @author Innokenty Shuvalov innokenty@yandex-team.ru
+ */
+@RunWith(Parameterized.class)
+public class LoadStrategiesTest {
+
+ @Parameters(name = "{2}")
+ public static Collection