diff --git a/build.gradle b/build.gradle index 4f4d34b..2a05aa0 100644 --- a/build.gradle +++ b/build.gradle @@ -37,9 +37,17 @@ dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version" compile 'no.tornado:tornadofx:1.7.11' + compile 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.19.3' + compile 'org.jetbrains.kotlinx:kotlinx-coroutines-javafx:0.19.3' compile 'com.github.salomonbrys.kodein:kodein:4.1.0' compile 'org.seleniumhq.selenium:selenium-java:3.0.1' testCompile 'junit:junit:4.12' +} + +kotlin { + experimental { + coroutines "enable" + } } \ No newline at end of file diff --git a/src/main/kotlin/Constants.kt b/src/main/kotlin/Constants.kt index 01902b1..06cc48d 100644 --- a/src/main/kotlin/Constants.kt +++ b/src/main/kotlin/Constants.kt @@ -26,6 +26,6 @@ object CONSTANTS{ } object CORTEINGLES{ - val URL = "https://elcorteingles.es" + val URL = "https://www.elcorteingles.es" } } \ No newline at end of file diff --git a/src/main/kotlin/MainActivityPresenter.kt b/src/main/kotlin/MainActivityPresenter.kt index fbf5516..4e139c0 100644 --- a/src/main/kotlin/MainActivityPresenter.kt +++ b/src/main/kotlin/MainActivityPresenter.kt @@ -1,5 +1,8 @@ import di.kdi import domain.Product +import kotlinx.coroutines.experimental.async +import kotlinx.coroutines.experimental.javafx.JavaFx +import kotlinx.coroutines.experimental.launch import tornadofx.Controller import tornadofx.observable import usecases.* @@ -25,35 +28,36 @@ class MainActivityPresenter : Controller() { val selectedStores = stores.filter { (_, value) -> value }.map { (key, _) -> key } val products = mutableListOf() - if (selectedStores.contains("https://www.amazon.es")) { - searchItemsForStore(amazonSearchProduct, brands, article, pages, products) - } - - if (selectedStores.contains("https://www.fnac.es")) { - searchItemsForStore(fnacSearchProduct, brands, article, pages, products) - } + launch(JavaFx) { + if (brands.isNotEmpty()) { + selectedStores.forEach { store -> + brands.map { brand -> + async { searchItemsForStore(store, brand, article, pages, products) } + }.map { it.await() } + } + } else { + selectedStores.forEach { + async { searchItemsForStore(it, null, article, pages, products) }.await() + } + } + + ResultsActivity.navigateWithPreviousResults() - if (selectedStores.contains("https://www.elcorteingles.es")) { - searchItemsForStore(corteInglesSearchProduct, brands, article, pages, products) } - ResultsActivity.navigateWithPreviousResults() - } - private fun searchItemsForStore(storeUseCase: ISearchProducts, brands: List, article: String, pages: Int, products: MutableList) { - if (brands.isNotEmpty()) { - val storeProducts = brands - .map { brand: String -> - storeUseCase(if (article == articles[0]) "Cafetera" else article, brand, pages) - }.flatten() - addProcessedProducts(storeProducts) - products.addAll(storeProducts) - } else { - val storeProducts = storeUseCase(if (article == articles[0]) "Cafetera" else article, page = pages) - addProcessedProducts(storeProducts) - products.addAll(storeProducts) + private fun searchItemsForStore(storeUrl: String, brand: String?, article: String, pages: Int, products: MutableCollection) { + val productName = if (article == articles[0]) "Cafetera" else article + val result = when (storeUrl) { + CONSTANTS.FNAC.URL -> fnacSearchProduct(productName, brand, pages) + CONSTANTS.AMAZON.URL -> amazonSearchProduct(productName, brand, pages) + CONSTANTS.CORTEINGLES.URL -> corteInglesSearchProduct(productName, brand, pages) + else -> emptyList() } + addProcessedProducts(result) + products.addAll(result) } + } \ No newline at end of file diff --git a/src/main/kotlin/datasource/Stores/StoreRepository.kt b/src/main/kotlin/datasource/Stores/StoreRepository.kt index 2a7813e..8cb8d01 100644 --- a/src/main/kotlin/datasource/Stores/StoreRepository.kt +++ b/src/main/kotlin/datasource/Stores/StoreRepository.kt @@ -5,11 +5,12 @@ import org.openqa.selenium.By import org.openqa.selenium.JavascriptExecutor import org.openqa.selenium.WebDriver import org.openqa.selenium.WebElement +import org.openqa.selenium.chrome.ChromeDriver import org.openqa.selenium.interactions.Actions abstract class StoreRepository { - val driver: WebDriver by kdi() + val driver: WebDriver = ChromeDriver() abstract fun waitForPageToLoad() fun browse(str: String) { @@ -39,4 +40,8 @@ abstract class StoreRepository { (driver as JavascriptExecutor).executeScript("arguments[0].scrollIntoView(true);", element) Thread.sleep(1000) } + + fun destroy() { + driver.close() + } } diff --git a/src/main/kotlin/usecases/AmazonSearchProduct.kt b/src/main/kotlin/usecases/AmazonSearchProduct.kt index ea3ed46..2fb4ad6 100644 --- a/src/main/kotlin/usecases/AmazonSearchProduct.kt +++ b/src/main/kotlin/usecases/AmazonSearchProduct.kt @@ -1,6 +1,6 @@ package usecases -import datasource.BrandDAO +import datasource.Stores.AmazonRepository import datasource.Stores.StoreRepository import di.kdi import domain.BrandNotFoundException @@ -11,7 +11,7 @@ import org.openqa.selenium.WebElement class AmazonSearchProduct : ISearchProducts() { - override val webDriver: StoreRepository by kdi(CONSTANTS.AMAZON.URL) + override val webDriver: StoreRepository = AmazonRepository() override operator fun invoke(productName: String, brand: String?, page: Int): List { val result = mutableListOf() @@ -21,12 +21,14 @@ class AmazonSearchProduct : ISearchProducts() { webDriver.search(inputBar, productName) webDriver.waitForPageToLoad() + Thread.sleep(2000) if (brand != null) { try { this.selectBrand(brand) Thread.sleep(1000) } catch (e: BrandNotFoundException) { + webDriver.destroy() return result } } @@ -45,11 +47,13 @@ class AmazonSearchProduct : ISearchProducts() { try { val nextPage = webDriver.findElement(By.id("pagnNextLink")).getAttribute("href") webDriver.browse(nextPage) - } catch (ex: Exception) { + } catch (e: Exception) { + webDriver.destroy() return result } } + webDriver.destroy() return result } diff --git a/src/main/kotlin/usecases/ElCorteInglesSearchProduct.kt b/src/main/kotlin/usecases/ElCorteInglesSearchProduct.kt index c60b0ee..8fd917f 100644 --- a/src/main/kotlin/usecases/ElCorteInglesSearchProduct.kt +++ b/src/main/kotlin/usecases/ElCorteInglesSearchProduct.kt @@ -1,6 +1,7 @@ package usecases import datasource.BrandDAO +import datasource.Stores.CorteInglesRepository import datasource.Stores.StoreRepository import di.kdi import domain.BrandNotFoundException @@ -10,7 +11,7 @@ import org.openqa.selenium.By import org.openqa.selenium.WebElement class ElCorteInglesSearchProduct: ISearchProducts() { - override val webDriver: StoreRepository by kdi(CONSTANTS.CORTEINGLES.URL) + override val webDriver: StoreRepository = CorteInglesRepository() override operator fun invoke(productName: String, brand: String?, page: Int): List { val result = mutableListOf() @@ -26,6 +27,7 @@ class ElCorteInglesSearchProduct: ISearchProducts() { this.selectBrand(brand) Thread.sleep(1000) } catch (e: BrandNotFoundException) { + webDriver.destroy() return result } } @@ -50,10 +52,12 @@ class ElCorteInglesSearchProduct: ISearchProducts() { val nextPage = webDriver.findElement(By.cssSelector("ul.a-unordered-list::nth-child(8)")).getAttribute("href") webDriver.browse(nextPage) } catch (ex: Exception) { + webDriver.destroy() return result } } + webDriver.destroy() return result } diff --git a/src/main/kotlin/usecases/FnacSearchProduct.kt b/src/main/kotlin/usecases/FnacSearchProduct.kt index 692d217..55e0f5e 100644 --- a/src/main/kotlin/usecases/FnacSearchProduct.kt +++ b/src/main/kotlin/usecases/FnacSearchProduct.kt @@ -1,5 +1,6 @@ package usecases +import datasource.Stores.FnacRepository import datasource.BrandDAO import datasource.Stores.StoreRepository import di.kdi @@ -11,7 +12,7 @@ import org.openqa.selenium.WebElement class FnacSearchProduct : ISearchProducts() { - override val webDriver: StoreRepository by kdi(CONSTANTS.FNAC.URL) + override val webDriver: StoreRepository = FnacRepository() private val allBrandsList: List = brandsDAO.getAll() override fun invoke(productName: String, brand: String?, page: Int): List { @@ -36,6 +37,7 @@ class FnacSearchProduct : ISearchProducts() { this.selectBrand(brand) Thread.sleep(1000) } catch (e: BrandNotFoundException) { + webDriver.destroy() return result } } @@ -53,10 +55,12 @@ class FnacSearchProduct : ISearchProducts() { try { webDriver.findElement(By.className("actionNext")).click() } catch (ex: Exception) { + webDriver.destroy() return result } } + webDriver.destroy() return result } diff --git a/src/main/kotlin/usecases/ISearchProducts.kt b/src/main/kotlin/usecases/ISearchProducts.kt index 0fe55f3..77a8ed7 100644 --- a/src/main/kotlin/usecases/ISearchProducts.kt +++ b/src/main/kotlin/usecases/ISearchProducts.kt @@ -17,7 +17,7 @@ abstract class ISearchProducts { "de", "para", "capsulas", "espresso", "automatica", "filtro", "molinillo", "multibebida", "electrica", "expresso", "vivy", "grind", "goteo", "brew", "superautomatica", "n", "senseo", "intense", "coffee", "maker", "blanco", "blanca", "con", "jarra", - "dolce", "gusto", "f", "nescafe", "italiana", "hidro-presion", "russell", "hobbs" + "dolce", "gusto", "f", "nescafe", "italiana", "hidro-presion", "russell", "hobbs", "super" ).union(brandsDAO.getAll().map(String::toLowerCase)).toList() } diff --git a/src/main/resources/productos.txt b/src/main/resources/productos.txt index 9ffc0e1..d211b21 100644 --- a/src/main/resources/productos.txt +++ b/src/main/resources/productos.txt @@ -1,6 +1,6 @@ -Cafeteras italianas -Cafeteras de goteo -Cafeteras de espresso manuales -Cafeteras de capsulas -Cafeteras automaticas -Cafeteras combinadas espresso/goteo \ No newline at end of file +Cafetera italianas +Cafetera de goteo +Cafetera espresso manual +Cafetera capsulas +Cafetera automatica +Cafetera combinada espresso y goteo \ No newline at end of file