diff --git a/Bots.ipr b/Bots.ipr
index 48d3590a..94516c63 100644
--- a/Bots.ipr
+++ b/Bots.ipr
@@ -303,18 +303,12 @@
-
-
-
-
-
-
diff --git a/README.md b/README.md
index c37e5307..8a4aece9 100644
--- a/README.md
+++ b/README.md
@@ -27,16 +27,16 @@ Just import add the library to your project with one of these options:
org.telegram
telegrambots
- 3.3
+ 3.4
```
```gradle
- compile "org.telegram:telegrambots:3.3"
+ compile "org.telegram:telegrambots:3.4"
```
- 2. Using Jitpack from [here](https://jitpack.io/#rubenlagus/TelegramBots/3.3)
- 3. Download the jar(including all dependencies) from [here](https://github.com/rubenlagus/TelegramBots/releases/tag/v3.3)
+ 2. Using Jitpack from [here](https://jitpack.io/#rubenlagus/TelegramBots/3.4)
+ 3. Download the jar(including all dependencies) from [here](https://github.com/rubenlagus/TelegramBots/releases/tag/v3.4)
In order to use Long Polling mode, just create your own bot extending `org.telegram.telegrambots.bots.TelegramLongPollingBot`.
@@ -50,7 +50,7 @@ Once done, you just need to create a `org.telegram.telegrambots.TelegramBotsApi`
// Example taken from https://github.com/rubenlagus/TelegramBotsExample
public class Main {
public static void main(String[] args) {
-
+ ApiContextInitializer.init();
TelegramBotsApi telegramBotsApi = new TelegramBotsApi();
try {
telegramBotsApi.registerBot(new ChannelHandlers());
diff --git a/TelegramBots.wiki/Changelog.md b/TelegramBots.wiki/Changelog.md
index 2027e50b..1ca38cc0 100644
--- a/TelegramBots.wiki/Changelog.md
+++ b/TelegramBots.wiki/Changelog.md
@@ -1,5 +1,12 @@
-### 3.2 ###
-1. Support for Api Version [3.3](https://core.telegram.org/bots/api-changelog#july-21-2017)
+### 3.4 ###
+1. Support for Api Version [3.4](https://core.telegram.org/bots/api-changelog#october-11-2017)
+2. Use regular expressions to split parameters in `TelegramLongPollingCommandBot` (#309)
+3. Option to handle bunch of updates at a time via `onUpdatesReceived` in `TelegramLongPollingBot` (#284)
+4. Fix characters encoding (#275)
+
+
+### 3.3 ###
+1. Support for Api Version [3.3](https://core.telegram.org/bots/api-changelog#august-23-2017)
### 3.2 ###
diff --git a/TelegramBots.wiki/Getting-Started.md b/TelegramBots.wiki/Getting-Started.md
index c8f49e42..179577fb 100644
--- a/TelegramBots.wiki/Getting-Started.md
+++ b/TelegramBots.wiki/Getting-Started.md
@@ -11,13 +11,13 @@ First you need ot get the library and add it to your project. There are few poss
org.telegram
telegrambots
- 3.3
+ 3.4
```
* With **Gradle**:
```groovy
- compile group: 'org.telegram', name: 'telegrambots', version: '3.3'
+ compile group: 'org.telegram', name: 'telegrambots', version: '3.4'
```
2. Don't like **Maven Central Repository**? It can also be taken from [Jitpack](https://jitpack.io/#rubenlagus/TelegramBots).
diff --git a/pom.xml b/pom.xml
index 15e915d9..9e5c6e2e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,7 +7,7 @@
org.telegram
Bots
pom
- 3.3
+ 3.4
telegrambots
@@ -26,6 +26,6 @@
true
- 3.3
+ 3.4
\ No newline at end of file
diff --git a/telegrambots-abilities/README.md b/telegrambots-abilities/README.md
index 8c8f6ba6..7d6e6d86 100644
--- a/telegrambots-abilities/README.md
+++ b/telegrambots-abilities/README.md
@@ -18,19 +18,19 @@ Usage
org.telegram
telegrambots-abilities
- 3.3
+ 3.4
```
**Gradle**
```gradle
- compile "org.telegram:telegrambots-abilities:3.3"
+ compile "org.telegram:telegrambots-abilities:3.4"
```
-**JitPack** - [JitPack](https://jitpack.io/#rubenlagus/TelegramBots/v3.3)
+**JitPack** - [JitPack](https://jitpack.io/#rubenlagus/TelegramBots/v3.4)
-**Plain imports** - [Here](https://github.com/rubenlagus/TelegramBots/releases/tag/v3.3)
+**Plain imports** - [Here](https://github.com/rubenlagus/TelegramBots/releases/tag/v3.4)
Motivation
----------
diff --git a/telegrambots-abilities/pom.xml b/telegrambots-abilities/pom.xml
index 4565f134..33154d65 100644
--- a/telegrambots-abilities/pom.xml
+++ b/telegrambots-abilities/pom.xml
@@ -5,7 +5,7 @@
4.0.0
org.telegram
telegrambots-abilities
- 3.3
+ 3.4
jar
Telegram Ability Bot
@@ -65,7 +65,7 @@
UTF-8
UTF-8
- 3.3
+ 3.4
3.5
3.0.4
19.0
diff --git a/telegrambots-extensions/README.md b/telegrambots-extensions/README.md
index bf75827a..35e40b10 100644
--- a/telegrambots-extensions/README.md
+++ b/telegrambots-extensions/README.md
@@ -16,12 +16,12 @@ Just import add the library to your project with one of these options:
org.telegram
telegrambotsextensions
- 3.3
+ 3.4
```
2. Using Gradle:
```gradle
- compile "org.telegram:telegrambotsextensions:3.3"
+ compile "org.telegram:telegrambotsextensions:3.4"
```
\ No newline at end of file
diff --git a/telegrambots-extensions/pom.xml b/telegrambots-extensions/pom.xml
index c8ef2b38..0a8913f2 100644
--- a/telegrambots-extensions/pom.xml
+++ b/telegrambots-extensions/pom.xml
@@ -5,7 +5,7 @@
4.0.0
org.telegram
telegrambotsextensions
- 3.3
+ 3.4
jar
Telegram Bots Extensions
@@ -59,7 +59,7 @@
UTF-8
UTF-8
- 3.3
+ 3.4
diff --git a/telegrambots-extensions/src/main/java/org/telegram/telegrambots/bots/commandbot/commands/BotCommand.java b/telegrambots-extensions/src/main/java/org/telegram/telegrambots/bots/commandbot/commands/BotCommand.java
index 02da6ebd..00f490db 100644
--- a/telegrambots-extensions/src/main/java/org/telegram/telegrambots/bots/commandbot/commands/BotCommand.java
+++ b/telegrambots-extensions/src/main/java/org/telegram/telegrambots/bots/commandbot/commands/BotCommand.java
@@ -11,7 +11,7 @@ import org.telegram.telegrambots.bots.AbsSender;
*/
public abstract class BotCommand {
public final static String COMMAND_INIT_CHARACTER = "/";
- public static final String COMMAND_PARAMETER_SEPARATOR = " ";
+ public static final String COMMAND_PARAMETER_SEPARATOR_REGEXP = "\\s+";
private final static int COMMAND_MAX_LENGTH = 32;
private final String commandIdentifier;
@@ -75,4 +75,4 @@ public abstract class BotCommand {
* @param arguments passed arguments
*/
public abstract void execute(AbsSender absSender, User user, Chat chat, String[] arguments);
-}
\ No newline at end of file
+}
diff --git a/telegrambots-extensions/src/main/java/org/telegram/telegrambots/bots/commandbot/commands/CommandRegistry.java b/telegrambots-extensions/src/main/java/org/telegram/telegrambots/bots/commandbot/commands/CommandRegistry.java
index 17da10d3..99858e3f 100644
--- a/telegrambots-extensions/src/main/java/org/telegram/telegrambots/bots/commandbot/commands/CommandRegistry.java
+++ b/telegrambots-extensions/src/main/java/org/telegram/telegrambots/bots/commandbot/commands/CommandRegistry.java
@@ -97,7 +97,7 @@ public final class CommandRegistry implements ICommandRegistry {
String text = message.getText();
if (text.startsWith(BotCommand.COMMAND_INIT_CHARACTER)) {
String commandMessage = text.substring(1);
- String[] commandSplit = commandMessage.split(BotCommand.COMMAND_PARAMETER_SEPARATOR);
+ String[] commandSplit = commandMessage.split(BotCommand.COMMAND_PARAMETER_SEPARATOR_REGEXP);
String command = removeUsernameFromCommandIfNeeded(commandSplit[0]);
@@ -126,4 +126,4 @@ public final class CommandRegistry implements ICommandRegistry {
}
return command;
}
-}
\ No newline at end of file
+}
diff --git a/telegrambots-meta/pom.xml b/telegrambots-meta/pom.xml
index 501eec82..20cd6cb4 100644
--- a/telegrambots-meta/pom.xml
+++ b/telegrambots-meta/pom.xml
@@ -5,7 +5,7 @@
4.0.0
org.telegram
telegrambots-meta
- 3.3
+ 3.4
jar
Telegram Bots Meta
diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/methods/StopMessageLiveLocation.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/methods/StopMessageLiveLocation.java
new file mode 100644
index 00000000..9b8ff3ef
--- /dev/null
+++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/methods/StopMessageLiveLocation.java
@@ -0,0 +1,157 @@
+package org.telegram.telegrambots.api.methods;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.type.TypeReference;
+import org.telegram.telegrambots.api.objects.Message;
+import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
+import org.telegram.telegrambots.api.objects.replykeyboard.InlineKeyboardMarkup;
+import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
+import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Objects;
+
+/**
+ * @author Ruben Bermudez
+ * @version 1.0
+ * Use this method to stop updating a live location message sent by the bot or via the bot (for inline bots)
+ * before live_period expires. On success, if the message was sent by the bot, the sent Message is returned,
+ * otherwise True is returned.
+ */
+public class StopMessageLiveLocation extends BotApiMethod {
+ public static final String PATH = "stopMessageLiveLocation";
+
+ private static final String CHATID_FIELD = "chat_id";
+ private static final String MESSAGEID_FIELD = "message_id";
+ private static final String INLINE_MESSAGE_ID_FIELD = "inline_message_id";
+ private static final String REPLYMARKUP_FIELD = "reply_markup";
+
+ /**
+ * Required if inline_message_id is not specified. Unique identifier for the chat to send the
+ * message to (Or username for channels)
+ */
+ @JsonProperty(CHATID_FIELD)
+ private String chatId;
+ /**
+ * Required if inline_message_id is not specified. Unique identifier of the sent message
+ */
+ @JsonProperty(MESSAGEID_FIELD)
+ private Integer messageId;
+ /**
+ * Required if chat_id and message_id are not specified. Identifier of the inline message
+ */
+ @JsonProperty(INLINE_MESSAGE_ID_FIELD)
+ private String inlineMessageId;
+ @JsonProperty(REPLYMARKUP_FIELD)
+ private InlineKeyboardMarkup replyMarkup; ///< Optional. A JSON-serialized object for an inline keyboard.
+
+ public StopMessageLiveLocation() {
+ super();
+ }
+
+ public String getChatId() {
+ return chatId;
+ }
+
+ public StopMessageLiveLocation setChatId(String chatId) {
+ this.chatId = chatId;
+ return this;
+ }
+
+ public StopMessageLiveLocation setChatId(Long chatId) {
+ Objects.requireNonNull(chatId);
+ this.chatId = chatId.toString();
+ return this;
+ }
+
+ public Integer getMessageId() {
+ return messageId;
+ }
+
+ public StopMessageLiveLocation setMessageId(Integer messageId) {
+ this.messageId = messageId;
+ return this;
+ }
+
+ public String getInlineMessageId() {
+ return inlineMessageId;
+ }
+
+ public StopMessageLiveLocation setInlineMessageId(String inlineMessageId) {
+ this.inlineMessageId = inlineMessageId;
+ return this;
+ }
+
+ public InlineKeyboardMarkup getReplyMarkup() {
+ return replyMarkup;
+ }
+
+ public StopMessageLiveLocation setReplyMarkup(InlineKeyboardMarkup replyMarkup) {
+ this.replyMarkup = replyMarkup;
+ return this;
+ }
+
+ @Override
+ public String getMethod() {
+ return PATH;
+ }
+
+ @Override
+ public Serializable deserializeResponse(String answer) throws TelegramApiRequestException {
+ try {
+ ApiResponse result = OBJECT_MAPPER.readValue(answer,
+ new TypeReference>(){});
+ if (result.getOk()) {
+ return result.getResult();
+ } else {
+ throw new TelegramApiRequestException("Error stopping message live location", result);
+ }
+ } catch (IOException e) {
+ try {
+ ApiResponse result = OBJECT_MAPPER.readValue(answer,
+ new TypeReference>() {
+ });
+ if (result.getOk()) {
+ return result.getResult();
+ } else {
+ throw new TelegramApiRequestException("Error stopping message live location", result);
+ }
+ } catch (IOException e2) {
+ throw new TelegramApiRequestException("Unable to deserialize response", e);
+ }
+ }
+ }
+
+ @Override
+ public void validate() throws TelegramApiValidationException {
+ if (inlineMessageId == null) {
+ if (chatId == null) {
+ throw new TelegramApiValidationException("ChatId parameter can't be empty if inlineMessageId is not present", this);
+ }
+ if (messageId == null) {
+ throw new TelegramApiValidationException("MessageId parameter can't be empty if inlineMessageId is not present", this);
+ }
+ } else {
+ if (chatId != null) {
+ throw new TelegramApiValidationException("ChatId parameter must be empty if inlineMessageId is provided", this);
+ }
+ if (messageId != null) {
+ throw new TelegramApiValidationException("MessageId parameter must be empty if inlineMessageId is provided", this);
+ }
+ }
+ if (replyMarkup != null) {
+ replyMarkup.validate();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "StopMessageLiveLocation{" +
+ "chatId='" + chatId + '\'' +
+ ", messageId=" + messageId +
+ ", inlineMessageId='" + inlineMessageId + '\'' +
+ ", replyMarkup=" + replyMarkup +
+ '}';
+ }
+}
diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/methods/groupadministration/DeleteStickerSetName.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/methods/groupadministration/DeleteStickerSetName.java
new file mode 100644
index 00000000..5dc0e858
--- /dev/null
+++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/methods/groupadministration/DeleteStickerSetName.java
@@ -0,0 +1,93 @@
+package org.telegram.telegrambots.api.methods.groupadministration;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.type.TypeReference;
+import org.telegram.telegrambots.api.methods.BotApiMethod;
+import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
+import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
+import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
+
+import java.io.IOException;
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * @author Ruben Bermudez
+ * @version 3.4
+ * Use this method to delete a group sticker set from a supergroup.
+ * The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
+ * Use the field can_set_sticker_set optionally returned in getChat requests to check if the bot can use this method.
+ * Returns True on success.
+ */
+public class DeleteStickerSetName extends BotApiMethod {
+ public static final String PATH = "deleteChatStickerSet";
+
+ private static final String CHATID_FIELD = "chat_id";
+
+ @JsonProperty(CHATID_FIELD)
+ private String chatId; ///< Unique identifier for the chat to send the message to (Or username for channels)
+
+ public DeleteStickerSetName() {
+ super();
+ }
+
+ public DeleteStickerSetName(String chatId) {
+ super();
+ this.chatId = checkNotNull(chatId);
+ }
+
+ public DeleteStickerSetName(Long chatId) {
+ super();
+ this.chatId = checkNotNull(chatId).toString();
+ }
+
+ public String getChatId() {
+ return chatId;
+ }
+
+ public DeleteStickerSetName setChatId(String chatId) {
+ this.chatId = chatId;
+ return this;
+ }
+
+ public DeleteStickerSetName setChatId(Long chatId) {
+ Objects.requireNonNull(chatId);
+ this.chatId = chatId.toString();
+ return this;
+ }
+
+ @Override
+ public String getMethod() {
+ return PATH;
+ }
+
+ @Override
+ public Boolean deserializeResponse(String answer) throws TelegramApiRequestException {
+ try {
+ ApiResponse result = OBJECT_MAPPER.readValue(answer,
+ new TypeReference>(){});
+ if (result.getOk()) {
+ return result.getResult();
+ } else {
+ throw new TelegramApiRequestException("Error deleting sticker set name", result);
+ }
+ } catch (IOException e) {
+ throw new TelegramApiRequestException("Unable to deserialize response", e);
+ }
+ }
+
+ @Override
+ public void validate() throws TelegramApiValidationException {
+ if (chatId == null || chatId.isEmpty()) {
+ throw new TelegramApiValidationException("ChatId can't be empty", this);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "GetChat{" +
+ "chatId='" + chatId + '\'' +
+ '}';
+ }
+}
diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/methods/groupadministration/SetChatStickerSet.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/methods/groupadministration/SetChatStickerSet.java
new file mode 100644
index 00000000..15fa288a
--- /dev/null
+++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/methods/groupadministration/SetChatStickerSet.java
@@ -0,0 +1,111 @@
+package org.telegram.telegrambots.api.methods.groupadministration;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.type.TypeReference;
+import org.telegram.telegrambots.api.methods.BotApiMethod;
+import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
+import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
+import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
+
+import java.io.IOException;
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * @author Ruben Bermudez
+ * @version 1.0
+ * Use this method to set a new group sticker set for a supergroup.
+ * The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
+ * Use the field can_set_sticker_set optionally returned in getChat requests to check if the bot can use this method.
+ * Returns True on success.
+ */
+public class SetChatStickerSet extends BotApiMethod {
+ public static final String PATH = "setChatStickerSet";
+
+ private static final String CHATID_FIELD = "chat_id";
+ private static final String STICKERSETNAME_FIELD = "sticker_set_name";
+
+ @JsonProperty(CHATID_FIELD)
+ private String chatId; ///< Unique identifier for the chat to send the message to (Or username for channels)
+ @JsonProperty(STICKERSETNAME_FIELD)
+ private String stickerSetName; ///< Name of the sticker set to be set as the group sticker set
+
+ public SetChatStickerSet() {
+ super();
+ }
+
+ public SetChatStickerSet(String chatId, String stickerSetName) {
+ super();
+ this.chatId = checkNotNull(chatId);
+ this.stickerSetName = checkNotNull(stickerSetName);
+ }
+
+ public SetChatStickerSet(Long chatId) {
+ super();
+ this.chatId = checkNotNull(chatId).toString();
+ }
+
+ public String getChatId() {
+ return chatId;
+ }
+
+ public SetChatStickerSet setChatId(String chatId) {
+ this.chatId = chatId;
+ return this;
+ }
+
+ public SetChatStickerSet setChatId(Long chatId) {
+ Objects.requireNonNull(chatId);
+ this.chatId = chatId.toString();
+ return this;
+ }
+
+ public String getStickerSetName() {
+ return stickerSetName;
+ }
+
+ public SetChatStickerSet setStickerSetName(String stickerSetName) {
+ Objects.requireNonNull(stickerSetName);
+ this.stickerSetName = stickerSetName;
+ return this;
+ }
+
+ @Override
+ public String getMethod() {
+ return PATH;
+ }
+
+ @Override
+ public Boolean deserializeResponse(String answer) throws TelegramApiRequestException {
+ try {
+ ApiResponse result = OBJECT_MAPPER.readValue(answer,
+ new TypeReference>(){});
+ if (result.getOk()) {
+ return result.getResult();
+ } else {
+ throw new TelegramApiRequestException("Error setting chat sticker set", result);
+ }
+ } catch (IOException e) {
+ throw new TelegramApiRequestException("Unable to deserialize response", e);
+ }
+ }
+
+ @Override
+ public void validate() throws TelegramApiValidationException {
+ if (chatId == null || chatId.isEmpty()) {
+ throw new TelegramApiValidationException("ChatId can't be empty", this);
+ }
+ if (stickerSetName == null || stickerSetName.isEmpty()) {
+ throw new TelegramApiValidationException("StickerSetName can't be empty", this);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "SetChatStickerSet{" +
+ "chatId='" + chatId + '\'' +
+ ", stickerSetName='" + stickerSetName + '\'' +
+ '}';
+ }
+}
diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/methods/send/SendLocation.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/methods/send/SendLocation.java
index 74f58ced..83d98a5e 100644
--- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/methods/send/SendLocation.java
+++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/methods/send/SendLocation.java
@@ -2,7 +2,6 @@ package org.telegram.telegrambots.api.methods.send;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
-
import org.telegram.telegrambots.api.methods.BotApiMethod;
import org.telegram.telegrambots.api.objects.Message;
import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
@@ -13,11 +12,12 @@ import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
import java.io.IOException;
import java.util.Objects;
+import static com.google.common.base.Preconditions.checkNotNull;
+
/**
* @author Ruben Bermudez
* @version 1.0
- * @brief Use this method to send point on the map. On success, the sent Message is returned.
- * @date 20 of June of 2015
+ * Use this method to send point on the map. On success, the sent Message is returned.
*/
public class SendLocation extends BotApiMethod {
public static final String PATH = "sendlocation";
@@ -28,6 +28,7 @@ public class SendLocation extends BotApiMethod {
private static final String DISABLENOTIFICATION_FIELD = "disable_notification";
private static final String REPLYTOMESSAGEID_FIELD = "reply_to_message_id";
private static final String REPLYMARKUP_FIELD = "reply_markup";
+ private static final String LIVEPERIOD_FIELD = "live_period";
@JsonProperty(CHATID_FIELD)
private String chatId; ///< Unique identifier for the chat to send the message to (Or username for channels)
@@ -41,11 +42,20 @@ public class SendLocation extends BotApiMethod {
private Integer replyToMessageId; ///< Optional. If the message is a reply, ID of the original message
@JsonProperty(REPLYMARKUP_FIELD)
private ReplyKeyboard replyMarkup; ///< Optional. JSON-serialized object for a custom reply keyboard
+ @JsonProperty(LIVEPERIOD_FIELD)
+ private Integer livePeriod; ///< Optional. Period in seconds for which the location will be updated (see Live Locations), should be between 60 and 86400.
public SendLocation() {
super();
}
+ public SendLocation(Float latitude, Float longitude) {
+ super();
+ this.latitude = checkNotNull(latitude);
+ this.longitude = checkNotNull(longitude);
+ }
+
+
public String getChatId() {
return chatId;
}
@@ -56,7 +66,6 @@ public class SendLocation extends BotApiMethod {
}
public SendLocation setChatId(Long chatId) {
- Objects.requireNonNull(chatId);
this.chatId = chatId.toString();
return this;
}
@@ -66,6 +75,7 @@ public class SendLocation extends BotApiMethod {
}
public SendLocation setLatitude(Float latitude) {
+ Objects.requireNonNull(latitude);
this.latitude = latitude;
return this;
}
@@ -75,6 +85,7 @@ public class SendLocation extends BotApiMethod {
}
public SendLocation setLongitude(Float longitude) {
+ Objects.requireNonNull(longitude);
this.longitude = longitude;
return this;
}
@@ -111,6 +122,15 @@ public class SendLocation extends BotApiMethod {
return this;
}
+ public Integer getLivePeriod() {
+ return livePeriod;
+ }
+
+ public SendLocation setLivePeriod(Integer livePeriod) {
+ this.livePeriod = livePeriod;
+ return this;
+ }
+
@Override
public String getMethod() {
return PATH;
@@ -145,6 +165,9 @@ public class SendLocation extends BotApiMethod {
if (replyMarkup != null) {
replyMarkup.validate();
}
+ if (livePeriod != null && (livePeriod < 60 || livePeriod > 86400)) {
+ throw new TelegramApiValidationException("Live period parameter must be between 60 and 86400", this);
+ }
}
@Override
@@ -153,8 +176,10 @@ public class SendLocation extends BotApiMethod {
"chatId='" + chatId + '\'' +
", latitude=" + latitude +
", longitude=" + longitude +
+ ", disableNotification=" + disableNotification +
", replyToMessageId=" + replyToMessageId +
", replyMarkup=" + replyMarkup +
+ ", livePeriod=" + livePeriod +
'}';
}
}
diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/methods/updatingmessages/EditMessageLiveLocation.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/methods/updatingmessages/EditMessageLiveLocation.java
new file mode 100644
index 00000000..2260b035
--- /dev/null
+++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/methods/updatingmessages/EditMessageLiveLocation.java
@@ -0,0 +1,192 @@
+package org.telegram.telegrambots.api.methods.updatingmessages;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.type.TypeReference;
+import org.telegram.telegrambots.api.methods.BotApiMethod;
+import org.telegram.telegrambots.api.objects.Message;
+import org.telegram.telegrambots.api.objects.replykeyboard.ApiResponse;
+import org.telegram.telegrambots.api.objects.replykeyboard.InlineKeyboardMarkup;
+import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
+import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Objects;
+
+/**
+ * @author Ruben Bermudez
+ * @version 1.0
+ * Use this method to edit live location messages sent by the bot or via the bot (for inline bots).
+ * A location can be edited until its live_period expires or editing is explicitly disabled by a call to
+ * stopMessageLiveLocation. On success, if the edited message was sent by the bot, the edited Message is returned,
+ * otherwise True is returned.
+ */
+public class EditMessageLiveLocation extends BotApiMethod {
+ public static final String PATH = "editMessageLiveLocation";
+
+ private static final String CHATID_FIELD = "chat_id";
+ private static final String MESSAGEID_FIELD = "message_id";
+ private static final String INLINE_MESSAGE_ID_FIELD = "inline_message_id";
+ private static final String LATITUDE_FIELD = "latitude";
+ private static final String LONGITUDE_FIELD = "longitude";
+ private static final String REPLYMARKUP_FIELD = "reply_markup";
+
+ /**
+ * Required if inline_message_id is not specified. Unique identifier for the chat to send the
+ * message to (Or username for channels)
+ */
+ @JsonProperty(CHATID_FIELD)
+ private String chatId;
+ /**
+ * Required if inline_message_id is not specified. Unique identifier of the sent message
+ */
+ @JsonProperty(MESSAGEID_FIELD)
+ private Integer messageId;
+ /**
+ * Required if chat_id and message_id are not specified. Identifier of the inline message
+ */
+ @JsonProperty(INLINE_MESSAGE_ID_FIELD)
+ private String inlineMessageId;
+ @JsonProperty(LATITUDE_FIELD)
+ private Float latitude; ///< Latitude of new location
+ @JsonProperty(LONGITUDE_FIELD)
+ private Float longitud; ///< Longitude of new location
+ @JsonProperty(REPLYMARKUP_FIELD)
+ private InlineKeyboardMarkup replyMarkup; ///< Optional. A JSON-serialized object for an inline keyboard.
+
+ public EditMessageLiveLocation() {
+ super();
+ }
+
+ public String getChatId() {
+ return chatId;
+ }
+
+ public EditMessageLiveLocation setChatId(String chatId) {
+ this.chatId = chatId;
+ return this;
+ }
+
+ public EditMessageLiveLocation setChatId(Long chatId) {
+ this.chatId = chatId.toString();
+ return this;
+ }
+
+ public Integer getMessageId() {
+ return messageId;
+ }
+
+ public EditMessageLiveLocation setMessageId(Integer messageId) {
+ this.messageId = messageId;
+ return this;
+ }
+
+ public String getInlineMessageId() {
+ return inlineMessageId;
+ }
+
+ public EditMessageLiveLocation setInlineMessageId(String inlineMessageId) {
+ this.inlineMessageId = inlineMessageId;
+ return this;
+ }
+
+ public InlineKeyboardMarkup getReplyMarkup() {
+ return replyMarkup;
+ }
+
+ public EditMessageLiveLocation setReplyMarkup(InlineKeyboardMarkup replyMarkup) {
+ this.replyMarkup = replyMarkup;
+ return this;
+ }
+
+ public Float getLatitude() {
+ return latitude;
+ }
+
+ public EditMessageLiveLocation setLatitude(Float latitude) {
+ Objects.requireNonNull(chatId);
+ this.latitude = latitude;
+ return this;
+ }
+
+ public Float getLongitud() {
+ return longitud;
+ }
+
+ public EditMessageLiveLocation setLongitud(Float longitud) {
+ Objects.requireNonNull(chatId);
+ this.longitud = longitud;
+ return this;
+ }
+
+ @Override
+ public String getMethod() {
+ return PATH;
+ }
+
+ @Override
+ public Serializable deserializeResponse(String answer) throws TelegramApiRequestException {
+ try {
+ ApiResponse result = OBJECT_MAPPER.readValue(answer,
+ new TypeReference>(){});
+ if (result.getOk()) {
+ return result.getResult();
+ } else {
+ throw new TelegramApiRequestException("Error editing message live location", result);
+ }
+ } catch (IOException e) {
+ try {
+ ApiResponse result = OBJECT_MAPPER.readValue(answer,
+ new TypeReference>() {
+ });
+ if (result.getOk()) {
+ return result.getResult();
+ } else {
+ throw new TelegramApiRequestException("Error editing message live location", result);
+ }
+ } catch (IOException e2) {
+ throw new TelegramApiRequestException("Unable to deserialize response", e);
+ }
+ }
+ }
+
+ @Override
+ public void validate() throws TelegramApiValidationException {
+ if (inlineMessageId == null) {
+ if (chatId == null) {
+ throw new TelegramApiValidationException("ChatId parameter can't be empty if inlineMessageId is not present", this);
+ }
+ if (messageId == null) {
+ throw new TelegramApiValidationException("MessageId parameter can't be empty if inlineMessageId is not present", this);
+ }
+ } else {
+ if (chatId != null) {
+ throw new TelegramApiValidationException("ChatId parameter must be empty if inlineMessageId is provided", this);
+ }
+ if (messageId != null) {
+ throw new TelegramApiValidationException("MessageId parameter must be empty if inlineMessageId is provided", this);
+ }
+ }
+ if (latitude == null) {
+ throw new TelegramApiValidationException("Latitude parameter can't be empty", this);
+ }
+ if (longitud == null) {
+ throw new TelegramApiValidationException("Longitud parameter can't be empty", this);
+ }
+ if (replyMarkup != null) {
+ replyMarkup.validate();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "EditMessageLiveLocation{" +
+ "chatId='" + chatId + '\'' +
+ ", messageId=" + messageId +
+ ", inlineMessageId='" + inlineMessageId + '\'' +
+ ", latitude=" + latitude +
+ ", longitud=" + longitud +
+ ", replyMarkup=" + replyMarkup +
+ '}';
+ }
+}
diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/objects/Chat.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/objects/Chat.java
index 0ac20c70..6d26e953 100644
--- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/objects/Chat.java
+++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/objects/Chat.java
@@ -22,6 +22,8 @@ public class Chat implements BotApiObject {
private static final String DESCRIPTION_FIELD = "description";
private static final String INVITELINK_FIELD = "invite_link";
private static final String PINNEDMESSAGE_FIELD = "pinned_message";
+ private static final String STICKERSETNAME_FIELD = "sticker_set_name";
+ private static final String CANSETSTICKERSET_FIELD = "can_set_sticker_set";
private static final String USERCHATTYPE = "private";
private static final String GROUPCHATTYPE = "group";
@@ -59,6 +61,10 @@ public class Chat implements BotApiObject {
private String inviteLink; ///< Optional. Chat invite link, for supergroups and channel chats. Returned only in getChat.
@JsonProperty(PINNEDMESSAGE_FIELD)
private Message pinnedMessage; ///< Optional. Pinned message, for supergroups. Returned only in getChat.
+ @JsonProperty(STICKERSETNAME_FIELD)
+ private String stickerSetName; ///< Optional. For supergroups, name of Group sticker set. Returned only in getChat.
+ @JsonProperty(CANSETSTICKERSET_FIELD)
+ private Message canSetStickerSet; ///< Optional. True, if the bot can change group the sticker set. Returned only in getChat.
public Chat() {
super();
@@ -120,6 +126,14 @@ public class Chat implements BotApiObject {
return pinnedMessage;
}
+ public String getStickerSetName() {
+ return stickerSetName;
+ }
+
+ public Message getCanSetStickerSet() {
+ return canSetStickerSet;
+ }
+
@Override
public String toString() {
return "Chat{" +
@@ -134,6 +148,8 @@ public class Chat implements BotApiObject {
", description='" + description + '\'' +
", inviteLink='" + inviteLink + '\'' +
", pinnedMessage=" + pinnedMessage +
+ ", stickerSetName='" + stickerSetName + '\'' +
+ ", canSetStickerSet=" + canSetStickerSet +
'}';
}
}
diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/objects/Message.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/objects/Message.java
index d396ce8a..b4d0fb37 100644
--- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/objects/Message.java
+++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/objects/Message.java
@@ -24,6 +24,7 @@ public class Message implements BotApiObject {
private static final String FORWARDDATE_FIELD = "forward_date";
private static final String TEXT_FIELD = "text";
private static final String ENTITIES_FIELD = "entities";
+ private static final String CAPTIONENTITIES_FIELD = "caption_entities";
private static final String AUDIO_FIELD = "audio";
private static final String DOCUMENT_FIELD = "document";
private static final String PHOTO_FIELD = "photo";
@@ -77,6 +78,12 @@ public class Message implements BotApiObject {
*/
@JsonProperty(ENTITIES_FIELD)
private List entities;
+ /**
+ * Optional. For messages with a caption, special entities like usernames,
+ * URLs, bot commands, etc. that appear in the caption
+ */
+ @JsonProperty(CAPTIONENTITIES_FIELD)
+ private List captionEntities;
@JsonProperty(AUDIO_FIELD)
private Audio audio; ///< Optional. Message is an audio file, information about the file
@JsonProperty(DOCUMENT_FIELD)
@@ -206,6 +213,13 @@ public class Message implements BotApiObject {
return entities;
}
+ public List getCaptionEntities() {
+ if (captionEntities != null) {
+ captionEntities.forEach(x -> x.computeText(caption));
+ }
+ return captionEntities;
+ }
+
public Audio getAudio() {
return audio;
}
@@ -390,6 +404,14 @@ public class Message implements BotApiObject {
return videoNote;
}
+ public String getAuthorSignature() {
+ return authorSignature;
+ }
+
+ public String getForwardSignature() {
+ return forwardSignature;
+ }
+
@Override
public String toString() {
return "Message{" +
@@ -402,6 +424,7 @@ public class Message implements BotApiObject {
", forwardDate=" + forwardDate +
", text='" + text + '\'' +
", entities=" + entities +
+ ", captionEntities=" + captionEntities +
", audio=" + audio +
", document=" + document +
", photo=" + photo +
@@ -430,6 +453,8 @@ public class Message implements BotApiObject {
", invoice=" + invoice +
", successfulPayment=" + successfulPayment +
", videoNote=" + videoNote +
+ ", authorSignature='" + authorSignature + '\'' +
+ ", forwardSignature='" + forwardSignature + '\'' +
'}';
}
}
diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/objects/inlinequery/inputmessagecontent/InputLocationMessageContent.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/objects/inlinequery/inputmessagecontent/InputLocationMessageContent.java
index cda61d2a..75fc3069 100644
--- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/objects/inlinequery/inputmessagecontent/InputLocationMessageContent.java
+++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/objects/inlinequery/inputmessagecontent/InputLocationMessageContent.java
@@ -4,33 +4,46 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
/**
* @author Ruben Bermudez
* @version 1.0
- * @brief Represents the content of a location message to be sent as the result of an inline query.
+ * Represents the content of a location message to be sent as the result of an inline query.
* @note This will only work in Telegram versions released after 9 April, 2016. Older clients will
* ignore them.
- * @date 10 of April of 2016
*/
public class InputLocationMessageContent implements InputMessageContent {
private static final String LATITUDE_FIELD = "latitude";
private static final String LONGITUDE_FIELD = "longitude";
+ private static final String LIVEPERIOD_FIELD = "live_period";
@JsonProperty(LATITUDE_FIELD)
private Float latitude; ///< Latitude of the location in degrees
@JsonProperty(LONGITUDE_FIELD)
private Float longitude; ///< Longitude of the location in degrees
+ @JsonProperty(LIVEPERIOD_FIELD)
+ private Integer livePeriod; ///< Optional. Period in seconds for which the location can be updated, should be between 60 and 86400.
public InputLocationMessageContent() {
super();
}
+ public InputLocationMessageContent(Float latitude, Float longitude) {
+ super();
+ this.latitude = checkNotNull(latitude);
+ this.longitude = checkNotNull(longitude);
+ }
+
public Float getLongitude() {
return longitude;
}
public InputLocationMessageContent setLongitude(Float longitude) {
+ Objects.requireNonNull(longitude);
this.longitude = longitude;
return this;
}
@@ -40,10 +53,20 @@ public class InputLocationMessageContent implements InputMessageContent {
}
public InputLocationMessageContent setLatitude(Float latitude) {
+ Objects.requireNonNull(latitude);
this.latitude = latitude;
return this;
}
+ public Integer getLivePeriod() {
+ return livePeriod;
+ }
+
+ public InputLocationMessageContent setLivePeriod(Integer livePeriod) {
+ this.livePeriod = livePeriod;
+ return this;
+ }
+
@Override
public void validate() throws TelegramApiValidationException {
if (latitude == null) {
@@ -52,13 +75,17 @@ public class InputLocationMessageContent implements InputMessageContent {
if (longitude == null) {
throw new TelegramApiValidationException("Longitude parameter can't be empty", this);
}
+ if (livePeriod != null && (livePeriod < 60 || livePeriod > 86400)) {
+ throw new TelegramApiValidationException("Live period parameter must be between 60 and 86400", this);
+ }
}
@Override
public String toString() {
return "InputLocationMessageContent{" +
- "latitude='" + latitude + '\'' +
- ", longitude='" + longitude + '\'' +
+ "latitude=" + latitude +
+ ", longitude=" + longitude +
+ ", livePeriod=" + livePeriod +
'}';
}
}
diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/objects/inlinequery/result/InlineQueryResultLocation.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/objects/inlinequery/result/InlineQueryResultLocation.java
index fa3b973d..a1ff830e 100644
--- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/objects/inlinequery/result/InlineQueryResultLocation.java
+++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/api/objects/inlinequery/result/InlineQueryResultLocation.java
@@ -9,12 +9,11 @@ import org.telegram.telegrambots.exceptions.TelegramApiValidationException;
/**
* @author Ruben Bermudez
* @version 1.0
- * @brief Represents a location on a map. By default, the location will be sent by the user.
+ * Represents a location on a map. By default, the location will be sent by the user.
* Alternatively, you can use input_message_content to send a message with the specified content
* instead of the location.
* @note This will only work in Telegram versions released after 9 April, 2016. Older clients will
* ignore them.
- * @date 10 of April of 2016
*/
public class InlineQueryResultLocation implements InlineQueryResult {
@@ -28,6 +27,7 @@ public class InlineQueryResultLocation implements InlineQueryResult {
private static final String THUMBURL_FIELD = "thumb_url";
private static final String THUMBWIDTH_FIELD = "thumb_width";
private static final String THUMBHEIGHT_FIELD = "thumb_height";
+ private static final String LIVEPERIOD_FIELD = "live_period";
@JsonProperty(TYPE_FIELD)
private final String type = "location"; ///< Type of the result, must be "location"
@@ -49,6 +49,8 @@ public class InlineQueryResultLocation implements InlineQueryResult {
private Integer thumbWidth; ///< Optional. Thumbnail width
@JsonProperty(THUMBHEIGHT_FIELD)
private Integer thumbHeight; ///< Optional. Thumbnail height
+ @JsonProperty(LIVEPERIOD_FIELD)
+ private Integer livePeriod; ///< Optional. Period in seconds for which the location can be updated, should be between 60 and 86400.
public InlineQueryResultLocation() {
super();
@@ -139,6 +141,15 @@ public class InlineQueryResultLocation implements InlineQueryResult {
return this;
}
+ public Integer getLivePeriod() {
+ return livePeriod;
+ }
+
+ public InlineQueryResultLocation setLivePeriod(Integer livePeriod) {
+ this.livePeriod = livePeriod;
+ return this;
+ }
+
@Override
public void validate() throws TelegramApiValidationException {
if (id == null || id.isEmpty()) {
@@ -153,6 +164,9 @@ public class InlineQueryResultLocation implements InlineQueryResult {
if (longitude == null) {
throw new TelegramApiValidationException("Longitude parameter can't be empty", this);
}
+ if (livePeriod != null && (livePeriod < 60 || livePeriod > 86400)) {
+ throw new TelegramApiValidationException("Live period parameter must be between 60 and 86400", this);
+ }
if (inputMessageContent != null) {
inputMessageContent.validate();
}
@@ -166,14 +180,15 @@ public class InlineQueryResultLocation implements InlineQueryResult {
return "InlineQueryResultLocation{" +
"type='" + type + '\'' +
", id='" + id + '\'' +
- ", mimeType='" + latitude + '\'' +
- ", documentUrl='" + longitude + '\'' +
- ", thumbHeight=" + thumbHeight +
- ", thumbWidth=" + thumbWidth +
- ", thumbUrl='" + thumbUrl + '\'' +
", title='" + title + '\'' +
- ", inputMessageContent='" + inputMessageContent + '\'' +
- ", replyMarkup='" + replyMarkup + '\'' +
+ ", latitude=" + latitude +
+ ", longitude=" + longitude +
+ ", replyMarkup=" + replyMarkup +
+ ", inputMessageContent=" + inputMessageContent +
+ ", thumbUrl='" + thumbUrl + '\'' +
+ ", thumbWidth=" + thumbWidth +
+ ", thumbHeight=" + thumbHeight +
+ ", livePeriod=" + livePeriod +
'}';
}
}
diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/generics/LongPollingBot.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/generics/LongPollingBot.java
index ce9bda79..32118616 100644
--- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/generics/LongPollingBot.java
+++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/generics/LongPollingBot.java
@@ -3,6 +3,8 @@ package org.telegram.telegrambots.generics;
import org.telegram.telegrambots.api.objects.Update;
import org.telegram.telegrambots.exceptions.TelegramApiRequestException;
+import java.util.List;
+
/**
* @author Ruben Bermudez
* @version 1.0
@@ -16,6 +18,15 @@ public interface LongPollingBot {
*/
void onUpdateReceived(Update update);
+ /**
+ * This method is called when receiving updates via GetUpdates method.
+ * If not reimplemented - it just sends updates by one into {@link #onUpdateReceived(Update)}
+ * @param updates list of Update received
+ */
+ default void onUpdatesReceived(List updates) {
+ updates.forEach(this::onUpdateReceived);
+ }
+
/**
* Return bot username of this bot
*/
diff --git a/telegrambots/pom.xml b/telegrambots/pom.xml
index 36e7b5f1..d514c5dd 100644
--- a/telegrambots/pom.xml
+++ b/telegrambots/pom.xml
@@ -5,7 +5,7 @@
4.0.0
org.telegram
telegrambots
- 3.3
+ 3.4
jar
Telegram Bots
@@ -66,7 +66,7 @@
2.8.7
2.8.0
2.5
- 3.3
+ 3.4
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 c4c09f29..82546c59 100644
--- a/telegrambots/src/main/java/org/telegram/telegrambots/bots/DefaultAbsSender.java
+++ b/telegrambots/src/main/java/org/telegram/telegrambots/bots/DefaultAbsSender.java
@@ -133,6 +133,7 @@ public abstract class DefaultAbsSender extends AbsSender {
HttpPost httppost = configuredHttpPost(url);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
+ builder.setLaxMode();
builder.setCharset(StandardCharsets.UTF_8);
builder.addTextBody(SendDocument.CHATID_FIELD, sendDocument.getChatId(), TEXT_PLAIN_CONTENT_TYPE);
if (sendDocument.isNewDocument()) {
@@ -177,6 +178,7 @@ public abstract class DefaultAbsSender extends AbsSender {
HttpPost httppost = configuredHttpPost(url);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
+ builder.setLaxMode();
builder.setCharset(StandardCharsets.UTF_8);
builder.addTextBody(SendPhoto.CHATID_FIELD, sendPhoto.getChatId(), TEXT_PLAIN_CONTENT_TYPE);
if (sendPhoto.isNewPhoto()) {
@@ -221,6 +223,7 @@ public abstract class DefaultAbsSender extends AbsSender {
HttpPost httppost = configuredHttpPost(url);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
+ builder.setLaxMode();
builder.setCharset(StandardCharsets.UTF_8);
builder.addTextBody(SendVideo.CHATID_FIELD, sendVideo.getChatId(), TEXT_PLAIN_CONTENT_TYPE);
if (sendVideo.isNewVideo()) {
@@ -274,6 +277,7 @@ public abstract class DefaultAbsSender extends AbsSender {
HttpPost httppost = configuredHttpPost(url);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
+ builder.setLaxMode();
builder.setCharset(StandardCharsets.UTF_8);
builder.addTextBody(SendVideoNote.CHATID_FIELD, sendVideoNote.getChatId(), TEXT_PLAIN_CONTENT_TYPE);
if (sendVideoNote.isNewVideoNote()) {
@@ -322,6 +326,7 @@ public abstract class DefaultAbsSender extends AbsSender {
HttpPost httppost = configuredHttpPost(url);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
+ builder.setLaxMode();
builder.setCharset(StandardCharsets.UTF_8);
builder.addTextBody(SendSticker.CHATID_FIELD, sendSticker.getChatId(), TEXT_PLAIN_CONTENT_TYPE);
if (sendSticker.isNewSticker()) {
@@ -367,6 +372,7 @@ public abstract class DefaultAbsSender extends AbsSender {
String url = getBaseUrl() + SendAudio.PATH;
HttpPost httppost = configuredHttpPost(url);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
+ builder.setLaxMode();
builder.setCharset(StandardCharsets.UTF_8);
builder.addTextBody(SendAudio.CHATID_FIELD, sendAudio.getChatId(), TEXT_PLAIN_CONTENT_TYPE);
if (sendAudio.isNewAudio()) {
@@ -426,6 +432,7 @@ public abstract class DefaultAbsSender extends AbsSender {
String url = getBaseUrl() + SendVoice.PATH;
HttpPost httppost = configuredHttpPost(url);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
+ builder.setLaxMode();
builder.setCharset(StandardCharsets.UTF_8);
builder.addTextBody(SendVoice.CHATID_FIELD, sendVoice.getChatId(), TEXT_PLAIN_CONTENT_TYPE);
if (sendVoice.isNewVoice()) {
@@ -473,6 +480,7 @@ public abstract class DefaultAbsSender extends AbsSender {
HttpPost httppost = configuredHttpPost(url);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
+ builder.setLaxMode();
builder.setCharset(StandardCharsets.UTF_8);
builder.addTextBody(SetChatPhoto.CHATID_FIELD, setChatPhoto.getChatId(), TEXT_PLAIN_CONTENT_TYPE);
if (setChatPhoto.getPhoto() != null) {
@@ -498,6 +506,7 @@ public abstract class DefaultAbsSender extends AbsSender {
String url = getBaseUrl() + AddStickerToSet.PATH;
HttpPost httppost = configuredHttpPost(url);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
+ builder.setLaxMode();
builder.setCharset(StandardCharsets.UTF_8);
builder.addTextBody(AddStickerToSet.USERID_FIELD, addStickerToSet.getUserId().toString(), TEXT_PLAIN_CONTENT_TYPE);
builder.addTextBody(AddStickerToSet.NAME_FIELD, addStickerToSet.getName(), TEXT_PLAIN_CONTENT_TYPE);
@@ -533,6 +542,7 @@ public abstract class DefaultAbsSender extends AbsSender {
String url = getBaseUrl() + CreateNewStickerSet.PATH;
HttpPost httppost = configuredHttpPost(url);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
+ builder.setLaxMode();
builder.setCharset(StandardCharsets.UTF_8);
builder.addTextBody(CreateNewStickerSet.USERID_FIELD, createNewStickerSet.getUserId().toString(), TEXT_PLAIN_CONTENT_TYPE);
builder.addTextBody(CreateNewStickerSet.NAME_FIELD, createNewStickerSet.getName(), TEXT_PLAIN_CONTENT_TYPE);
@@ -570,6 +580,7 @@ public abstract class DefaultAbsSender extends AbsSender {
String url = getBaseUrl() + UploadStickerFile.PATH;
HttpPost httppost = configuredHttpPost(url);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
+ builder.setLaxMode();
builder.setCharset(StandardCharsets.UTF_8);
builder.addTextBody(UploadStickerFile.USERID_FIELD, uploadStickerFile.getUserId().toString(), TEXT_PLAIN_CONTENT_TYPE);
if (uploadStickerFile.getNewPngStickerFile() != null) {
diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/bots/TelegramLongPollingBot.java b/telegrambots/src/main/java/org/telegram/telegrambots/bots/TelegramLongPollingBot.java
index ef2eb08f..50da8e71 100644
--- a/telegrambots/src/main/java/org/telegram/telegrambots/bots/TelegramLongPollingBot.java
+++ b/telegrambots/src/main/java/org/telegram/telegrambots/bots/TelegramLongPollingBot.java
@@ -22,9 +22,8 @@ import java.nio.charset.StandardCharsets;
/**
* @author Ruben Bermudez
* @version 1.0
- * @brief Base abstract class for a bot that will get updates using
+ * Base abstract class for a bot that will get updates using
* long-polling method
- * @date 14 of January of 2016
*/
public abstract class TelegramLongPollingBot extends DefaultAbsSender implements LongPollingBot {
public TelegramLongPollingBot() {
diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/DefaultBotSession.java b/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/DefaultBotSession.java
index 1347e03a..23f5b618 100644
--- a/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/DefaultBotSession.java
+++ b/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/DefaultBotSession.java
@@ -27,7 +27,7 @@ import java.io.InvalidObjectException;
import java.net.SocketTimeoutException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidParameterException;
-import java.util.List;
+import java.util.*;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.TimeUnit;
@@ -52,6 +52,7 @@ public class DefaultBotSession implements BotSession {
private String token;
private int lastReceivedUpdate = 0;
private DefaultBotOptions options;
+ private UpdatesSupplier updatesSupplier;
@Inject
public DefaultBotSession() {
@@ -67,7 +68,7 @@ public class DefaultBotSession implements BotSession {
lastReceivedUpdate = 0;
- readerThread = new ReaderThread();
+ readerThread = new ReaderThread(updatesSupplier);
readerThread.setName(callback.getBotUsername() + " Telegram Connection");
readerThread.start();
@@ -97,6 +98,10 @@ public class DefaultBotSession implements BotSession {
}
}
+ public void setUpdatesSupplier(UpdatesSupplier updatesSupplier) {
+ this.updatesSupplier = updatesSupplier;
+ }
+
@Override
public void setOptions(BotOptions options) {
if (this.options != null) {
@@ -127,10 +132,16 @@ public class DefaultBotSession implements BotSession {
}
private class ReaderThread extends Thread implements UpdatesReader {
+
+ private final UpdatesSupplier updatesSupplier;
private CloseableHttpClient httpclient;
private ExponentialBackOff exponentialBackOff;
private RequestConfig requestConfig;
+ public ReaderThread(UpdatesSupplier updatesSupplier) {
+ this.updatesSupplier = Optional.ofNullable(updatesSupplier).orElse(this::getUpdatesFromServer);
+ }
+
@Override
public synchronized void start() {
httpclient = HttpClientBuilder.create()
@@ -172,62 +183,23 @@ public class DefaultBotSession implements BotSession {
setPriority(Thread.MIN_PRIORITY);
while (running) {
try {
- GetUpdates request = new GetUpdates()
- .setLimit(100)
- .setTimeout(ApiConstants.GETUPDATES_TIMEOUT)
- .setOffset(lastReceivedUpdate + 1);
-
- if (options.getAllowedUpdates() != null) {
- request.setAllowedUpdates(options.getAllowedUpdates());
- }
-
- String url = options.getBaseUrl() + token + "/" + GetUpdates.PATH;
- //http client
- HttpPost httpPost = new HttpPost(url);
- httpPost.addHeader("charset", StandardCharsets.UTF_8.name());
- httpPost.setConfig(requestConfig);
- httpPost.setEntity(new StringEntity(objectMapper.writeValueAsString(request), ContentType.APPLICATION_JSON));
-
- try (CloseableHttpResponse response = httpclient.execute(httpPost)) {
- HttpEntity ht = response.getEntity();
- BufferedHttpEntity buf = new BufferedHttpEntity(ht);
- String responseContent = EntityUtils.toString(buf, StandardCharsets.UTF_8);
-
- if (response.getStatusLine().getStatusCode() >= 500) {
- BotLogger.warn(LOGTAG, responseContent);
- synchronized (this) {
- this.wait(500);
- }
- } else {
- try {
- List updates = request.deserializeResponse(responseContent);
- exponentialBackOff.reset();
-
- if (updates.isEmpty()) {
- synchronized (this) {
- this.wait(500);
- }
- } else {
- updates.removeIf(x -> x.getUpdateId() < lastReceivedUpdate);
- lastReceivedUpdate = updates.parallelStream()
- .map(
- Update::getUpdateId)
- .max(Integer::compareTo)
- .orElse(0);
- receivedUpdates.addAll(updates);
-
- synchronized (receivedUpdates) {
- receivedUpdates.notifyAll();
- }
- }
- } catch (JSONException e) {
- BotLogger.severe(responseContent, LOGTAG, e);
- }
+ List updates = updatesSupplier.getUpdates();
+ if (updates.isEmpty()) {
+ synchronized (this) {
+ this.wait(500);
+ }
+ } else {
+ updates.removeIf(x -> x.getUpdateId() < lastReceivedUpdate);
+ lastReceivedUpdate = updates.parallelStream()
+ .map(
+ Update::getUpdateId)
+ .max(Integer::compareTo)
+ .orElse(0);
+ receivedUpdates.addAll(updates);
+
+ synchronized (receivedUpdates) {
+ receivedUpdates.notifyAll();
}
- } catch (SocketTimeoutException e) {
- BotLogger.fine(LOGTAG, e);
- } catch (InvalidObjectException | TelegramApiRequestException e) {
- BotLogger.severe(LOGTAG, e);
}
} catch (InterruptedException e) {
if (!running) {
@@ -250,6 +222,64 @@ public class DefaultBotSession implements BotSession {
}
BotLogger.debug(LOGTAG, "Reader thread has being closed");
}
+
+ private List getUpdatesFromServer() throws InterruptedException, Exception {
+ GetUpdates request = new GetUpdates()
+ .setLimit(100)
+ .setTimeout(ApiConstants.GETUPDATES_TIMEOUT)
+ .setOffset(lastReceivedUpdate + 1);
+
+ if (options.getAllowedUpdates() != null) {
+ request.setAllowedUpdates(options.getAllowedUpdates());
+ }
+
+ String url = options.getBaseUrl() + token + "/" + GetUpdates.PATH;
+ //http client
+ HttpPost httpPost = new HttpPost(url);
+ httpPost.addHeader("charset", StandardCharsets.UTF_8.name());
+ httpPost.setConfig(requestConfig);
+ httpPost.setEntity(new StringEntity(objectMapper.writeValueAsString(request), ContentType.APPLICATION_JSON));
+
+ try (CloseableHttpResponse response = httpclient.execute(httpPost)) {
+ HttpEntity ht = response.getEntity();
+ BufferedHttpEntity buf = new BufferedHttpEntity(ht);
+ String responseContent = EntityUtils.toString(buf, StandardCharsets.UTF_8);
+
+ if (response.getStatusLine().getStatusCode() >= 500) {
+ BotLogger.warn(LOGTAG, responseContent);
+ synchronized (this) {
+ this.wait(500);
+ }
+ } else {
+ try {
+ List updates = request.deserializeResponse(responseContent);
+ exponentialBackOff.reset();
+ return updates;
+ } catch (JSONException e) {
+ BotLogger.severe(responseContent, LOGTAG, e);
+ }
+ }
+ } catch (SocketTimeoutException e) {
+ BotLogger.fine(LOGTAG, e);
+ } catch (InvalidObjectException | TelegramApiRequestException e) {
+ BotLogger.severe(LOGTAG, e);
+ }
+ return Collections.emptyList();
+ }
+ }
+
+ public interface UpdatesSupplier {
+
+ List getUpdates() throws InterruptedException, Exception;
+ }
+
+ private List getUpdateList() {
+ List updates = new ArrayList<>();
+ for (Iterator it = receivedUpdates.iterator(); it.hasNext();) {
+ updates.add(it.next());
+ it.remove();
+ }
+ return updates;
}
private class HandlerThread extends Thread implements UpdatesHandler {
@@ -258,17 +288,17 @@ public class DefaultBotSession implements BotSession {
setPriority(Thread.MIN_PRIORITY);
while (running) {
try {
- Update update = receivedUpdates.pollLast();
- if (update == null) {
+ List updates = getUpdateList();
+ if (updates.isEmpty()) {
synchronized (receivedUpdates) {
receivedUpdates.wait();
- update = receivedUpdates.pollLast();
- if (update == null) {
+ updates = getUpdateList();
+ if (updates.isEmpty()) {
continue;
}
}
}
- callback.onUpdateReceived(update);
+ callback.onUpdatesReceived(updates);
} catch (InterruptedException e) {
BotLogger.debug(LOGTAG, e);
} catch (Exception e) {
diff --git a/telegrambots/src/test/java/org/telegram/telegrambots/test/TelegramLongPollingBotTest.java b/telegrambots/src/test/java/org/telegram/telegrambots/test/TelegramLongPollingBotTest.java
new file mode 100644
index 00000000..23dbfc6d
--- /dev/null
+++ b/telegrambots/src/test/java/org/telegram/telegrambots/test/TelegramLongPollingBotTest.java
@@ -0,0 +1,24 @@
+package org.telegram.telegrambots.test;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.telegram.telegrambots.api.objects.Update;
+import org.telegram.telegrambots.bots.TelegramLongPollingBot;
+
+import static java.util.Arrays.asList;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyList;
+
+public class TelegramLongPollingBotTest {
+
+ @Test
+ public void testOnUpdateReceived() throws Exception {
+ TelegramLongPollingBot bot = Mockito.mock(TelegramLongPollingBot.class);
+ Mockito.doCallRealMethod().when(bot).onUpdatesReceived(any());
+ Update update1 = new Update();
+ Update update2 = new Update();
+ bot.onUpdatesReceived(asList(update1, update2));
+ Mockito.verify(bot).onUpdateReceived(update1);
+ Mockito.verify(bot).onUpdateReceived(update2);
+ }
+}
\ No newline at end of file
diff --git a/telegrambots/src/test/java/org/telegram/telegrambots/test/TestDefaultBotSession.java b/telegrambots/src/test/java/org/telegram/telegrambots/test/TestDefaultBotSession.java
index c37fd5a6..17d4aa65 100644
--- a/telegrambots/src/test/java/org/telegram/telegrambots/test/TestDefaultBotSession.java
+++ b/telegrambots/src/test/java/org/telegram/telegrambots/test/TestDefaultBotSession.java
@@ -11,12 +11,20 @@ import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.Matchers;
import org.mockito.Mockito;
+import org.telegram.telegrambots.api.objects.Update;
import org.telegram.telegrambots.bots.DefaultBotOptions;
+import org.telegram.telegrambots.generics.LongPollingBot;
import org.telegram.telegrambots.test.Fakes.FakeLongPollingBot;
import org.telegram.telegrambots.updatesreceivers.DefaultBotSession;
import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.IntStream;
/**
* @author Ruben Bermudez
@@ -79,7 +87,85 @@ public class TestDefaultBotSession {
session.stop();
}
+ @Test
+ public void testUpdates() throws Exception {
+ LongPollingBot bot = Mockito.spy(new FakeLongPollingBot());
+ session = getDefaultBotSession(bot);
+ AtomicInteger flag = new AtomicInteger();
+ Update[] updates = createFakeUpdates(9);
+ session.setUpdatesSupplier(createFakeUpdatesSupplier(flag, updates));
+ session.start();
+ Thread.sleep(1000);
+ Mockito.verify(bot, Mockito.never()).onUpdateReceived(Matchers.any());
+ flag.compareAndSet(0, 1);
+ Thread.sleep(1000);
+ Mockito.verify(bot).onUpdateReceived(updates[0]);
+ Mockito.verify(bot).onUpdateReceived(updates[1]);
+ flag.compareAndSet(2, 3);
+ Thread.sleep(1000);
+ Mockito.verify(bot).onUpdateReceived(updates[2]);
+ Mockito.verify(bot).onUpdateReceived(updates[3]);
+ Mockito.verify(bot).onUpdateReceived(updates[4]);
+ flag.compareAndSet(4, 5);
+ Thread.sleep(1000);
+ Mockito.verify(bot).onUpdateReceived(updates[5]);
+ Mockito.verify(bot).onUpdateReceived(updates[6]);
+ Mockito.verify(bot).onUpdateReceived(updates[7]);
+ Mockito.verify(bot).onUpdateReceived(updates[8]);
+ session.stop();
+ }
+
+ @Test
+ public void testBatchUpdates() throws Exception {
+ LongPollingBot bot = Mockito.spy(new FakeLongPollingBot());
+ session = getDefaultBotSession(bot);
+ AtomicInteger flag = new AtomicInteger();
+ Update[] updates = createFakeUpdates(9);
+ session.setUpdatesSupplier(createFakeUpdatesSupplier(flag, updates));
+ session.start();
+ Thread.sleep(1000);
+ Mockito.verify(bot, Mockito.never()).onUpdateReceived(Matchers.any());
+ flag.compareAndSet(0, 1);
+ Thread.sleep(1000);
+ Mockito.verify(bot).onUpdatesReceived(Arrays.asList(updates[0], updates[1]));
+ flag.compareAndSet(2, 3);
+ Thread.sleep(1000);
+ Mockito.verify(bot).onUpdatesReceived(Arrays.asList(updates[2], updates[3], updates[4]));
+ flag.compareAndSet(4, 5);
+ Thread.sleep(1000);
+ Mockito.verify(bot).onUpdatesReceived(Arrays.asList(updates[5], updates[6], updates[7], updates[8]));
+ session.stop();
+ }
+
+ private Update[] createFakeUpdates(int count) {
+ return IntStream.range(0, count).mapToObj(x -> {
+ Update mock = Mockito.mock(Update.class);
+ Mockito.when(mock.getUpdateId()).thenReturn(x);
+ return mock;
+ }).toArray(Update[]::new);
+ }
+
+ private DefaultBotSession.UpdatesSupplier createFakeUpdatesSupplier(AtomicInteger flag, Update[] updates) {
+ return new DefaultBotSession.UpdatesSupplier() {
+ @Override
+ public List getUpdates() throws InterruptedException, Exception {
+ if (flag.compareAndSet(1, 2)) {
+ return Arrays.asList(updates[0], updates[1]);
+ } else if (flag.compareAndSet(3, 4)) {
+ return Arrays.asList(updates[2], updates[3], updates[4]);
+ } else if (flag.compareAndSet(5, 6)) {
+ return Arrays.asList(updates[5], updates[6], updates[7], updates[8]);
+ }
+ return Collections.emptyList();
+ }
+ };
+ }
+
private DefaultBotSession getDefaultBotSession() throws IOException {
+ return getDefaultBotSession(new FakeLongPollingBot());
+ }
+
+ private DefaultBotSession getDefaultBotSession(LongPollingBot bot) throws IOException {
HttpResponse response = new BasicHttpResponse(new BasicStatusLine(
new ProtocolVersion("HTTP", 1, 1), 200, ""));
response.setStatusCode(200);
@@ -89,7 +175,7 @@ public class TestDefaultBotSession {
Mockito.when(mockHttpClient.execute(Mockito.any(HttpPost.class)))
.thenReturn(response);
DefaultBotSession session = new DefaultBotSession();
- session.setCallback(new FakeLongPollingBot());
+ session.setCallback(bot);
session.setOptions(new DefaultBotOptions());
return session;
}