How do I save the id from chatid with the telegram api - java

Hello. I'm trying to solve this problem for a while now. For some
reason I keep getting null pointer exception when I try to save a
object in my repository. Below you can see what happens and my
functions.
java.lang.NullPointerException at com.br.einstein.api.service.ApiTelegram.sendMsg(ApiTelegram.java:104)
at
com.br.einstein.api.service.ApiTelegram.onUpdateReceived(ApiTelegram.java:81)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1541) at
org.telegram.telegrambots.meta.generics.LongPollingBot.onUpdatesReceived(LongPollingBot.java:27)
at
org.telegram.telegrambots.updatesreceivers.DefaultBotSession$HandlerThread.run(DefaultBotSession.java:317)
public void onUpdateReceived(Update update) {
ApiEinstein api = new ApiEinstein();
try {
JsonObject objSession = api.getSessionDetails();
String message = update.getMessage().getText();
api.sendChatRequest(objSession);
List < String > list = new ApiEinstein().ReadChatDetails(objSession);
sendMsg(update.getMessage().getChatId().toString(), list.toString());
new ApiEinstein().SendChatMessage(objSession, message);
api.syncChatSession(objSession);
} catch (Exception e) {
e.printStackTrace();
}
}
public synchronized void sendMsg(String chatId, String s) {
SendMessage sendMessage = new SendMessage();
// sendMessage.enableMarkdown(true);
sendMessage.setChatId(chatId);
sendMessage.setText(s);
long id = Long.valueOf(chatId);
Telegram telegram = new Telegram();
telegram.setChatId(id);
repository.save(telegram);
try {
execute(sendMessage);
} catch (TelegramApiException e) {
e.printStackTrace();
}
} ```

Related

How can I answer to callback in Java telegram bot?

I'm writing a Java bot with https://github.com/rubenlagus/TelegramBots, and I have a problem, when I click inline keyboard button, this little clock:
appears and after some time it says that my bot is not responding. My bot is actually fully functional except this one thing. Here is how I receive callbacks:
#Override
public void onUpdateReceived(Update update) {
var messagesToSend = updateReceiver.handle(update);
if (messagesToSend != null && !messagesToSend.isEmpty()) {
messagesToSend.forEach(response -> {
if (response instanceof SendMessage) {
try {
execute((SendMessage) response);
} catch (TelegramApiException e) {
e.printStackTrace();
}
} else if (response instanceof SendPhoto) {
try {
execute((SendPhoto) response);
} catch (TelegramApiException e) {
e.printStackTrace();
}
} else if (response instanceof FileSaveRequest) {
FileSaveRequest request = (FileSaveRequest) response;
try {
saveFile(request);
} catch (TelegramApiException | IOException e) {
e.printStackTrace();
}
}
});
}
}
=
This is only part of the whole code
} else if (update.hasCallbackQuery()) {
final CallbackQuery callbackQuery = update.getCallbackQuery();
final long chatId = callbackQuery.getFrom().getId();
final User user = userRepository.findById(chatId)
.orElseGet(() -> userRepository.save(new User(chatId)));
AnswerCallbackQuery acceptCallback = new AnswerCallbackQuery();
acceptCallback.setShowAlert(false);
acceptCallback.setCallbackQueryId(String.valueOf(update.getCallbackQuery().getId()));
acceptCallback.setCacheTime(1000);
List<PartialBotApiMethod<? extends Serializable>> resultList =
new ArrayList<>(
getHandlerByCallBackQuery(callbackQuery.getData())
.handle(user, callbackQuery.getData()));
resultList.add(acceptCallback);
return resultList;
}
As you can see, I still attach AnswerCallbackQuery but it still doesent work. What's wrong?
you must use answercallbackquery
I just already solve that issue. It's not problem on Library but it could error in some exceptions.
var messagesToSend = updateReceiver.handle(update);
if (messagesToSend != null && !messagesToSend.isEmpty()) {
I dont have full your code but I think there's some confused written and happen exception before if (update.callbackQuery())...
Here is my sample:
#Override
public void onUpdateReceived(Update update) {
// I have error, cannot getCallbackQuery because of print which call method getMessage.getText() is null -> happen exception error on the println
// -> System.out.println(update.getMessage.getText());
if (update.hasMessage() && !update.getMessage().getText().isEmpty()) {
String chat_id = update.getMessage().getChatId().toString();
if (update.getMessage().getText().equals("/start")) {
SendMessage sendMessage = new SendMessage();
sendMessage.setText("Here is option:");
sendMessage.setChatId(chat_id);
sendMessage.setParseMode(ParseMode.MARKDOWN);
InlineKeyboardMarkup inlineKeyboardMarkup = new InlineKeyboardMarkup();
List<List<InlineKeyboardButton>> listInlineButton = new ArrayList<>();
List<InlineKeyboardButton> reportSaleBtn = new ArrayList<>();
List<InlineKeyboardButton> reportBuyBtn = new ArrayList<>();
List<InlineKeyboardButton> reportPriceBtn = new ArrayList<>();
InlineKeyboardButton saleBtn = new InlineKeyboardButton();
InlineKeyboardButton buyBtn = new InlineKeyboardButton();
InlineKeyboardButton priceBtn = new InlineKeyboardButton();
saleBtn.setText(Constant.SALE_REPORT_TEXT);
saleBtn.setCallbackData(Constant.SALE_REPORT);
buyBtn.setText(Constant.BUY_REPORT_TEXT);
buyBtn.setCallbackData(Constant.BUY_REPORT);
priceBtn.setText(Constant.PRICE_TEXT);
priceBtn.setCallbackData(Constant.PRICE_REPORT);
reportSaleBtn.add(saleBtn);
reportBuyBtn.add(buyBtn);
reportPriceBtn.add(priceBtn);
listInlineButton.add(reportSaleBtn);
listInlineButton.add(reportBuyBtn);
listInlineButton.add(reportPriceBtn);
inlineKeyboardMarkup.setKeyboard(listInlineButton);
sendMessage.setReplyMarkup(inlineKeyboardMarkup);
try {
execute(sendMessage);
} catch (TelegramApiException e) {
e.printStackTrace();
}
}
}
else if (update.hasCallbackQuery()) {
CallbackQuery callbackQuery = update.getCallbackQuery();
String data = callbackQuery.getData();
String chat_id = callbackQuery.getMessage().getChat().getId().toString();
SendChatAction sendChatAction = new SendChatAction();
if (data.equals(Constant.SALE_REPORT)) {
sendChatAction.setChatId(chat_id);
SendMessage sendMessage = new SendMessage();
sendMessage.setText("Generating report, please wait!");
sendMessage.setChatId(chat_id);
try {
sendChatAction.setAction(ActionType.TYPING);
execute(sendChatAction);
execute(sendMessage);
} catch (TelegramApiException e) {
e.printStackTrace();
}
}
}
Why it got an error. Click we click on /start Bot will display all inlinekeyboard.
In the button you only setText() and setCallbackData(). So update.GetMessage() is null.
In while update.getMessage().getText() is null cannot print out. So it is error and it skip the else if (update.hasCallbackQuery()) {...}
I think you can check again your code below:
#Override
public void onUpdateReceived(Update update) {
//check carefully before if may there's exception error before if
}
I hope what I explain may solve your problems too.

How to extract try catch outside method?

I have this method sendParameterValueAsMQTTMessage() which I use to publish message via MQTT on a specific topic. I am using try catch two times after another (not nested) but it still seems somewhat ugly and overcrowding the method. I read an article on clean code where Uncle Bob talks about extracting the body of try catch but I seem to not grasp it quite well or at least not in my case.
How could I get rid of the try catch in my method by extracting it outside?
public void sendParameterValueAsMQTTMessage() {
String payload = null;
try {
payload = convertToJSONString("range", String.valueOf(range));
} catch (JSONException e) {
this.logger.log(Level.ERROR, e);
}
MQTTMessage message = new MQTTMessage(MQTTTopics.RANGE_TOPIC,payload,0);
try {
this.client.publish(message);
Thread.sleep(3000);
} catch (Exception e) {
this.logger.log(Level.ERROR, e);
}
}
there are multiple different problems with provided code, here is how I'd refactor it:
public void sendParameterValueAsMQTTMessage() {
final String payload = tryGetPayloadAsJson();
if (payload != null) {
trySendPayloadViaMQTT(payload);
}
}
private String tryGetPayloadAsJson() {
try {
return convertToJSONString("range", String.valueOf(range));
} catch (JSONException e) {
this.logger.log(Level.ERROR, e);
}
return null;
}
private void trySendPayloadViaMQTT(final String payload) {
try {
final MQTTMessage message = new MQTTMessage(MQTTTopics.RANGE_TOPIC, payload, 0);
this.client.publish(message);
Thread.sleep(3000);
} catch (Exception e) {
this.logger.log(Level.ERROR, e);
}
}
one thing which might be improved here based on Uncle Bob's advice is to actually move try/catch outside of trySendPayloadViaMQTT, like this:
public void sendParameterValueAsMQTTMessage() {
final String payload = tryGetPayloadAsJson();
if (payload != null) {
trySendPayloadViaMQTT(payload);
}
}
private String tryGetPayloadAsJson() {
try {
return convertToJSONString("range", String.valueOf(range));
} catch (JSONException e) {
this.logger.log(Level.ERROR, e);
}
return null;
}
private void trySendPayloadViaMQTT(final String payload) {
try {
sendPayloadViaMQTT(payload);
} catch (Exception e) {
this.logger.log(Level.ERROR, e);
}
}
private void sendPayloadViaMQTT(final String payload) {
final MQTTMessage message = new MQTTMessage(MQTTTopics.RANGE_TOPIC, payload, 0);
this.client.publish(message);
Thread.sleep(3000);
}
you can put all of your code in just one try block and set multiple catches, when ever an exception be happened, the catch that is revelated to it will be execute, like:
try{
int a[]=new int[5];
a[5]=30/0;
}
catch(ArithmeticException e)
{
System.out.println("Arithmetic Exception occurs");
}
catch(ArrayIndexOutOfBoundsException e)
{
System.out.println("ArrayIndexOutOfBounds Exception occurs");
}
You can use single general catch for both possible exceptions inside the method as following:
public void sendParameterValueAsMQTTMessage() {
String payload = null;
try {
payload = convertToJSONString("range", String.valueOf(range));
MQTTMessage message = new MQTTMessage(MQTTTopics.RANGE_TOPIC,payload,0);
this.client.publish(message);
Thread.sleep(3000);
} catch (Exception e) {
this.logger.log(Level.ERROR, e);
}
}
public void sendParameterValueAsMQTTMessage() {
String payload = null;
try {
payload = convertToJSONString("range", String.valueOf(range));
} catch (JSONException e) {
this.logger.log(Level.ERROR, e);
}
MQTTMessage message = new MQTTMessage(MQTTTopics.RANGE_TOPIC,payload,0);
publishMessage(message); //extracted in a new method
}
public void publishMessage(MQTTMessage message){
try {
this.client.publish(message);
Thread.sleep(3000);
} catch (Exception e) {
this.logger.log(Level.ERROR, e);
}
}

JAVA Telegram bots api Error getting updates: Conflict: terminated by other long poll or webhook

I am using JAVA Telegram Bot API with Spring framework , I had a method in my HomeController and i had a class that handle all of the incoming messages from users. I got these errors in my spring log,then i got duplicated response from telegram bot API .whats is the problem ?
#PostConstruct
public void initBots() {
ApiContextInitializer.init();
TelegramBotsApi botsApi = new TelegramBotsApi();
BotService botService = new BotService();
try {
botsApi.registerBot(botService);
} catch (TelegramApiException e) {
e.printStackTrace();
}
}
[abrsystem1_bot Telegram Connection] org.telegram.telegrambots.logging.BotLogger.severe
BOTSESSION
org.telegram.telegrambots.exceptions.TelegramApiRequestException:
Error getting updates: [409] Conflict: terminated by other long poll
or webhook at
org.telegram.telegrambots.api.methods.updates.GetUpdates.deserializeResponse(GetUpdates.java:119)
at
org.telegram.telegrambots.updatesreceivers.DefaultBotSession$ReaderThread.getUpdatesFromServer(DefaultBotSession.java:255)
at
org.telegram.telegrambots.updatesreceivers.DefaultBotSession$ReaderThread.run(DefaultBotSession.java:186)
#Override
public void onUpdateReceived(Update update) {
try {
if (update.hasMessage() && update.getMessage().hasText()) {
String message_text = update.getMessage().getText();
String wellcome_text = "برای ثبت نام در سایت شماره تلفن همراه خود را به اشتراک بگذارید";
long chat_id = update.getMessage().getChatId();
if (message_text.equals("/start")) {
try {
SendMessage message = new SendMessage()
.setChatId(chat_id)
.setText(wellcome_text);
ReplyKeyboardMarkup keyboardMarkup = new ReplyKeyboardMarkup();
List<KeyboardRow> keyboard = new ArrayList<KeyboardRow>();
KeyboardRow row = new KeyboardRow();
row.add((new KeyboardButton().setText("اشتراک شماره موبایل").setRequestContact(true)));
keyboard.add(row);
keyboardMarkup.setKeyboard(keyboard);
message.setReplyMarkup(keyboardMarkup);
try {
execute(message);
} catch (TelegramApiException e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
} else if (message_text.equals("تایید مشخصات کاربری")) {
SendMessage sendMessage = new SendMessage();
sendMessage.setChatId(chat_id).setText("اطلاعات مورد تایید قرار گرفت");
try {
execute(sendMessage);
removeMarker(chat_id);
showContactInfo(chat_id, update);
} catch (Exception ex) {
ex.printStackTrace();
}
} else if (message_text.equals("تغییر مشخصات")) {
} else {
showUnknownCommand(chat_id);
}
} else if (update.getMessage().getContact() != null && update.getMessage().getChat() != null) {
long chat_id = update.getMessage().getChatId();
showContactInfo(chat_id, update);
}
} catch (Exception e) {
e.printStackTrace();
}
}
I finally solved my problem after a day!when i was debugging my project with intellij idea on my computer , i created many instances for debug so i got multiple response from same chat id in telegram bot.so boring problem....

Some server generated events do not get delivered to the client in production over websockets

Bottom line:
Some server generated events do not get delivered to the client in production over websockets. However, the websocket connections get established just fine.
Case study:
I open Google Chrome and connect to our server. Open the devtools. Under WS tab, I see that connection got established fine, but I receive no frames when, let’s say, server needs to update something on the page. I wait for a while and sometimes (only sometimes) I get some events with a huge amount of delay. This works as expected locally however.
Question:
Has anyone seen similar websocket behavior and has any suggestions on how to eliminate variables for this investigation.
Infrastructure:
Server: Linux Tomcat
Two servers that handle:
1. Traffic from Devices (Communicating over TCP/IP with the Server)
2. Traffic from Users
Users and Devices are many to many relationship. If a user gets connected to a server that doesn’t have a device connected. This server looks on the other server and handles the info exchange.
There is a firewall in front of the servers.
Code:
https://github.com/kino6052/websockets-issue
WebSocketServerEndpoint.java
#ServerEndpoint("/actions")
public class WebSocketServerEndpoint {
static private final org.slf4j.Logger logger = LoggerFactory.getLogger(WebSocketServerEndpoint.class);
#OnOpen
public void open(Session session) {
WebSocketSessionHandler.addSession(session);
}
#OnClose
public void close(Session session) {
WebSocketSessionHandler.removeSession(session);
}
#OnError
public void onError(Throwable error) {
//Logger.getLogger(WebSocketServerEndpoint.class.getName()).log(Level.SEVERE, null, error);
}
#OnMessage
public void handleMessage(String message, Session session) {
try (JsonReader reader = Json.createReader(new StringReader(message))) {
JsonObject jsonMessage = reader.readObject();
Long userId = null;
Long tenantId = null;
switch (WebSocketActions.valueOf(jsonMessage.getString("action"))){
case SaveUserId:
userId = getUserId(jsonMessage);
tenantId = getTenantId(jsonMessage);
Long userIdKey = WebSocketSessionHandler.saveUserId(userId, session);
Long tenantUserKey = WebSocketSessionHandler.saveTenantUser(tenantId, userId);
WebSocketSessionHandler.updateUserSessionKeys(session, tenantUserKey, userIdKey); // Needed for Making Weak Maps Keep Their Keys if Session is Currently Active
}
} catch (Exception e) {
logger.error(e.toString());
}
}
private Long getUserId(JsonObject jsonMessage) {
Long userId = null;
try {
userId = Long.parseLong(((Integer) jsonMessage.getInt("userId")).toString());
return userId;
} catch (Exception e) {
logger.error(e.getMessage());
return userId;
}
}
private Long getTenantId(JsonObject jsonMessage) {
Long tenantId = null;
try {
tenantId = Long.parseLong(((Integer) jsonMessage.getInt("tenantId")).toString());
return tenantId;
} catch (Exception e) {
logger.error(e.getMessage());
return tenantId;
}
}
}
WebSocketService.java
#Singleton
public class WebSocketService {
private static final Logger logger = LoggerFactory.getLogger(WebSocketService.class);
public enum WebSocketEvents{
OnConnection,
OnActivity,
OnAccesspointStatus,
OnClosedStatus,
OnConnectedStatus,
OnAlert,
OnSessionExpired
}
public enum WebSocketActions{
SaveUserId
}
#WebPost("/lookupWebSocketSessions")
public WebResponse lookupWebSocketSessions(#JsonArrayParam("userIds") List<Integer> userIds, #WebParam("message") String message){
try {
for (Integer userIdInt : userIds) {
Long userId = Long.parseLong(userIdInt.toString());
if (WebSocketSessionHandler.sendToUser(userId, message) == 0) {
} else {
//logger.debug("Couldn't Send to User");
}
}
} catch (ClassCastException e) {
//logger.error(e.getMessage());
return webResponseBuilder.fail(e);
} catch (Exception e) {
//logger.error(e.getMessage());
return webResponseBuilder.fail(e);
}
return webResponseBuilder.success(message);
}
#WebPost("/lookupWebSocketHistorySessions")
public WebResponse lookupWebSocketHistorySessions(#JsonArrayParam("userIds") List<Integer> userIds, #WebParam("message") String message){
try {
for (Integer userIdInt : userIds) {
Long userId = Long.parseLong(userIdInt.toString());
if (WebSocketHistorySessionHandler.sendToUser(userId, message) == 0) {
} else {
//logger.debug("Couldn't Send to User");
}
}
} catch (ClassCastException e) {
//logger.error(e.getMessage());
return webResponseBuilder.fail(e);
} catch (Exception e) {
//logger.error(e.getMessage());
return webResponseBuilder.fail(e);
}
return webResponseBuilder.success(message);
}
// Kick Out a User if Their Session is no Longer Valid
public void sendLogout(User user) {
try {
Long userId = user.getId();
List<Long> userIds = new ArrayList<>();
userIds.add(userId);
JSONObject result = new JSONObject();
result.put("userId", userId);
JSON message = WebSocketSessionHandler.createMessage(WebSocketEvents.OnSessionExpired, result);
lookOnOtherServers(userIds, message);
} catch (Exception e) {
logger.error("Couldn't Logout User");
}
}
// Send History after Processing Data
// Returns "0" if success, "-1" otherwise
public int sendHistory(Activity activity) {
try {
TimezoneService.TimeZoneConfig timeZoneConfig = timezoneService.getTimezoneConfigsByAp(null, activity.getAccesspointId());
JSONObject result = (JSONObject) JSONSerializer.toJSON(activity);
String timezoneId = timezoneService.convertTimezoneConfigToTimezoneId(timeZoneConfig);
result.put("timezoneString", timezoneId);
result.put(
"profileId",
userDao.getUserProfileId(activity.getUserId())
);
JSON message = WebSocketHistorySessionHandler.createMessage(WebSocketEvents.OnActivity, result);
List<Long> userIds = getUsersSubscribedToActivity(activity.getTenantId());
lookOnOtherServersHistory(userIds, message);
return 0;
} catch (Exception e) {
//logger.error("Couldn't Send History");
return -1;
}
}
// SendAlertUpdate after Processing Data
public void sendAlertUpdate(Alert alert) {
try {
List<Long> userIds = getUsersUnderTenantByAccesspointId(alert.getAccesspointId());
JSONObject result = JSONObject.fromObject(alert);
JSON message = WebSocketSessionHandler.createMessage(WebSocketEvents.OnAlert, result);
lookOnOtherServers(userIds, message);
} catch (Exception e) {
//logger.error("Couldn't Send Aleart");
}
}
// Send Connected Status after Processing Data
public void sendConnectedStatus(Long accesspointId, Boolean isConnected) {
try {
List<Long> userIds = getUsersUnderTenantByAccesspointId(accesspointId);
JSONObject result = new JSONObject();
result.put("accesspointId", accesspointId);
result.put("isConnected", isConnected);
JSON message = WebSocketSessionHandler.createMessage(WebSocketEvents.OnConnectedStatus, result);
lookOnOtherServers(userIds, message);
} catch (Exception e) {
//logger.error("Couldn't Send Connected Status");
}
}
public int sendHistory(CredentialActivity activity) {
try {
TimezoneService.TimeZoneConfig timeZoneConfig = timezoneService.getTimezoneConfigsByAp(null, activity.getAccesspointId());
JSONObject result = (JSONObject) JSONSerializer.toJSON(activity);
String timezoneId = timezoneService.convertTimezoneConfigToTimezoneId(timeZoneConfig);
result.put("timezoneString", timezoneId);
result.put(
"profileId",
userDao.getUserProfileId(activity.getUserId())
);
JSON message = WebSocketHistorySessionHandler.createMessage(WebSocketEvents.OnActivity, result);
List<Long> userIds = getUsersUnderTenantByAccesspointId(activity.getAccesspointId());
lookOnOtherServersHistory(userIds, message);
return 0;
} catch (Exception e) {
return -1;
}
}
public Boolean isUserSessionAvailable(Long id) {
return WebSocketSessionHandler.isUserSessionAvailable(id);
}
public void lookOnOtherServers(List<Long> userId, JSON data){
List<String> urls = awsService.getServerURLs();
for (String url : urls) {
postJSONDataToUrl(url, userId, data);
}
}
public void lookOnOtherServersHistory(List<Long> userId, JSON data){
List<String> urls = awsService.getServerURLsHistory();
for (String url : urls) {
postJSONDataToUrl(url, userId, data);
}
}
public int sendClosedStatus(AccesspointStatus accesspointStatus){
try {
JSONObject accesspointStatusJSON = new JSONObject();
accesspointStatusJSON.put("accesspointId", accesspointStatus.getAccesspointId());
accesspointStatusJSON.put("openStatus", accesspointStatus.getOpenStatus());
List<Long> userIds = getUsersUnderTenantByAccesspointId(accesspointStatus.getAccesspointId());
lookOnOtherServers(userIds, accesspointStatusJSON);
return 0;
} catch (Exception e) {
return -1;
}
}
public List<Long> getUsersSubscribedToActivity(Long tenantId) {
List<Long> userList = WebSocketSessionHandler.getUsersForTenant(tenantId);
return userList;
}
private List<Long> getUsersUnderTenantByAccesspointId(Long accesspointId) {
List<Long> userList = new ArrayList<>();
User user = userDao.getBackgroundUserByAccesspoint(accesspointId);
List<Record> recordList = tenantDao.getTenantsByUser(user, user.getId());
for (Record record : recordList) {
Long tenantId = (Long) record.get("id");
userList.addAll(getUsersSubscribedToActivity(tenantId));
}
return userList;
}
public void postJSONDataToUrl(String url, List<Long> userId, JSON data) throws AppException {
List<NameValuePair> parameters;
HttpResponse httpResponse;
HttpClientService.SimpleHttpClient simpleHttpClient = httpClientService.createHttpClient(url);
try {
parameters = httpClientService.convertJSONObjectToNameValuePair(userId, data);
} catch (Exception e) {
throw new AppException("Couldn't Convert Input Parameters");
}
try {
httpResponse = simpleHttpClient.sendHTTPPost(parameters);
} catch (Exception e) {
throw new AppException("Couldn't Get Data from the Server");
}
if (httpResponse == null) {
throw new AppException("Couldn't Send to Another Server");
} else {
//logger.error(httpResponse.getStatusLine().toString());
}
}
}
WebSocketSessionHandler.java
public class WebSocketSessionHandler {
// Apparently required to instantiate the dialogue,
// ideally it would be better to just create session map where sessions are mapped to userId,
// however, userId will be send only after the session is created.
// TODO: Investigate Instantiation of WebSocket Session Further
// WeakHashMap is Used for Automatic Memory Management (So That Removal of Keys That are no Longer Used Can be Automatically Performed)
// NOTE: However, it Requires Certain Precautions to Make Sure Their Keys Don't Expire Unexpectedly, Look for the Commented Code Below
private static final Map<Long, Set<Session>> sessionMap = new WeakHashMap<>();
private static final Map<Long, Set<Long>> tenantUserMap = new WeakHashMap<>();
public WebSocketSessionHandler() {}
public static List<Long> getUsersForTenant(Long tenantId) {
List<Long> userIds = new ArrayList<>();
Set<Long> userIdsSet = tenantUserMap.get(tenantId);
if (userIdsSet != null) {
for (Long userId : userIdsSet){
userIds.add(userId);
}
}
return userIds;
}
public static Boolean isUserSessionAvailable(Long id){
Set<Session> userSessions = sessionMap.get(id);
if (userSessions == null || userSessions.size() == 0) {
return false;
} else {
return true;
}
}
// addSession() should add "session" to "sessions" set
// returns: "0" if success and "-1" otherwise
public static int addSession(Session session) {
int output;
try {
final long ONE_DAY = 86400000;
session.setMaxIdleTimeout(ONE_DAY);
sessions.put(session, new ArrayList<>());
return sendToSession(session, createMessage(WebSocketEvents.OnConnection, "Successfully Connected"));
} catch (Exception e) {
logger.error("Couldn't Add Session");
return -1;
}
}
// removeSession() should remove "session" from "sessions" set
// Scenarios:
// sessions is null?
// returns: "0" if success and "-1" otherwise
public static int removeSession( Session session) {
try {
closeSessionProperly(session);
if (sessions.remove(session) != null) {
return 0;
} else {
return -1;
}
} catch (Exception e) {
logger.error("Couldn't Remove Session");
return -1;
}
}
private static void closeSessionProperly(Session session) {
try {
session.close();
} catch (IOException ex) {
}
}
public static Long getKeyFromMap(Map map, Long key){ // Needed for Weak Maps
Set<Long> keySet = map.keySet();
for (Long keyReference : keySet) {
if (keyReference == key) {
return keyReference;
}
}
return key; // If Not Found Return the Value Passed in
}
// saveUserId() should create an { userId -> session } entry in sessionMap
public static Long saveUserId(Long userId, Session session){
// Test Scenarios:
// Can userId be null or wrong?
// Can session be null or wrong?
try {
userId = getKeyFromMap(sessionMap, userId); // Required for Weak Maps to Work Correctly
Set<Session> sessionsForUser = sessionMap.get(userId);
if (sessionsForUser == null) {
sessionsForUser = new HashSet<>();
}
sessionsForUser.add(session);
sessionMap.put(userId, sessionsForUser);
return userId;
} catch (Exception e) {
logger.error("Couldn't Save User Id");
return null;
}
}
// saveUserId() should create an { userId -> session } entry in sessionMap
public static Long saveTenantUser(Long tenantId, Long userId){
// Test Scenarios:
// Can userId be null or wrong?
// Can session be null or wrong?
try {
tenantId = getKeyFromMap(tenantUserMap, tenantId); // Required for Weak Maps to Work Correctly
Set<Long> users = tenantUserMap.get(tenantId);
if (users == null) {
users = new HashSet<>();
}
users.add(userId);
tenantUserMap.put(tenantId, users);
return tenantId;
} catch (Exception e) {
logger.error("Couldn't Save Tenant User");
return null;
}
}
public static void updateUserSessionKeys(Session session, Long tenantId, Long userId) {
try {
List<Long> userSessionKeys = sessions.get(session);
userSessionKeys.add(0, tenantId);
userSessionKeys.add(1, userId);
} catch (Exception e) {
logger.error("Couldn't Update User Session Keys");
}
}
// removeUserId() should remove an { userId -> session } entry in sessionMap
// returns: "0" if success and "-1" otherwise
public static int removeUserId( Long userId) {
try {
sessionMap.remove(userId);
return 0;
} catch (Exception e) {
return -1;
}
}
// sendAccesspointStatus() should compose JSON message and pass it to sendToUser()
// returns: "0" if success and "-1" otherwise
public static int sendClosedStatus(Long userId, JSONObject accesspointStatus) {
try {
JSONObject accesspointStatusEventMessage = (JSONObject) createMessage(WebSocketEvents.OnClosedStatus, accesspointStatus);
sendToUser(userId, accesspointStatusEventMessage);
return 0;
} catch (Exception e) {
return -1;
}
}
// sendToUser() sends message to session that is mapped to userId
// returns: "0" if success and "-1" otherwise
public static int sendToUser( Long userId, JSON message) {
if (sessionMap.containsKey(userId)) {
Set<Session> sessionsForUser = sessionMap.get(userId);
for (Session session : sessionsForUser) {
if (!session.isOpen()) {
sessions.remove(session);
continue;
}
sendToSession(session, message);
}
return 0;
} else {
return -1;
}
}
// sendToSession() sends string message to session
// returns: "0" if success and "-1" otherwise
private static int sendToSession( Session session, JSON message){
try {
try {
Long tenantId = sessions.get(session).get(0);
((JSONObject) message).put("tenantId", tenantId);
} catch (Exception e) {
logger.error("No tenantId Found");
}
session.getBasicRemote().sendText(message.toString());
return 0;
} catch (IOException e) {
try {
session.close();
} catch (IOException ex) {
}
closeSessionProperly(session);
sessions.remove(session);
return -1;
}
}
// sendToSession() sends string message to session
// returns: "0" if success and "-1" otherwise
private static int sendToSession( Session session, String message){
try {
JSONObject newMessage = JSONObject.fromObject(message);
try {
Long tenantId = sessions.get(session).get(0);
newMessage.put("tenantId", tenantId);
} catch (Exception e) {
logger.error("No tenantId Found");
}
session.getBasicRemote().sendText(newMessage.toString());
return 0;
} catch (IOException e) {
closeSessionProperly(session);
sessions.remove(session);
return -1;
}
}
}
Probably not the only bug, but your WebSocketSessionHandler class is not thread-safe. It uses WeakHashMap internally which is not synchronized. Concurrent access to these maps may result in unexpected behavior, which may or may not cause the effects you are seeing.
Turns out this was a correct assumption. A general rule of thumb: Unexpected Behaviour ~ Race Condition
Probably not the only bug, but your WebSocketSessionHandler class is not thread-safe. It uses WeakHashMap internally which is not synchronized. Concurrent access to these maps may result in unexpected behavior, which may or may not cause the effects you are seeing.
(copied from my comment. Turns out this was the solution)

XMPP Group chat java - logic to join users in room inside invitation listener is not working

I am trying to create sample java application to implement the MultiUserChat of XMPP. Some how I can able to create user and make it online in openfire. Can any one suggest how to join all the users to the created chatRoom?
Here is my sample code inside the class SampleMultiUserChat Where I invite all the users to join the group but it is not getting joined. What I am missing?
SampleMultiUserChat(){
oConnectionConfiguration = new ConnectionConfiguration("10.10.1.105",5223);
createChatRoom();
}
/**
* #param args
*/
public static void main(String[] args) {
SampleMultiUserChat oSampleMultiUserChat = new SampleMultiUserChat();
for(int i = 2; i < 4; i++){
oSampleMultiUserChat.openXMPPConnection("user"+i);
oSampleMultiUserChat.createAcceptInvitationListener("user"+i);
oSampleMultiUserChat.inviteToJoinRoom("user"+i);
}
Thread mainThread = Thread.currentThread();
while(true){
try {
mainThread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void openXMPPConnection(String user){
XMPPConnection oXmppConnection = new XMPPConnection(oConnectionConfiguration);
try {
oXmppConnection.connect();
oXmppConnection.login(user, "60474c9c10d7142b7508ce7a50acf414");
userConnection.put(user, oXmppConnection);
} catch (XMPPException e) {
System.out.println("Exception occured in login in user : "+user);
}
}
private void createChatRoom(){
XMPPConnection oXmppConnection = new XMPPConnection(oConnectionConfiguration);
try {
oXmppConnection.connect();
oXmppConnection.login("user1", "60474c9c10d7142b7508ce7a50acf414");
myChattingRoom = new MultiUserChat(oXmppConnection, "mychattingroom#conference.10.10.1.105");
myChattingRoom.create("roomNickName");
myChattingRoom.sendConfigurationForm(new Form(Form.TYPE_SUBMIT));
} catch (XMPPException e) {
e.printStackTrace();
}
}
private void inviteToJoinRoom(String user){
myChattingRoom.invite(user+"#10.10.1.105", "Please join my chatting room");
System.out.println("sent invitation by "+user);
}
private void sendMessage(String msg){
try {
myChattingRoom.sendMessage(msg);
} catch (XMPPException e) {
System.out.println("Exception occured while sending msg to chat room"+e);
}
}
private void createAcceptInvitationListener(String user){
MultiUserChat.addInvitationListener(userConnection.get(user), new InvitationListener() {
public void invitationReceived(Connection connection, String room, String inviter,
String reason, String password, Message msg) {
try {
myChattingRoom.join(connection.getUser().substring(0, connection.getUser().indexOf("#")));
} catch (XMPPException e) {
e.printStackTrace();
}
}
});
}
Thanks in advance.
I solved my above problem by creating new instance of MultiUserChat.
Here is my edited method 'createAcceptInvitationListener'
private void createAcceptInvitationListener(String user){
System.out.println("inside create accept invitation listener");
final XMPPConnection oXmppConnection = userConnection.get(user);
MultiUserChat.addInvitationListener(oXmppConnection, new InvitationListener() {
public void invitationReceived(Connection connection, String room, String inviter,
String reason, String password, Message msg) {
System.out.println("inside invitation received method");
try {
System.out.println(connection.getUser().substring(0, connection.getUser().indexOf("#")));
MultiUserChat myChattingRoom = new MultiUserChat(oXmppConnection, "mychattingroom#conference.10.10.1.105");
myChattingRoom.join(connection.getUser().substring(0, connection.getUser().indexOf("#")));
} catch (Exception e) {
e.printStackTrace();
System.out.println("Exception occured while joining the chat room : "+e);
}
}
});
}
private void reservedRoomsCreation(MultiUserChat myChattingRoom) throws XMPPException{
Form form = myChattingRoom.getConfigurationForm();
Form submitForm = form.createAnswerForm();
for(Iterator fields = form.getFields(); fields.hasNext();){
FormField formFields = (FormField) fields.next();
if (!FormField.TYPE_HIDDEN.equals(formFields.getType()) && formFields.getVariable() != null) {
submitForm.setDefaultAnswer(formFields.getVariable());
}
}
submitForm.setAnswer("muc#roomconfig_persistentroom", true);
myChattingRoom.sendConfigurationForm(submitForm);
}

Categories

Resources