remove ListenerAdapter with a timer - java

so I have the following problem, I want to make a minigame on a text channel, the problem is, I want to create some sort of timeout so that people don't create multiple "listenerAdapter" instances that will just overload the bot.
the command I use to load my game event (ListenerAdapter is as follows).
#Override
public void handle(List<String> args, GuildMessageReceivedEvent event) {
// TODO Auto-generated method stub
TextChannel channel = event.getChannel();
channel.sendMessage("please type \"joingame\" to join! ").queue();
event.getJDA().addEventListener(new MinigameEvent(channel, event.getAuthor(), event));
}
then , the code I use for loading players in, is the following:
public class MinigameEvent extends ListenerAdapter {
private final long channelId, authorId;
private final int players=3;
private ArraySet<User> users;
private String textMsg;
private Message target;
private GuildMessageReceivedEvent outTimerEvent;
private boolean cancelEvent;
public MinigameEvent(MessageChannel channel, User author, GuildMessageReceivedEvent outTimerEvent) {
this.channelId = channel.getIdLong();
this.authorId = author.getIdLong();
this.outTimerEvent=outTimerEvent;
cancelEvent=false;
this.timeOut(channel);
users=new ArraySet<User>();
users.add(author);
textMsg=("registered users: "+author.getName());
channel.sendMessage(textMsg).queue((new Consumer<Message>()
{
#Override
public void accept(Message t)
{
target = t;
}
}));
}
#Override
public void onMessageReceived(MessageReceivedEvent event) {
if(event.getAuthor().isBot()) {
return;
}
//not respond on other channels
if (event.getChannel().getIdLong() != channelId) {
return;
}
MessageChannel channel = event.getChannel();
String content = event.getMessage().getContentRaw();
if(content.equalsIgnoreCase("joingame")) {
users.add(event.getAuthor());
textMsg=textMsg+", "+event.getAuthor().getName();
target.editMessage(textMsg).queue();
if(users.size()==players) {
event.getChannel().sendMessage("starting").queue();
event.getJDA().removeEventListener(this);
}
}
if(content.equalsIgnoreCase("cancel") && event.getAuthor().getIdLong()==authorId) {
cancelEvent=true;
event.getJDA().removeEventListener(this);
event.getChannel().sendMessage("this game has been canceled").queue();
}
}
private void timeOut(MessageChannel channel) {
Timer timer = new Timer();
TimerTask cooldown = new TimerTask() {
#Override
public void run() {
if(cancelEvent) {
return;
}
if(users.size()<players) {
outTimerEvent.getJDA().removeEventListener(this);
try {
destroyEvent();
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
channel.sendMessage("not enough players, the game has been cancelled").queue();
}else {
return;
}
}
};
timer.schedule(cooldown, 10000L);
}
private void destroyEvent() throws Throwable {
this.finalize();
}
}
when I get to 3 people, the Listener adapter stops working as intended, also when the author of the event (the one who used the !minigame command) types cancel. but when the timer goes off, it sends the message indicating the game has been cancelled, but the listener adapter is still running, if someone tries to join after, it will allow him to do so.
I currently solved the issue by using the finalize method, but I thought that you could just do something like event.getJDA().removeEventListener(this);

Your problem is that your this refers to the nearest class declaration. In this case this is the anonymous class created by your new TimeTask() { .... To refer to the outer class which actually is registered as the listener you have to use MinigameEvent.this instead.
Read More
I would highly recommend using a lambda expression instead which doesn't have this problem. Another thing to note is your use of timer which will result in thread leaks because they are never shutdown by your code (How to cleanup a timer). Even better would be to use a single ScheduledExecutorService which you should re-use to schedule everything you need rather than creating a new one for every task. This can then be shutdown once your process ends (like the onShutdown event in JDA which is fired when shutdown() is called).

Related

Generic Thread which could be paused/resumed and execute user's Runnable Actions

AIM : To make a generic Thread class that is independent of the parent calling it, can be started/stopped/paused/resumed by the parent class calling it and perform user defined tasks (via runnable)
MY RESEARCH :
SO_1
SO_2
SO_3
SO_4
SO_5
SomeBlog
SomeBlog2
OracleBlog
Problem : from what i have understood:
Starting a background thread: threadObj.start() will execute statements of run() function of a class implementing Runnable Interface.
Stopping a background thread : threadObj.interrupt() will stop a thread from executing
Pausing a thread : threadObj.wait() will pause the thread,although, it requires additional synchronised lock mechanism
Resuming a thread :threadObj.notifyAll() will release resume the object, after handling the synchronised lock mechanism
Thus based on this, i wrote a generic Thread class that is supposed to run a user's set of tasks and play/pause/resume/stop via ui buttons, BUT ITS NOT WORKING:
Generic Thread.java
public class PausibleThread extends Thread {
public static final String TAG ="PausibleThread>>";
#Nullable
PausibleRunnable runnable ;
public PausibleThread(#Nullable Runnable target) {
super(target);
PausibleRunnable r = new PausibleRunnable(target);
runnable=r;
}
#Override
public synchronized void start() { super.start(); }
public synchronized void stopThread(){ this.interrupt(); }
public synchronized void pauseThread(){ runnable.pause(); }
public synchronized void resumeThread(){ runnable.resume(); }
PausibleRunnable.java:
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class PausibleRunnable implements Runnable {
private Object lockerObject;
private boolean isPaused;
private boolean isFinished;
public static final String TAG="PausibleRunnable";
#Nullable
Runnable usrAction = null;
public PausibleRunnable(#NonNull Runnable usrAction) {
lockerObject = new Object();
isPaused = false;isFinished = false;
this.usrAction = usrAction;
}
public void run() {
while (!isFinished) {
if(isPaused) {
runPauseLoop();
}
else {
runUserAction();
isFinished=true;
}
}
}
private void runPauseLoop() {
synchronized (lockerObject) {
while (isPaused) {
try { lockerObject.wait(); }
catch (InterruptedException e) { e.printStackTrace(); }
}
}
}
private void runUserAction() {
if(usrAction !=null){ usrAction.run(); }
else { Log.e(TAG, "run: userAction is NULL" ); }
}
public void pause() {
synchronized (lockerObject) { isPaused = true; }
}
public void resume() {
synchronized (lockerObject) {
isPaused = false;
lockerObject.notifyAll();
}
}
}
Ui creating a Pausible Thread and implementing various functions of it:
//full class implementation at : https://paste.ubuntu.com/p/cTpW5Wt3Fy/
int totalRunTime = 20 * 5;
Pausible thread bgThread;
private void initThread() {
Runnable r = () -> {
try {
while (totalRunTime > 0) {
Thread.sleep(500);
totalRunTime--;
updateUi();
}
}
catch (Exception e) { e.printStackTrace(); }
};
bgThread = new PausibleThread(r);
}
private void updateUi() {
String data = "TotalRunTime=" + totalRunTime;
runOnUiThread(() -> tvTerminal.setText(data));
}
#Override
public void onClick(View v) {
if (bgThread == null) {
makeShortToast("Can't perform action, bg thread is null");
return;
}
if (v.getId() == fabPause.getId()) {bgThread.pauseThread(); }
else if (v.getId() == fabResume.getId()) { bgThread.resumeThread(); }
else if (v.getId() == fabStop.getId()) { bgThread.stopThread(); }
else if (v.getId() == fabStart.getId()) { bgThread.start(); }
}
But this does not work. Why? I am taking a wild guess here, but i think the runnable is only running user's action to run a big sized loop and not repeatedly checking for play/pause. So what am i supposed to do?
ui sample image : https://i.imgur.com/kmj3Bwt.png
You asked: "But this doesn't work. Why?"
I answer:
Your solution does not work because you are always running in the loop inside runUserAction. You never break out of that loop to check if you are paused.
I'm afraid you'll have to remodel your solution to run usrAction in shorter loops, otherwise you will either lose state (assuming you interrupt that loop from outside), which will end up in undefined behavior, OR you will only break out of it when it's over, OR you'll pause your loop at states you don't really want to pause at [e.g. while making a network call -- after resumed you'll get a SocketTimeoutException].
I'd suggest you to go with the former approach as it's more elegant.
Edit:
Another possible solution: every iteration inside the usrAction check for PausableThread's state, i.e. see whether it's paused, stopped or whatever.
Try this:
PausableRunnable.java
public synchronized boolean canContinue() throws Exception {
synchronized (lockerObject) {
if (isPaused) {
lockerObject.wait();
}
if (isFinished) {
return false;
}
return true;
}
}
PausableThread.java
public boolean canContinue() throws Exception {
return runnable.canContinue();
}
and the Application.java
private void initThread() {
Runnable r = () -> {
try {
while (totalRunTime > 0) {
if (bgThread.canContinue()) { // <--- !!!!!!
Thread.sleep(200);
totalRunTime--;
updateUi();
}
}
}
catch (Exception e) { e.printStackTrace(); }
};
bgThread = new PausibleThread(r);
}
This way you can run your application Runnable and still obey PausableThread's states at the times the runnable can tollereate. I.e. before/after transaction or other piece of calculation that is not supposed to be interrupted.
Edit 2:
feel free to lose ´synchronized´ modifier on methods like pause or resume, since you are already operating inside synchronized blocks in them.

Is there an opposite to an action listener in java so it performs a command when an action isn't happening?

I have made a basic chat application in java using eclipse. I am now starting to add extra features to it and am currently stuck on a feature that tells the user when the other person is typing, similar to whatsapp and facebook messenger.
currently i have an integer that records if the user is typing
public int typing = 0;
when it is 0 the user isn't typing when it is 1 they are (a boolean wouldn't work for some reason)
I have an action listener on the textbox that listens for a caret update and excecutes this code:
isTyping = 1;
String typing = ("t-");
client.send(typing.getBytes());
The server then relays this back to the other clients and when they recieve this message that gets sent if they are not typing it will make the someone is typing label appear.
What i would like is something to listen for when the caret is not updating to execute this code:
isTyping = 0;
String typing = ("n-");
client.send(typing.getBytes());
Is this possible or is there a way to make this work as i seem to need to listen for no carat update?
I suggest avoiding the listener and creating a thread:
The created thread checks the value of textbox and remembers the current value of the textbox in a loop. If the value hasn't changed since the last check, it means that the user is not typing. It is up to you to consider frequency of the check and maybe only a length of the value could be used for the check.
Make a single “expiration” Timer that waits a short delay, and then executes your “not typing” action. Whenever the text field’s document changes, restart the Timer, to ensure it only manages to execute when there is a lull in the user’s typing:
JTextField textField = /* ... */;
ActionListener idleSender = new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
isTyping = false;
client.send("n-".getBytes(StandardCharsets.UTF_8));
}
};
int delay = 2000; // 2 seconds
final Timer sendTimer = new Timer(delay, idleSender);
sendTimer.setRepeats(false);
sendTimer.start();
textField.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void insertUpdate(DocumentEvent event) {
sendTimer.restart();
}
#Override
public void removeUpdate(DocumentEvent event) {
sendTimer.restart();
}
#Override
public void changedUpdate(DocumentEvent event) {
sendTimer.restart();
}
});
Some notes:
It is important to use javax.swing.Timer, not java.util.Timer. The latter uses its own thread, while the former always executes its task on the AWT Event Dispatch Thread. Calling (almost) any AWT or Swing method on any thread other than the EDT is not allowed, and while violating that rule may not generate an exception, things tend to break intermittently and unpredictably.
Using typing.getBytes() without passing an charset to getBytes() may cause data corruption on the other side. It will convert bytes using the underlying system’s default charset, which may not be the same as the server’s default charset. It is a good idea to use "n-".getBytes(StandardCharsets.UTF_8) instead.
I don’t know what “a boolean wouldn’t work for some reason” actually means, but booleans work perfectly in all circumstances. If you had a problem, you will be doing yourself a service by finding out what that problem is and fixing it, rather than writing peculiar code that sidesteps the issue, only to come back to it months later and wonder why you are using 0 and 1 in place of false and true.
Performing a command while an action isn't happening isn't really possible, because it doesn't answer one crucial question - how often should it happen? Always isn't really an answer - that would require an infinite loop constantly executing, which will throttle your application as a whole.
That said, you can set up a timed delay for sending a notification that the person has stopped editing. In my mind it would count down (via thread sleep) towards 0 and refresh to a set (positive) amount whenever a key is pressed, but it could be the opposite as well (as AJ suggests in the comments).
public class NotificationSender {
private boolean isEditing;
private final Object isEditingLock;
private DelayedTurnOffThread turnOffThread;
private static final long MS_TO_OFF_NOTIFICATION = 1000;
public NotificationSender() {
isEditing = false;
isEditingLock = new Object();
turnOffThread = null;
}
private void sendEditingNotification(String newContent) {
System.out.println("Editing, new content=" + newContent);
}
private void sendStopEditingNotification() {
System.out.println("Editing stopped");
}
public boolean isEditing() {
synchronized (isEditingLock) {
return isEditing;
}
}
public void doEdit(String newContent) {
synchronized (isEditingLock) {
isEditing = true;
sendEditingNotification(newContent);
if (turnOffThread != null) {
turnOffThread.interrupt();
}
turnOffThread = new DelayedTurnOffThread();
turnOffThread.start();
}
}
private class DelayedTurnOffThread extends Thread {
#Override
public void run() {
try {
Thread.sleep(MS_TO_OFF_NOTIFICATION);
synchronized (isEditingLock) {
isEditing = false;
sendStopEditingNotification();
}
} catch (InterruptedException e) {
//Do nothing - superceded by other turnoff thread
}
}
}
//
//DEMO CODE BELOW
//
private static class NotificationDemo extends JFrame {
private NotificationSender notificationSender;
public NotificationDemo() {
notificationSender = new NotificationSender();
JTextField textField = new JTextField();
getContentPane().add(textField, BorderLayout.CENTER);
textField.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
notificationSender.doEdit(((JTextField)e.getSource()).getText() + e.getKeyChar());
}
#Override public void keyPressed(KeyEvent e) {}
#Override public void keyReleased(KeyEvent e) {}
});
pack();
setLocationRelativeTo(null);
setVisible(true);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
}
public static void main(String[] args) {
new NotificationDemo();
}
}

How to make JUnit4 "Wait" for asynchronous job to finish before running tests

I am trying to write a test for my android app that communicates with a cloud service.
Theoretically the flow for the test is supposed to be this:
Send request to the server in a worker thread
Wait for the response from the server
Check the response returned by the server
I am trying to use Espresso's IdlingResource class to accomplish that but it is not working as expected. Here's what I have so far
My Test:
#RunWith(AndroidJUnit4.class)
public class CloudManagerTest {
FirebaseOperationIdlingResource mIdlingResource;
#Before
public void setup() {
mIdlingResource = new FirebaseOperationIdlingResource();
Espresso.registerIdlingResources(mIdlingResource);
}
#Test
public void testAsyncOperation() {
Cloud.CLOUD_MANAGER.getDatabase().getCategories(new OperationResult<List<Category>>() {
#Override
public void onResult(boolean success, List<Category> result) {
mIdlingResource.onOperationEnded();
assertTrue(success);
assertNotNull(result);
}
});
mIdlingResource.onOperationStarted();
}
}
The FirebaseOperationIdlingResource
public class FirebaseOperationIdlingResource implements IdlingResource {
private boolean idleNow = true;
private ResourceCallback callback;
#Override
public String getName() {
return String.valueOf(System.currentTimeMillis());
}
public void onOperationStarted() {
idleNow = false;
}
public void onOperationEnded() {
idleNow = true;
if (callback != null) {
callback.onTransitionToIdle();
}
}
#Override
public boolean isIdleNow() {
synchronized (this) {
return idleNow;
}
}
#Override
public void registerIdleTransitionCallback(ResourceCallback callback) {
this.callback = callback;
}}
When used with Espresso's view matchers the test is executed properly, the activity waits and then check the result.
However plain JUNIT4 assert methods are ignored and JUnit is not waiting for my cloud operation to complete.
Is is possible that IdlingResource only work with Espresso methods ? Or am I doing something wrong ?
I use Awaitility for something like that.
It has a very good guide, here is the basic idea:
Wherever you need to wait:
await().until(newUserIsAdded());
elsewhere:
private Callable<Boolean> newUserIsAdded() {
return new Callable<Boolean>() {
public Boolean call() throws Exception {
return userRepository.size() == 1; // The condition that must be fulfilled
}
};
}
I think this example is pretty similar to what you're doing, so save the result of your asynchronous operation to a field, and check it in the call() method.
Junit will not wait for async tasks to complete. You can use CountDownLatch to block the thread, until you receive response from server or timeout.
Countdown latch is a simple yet elegant solution and does NOT need an external library. It also helps you focus on the actual logic to be tested rather than over-engineering the async wait or waiting for a response
void testBackgroundJob() {
Latch latch = new CountDownLatch(1);
//Do your async job
Service.doSomething(new Callback() {
#Override
public void onResponse(){
ACTUAL_RESULT = SUCCESS;
latch.countDown(); // notify the count down latch
// assertEquals(..
}
});
//Wait for api response async
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
assertEquals(expectedResult, ACTUAL_RESULT);
}

How to wait for user action in Sparkle updater(java app)?

So I have SparkleAcrivator class
public class SparkleActivator {
private static boolean sparkleLibLoaded = false;
//private String downloadLink;
private String menuItemTitle;
public native static void initSparkle(String pathToSparkleFramework,
boolean updateAtStartup,
int checkInterval,
/*String downloadLink,*/
String menuItemTitle);
private boolean updateAtStartup = true;
private int checkInterval = 86400;
public SparkleActivator(/*String downloadLink, */String menuItemTitle) {
//this.downloadLink = downloadLink;
this.menuItemTitle = menuItemTitle;
}
public void start() throws Exception {
try {
if(!SparkleActivator.sparkleLibLoaded) {
System.loadLibrary("sparkle_init");
SparkleActivator.sparkleLibLoaded = true;
}
} catch (Exception ex) {
ex.printStackTrace();
return;
}
initSparkle(System.getProperty("user.dir") + "/../../Frameworks/Sparkle.framework",
updateAtStartup, checkInterval, /*downloadLink, */menuItemTitle);
}
}
And main class where I start my standalone application and use Sparkle
public static void main(final String... args) {
if (Helper.isOsx()) {
try {
sparkleActivator.start();
} catch (Exception e) {
new ExceptionHandler(true, 19).handleException(new NotFountSparkleInitException());
return;
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
initApp();
}
});
}
else {
}
There problem is Sparkle and my app starts almost simultaneously, but I need wait for action from user in Sparkle window and then start my app.
Thank for any help.
What we know is that Sparkle updater requires to be called on the main thread (i.e. GUI thread). Therefore, your app needs to be running to call it. I don't think there is an obvious way to solve this problem. However,...
One way that you can circumvent the issue is to set your app's visibility to false until the user has finished interacting with your updater.
For example, you can add an event listener to your JNI or add listeners to your updater thread. However, the listener on the thread needs to return on user actions instead of when finished.

BlackBerry class equivalent to AsyncTask?

My requirement is to have a thread that maintains a socket connection between a BlackBerry device and a server and exchanges commands, similar to request and response.
My problem is that I need to have this thread running in the background all the time and keep the UI available to the user. So, when there is a command from the server, this thread parses it and updates the UI and also if there's an action from the BlackBerry user, it sends it to the server and the server in turn handles it.
I developed the same application in Android using AsyncTask and it's working well. But in BlackBerry, as there's no such class, I used the invokeLater() option. The communication works fine between the server and the BB device, but the UI is frozen on the BlackBerry.
Anyone have any idea how to get this right?
Vishal is on the right track, but a little more is needed to match Android's AsyncTask. Since enums and generics aren't available with Java 1.3 on BlackBerry, you can't match the Android API perfectly.
But, you could do something like this (not tested ... this is just a starting point for you):
import net.rim.device.api.ui.UiApplication;
public abstract class AsyncTask {
public static final int FINISHED = 0;
public static final int PENDING = 1;
public static final int RUNNING = 2;
private int _status = PENDING;
private boolean _cancelled = false;
private Thread _worker;
/** subclasses MUST implement this method */
public abstract Object doInBackground(Object[] params);
protected void onPreExecute() {
// default implementation does nothing
}
protected void onPostExecute(Object result) {
// default implementation does nothing
}
protected void onProgressUpdate(Object[] values) {
// default implementation does nothing
}
protected void onCancelled() {
// default implementation does nothing
}
protected void onCancelled(Object result) {
onCancelled();
}
public final int getStatus() {
return _status;
}
public final boolean isCancelled() {
return _cancelled;
}
public final boolean cancel(boolean mayInterruptIfRunning) {
if (_status == FINISHED || _cancelled) {
return false;
} else {
_cancelled = true;
if (mayInterruptIfRunning && _status == RUNNING) {
// NOTE: calling Thread.interrupt() usually doesn't work
// well, unless you don't care what state the background
// processing is left in. I'm not 100% sure that this is how
// Android's AsyncTask implements cancel(true), but I
// normally just cancel background tasks by letting the
// doInBackground() method check isCancelled() at multiple
// points in its processing.
_worker.interrupt();
}
return true;
}
}
protected final void publishProgress(final Object[] values) {
// call back onProgressUpdate on the UI thread
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
onProgressUpdate(values);
}
});
}
private void completeTask(final Object result) {
// transmit the result back to the UI thread
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
// TODO: not sure if status should be FINISHED before or after onPostExecute()
_status = FINISHED;
}
});
}
public AsyncTask execute(final Object[] params) throws IllegalStateException {
if (getStatus() != PENDING) {
throw new IllegalStateException("An AsyncTask can only be executed once!");
} else {
try {
onPreExecute();
_worker = new Thread(new Runnable() {
public void run() {
try {
// run background work on this worker thread
final Object result = doInBackground(params);
completeTask(result);
} catch (Exception e) {
// I believe if Thread.interrupt() is called, we'll arrive here
completeTask(null);
}
}
});
_status = RUNNING;
_worker.start();
} catch (Exception e) {
// TODO: handle this exception
}
}
return this;
}
}
Also, it's important to keep in mind the Threading Rules for Android's AsyncTask, which apply to the above implementation, too:
Threading rules
There are a few threading rules that must be followed
for this class to work properly:
The AsyncTask class must be loaded on the UI thread. This is done
automatically as of JELLY_BEAN.
The task instance must be created on
the UI thread.
execute(Params...) must be invoked on the UI thread.
Do not call onPreExecute(), onPostExecute(Result),
doInBackground(Params...), onProgressUpdate(Progress...) manually.
The task can be executed only once (an exception will be thrown if a
second execution is attempted.)
You can create a Class that extends my implementation of class AsyncTask. Good Luck :)
Here the methods onPreExecute, onPostExecute are executed on UI thread and doInBackground is called on worker thread. Since onPreExecute, onPostExecute are abstract you can override them and provide your implementation like showing and dismissing progress dialog.
The sequence in which methods get's executed is
1) onPreExecute
2) doInBackground
3) onPostExecute
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.Dialog;
public abstract class AsyncTask {
Runnable runnable;
Thread threadToRun;
public abstract void onPreExecute();
public abstract void onPostExecute();
public abstract void doInBackground();
public void execute() {
try {
runnable = new Runnable() {
public void run() {
// TODO Auto-generated method stub
UiApplication.getUiApplication().invokeLater(
new Runnable() {
public void run() {
// TODO Auto-generated method stub
onPreExecute();
}
});
doInBackground();
UiApplication.getUiApplication().invokeLater(
new Runnable() {
public void run() {
// TODO Auto-generated method stub
onPostExecute();
}
});
}
};
threadToRun = new Thread(runnable);
threadToRun.start();
} catch (Exception e) {
// TODO: handle exception
Dialog.alert("Async Error Occured. " + e.toString());
}
}
}

Categories

Resources