Skip to content

Commit 0b79471

Browse files
committed
refactor
1 parent 46bad13 commit 0b79471

File tree

8 files changed

+179
-19
lines changed

8 files changed

+179
-19
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright (C) 2009-2019 Slava Semushin <slava.semushin@gmail.com>
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation; either version 2 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program; if not, write to the Free Software
16+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17+
*/
18+
package ru.mystamps.web.common;
19+
20+
import java.util.function.Consumer;
21+
import java.util.function.Supplier;
22+
import org.apache.commons.lang3.time.StopWatch;
23+
24+
public final class ExecutionTimeUtils {
25+
26+
private ExecutionTimeUtils() {
27+
}
28+
29+
public static <R> R measureAndLog(Supplier<R> func, Consumer<StopWatch> logger) {
30+
// Why we don't use Spring's StopWatch?
31+
// 1) because its javadoc says that it's not intended for production
32+
// 2) because we don't want to have strong dependencies on the Spring Framework
33+
StopWatch timer = new StopWatch();
34+
35+
// start() and stop() may throw IllegalStateException and in this case it's possible
36+
// that we won't generate anything or lose already generated result. I don't want to
37+
// make method body too complicated by adding many try/catches and I believe that such
38+
// exception will never happen because it would mean that we're using API in a wrong way.
39+
timer.start();
40+
R result = func.get();
41+
timer.stop();
42+
43+
logger.accept(timer);
44+
45+
return result;
46+
}
47+
48+
}

src/main/java/ru/mystamps/web/feature/series/importing/extractor/JsoupSiteParser.java

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.jsoup.nodes.Element;
3030
import org.slf4j.Logger;
3131
import org.slf4j.LoggerFactory;
32+
import ru.mystamps.web.feature.series.importing.sale.SeriesSaleInfo;
3233

3334
// Getters/setters/no-arg constructor are being used in unit tests
3435
@Getter(AccessLevel.PROTECTED)
@@ -74,6 +75,7 @@ public JsoupSiteParser(SiteParserConfiguration cfg) {
7475
/**
7576
* Parse HTML document to get info about series.
7677
*
78+
* @param htmlPage html page content
7779
* @return info about a series from the document
7880
*/
7981
@Override
@@ -93,14 +95,29 @@ public SeriesInfo parse(String htmlPage) {
9395
info.setQuantity(extractQuantity(body));
9496
info.setPerforated(extractPerforated(body));
9597
info.setMichelNumbers(extractMichelNumbers(body));
96-
info.setSellerName(extractSellerName(body));
97-
info.setSellerUrl(extractSellerUrl(body));
98-
info.setPrice(extractPrice(body));
99-
info.setCurrency(extractCurrency(body));
98+
info.setSaleInfo(extractSeriesSale(body));
10099

101100
return info;
102101
}
103102

103+
// @todo #1029 JsoupSiteParser.parseSeriesSale(): add unit tests
104+
/**
105+
* Parse HTML document to get info about series sale.
106+
*
107+
* @param htmlPage html page content
108+
* @return series sale info from the document
109+
*/
110+
@Override
111+
public SeriesSaleInfo parseSeriesSale(String htmlPage) {
112+
Validate.isTrue(StringUtils.isNotBlank(htmlPage), "Page content must be non-blank");
113+
114+
String baseUri = matchedUrl;
115+
Document doc = Jsoup.parse(htmlPage, baseUri);
116+
Element body = doc.body();
117+
118+
return extractSeriesSale(body);
119+
}
120+
104121
@Override
105122
public String toString() {
106123
return name;
@@ -186,6 +203,15 @@ protected String extractMichelNumbers(Element body) {
186203

187204
}
188205

206+
private SeriesSaleInfo extractSeriesSale(Element body) {
207+
String sellerName = extractSellerName(body);
208+
String sellerUrl = extractSellerUrl(body);
209+
String price = extractPrice(body);
210+
String currency = extractCurrency(body);
211+
212+
return new SeriesSaleInfo(sellerName, sellerUrl, price, currency);
213+
}
214+
189215
protected String extractSellerName(Element body) {
190216
String sellerName = getTextOfTheFirstElement(body, sellerLocator);
191217
if (sellerName == null) {

src/main/java/ru/mystamps/web/feature/series/importing/extractor/SeriesInfo.java

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import lombok.Getter;
2222
import lombok.Setter;
2323
import lombok.ToString;
24+
import ru.mystamps.web.feature.series.importing.sale.SeriesSaleInfo;
2425

2526
/**
2627
* Representation of a series info.
@@ -37,10 +38,8 @@ public class SeriesInfo {
3738
private String quantity;
3839
private String perforated;
3940
private String michelNumbers;
40-
private String sellerName;
41-
private String sellerUrl;
42-
private String price;
43-
private String currency;
41+
// the code assumes that saleInfo is always non-null
42+
private SeriesSaleInfo saleInfo;
4443

4544
/**
4645
* Check whether any info about a series is available.
@@ -53,8 +52,23 @@ public boolean isEmpty() {
5352
&& quantity == null
5453
&& perforated == null
5554
&& michelNumbers == null
56-
&& sellerName == null
57-
&& price == null;
55+
&& saleInfo.isEmpty();
56+
}
57+
58+
public String getSellerName() {
59+
return saleInfo.getSellerName();
60+
}
61+
62+
public String getSellerUrl() {
63+
return saleInfo.getSellerUrl();
64+
}
65+
66+
public String getPrice() {
67+
return saleInfo.getPrice();
68+
}
69+
70+
public String getCurrency() {
71+
return saleInfo.getCurrency();
5872
}
5973

6074
}

src/main/java/ru/mystamps/web/feature/series/importing/extractor/SiteParser.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
*/
1818
package ru.mystamps.web.feature.series.importing.extractor;
1919

20+
import ru.mystamps.web.feature.series.importing.sale.SeriesSaleInfo;
21+
2022
public interface SiteParser {
2123
SeriesInfo parse(String htmlPage);
24+
SeriesSaleInfo parseSeriesSale(String htmlPage);
2225
}

src/main/java/ru/mystamps/web/feature/series/importing/extractor/TimedSiteParser.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,14 @@
1717
*/
1818
package ru.mystamps.web.feature.series.importing.extractor;
1919

20+
import java.util.function.Consumer;
21+
import java.util.function.Supplier;
2022
import lombok.RequiredArgsConstructor;
2123
import org.apache.commons.lang3.StringUtils;
2224
import org.apache.commons.lang3.time.StopWatch;
2325
import org.slf4j.Logger;
26+
import ru.mystamps.web.common.ExecutionTimeUtils;
27+
import ru.mystamps.web.feature.series.importing.sale.SeriesSaleInfo;
2428

2529
// @todo #801 TimedSiteParser: add unit tests
2630
@RequiredArgsConstructor
@@ -55,6 +59,14 @@ public SeriesInfo parse(String htmlPage) {
5559
return result;
5660
}
5761

62+
@Override
63+
public SeriesSaleInfo parseSeriesSale(String htmlPage) {
64+
return ExecutionTimeUtils.measureAndLog(
65+
() -> parser.parseSeriesSale(htmlPage),
66+
(timer) -> log.debug("HTML page with {} characters has been parsed in {} msecs", StringUtils.length(htmlPage), timer.getTime())
67+
);
68+
}
69+
5870
@Override
5971
public String toString() {
6072
return parser.toString();
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright (C) 2009-2019 Slava Semushin <slava.semushin@gmail.com>
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation; either version 2 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program; if not, write to the Free Software
16+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17+
*/
18+
package ru.mystamps.web.feature.series.importing.sale;
19+
20+
import lombok.EqualsAndHashCode;
21+
import lombok.Getter;
22+
import lombok.RequiredArgsConstructor;
23+
import lombok.ToString;
24+
25+
/**
26+
* Representation of series sale info.
27+
*/
28+
@Getter
29+
@ToString
30+
@EqualsAndHashCode
31+
@RequiredArgsConstructor
32+
public class SeriesSaleInfo {
33+
private final String sellerName;
34+
private final String sellerUrl;
35+
private final String price;
36+
private final String currency;
37+
38+
/**
39+
* Check whether info about a series sale is available.
40+
*/
41+
public boolean isEmpty() {
42+
// The following fields aren't taken into account because:
43+
// - sellerUrl: SeriesInfoExtractorService might deduce it based on a page URL
44+
// - currency: SeriesInfoExtractorService might use a default value
45+
return sellerName == null && price == null;
46+
}
47+
48+
}

src/main/java/ru/mystamps/web/feature/series/importing/sale/SeriesSalesImportServiceImpl.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,7 @@ public SeriesSaleExtractedInfo downloadAndParse(String url) {
5858

5959
String content = result.getDataAsString();
6060

61-
// @todo #995 SiteParser: introduce a method for parsing only sales-related info
62-
SeriesInfo info = parser.parse(content);
61+
SeriesSaleInfo info = parser.parseSeriesSale(content);
6362
if (info.isEmpty()) {
6463
throw new RuntimeException("could not parse the page");
6564
}

src/test/java/ru/mystamps/web/feature/series/importing/extractor/JsoupSiteParserTest.java

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.junit.Rule;
2525
import org.junit.Test;
2626
import org.junit.rules.ExpectedException;
27+
import ru.mystamps.web.feature.series.importing.sale.SeriesSaleInfo;
2728
import ru.mystamps.web.tests.Random;
2829
import java.util.Locale;
2930

@@ -91,10 +92,14 @@ public void parseShouldExtractSeriesInfo() {
9192
expectedInfo.setCountryName(expectedCountry);
9293
expectedInfo.setIssueDate(expectedIssueDate);
9394
expectedInfo.setImageUrl(expectedImageUrl);
94-
expectedInfo.setSellerName(expectedSellerName);
95-
expectedInfo.setSellerUrl(expectedSellerUrl);
96-
expectedInfo.setPrice(expectedPrice);
97-
expectedInfo.setCurrency(expectedCurrency);
95+
96+
SeriesSaleInfo expectedSaleInfo = new SeriesSaleInfo(
97+
expectedSellerName,
98+
expectedSellerUrl,
99+
expectedPrice,
100+
expectedCurrency
101+
);
102+
expectedInfo.setSaleInfo(expectedSaleInfo);
98103

99104
String html = String.format(
100105
"<html>"
@@ -152,9 +157,14 @@ public void parseShouldExtractSeriesInfoFromFirstMatchedElements() {
152157
expectedInfo.setCountryName(expectedCountry);
153158
expectedInfo.setIssueDate(expectedIssueDate);
154159
expectedInfo.setImageUrl(expectedImageUrl);
155-
expectedInfo.setSellerName(expectedSellerName);
156-
expectedInfo.setSellerUrl(expectedSellerUrl);
157-
expectedInfo.setPrice(expectedPrice);
160+
161+
SeriesSaleInfo expectedSaleInfo = new SeriesSaleInfo(
162+
expectedSellerName,
163+
expectedSellerUrl,
164+
expectedPrice,
165+
null
166+
);
167+
expectedInfo.setSaleInfo(expectedSaleInfo);
158168

159169
String html = String.format(
160170
"<html>"

0 commit comments

Comments
 (0)