Skip to content

Instantly share code, notes, and snippets.

@uptown
Created August 19, 2019 09:20
Show Gist options
  • Save uptown/7b13163031c296b4da6db66c0c3270af to your computer and use it in GitHub Desktop.
Save uptown/7b13163031c296b4da6db66c0c3270af to your computer and use it in GitHub Desktop.
package co.halfz.commons.http;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
import org.apache.http.protocol.HttpContext;
import java.util.concurrent.CompletionStage;
public interface CompletableHttpAsyncClient {
<T> CompletionStage<T> execute(HttpAsyncRequestProducer httpAsyncRequestProducer,
HttpAsyncResponseConsumer<T> httpAsyncResponseConsumer, HttpContext httpContext);
<T> CompletionStage<T> execute(HttpAsyncRequestProducer httpAsyncRequestProducer,
HttpAsyncResponseConsumer<T> httpAsyncResponseConsumer);
CompletionStage<HttpResponse> execute(HttpHost httpHost, HttpRequest httpRequest, HttpContext httpContext);
CompletionStage<HttpResponse> execute(HttpHost httpHost, HttpRequest httpRequest);
CompletionStage<HttpResponse> execute(HttpUriRequest httpUriRequest, HttpContext httpContext);
CompletionStage<HttpResponse> execute(HttpUriRequest httpUriRequest);
}
package co.halfz.commons.http;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.nio.client.HttpAsyncClient;
import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
import org.apache.http.protocol.HttpContext;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.function.Consumer;
public class CompletableHttpAsyncClientImpl implements CompletableHttpAsyncClient {
private final HttpAsyncClient httpAsyncClient;
public CompletableHttpAsyncClientImpl(HttpAsyncClient httpAsyncClient) {
this.httpAsyncClient = httpAsyncClient;
}
public <T> CompletionStage<T> execute(HttpAsyncRequestProducer httpAsyncRequestProducer, HttpAsyncResponseConsumer<T> httpAsyncResponseConsumer, HttpContext httpContext) {
return toCompletableFuture(fc -> httpAsyncClient.execute(httpAsyncRequestProducer, httpAsyncResponseConsumer, httpContext, fc));
}
public <T> CompletionStage<T> execute(HttpAsyncRequestProducer httpAsyncRequestProducer, HttpAsyncResponseConsumer<T> httpAsyncResponseConsumer) {
return toCompletableFuture(fc -> httpAsyncClient.execute(httpAsyncRequestProducer, httpAsyncResponseConsumer, fc));
}
public CompletionStage<HttpResponse> execute(HttpHost httpHost, HttpRequest httpRequest, HttpContext httpContext) {
return toCompletableFuture(fc -> httpAsyncClient.execute(httpHost, httpRequest, httpContext, fc));
}
public CompletionStage<HttpResponse> execute(HttpHost httpHost, HttpRequest httpRequest) {
return toCompletableFuture(fc -> httpAsyncClient.execute(httpHost, httpRequest, fc));
}
public CompletionStage<HttpResponse> execute(HttpUriRequest httpUriRequest, HttpContext httpContext) {
return toCompletableFuture(fc -> httpAsyncClient.execute(httpUriRequest, httpContext, fc));
}
public CompletionStage<HttpResponse> execute(HttpUriRequest httpUriRequest) {
return toCompletableFuture(fc -> httpAsyncClient.execute(httpUriRequest, fc));
}
private static <T> CompletionStage<T> toCompletableFuture(Consumer<FutureCallback<T>> c) {
CompletableFuture<T> promise = new CompletableFuture<>();
c.accept(new FutureCallback<T>() {
@Override
public void completed(T t) {
promise.complete(t);
}
@Override
public void failed(Exception e) {
promise.completeExceptionally(e);
}
@Override
public void cancelled() {
promise.cancel(true);
}
});
return promise;
}
}
package co.halfz.holiday;
import co.halfz.commons.base.BaseObject;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.time.LocalDate;
@Getter
@Setter
@AllArgsConstructor(staticName = "of")
@NoArgsConstructor
public class Holiday extends BaseObject {
private String name;
private LocalDate date;
}
package co.halfz.holiday;
import co.halfz.commons.http.CompletableHttpAsyncClient;
import org.apache.commons.io.IOUtils;
import org.apache.http.client.methods.HttpGet;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.util.UriComponentsBuilder;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletionException;
import java.util.concurrent.CompletionStage;
import java.util.stream.Collectors;
@Service
public class HolidayService {
private final static String SERVICE_KEY = "SERVICE_KEY";
private final static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
@Autowired
private CompletableHttpAsyncClient asyncClient;
public Holiday findHoliday(LocalDate date) {
return findHolidays(date.getYear()).stream()
.filter(holiday -> holiday.getDate()
.equals(date))
.findAny()
.orElse(null);
}
public List<Holiday> findHolidays(LocalDate fromDate, LocalDate endDate) {
if (fromDate.isAfter(endDate))
return Collections.emptyList();
List<Holiday> holidays = findHolidays(fromDate.getYear());
if (fromDate.getYear() != endDate.getYear()) {
holidays = new ArrayList<>(holidays);
holidays.addAll(findHolidays(endDate.getYear()));
}
return holidays.stream()
.filter(holiday -> holiday.getDate()
.isBefore(endDate.plusDays(1)) && holiday.getDate()
.isAfter(fromDate.minusDays(1)))
.collect(Collectors.toList());
}
@SuppressWarnings("unchecked")
public List<Holiday> findHolidays(int year) {
List<CompletionStage<List<Holiday>>> holidays = new ArrayList<>();
for (int i = 1; i < 13; i++) {
holidays.add(findHolidays(year, i));
}
return holidays.stream()
.flatMap(r -> r.toCompletableFuture()
.join()
.stream())
.collect(Collectors.toList());
}
public boolean isHoliday(LocalDate date) {
return findHolidays(date.getYear()).stream()
.anyMatch(holiday -> holiday.getDate()
.equals(date));
}
private CompletionStage<List<Holiday>> findHolidays(int year, int month) {
UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromHttpUrl(
"http://apis.data.go.kr/B090041/openapi/service/SpcdeInfoService/getRestDeInfo");
uriComponentsBuilder.queryParam("ServiceKey", SERVICE_KEY);
uriComponentsBuilder.queryParam("solYear", year);
uriComponentsBuilder.queryParam("solMonth", String.format("%02d", month));
HttpGet httpGet = new HttpGet(uriComponentsBuilder.toUriString());
return asyncClient.execute(httpGet)
.thenApply(response -> {
try {
String ret = IOUtils.toString(response.getEntity()
.getContent(), StandardCharsets.UTF_8);
Document parse = Jsoup.parse(ret);
return parse.select("items > item")
.stream()
.map(element -> {
String datename = element.getElementsByTag("datename")
.first()
.textNodes()
.get(0)
.text();
String locdate = element.getElementsByTag("locdate")
.text();
return Holiday.of(datename, LocalDate.parse(locdate, formatter));
})
.collect(Collectors.toList());
} catch (IOException e) {
throw new CompletionException(e);
}
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment