So, guys, I'm doing a telegram long polling bot, via Java, via telegram bots API.
I made an integer for a test to do +1 after good answer and nothing with integer, while answer is wrong.
public void onUpdateReceived(Update update) {
int i=0;
on the very beginning of on update receive.
and when a user starts test he sees a markup keyboard with the first question and 4 answers
else if (message_text.equals("test"))
{
SendMessage message = new SendMessage() // Create a message object object
.setChatId(chat_id)
.setText("Test");
// Create ReplyKeyboardMarkup object
ReplyKeyboardMarkup keyboardMarkup = new ReplyKeyboardMarkup();
// Create the keyboard (list of keyboard rows)
List<KeyboardRow> keyboard = new ArrayList<>();
// Create a keyboard row
KeyboardRow row = new KeyboardRow();
// Set each button, you can also use KeyboardButton objects if you need something else than text
row.add("1. М");
row.add("2. end");
// Add the first row to the keyboard
keyboard.add(row);
// Create another keyboard row
row = new KeyboardRow();
row.add("3. К");
row.add("4. Т");
keyboard.add(row);
// Set the keyboard to the markup
keyboardMarkup.setKeyboard(keyboard);
// Add it to the message
message.setReplyMarkup(keyboardMarkup);
try
{
sendMessage(message); // Call method to send the photo
}
catch (TelegramApiException e)
{
e.printStackTrace();
}
}
else if (message_text.equals("1. М"))
{
i=i+1;
SendMessage message = new SendMessage() // Create a message object object
.setChatId(chat_id)
.setText("Test");
ReplyKeyboardMarkup keyboardMarkup = new ReplyKeyboardMarkup();
List<KeyboardRow> keyboard = new ArrayList<>();
KeyboardRow row = new KeyboardRow();
row.add("1. М");
row.add("2. end");
keyboard.add(row);
row = new KeyboardRow();
row.add("3. К");
row.add("4. Т");
keyboard.add(row);
keyboardMarkup.setKeyboard(keyboard);
message.setReplyMarkup(keyboardMarkup);
try
{
sendMessage(message);
}
catch (TelegramApiException e)
{
e.printStackTrace();
}
}
else if (message_text.equals("2. end"))
{
if (i == 1) {
SendMessage message = new SendMessage()
.setChatId(chat_id)
.setText("roflan");
try {
sendMessage(message);
} catch (TelegramApiException e) {
e.printStackTrace();
}
}
}
if I will write "!=1" , after"2. end" it always shows the result. It does not matter how many time user answer the first button, i+1 doesn't work. Where is a problem with my logic?
Let's forget about Telegram API just to watch what is happening with your int i variable.
Everytime the onUpdateReceived() is called, int i is declaring inside this method and initialising with value 0.
It looks like this
public class Scope {
public static void main(String[] args) {
System.out.println(getI());
System.out.println(getI());
}
private static int getI() {
int i = 0;
i++;
return i;
}
}
The output will be
1
1
To make your program work as you expect you should declare int i outside of onUpdateReceived() scope. The most obvious way is creating a static variable.
public class Scope {
public static void main(String[] args) {
System.out.println(getI());
System.out.println(getI());
System.out.println(getI());
System.out.println(getI());
}
private static int i = 0;
private static int getI() {
i++;
return i;
}
}
The output will be
1
2
3
4
So, now your code should look like this one
public class Bot extends TelegramLongPollingBot {
private static int i = 0;
public void onUpdateReceived() {
/*...*/
else if (update.hasMessage() && update.getMessage().hasText() && update.getMessage().getText().equals("1. M")) {
i++;
} else if (update.hasMessage() && update.getMessage().hasText() && update.getMessage().getText().equals("1. end")) {
System.out.println(i);
}
/*...*/
}
public String getBotToken() {
return "...";
}
public String getBotUsername() {
return "...";
}
}
Related
I need your help. I should use the java.util.concurrent package in my exercise but I don't know how to do it. The question is only about the get method.
public String getInput() {
if (inputList.isEmpty()) return null;
String input = inputList.get(0);
inputList.remove(0);
return input;
}
How do I need to write the code to wait till the given list (variable: inputList) becomes non-empty?
Greetings
you could try using the LinkedBlockingDeque class from the java.util.concurrent
package which implements the BlockingDequeinterface.
it lets you add items to the BlockingDeque and the take* methods block until there is an element available and remove it after fetching. Have a look at the Javadoc
Here is an example:
public class Queue {
BlockingDeque<String> inputList = new LinkedBlockingDeque<>();
public String getInput() {
try {
System.out.println("waiting on queue");
String input = inputList.takeFirst();
System.out.println("taken " + input);
return input;
} catch (InterruptedException e) {
e.printStackTrace();
return null;
}
}
public static void main(String[] args) {
Queue queue = new Queue();
new Thread(() -> {
try {
Thread.sleep(4000);
queue.inputList.add("string");
System.out.println("added string");
Thread.sleep(2000);
queue.inputList.add("string1");
System.out.println("added string 1");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
for (int i = 0; i < 2; i++){
queue.getInput();
}
}
}
I have recently been following some tutorials on how to program and whilst programming the public static void for an array, the tutorial said to declare the array as an object. Below is the code for the array and at the end of the code I have put a split between the two sections so it is visible to as where my question lies
import java.io.*;
import java.lang.*;
public class LoginList
{
int arraySize=500;
Login[] arrayLogin=new Login[arraySize];
int nextPosition=0;
int LoginLocation=-1;
public void addLogin(Login tempLoginParameters)
{
arrayLogin[nextPosition] = tempLoginParameters;
nextPosition++;
}
public void writeLogins()
{
try
{
BufferedWriter LoginWriter = new BufferedWriter(new FileWriter("LoginDetails.txt"));
for(int i=0;i<nextPosition;i++)
{
LoginWriter.write(arrayLogin[i].toString());
LoginWriter.newLine();
}
LoginWriter.close();
}
catch(Exception e)
{
System.out.println("Error with writer");
}
}
public void readLogins()
{
try
{
BufferedReader LoginReader = new BufferedReader(new FileReader("LoginDetails.txt"));
String ReadLine = LoginReader.readLine();
while(ReadLine!= null)
{
String[] arrayStringLogin = ReadLine.split(", ");
Login tempLogin = new Login();
tempLogin.UserName = arrayStringLogin[0];
tempLogin.Password = arrayStringLogin[1];
arrayLogin[nextPosition] = tempLogin;
nextPosition++;
ReadLine = LoginReader.readLine();
}
}
catch(Exception e)
{
System.out.println("Error with reader");
}
}
public void displayLoginDetails()
{
for(int i=0;i<nextPosition;i++)
{
System.out.println("Login "+nextPosition+": "+arrayLogin[i].toString());
}
}
public void searchLogins(String TempLog)
{
LoginLocation=-1;
for(int i=0;i<nextPosition;i++)
{
if(arrayLogin[i].UserName.equals(TempLog))
{
System.out.println("Match At Position:"+i);
LoginLocation=i;
}
else
{
System.out.println("No match for UserName");
}
}
}
public static void main(String[] args)
{
LoginList ll = new LoginList(); //Declares the array as an object
Why is it that you have to declare the array as an object? Look just above here.
Login tempLogin = new Login();
ll.readLogins();
ll.displayLoginDetails();
}
}
LoginList is not an array, it's a class that happens to have an array of Login objects as one of its instance members. The code in main creates an object of type LoginList and calls its methods; the LoginList object uses an array internally, but the main method doesn't have to know about it.
I'm trying to implement a mechanism that deletes cached files when the objects that hold them die, and decided to use PhantomReferences to get notified on garbage collection of an object. The problem is I keep experiencing weird behavior of the ReferenceQueue. When I change something in my code it suddenly doesn't fetch objects anymore. So I tried to make this example for testing, and ran into the same problem:
public class DeathNotificationObject {
private static ReferenceQueue<DeathNotificationObject>
refQueue = new ReferenceQueue<DeathNotificationObject>();
static {
Thread deathThread = new Thread("Death notification") {
#Override
public void run() {
try {
while (true) {
refQueue.remove();
System.out.println("I'm dying!");
}
} catch (Throwable t) {
t.printStackTrace();
}
}
};
deathThread.setDaemon(true);
deathThread.start();
}
public DeathNotificationObject() {
System.out.println("I'm born.");
new PhantomReference<DeathNotificationObject>(this, refQueue);
}
public static void main(String[] args) {
for (int i = 0 ; i < 10 ; i++) {
new DeathNotificationObject();
}
try {
System.gc();
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
The output is:
I'm born.
I'm born.
I'm born.
I'm born.
I'm born.
I'm born.
I'm born.
I'm born.
I'm born.
I'm born.
Needless to say, changing the sleep time, calling gc multiple times etc. didn't work.
UPDATE
As suggested, I called Reference.enqueue() of my reference, which solved the problem.
The weird thing, is that I have some code that works perfectly (just tested it), although it never calls enqueue. Is it possible that putting the Reference into a Map somehow magically enqueued the reference?
public class ElementCachedImage {
private static Map<PhantomReference<ElementCachedImage>, File>
refMap = new HashMap<PhantomReference<ElementCachedImage>, File>();
private static ReferenceQueue<ElementCachedImage>
refQue = new ReferenceQueue<ElementCachedImage>();
static {
Thread cleanUpThread = new Thread("Image Temporary Files cleanup") {
#Override
public void run() {
try {
while (true) {
Reference<? extends ElementCachedImage> phanRef =
refQue.remove();
File f = refMap.remove(phanRef);
Calendar c = Calendar.getInstance();
c.setTimeInMillis(f.lastModified());
_log.debug("Deleting unused file: " + f + " created at " + c.getTime());
f.delete();
}
} catch (Throwable t) {
_log.error(t);
}
}
};
cleanUpThread.setDaemon(true);
cleanUpThread.start();
}
ImageWrapper img = null;
private static Logger _log = Logger.getLogger(ElementCachedImage.class);
public boolean copyToFile(File dest) {
try {
FileUtils.copyFile(img.getFile(), dest);
} catch (IOException e) {
_log.error(e);
return false;
}
return true;
}
public ElementCachedImage(BufferedImage bi) {
if (bi == null) throw new NullPointerException();
img = new ImageWrapper(bi);
PhantomReference<ElementCachedImage> pref =
new PhantomReference<ElementCachedImage>(this, refQue);
refMap.put(pref, img.getFile());
new Thread("Save image to file") {
#Override
public void run() {
synchronized(ElementCachedImage.this) {
if (img != null) {
img.saveToFile();
img.getFile().deleteOnExit();
}
}
}
}.start();
}
}
Some filtered output:
2013-08-05 22:35:01,932 DEBUG Save image to file: <>\AppData\Local\Temp\tmp7..0.PNG
2013-08-05 22:35:03,379 DEBUG Deleting unused file: <>\AppData\Local\Temp\tmp7..0.PNG created at Mon Aug 05 22:35:02 IDT 2013
The answer is, that in your example the PhantomReference itself is unreachable and hence garbage collected before the referred object itself is garbage collected. So at the time the object is GCed there is no more Reference and the GC does not know that it should enqueue something somewhere.
This of course is some kind of head-to-head race :-)
This also explains (without looking to deep into your new code) why putting the reference into some reachable collection makes the example work.
Just for reference (pun intended) here is a modified version of your first example which works (on my machine :-) I just added a set holding all references.
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.HashSet;
import java.util.Set;
public class DeathNotificationObject {
private static ReferenceQueue<DeathNotificationObject> refQueue = new ReferenceQueue<DeathNotificationObject>();
private static Set<Reference<DeathNotificationObject>> refs = new HashSet<>();
static {
Thread deathThread = new Thread("Death notification") {
#Override
public void run() {
try {
while (true) {
Reference<? extends DeathNotificationObject> ref = refQueue.remove();
refs.remove(ref);
System.out.println("I'm dying!");
}
} catch (Throwable t) {
t.printStackTrace();
}
}
};
deathThread.setDaemon(true);
deathThread.start();
}
public DeathNotificationObject() {
System.out.println("I'm born.");
PhantomReference<DeathNotificationObject> ref = new PhantomReference<DeathNotificationObject>(this, refQueue);
refs.add(ref);
}
public static void main(String[] args) {
for (int i = 0 ; i < 10 ; i++) {
new DeathNotificationObject();
}
try {
System.gc();
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Update
Calling enqueue by hand is possible in your example but not in real code. it gives plain wrong result. Let me show by calling enqueue in the constructor and using another main:
public DeathNotificationObject() {
System.out.println("I'm born.");
PhantomReference<DeathNotificationObject> ref = new PhantomReference<DeathNotificationObject>(this, refQueue);
ref.enqueue();
}
public static void main(String[] args) throws InterruptedException {
for (int i = 0 ; i < 5 ; i++) {
DeathNotificationObject item = new DeathNotificationObject();
System.out.println("working with item "+item);
Thread.sleep(1000);
System.out.println("stopped working with item "+item);
// simulate release item
item = null;
}
try {
System.gc();
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
The output will be like this:
I'm born.
I'm dying!
working with item DeathNotificationObject#6908b095
stopped working with item DeathNotificationObject#6908b095
Which means that whatever you wanted to do with the reference queue would be done when the item is still alive.
I have developed a client/server chat application using Java and I wish to know how can I remove a user from an array. When a specific client log-in the username is saved in username array and client ID in client array. To allow the server to accept multiple clients, I am using threads. Now can anyone guide me on how to remove a user from the array and also close the connection for that user.
Adding a new client and saving the ID in client array
public class AddClient implements Runnable {
Thread t;
AddClient(String tot) {
t = new Thread(this, tot);
t.start();
}
public void run() {
while (true) {
try {
try {
waitClient();
} catch (Exception ex) {
ex.printStackTrace();
}
for (int i = 0; i < client.length; i++) {
if (client[i] == 0) {
client[i] = i + 1;
id = i;
break;
}
}
//set stream to send and receive data
out[client[id]] = new ObjectOutputStream(connect.getOutputStream());
out[client[id]].flush();
in[client[id]] = new ObjectInputStream(connect.getInputStream());
The username is saved in the username array
username[client[id]] = cm.sender; //Add user in username[] array
Removing user
public synchronized void removeUser(int number) {
int position = number;
System.out.println("Server removing user " + username[number] + "which is client " + number);
for (int i = 0; i <= client.length; i++) {
if (position == client[i]) {
System.out.println("User to be remove found");
try {
client[i + 1] = client[i];
in[position].close();
out[position].close();
username[position] = null;
position = position - 1;
} catch (Exception e) {
e.printStackTrace();
}
}
}
I am trying to use HashTable to add and remove the client
public class ChatServerProtocol {
private String nick;
private AddClient a;
private Hashtable<String, AddClient> nicks = new Hashtable<String, AddClient>();
private boolean add_nick(String nick, AddClient a) {
if (nicks.containsKey(nick)) {
return false;
} else {
nicks.put(nick, a);
return true;
}
}
private boolean remove_nick(String nick, AddClient a) {
if (!(nicks.containsKey(nick))) {
return false;
} else {
nicks.remove(nick);
return true;
}
}
public ChatServerProtocol(AddClient a) throws IOException {
nick = null;
a = a;
}
But now how do I call the method add_nick. Whenever a client log-in the username is sent to the server and the server reads it as cm.sender. I also need to include the thread variable. So how to add the username so that later i can remove it.
ChatServerProtocol.add_nick(cm.sender);
No, saving in database won't be a good idea.. Remember you are saving details only for the length of the session and basic concept of database is to use it after the session. What happens if your session gets interruped because of network issues etc?
Just use Map instead of plain arrays, using key as client ID and value as username.. removing username will be a plain call such as map.remove(clientID);
EDIT AS YOU ASKED: Note that this code is not complete and only as much as you gave..
public class AddClient implements Runnable {
Thread t;
private Map<int, String> users = new HashMap <int, String>();
AddClient(String tot) {
t = new Thread(this, tot);
t.start();
}
public void run() {
while (true) {
try {
try {
waitClient();
} catch (Exception ex) {
ex.printStackTrace();
}
int clientId = users.size() + 1;
users.put(clientId, cm.sender);
//set stream to send and receive data
out[clientId] = new ObjectOutputStream(connect.getOutputStream());
out[clientId].flush();
in[clientId] = new ObjectInputStream(connect.getInputStream());
REMOVE USER METHOD
public synchronized void removeUser(int number) {
if(users.containsKey(number)) {
System.out.println("Server removing user " + users.get(number) + "which is client " + number);
users.remove(number);
} else {
System.out.println("User not in session");
}
}
I have a problem with my code. Code is about to find gateways/subnets and if program finds one it returns it to a class that called "call()" method. That part works fine but problem is that I want to pass ID of gateway(you know if gateway was 192.168.1.1 , it will also pass number 1 to class that fills vector of founded gateways). Problem is that for some reason vector that holds IDs of gateways is empty. Can you give me a clue how to fix problem ? Best regards.
Here is code that I used in my project:
int GateWayKey = 1;
int GateWayKeyStop=254;
String ip="";
StoredGW FoundedGW = new StoredGW();
int SubNetKey = 2;
int SubNetKeyStop = 254;
Vector <Integer> AllGateWays= new Vector <Integer>();
Vector <Future<String>> AllSQLs = new Vector <Future<String>>();
final int NUM_THREADS = Runtime.getRuntime().availableProcessors();
ExecutorService exec = Executors.newFixedThreadPool(NUM_THREADS);
public void run() {
for (;GateWayKey<=GateWayKeyStop;GateWayKey++){
ip="192.168."+GateWayKey+".1";
AllSQLs.add(exec.submit((new PingTask(ip,GateWayKey))));
}
AllGateWays = FoundedGW.GiveMeGWs();
for (int j : AllGateWays){
for (;SubNetKey<=SubNetKeyStop;SubNetKey++){
ip="192.168."+j+"."+SubNetKey;
AllSQLs.add (exec.submit(new PingTask(ip,null))));
}
exec.shutdown();
}
Here is class that preform pinging and storing ID of gateway:
public class PingTask implements Callable <String> {
String ips;
int GateWay;
public PingTask (){
}
public PingTask (String ip, int GateWayKey){
ips=ip;
GateWay=GateWayKey;
}
public String call(){
InetAddress address;
try {
address = InetAddress.getByName(ips);
try {
if (address.isReachable(5000)) {
StoredGW GWs = new StoredGW();
GWs.addNewGW(GateWay);
} else {
return null;
}
} catch (IOException e) {
return null;
}
} catch (UnknownHostException e) {
return null;
}
}
}
and here is class where I store GateWays
public class StoredGW {
Vector <Integer> AllFoundedGWs= new Vector<Integer>();
public void addNewGW(int i){
AllFoundedGWs.add(i);
}
public Vector<Integer> GiveMeGWs(){
return AllFoundedGWs;
}
}
The problem is here:
StoredGW GWs = new StoredGW();
GWs.addNewGW(GateWay);
You make a new StoreGW (as local variable) and then you throw it away. Instead use, FoundedGW. You have to make sure it is visible to your task, you might have to pass it as a constructor argument so that it can be used within your task.
Try this:
public class PingTask implements Callable <String> {
String ips;
int GateWay;
StoredGW store;
public PingTask (){
}
public PingTask (String ip, int GateWayKey, StoredGW store){
ips=ip;
GateWay=GateWayKey;
this.store = store;
}
public String call(){
InetAddress address;
try {
address = InetAddress.getByName(ips);
try {
if (address.isReachable(5000)) {
store.addNewGW(GateWay);
} else {
return null;
}
} catch (IOException e) {
return null;
}
} catch (UnknownHostException e) {
return null;
}
}
}
Then you can call it this way:
AllSQLs.add(exec.submit((new PingTask(ip,GateWayKey, FoundedGW))));
As an unrelated side note, you need to take a look at the standard for Java naming conventions, it'll make your code easier for others to understand.