Trying to write a UDP client-server application using Swing. Each instance of the client should be able to send messages to the Server (from the event dispatch thread) and also continuously listen for messages from other clients relayed through the server (on a worker thread using SwingWorker). I'm trying to implement a ListenWorker class now whose doInBackground method will continuously listen for UDP datagrams, and publish the data to the process() method, with will update a JTextArea on the client JFrame with the message. However, I'm running into some difficulties due to my inexperience with SwingWorker and general Swing concurrency. Here is the gist of the code I wrote so far:
public class ListenWorker extends SwingWorker<void, String> {
public ListenWorker(int port, JTextArea textArea){
// set up socket
}
protected void doInBackground(){
while(true){
// code to receive Datagram
publish(messageFromDatagram);
}
}
protected void process(List<String> messages){
for(String message : messages){
textArea.append(message);
}
}
}
However, my IDE is giving me an error in the first line where I start the class defintion, saying "illegal start of type" due to void being there. As far as I can see, I want my doInBackground to be a void method, since I intend it to run indefinitely, listening for datagrams from the various clients. Java doesn't seem to want to let me have it as a void method though. How would I code a way around this?
You probably want java.lang.Void to represent the doInBackground() return type; for example SwingWorker<Void, String>.
Addendum: doInBackground() would then return null.
Related
I am coding a discord bot in java, I use discord JDA, and the utilities dependency, I tried using the utilities one but I didn't get it to work, so I tried using just the normal JDA, this is what I did, but I need some way of telling the bot not to send the message in the new channel if the command wasn't ran.
public class NukeCommand extends ListenerAdapter {
#Override
public void onGuildMessageReceived(GuildMessageReceivedEvent event){
if (event.getMessage().getContentRaw().equalsIgnoreCase(".nuke")){
event.getChannel().createCopy().queue();
event.getChannel().delete().queue();
}
}
#Override
public void onTextChannelCreate(TextChannelCreateEvent createEvent){
createEvent.getChannel().sendMessage(":warning:Nuked channel:warning:\nhttps://imgur.com/a/93vq9R8").queue();
}
I am open for answers in both dependencies.
this is the effect I want: https://gyazo.com/e549fd8dda0ded62db19fb84e31d3a61
I have the same effect but it sends the message every time I create a text channel.
I want it to only send the message if the .nuke command was ran.
You said you already got it but I though I'd explain more about how it actually works and refine your answer.
ListenerAdapter's methods are called for every event that happens in the whole scope of the bot, for example if you have
class Adapter extends ListenerAdapter {
#Override
public void onMessageReceived(MessageReceivedEvent event){
/*This will be called for every message, everywhere, including the bot's private channel*/
}
}
So you need to filter those events inside the method's body, what you did on your answer was check if whoever sent the message has permissions to manage messages, which is not the one you actually need to delete channels, it is Permission.MANAGE_CHANNELS, you can find at the roles tab in your server.
Then you call createCopy() which basically creates a shallow copy of the channel's information
I don't think you actually wanted to do that.
Then you queue that action, (This is what actually executes it) it is put in a queue for asynchronous processing by JDA's threads, which will subsequently be sent to discord over the websocket connection.
That queue method can take a Consumer<TextChannel> as a parameter, what does that mean?
Basically a consumer represent an operation that takes a single parameter as input (In this case a TextChannel) and returns nothing. More about it here: https://docs.oracle.com/javase/8/docs/api/java/util/function/Consumer.html
The consumer you give in your answer is doing what you actually want to, sending the message, on the channel that was operated on by the previous queue, meaning that, createCopy() is completely useless, both TextChannel objects are the same, the appropriate would be:
event.getChannel().sendMessage(":warning:Nuked channel:warning:\nhttps://imgur.com/a/93vq9R8").queue();
After that, you delete the channel right away, which does not make that much sense, since most likely no one would even be able to see the nuked message.
For that, JDA provides another method for queueing tasks, this time with a delay:
queueAfter()
It takes a long as the value, and a TimeUnit object to specify what is the time unit of said value, for example:
event.getChannel().delete().queueAfter(10, TimeUnit.SECONDS);
This would queue the task to be executed in 10 seconds, and it does NOT stop the execution of your code, unlike the complete() method.
Alternatively to that, you could just use Thread.sleep() which takes a long value as input: Thread.sleep(10000) for 10 seconds (10000 milliseconds).
You can find a lot more information regarding JDA and start tips and here: https://github.com/DV8FromTheWorld/JDA#creating-the-jda-object
I found a solution you can pass a consumable or whatever its called into the .queue method, this code gets run whenever the channel is created.
what i did:
#Override
public void onGuildMessageReceived(GuildMessageReceivedEvent event){
if (event.getMember().hasPermission(Permission.MESSAGE_MANAGE)){
if (event.getMessage().getContentRaw().equalsIgnoreCase(".nuke")){
event.getChannel().createCopy().queue(channel->channel.sendMessage(":warning:Nuked channel:warning:\nhttps://imgur.com/a/93vq9R8").queue());
event.getChannel().delete().queue();
}
}
}
This seems to work (Without deleting the channel)
#Override
public void onMessageReceived(#NotNull MessageReceivedEvent event) {
String message = event.getMessage().getContentRaw();
if (message.toLowerCase().equals("$" + "clear")) {
for (int i = 0; i <= 1000; i++) {
TextChannel channel = (TextChannel) event.getChannel();
MessageHistory history = new MessageHistory(channel);
List<Message> msgs;
msgs = history.retrievePast(100).complete();
if (msgs.size() > 1) {
channel.deleteMessages(msgs).queue();
} else {
channel.sendMessage("Mensagens deletadas").queue();
return;
}
}
}`
I have program (MAIN) that has two thread that communicates with com port (COM) and TCP session (TCP).
If main (MAIN) program need info from TCP and COM modules it sends request message R (tR and cR). When threads have answer they send back answer A (tA and cA). I have problem, when I send reguest to COM (cR) and without getting answer from it have answer from TCP- tA. COM R-A should be somehow isolated from TCP interruption. How to solve this problem using JAVA 1.4 ?
UPD. On tA event MAIN initiates cR - request to COM port. Main can initiate request to COM by itself. I would like avoid to have second question to COM port without getting answer from first one.
UPD2. Actually whole system looks like picture below. cR might be started by tA or by uR. And cA can answer to TCP via tR or to UI via uA.
Following scenarios are correct
uR->cR->cA->tR-tA->cR->cA->uA
cA->tR->tA->cR
uR->cR->cA->uA
I'm getting troubles when two requests goes to COM at the same time.
cA->tR->tA->cR
uR->cR
I would like to allow new request only in case when COM returns answer to first caller.
As I understand correctly you have 2 threads in main method. 1 thread is interacting with with TCP and another with COM. Right?
If this is the case than what you can do is you can let handle thread 1 to handle all TCP request/response and thread 2 to handle all COM request/response. And the main thread is not aware of this. Until the time both thread finish their job independently the main threads wait and once both thread are done with their job, Main thread can resume its work. hence the communication of COM and TCP is completley separate. you can use Threads "join()" method here.
Did I answer your question?
You don't have to use multiple threads. Just read the request from the socket, synchronously process the request by communicating over the COM port, and then write the response over the socket.
There may be reasons to use multiple threads, though. For example, perhaps you want to be able to respond to socket requests with a time-out error if the COM port doesn't respond fast enough, but the serial port library you are using doesn't support a time-out configuration. In that case, you'll have to clarify your requirements. What do you want to happen if another request is received from the socket, but the COM thread is still stuck handling a previous request? You could wait, respond with an error immediately, etc.
Create a single-thread ExecutorService. Whenever you need to interact with the COM port, whether the request originates from the socket or from the main program itself, submit the task to this service. This will ensure that serial communications won't be interleaved with competing requests.
The basic idea here is to allow only one thread to use the COM port, consuming a queue of tasks produced by various other threads.
Here is one example that can explain your system. Here i have made a environment of caller receiver. Until caller not end with his or her statement receiver can not start with saying anything or respond to caller.
Caller.java
public class Caller implements Runnable {
MaintainACall call;
Caller(MaintainACall me)
{
call=me;
new Thread(this,"Mr X").start();
}
public void run()
{
String a[]={"Hello how r u", "I'm in vadodara"};
for(int i=0;i<2;i++)
{
call.sayHello(a[i]);
}
}
}
Receiver.java
public class Reciver implements Runnable {
MaintainACall call;
Reciver(MaintainACall call)
{
this.call=call;
new Thread(this,"Mr Y").start();
}
public void run()
{
call.Wtshesay();
}
}
MaintainACall.java
public class MaintainACall {
String say;
boolean valueSet=false;
synchronized String Wtshesay()
{
while(!valueSet)
try
{
wait();
}
catch(InterruptedException ie)
{
System.out.println(ie);
}
System.out.println("I have heared "+say);
valueSet=false;
notify();
return say;
}
synchronized void sayHello(String msg)
{
while(valueSet)
try
{
wait();
}
catch(InterruptedException ie)
{
System.out.println(ie);
}
say=msg;
valueSet=true;
System.out.println("She says "+say);
notify();
}
}
MainClass.java
public class MainClass {
public static void main(String arg[])
{
MaintainACall my=new MaintainACall();
new Caller(my);
new Reciver(my);
}
}
I have a question for you.
I have multiple Threads runnings of a class called ServerThread. When an specific event happens on ANY of those threads, I want to call a method of every other thread running in parallel.
public class ServerThread implements Runnable {
private TCPsocket clientSocket;
public ServerThread(Socket comSocket){
clientSocket = new TCPsocket(comSocket);
}
#Override
public void run(){
boolean waiting = true;
Message msg;
try{
while(waiting){
msg = clientSocket.getMessage();
shareMessage(msg);
}
}catch(Exception e){
ErrorLogger.toFile("EndConnection", e.toString());
}
}
public void shareMessage(Message msg){
clientSocket.sendMessage(msg);
}
}
I am talking about this specific line
shareMessage(msg);
which I would like to be called on every thread/instance
-- so that a message is sent to every client (in all tcp connections)
I've tried with synchronized but either I'm not using it well or that is not what I am looking for.
Another thing that might work is keeping a class with an static member which is a list of those tcpconnection objects and then do some loop in all every time.
Thanks for your help and time.
Edited with one possible solution
*Add an static array as a member of the class and add/remove objects of same class (or tcp sockets would also work)
private static ArrayList<ServerThread> handler;
...
handler.add(this);
...
handler.remove(this); //when client exists and thread stops
*Then create a method that iterates for each connection, and make it synchronized so that two threads won't interact at the same time. You may want to implement synchronized on your message sending methods as well.
public void shareMessage(Message msg){
//this.clientSocket.sendMessage(msg);
synchronized (handler){
for(ServerThread connection: handler){
try{
connection.clientSocket.sendMessage(msg);
} catch(Exception e){
connection.clientSocket.closeConnection();
}
}
}
}
First: synchronized is required to prevent race conditions when multiple threads want to call the same method and this method accesses/modifies shared data. So maybe (probably) you will need it somewhere but it does not provide you the functionality you require.
Second: You cannot command an other thread to call a method directly. It is not possible e.g. for ThreadA to call methodX in ThreadB.
I guess you have one thread per client. Probably each thread will block at clientSocket.getMessage() until the client sends a message. I don't know the implementation of TCPsocket but maybe it is possible to interrupt the thread. In this case you may need to catch a InterruptedException and ask some central data structure if the interrupt was caused because of a new shared message and to return the shared message.
Maybe it is also possible for TCPsocket.getMessage() to return, if no message was received for some time, in which case you would again have to ask a central data structure if there is a new shared message.
Maybe it is also possible to store all client connections in such a data structure and loop them every time, as you suggested. But keep in mind that the client might send a message at any time, maybe even at the exact same time when you try to send it the shared message received from another client. This might be no problem but this depends on your application. Also you have to consider that the message will also be shared with the client that sent it to your server in the first place…
Also take a look at java.util.concurrent and its subpackages, it is likely you find something useful there… ;-)
To summarize: There are many possibilities. Which one is the best depends on what you need. Please add some more detail to your question if you need more specific help.
I want to port my client from Java Swing(Java client) to Android(Android client).
Basically, my Java client have a thread, which run a forever while loop to receive UDP packets, and base on content of UDP packets, UI of the corresponding JFrame will be updated.
Now I want my Android client has a background worker like the thread in the Java client, and that worker will be initialized in the main activity. Then when there are some requests from the UDP socket, the main activity will start some corresponding activities (Chat Activities), then there are some other requests come from the UDP socket, the worker will update on the activity(this activity can be main activity or a Chat Activity) which is being displayed on the screen.
So my question is what the background worker should be:
Service
Normal Java thread
Asynctask
or what...
Which is the most appropriate with my requirements?
Thanks!
The background worker should be a service, because
A Service is an application component that can perform long-running
operations in the background and does not provide a user interface.
while your UI will be a activity, your service will read the UDP packets and the activity will be modified accordingly.
A Service is the most suitable candidate in your case.
There is a class Application class for each android application . First extend it and it will be initialized on very first time your app will start even before your Activity . Initialize/ start your normal java thread to perfrom background work here . The key advantage will be you can get instance of this application class anywhere from the app (It means you can control on the background thread from anywhere in the applicaion . Send background http request etc.. whatever ....) .Then initialize the handler on the UI thread of particular activity upon which you want to do changes and do something like this.
private Handler myHandler ;
public void checkBackgroundAndUpdateUi()
{
if(conetxt.getApplicationContext().getStatus == completed)
{
initializeHandler();
handler.postRunnable(myRunnable);
}
}
Runnable myRunnable = new Runnable(){
public void run()
{
// update your UI views here .....
}
};
private void initializeHandler(){
myHandler = new Handler ();
}
I haven't got any code at the moment but I have a situation where I will be implementing an Java application onto a wireless sensor. There can only be one main method.
There will be multiple other wireless sensors that can connect to my sensor. My sensor needs to do a calculation based on thhe information provided to me by the other sensors. Each sensor can choose whether or not they want to participate in the calculation. Every 1 second, my sensor does a calculation.
So basically, what I need is to listen for incoming sensors, provide them with a thread to interact with, and retrieve the information from each sensor.
My question is, in my application, how do I listen for incoming sensors (blocking call) and also free my application to carry out its calculations?
From a high level, this is what your application will do
==Main Thread==
start socket
Start processing thread
accept an incoming connection (this will cause the thread to block until a connection occurs)
start new thread to handle socket (handler thread) (alternatively use a thread pool, but that is more complicated)
return to 3
==Handler Thread==
Receive open socket from main thread
Save data coming in from socket to be given to processing thread
Finish and close socket
==Processing Thread==
Wait 1 second
Process data retrieved from step 2 of Handler Thread
Return to 1
You need another thread that receives the information of all the communication threads. You should look at the utilities in java.util.concurrent such a BlockingQueue that let threads pass data to one another thread-safely.
Most of all you should read a lot about multi-threading: it is not a trivial topic.
This will get you started. Add error/exception checking/handling as necessary.
public class Test {
static class WorkTask42 implements Runnable {
public void run() {
// background work
}
}
public static void main(String... args) throws Exception {
// repeat for each background task
WorkTask42 wt = new WorkTask42();
Thread a = new Thread(wt);
a.setDeamon(true);
a.start();
}
}