diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/bots/DefaultAbsSender.java b/telegrambots/src/main/java/org/telegram/telegrambots/bots/DefaultAbsSender.java index e7cbcec0..b84e012a 100644 --- a/telegrambots/src/main/java/org/telegram/telegrambots/bots/DefaultAbsSender.java +++ b/telegrambots/src/main/java/org/telegram/telegrambots/bots/DefaultAbsSender.java @@ -2,7 +2,6 @@ package org.telegram.telegrambots.bots; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import org.apache.commons.io.FileUtils; import org.apache.http.HttpEntity; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; @@ -14,6 +13,7 @@ import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.util.EntityUtils; import org.telegram.telegrambots.facilities.TelegramHttpClientBuilder; +import org.telegram.telegrambots.facilities.filedownloader.TelegramFileDownloader; import org.telegram.telegrambots.meta.api.methods.BotApiMethod; import org.telegram.telegrambots.meta.api.methods.groupadministration.SetChatPhoto; import org.telegram.telegrambots.meta.api.methods.send.*; @@ -36,10 +36,9 @@ import org.telegram.telegrambots.meta.updateshandlers.DownloadFileCallback; import org.telegram.telegrambots.meta.updateshandlers.SentCallback; import java.io.IOException; +import java.io.InputStream; import java.io.Serializable; import java.net.InetSocketAddress; -import java.net.MalformedURLException; -import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.concurrent.ExecutorService; @@ -61,6 +60,7 @@ public abstract class DefaultAbsSender extends AbsSender { private final DefaultBotOptions options; private volatile CloseableHttpClient httpClient; private volatile RequestConfig requestConfig; + private final TelegramFileDownloader telegramFileDownloader = new TelegramFileDownloader(this::getBotToken); protected DefaultAbsSender(DefaultBotOptions options) { super(); @@ -109,37 +109,35 @@ public abstract class DefaultAbsSender extends AbsSender { // Send Requests public final java.io.File downloadFile(String filePath) throws TelegramApiException { - if(filePath == null || filePath.isEmpty()){ - throw new TelegramApiException("Parameter file can not be null"); - } - String url = File.getFileUrl(getBotToken(), filePath); - String tempFileName = Long.toString(System.currentTimeMillis()); - return downloadToTemporaryFileWrappingExceptions(url, tempFileName); + return telegramFileDownloader.downloadFile(filePath); } public final java.io.File downloadFile(File file) throws TelegramApiException { - assertParamNotNull(file, "file"); - String url = file.getFileUrl(getBotToken()); - String tempFileName = file.getFileId(); - return downloadToTemporaryFileWrappingExceptions(url, tempFileName); + return telegramFileDownloader.downloadFile(file); + } + + public final java.io.File downloadFile(File file, java.io.File outputFile) throws TelegramApiException { + return telegramFileDownloader.downloadFile(file, outputFile); + } + + public final java.io.File downloadFile(String filePath, java.io.File outputFile) throws TelegramApiException { + return telegramFileDownloader.downloadFile(filePath, outputFile); } public final void downloadFileAsync(String filePath, DownloadFileCallback callback) throws TelegramApiException { - if(filePath == null || filePath.isEmpty()){ - throw new TelegramApiException("Parameter filePath can not be null"); - } - assertParamNotNull(callback, "callback"); - String url = File.getFileUrl(getBotToken(), filePath); - String tempFileName = Long.toString(System.currentTimeMillis()); - exe.submit(getDownloadFileAsyncJob(filePath, callback, url, tempFileName)); + telegramFileDownloader.downloadFileAsync(filePath, callback); } public final void downloadFileAsync(File file, DownloadFileCallback callback) throws TelegramApiException { - assertParamNotNull(file, "file"); - assertParamNotNull(callback, "callback"); - String url = file.getFileUrl(getBotToken()); - String tempFileName = file.getFileId(); - exe.submit(getDownloadFileAsyncJob(file, callback, url, tempFileName)); + telegramFileDownloader.downloadFileAsync(file, callback); + } + + public final InputStream downloadFileAsStream(String filePath) throws TelegramApiException { + return telegramFileDownloader.downloadFileAsStream(filePath); + } + + public final InputStream downloadFileAsStream(File file) throws TelegramApiException { + return telegramFileDownloader.downloadFileAsStream(file); } // Specific Send Requests @@ -720,38 +718,6 @@ public abstract class DefaultAbsSender extends AbsSender { } } - private Runnable getDownloadFileAsyncJob(T fileIdentifier, DownloadFileCallback callback, String url, String tempFileName) { - //noinspection Convert2Lambda - return new Runnable() { - @Override - public void run() { - try { - callback.onResult(fileIdentifier, downloadToTemporaryFile(url, tempFileName)); - } catch (MalformedURLException e) { - callback.onException(fileIdentifier, new TelegramApiException("Wrong url for file: " + url)); - } catch (IOException e) { - callback.onException(fileIdentifier, new TelegramApiRequestException("Error downloading the file", e)); - } - } - }; - } - - private java.io.File downloadToTemporaryFileWrappingExceptions(String url, String tempFileName) throws TelegramApiException { - try { - return downloadToTemporaryFile(url, tempFileName); - } catch (MalformedURLException e) { - throw new TelegramApiException("Wrong url for file: " + url); - } catch (IOException e) { - throw new TelegramApiRequestException("Error downloading the file", e); - } - } - - private java.io.File downloadToTemporaryFile(String url, String tempFileName) throws IOException { - java.io.File output = java.io.File.createTempFile(tempFileName, ".tmp"); - FileUtils.copyURLToFile(new URL(url), output); - return output; - } - private > String sendMethodRequest(Method method) throws TelegramApiValidationException, IOException { method.validate(); String url = getBaseUrl() + method.getMethod(); diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/facilities/TelegramFileDownloader.java b/telegrambots/src/main/java/org/telegram/telegrambots/facilities/TelegramFileDownloader.java deleted file mode 100644 index f6305df5..00000000 --- a/telegrambots/src/main/java/org/telegram/telegrambots/facilities/TelegramFileDownloader.java +++ /dev/null @@ -1,108 +0,0 @@ -package org.telegram.telegrambots.facilities; - -import org.apache.commons.io.FileUtils; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.telegram.telegrambots.bots.DefaultAbsSender; -import org.telegram.telegrambots.meta.api.objects.File; -import org.telegram.telegrambots.meta.exceptions.TelegramApiException; -import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException; -import org.telegram.telegrambots.meta.updateshandlers.DownloadFileCallback; - -import java.io.IOException; -import java.io.InputStream; -import java.net.MalformedURLException; -import java.util.concurrent.ExecutorService; - -@SuppressWarnings("Duplicates") -public class TelegramFileDownloader { - private DefaultAbsSender sender; - ExecutorService exe; - CloseableHttpClient httpClient = HttpClients.createDefault(); - - public final java.io.File downloadFile(String filePath) throws TelegramApiException { - if (filePath == null || filePath.isEmpty()) { - throw new TelegramApiException("Parameter file can not be null"); - } - String url = File.getFileUrl(sender.getBotToken(), filePath); - String tempFileName = Long.toString(System.currentTimeMillis()); - return downloadToTemporaryFileWrappingExceptions(url, tempFileName); - } - - public final java.io.File downloadFile(File file) throws TelegramApiException { - assertParamNotNull(file, "file"); - String url = file.getFileUrl(sender.getBotToken()); - String tempFileName = file.getFileId(); - return downloadToTemporaryFileWrappingExceptions(url, tempFileName); - } - - public final void downloadFileAsync(String filePath, DownloadFileCallback callback) throws TelegramApiException { - if (filePath == null || filePath.isEmpty()) { - throw new TelegramApiException("Parameter filePath can not be null"); - } - assertParamNotNull(callback, "callback"); - String url = File.getFileUrl(sender.getBotToken(), filePath); - String tempFileName = Long.toString(System.currentTimeMillis()); - exe.submit(getDownloadFileAsyncJob(filePath, callback, url, tempFileName)); - } - - public final void downloadFileAsync(File file, DownloadFileCallback callback) throws TelegramApiException { - assertParamNotNull(file, "file"); - assertParamNotNull(callback, "callback"); - String url = file.getFileUrl(sender.getBotToken()); - String tempFileName = file.getFileId(); - exe.submit(getDownloadFileAsyncJob(file, callback, url, tempFileName)); - } - - private Runnable getDownloadFileAsyncJob(T fileIdentifier, DownloadFileCallback callback, String url, String tempFileName) { - //noinspection Convert2Lambda - return new Runnable() { - @Override - public void run() { - try { - callback.onResult(fileIdentifier, downloadToTemporaryFile(url, tempFileName)); - } catch (MalformedURLException e) { - callback.onException(fileIdentifier, new TelegramApiException("Wrong url for file: " + url)); - } catch (IOException e) { - callback.onException(fileIdentifier, new TelegramApiRequestException("Error downloading the file", e)); - } - } - }; - } - - private java.io.File downloadToTemporaryFileWrappingExceptions(String url, String tempFileName) throws TelegramApiException { - try { - return downloadToTemporaryFile(url, tempFileName); - } catch (MalformedURLException e) { - throw new TelegramApiException("Wrong url for file: " + url); - } catch (IOException e) { - throw new TelegramApiRequestException("Error downloading the file", e); - } - } - - private java.io.File downloadToTemporaryFile(String url, String tempFileName) throws IOException { - final java.io.File output = java.io.File.createTempFile(tempFileName, ".tmp"); - - final HttpGet get = new HttpGet(url); - final HttpResponse response = httpClient.execute(get); - - final int statusCode = response.getStatusLine().getStatusCode(); - if (statusCode == HttpStatus.SC_OK) { - final InputStream content = response.getEntity().getContent(); - - FileUtils.copyInputStreamToFile(content, output); - } else { - throw new IOException("Unexpected Status code. Expected 200 got + statusCode"); - } - return output; - } - - private void assertParamNotNull(Object param, String paramName) throws TelegramApiException { - if (param == null) { - throw new TelegramApiException("Parameter " + paramName + " can not be null"); - } - } -} diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/facilities/filedownloader/DownloadFileException.java b/telegrambots/src/main/java/org/telegram/telegrambots/facilities/filedownloader/DownloadFileException.java new file mode 100644 index 00000000..b458b958 --- /dev/null +++ b/telegrambots/src/main/java/org/telegram/telegrambots/facilities/filedownloader/DownloadFileException.java @@ -0,0 +1,10 @@ +package org.telegram.telegrambots.facilities.filedownloader; + +/** + * Runtime Exception to wrap Exceptions thrown during file download + */ +public class DownloadFileException extends RuntimeException { + public DownloadFileException(final String message, final Throwable e) { + super(message, e); + } +} diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/facilities/filedownloader/TelegramFileDownloader.java b/telegrambots/src/main/java/org/telegram/telegrambots/facilities/filedownloader/TelegramFileDownloader.java new file mode 100644 index 00000000..02c34c9f --- /dev/null +++ b/telegrambots/src/main/java/org/telegram/telegrambots/facilities/filedownloader/TelegramFileDownloader.java @@ -0,0 +1,172 @@ +package org.telegram.telegrambots.facilities.filedownloader; + +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.HttpClients; +import org.telegram.telegrambots.meta.api.objects.File; +import org.telegram.telegrambots.meta.exceptions.TelegramApiException; +import org.telegram.telegrambots.meta.updateshandlers.DownloadFileCallback; + +import java.io.IOException; +import java.io.InputStream; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.ExecutionException; +import java.util.function.Supplier; + +import static org.apache.commons.io.FileUtils.copyInputStreamToFile; +import static org.apache.http.HttpStatus.SC_OK; + +/** + * Wraps the file downloading code into one class. + * @author Chase22 + * @version 1.0 + */ +public class TelegramFileDownloader { + private final HttpClient httpClient; + private final Supplier botTokenSupplier; + + public TelegramFileDownloader(final Supplier botTokenSupplier) { + this.botTokenSupplier = botTokenSupplier; + httpClient = HttpClients.createDefault(); + } + + public TelegramFileDownloader(final HttpClient httpClient, final Supplier botTokenSupplier) { + this.httpClient = httpClient; + this.botTokenSupplier = botTokenSupplier; + } + + public final java.io.File downloadFile(String filePath) throws TelegramApiException { + String tempFileName = Long.toString(System.currentTimeMillis()); + return downloadFile(filePath, getTempFile(tempFileName)); + } + + public final java.io.File downloadFile(File file) throws TelegramApiException { + return downloadFile(file, getTempFile(file.getFileId())); + } + + public final java.io.File downloadFile(File file, java.io.File outputFile) throws TelegramApiException { + if (file == null) { + throw new TelegramApiException("Parameter file can not be null"); + } + String url = file.getFileUrl(botTokenSupplier.get()); + return downloadToFile(url, outputFile); + } + + public final java.io.File downloadFile(String filePath, java.io.File outputFile) throws TelegramApiException { + if (filePath == null || filePath.isEmpty()) { + throw new TelegramApiException("Parameter file can not be null"); + } + String url = File.getFileUrl(botTokenSupplier.get(), filePath); + return downloadToFile(url, outputFile); + } + + public final InputStream downloadFileAsStream(String filePath) throws TelegramApiException { + try { + return getFileDownloadStreamFuture(File.getFileUrl(botTokenSupplier.get(), filePath)).get(); + } catch (InterruptedException e) { + throw new TelegramApiException("Error downloading file", e); + } catch (ExecutionException e) { + throw new TelegramApiException("Error downloading file", e.getCause()); + } + } + + public final InputStream downloadFileAsStream(File file) throws TelegramApiException { + try { + return getFileDownloadStreamFuture(file.getFileUrl(botTokenSupplier.get())).get(); + } catch (InterruptedException e) { + throw new TelegramApiException("Error downloading file", e); + } catch (ExecutionException e) { + throw new TelegramApiException("Error downloading file", e.getCause()); + } + } + + public final void downloadFileAsync(String filePath, DownloadFileCallback callback) throws TelegramApiException { + if (filePath == null || filePath.isEmpty()) { + throw new TelegramApiException("Parameter filePath can not be null"); + } + if (callback == null) { + throw new TelegramApiException("Parameter callback can not be null"); + } + String url = File.getFileUrl(botTokenSupplier.get(), filePath); + String tempFileName = Long.toString(System.currentTimeMillis()); + + getFileDownloadFuture(url, getTempFile(tempFileName)) + .thenAccept(output -> callback.onResult(filePath, output)) + .exceptionally(throwable -> { + // Unwrap java.util.concurrent.CompletionException + if (throwable instanceof CompletionException) { + callback.onException(filePath, new TelegramApiException("Error downloading file", throwable.getCause())); + } else { + callback.onException(filePath, new TelegramApiException("Error downloading file", throwable)); + } + return null; + }); + } + + public final void downloadFileAsync(File file, DownloadFileCallback callback) throws TelegramApiException { + if (file == null) { + throw new TelegramApiException("Parameter file can not be null"); + } + if (callback == null) { + throw new TelegramApiException("Parameter callback can not be null"); + } + String url = file.getFileUrl(botTokenSupplier.get()); + String tempFileName = file.getFileId(); + + getFileDownloadFuture(url, getTempFile(tempFileName)) + .thenAccept(output -> callback.onResult(file, output)) + .exceptionally(throwable -> { + callback.onException(file, new TelegramApiException("Error downloading file", throwable)); + return null; + }); + + } + + private java.io.File getTempFile(String tempFileName) throws TelegramApiException { + try { + return java.io.File.createTempFile(tempFileName, ".tmp"); + } catch (IOException e) { + throw new TelegramApiException("Error downloading file", e); + } + } + + private java.io.File downloadToFile(String url, java.io.File output) throws TelegramApiException { + try { + return getFileDownloadFuture(url, output).get(); + } catch (InterruptedException e) { + throw new TelegramApiException("File Download got interrupted", e); + } catch (ExecutionException e) { + throw new TelegramApiException("Error downloading file", e.getCause()); + } + } + + private CompletableFuture getFileDownloadFuture(String url, java.io.File output) { + return getFileDownloadStreamFuture(url).thenApply(stream -> { + try { + copyInputStreamToFile(stream, output); + return output; + } catch (IOException e) { + throw new DownloadFileException("Error writing downloaded file", e); + } + }); + } + + private CompletableFuture getFileDownloadStreamFuture(final String url) { + return CompletableFuture.supplyAsync(() -> { + try { + HttpResponse response = httpClient.execute(new HttpGet(url)); + final int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode == SC_OK) { + return response.getEntity().getContent(); + } else { + throw new TelegramApiException("Unexpected Status code while downloading file. Expected 200 got " + statusCode); + } + } catch (IOException | TelegramApiException e) { + throw new DownloadFileException("Error downloading file", e); + } + }); + } + +}