I'm trying to run a Jetty Server that can have a number of people connect to the server and see a list of print outs. I want everybody who connects to see the same values printed out.
For instance, if I have a single list keeping track of the time and I want 5 or so people to be able to go to my website (e.g. localhost:8080/time) and have them all see what time it is every 30 seconds, how would i set that up?
What I have:
I am using Jetty.
I created a single server bound to port 8080.
I created my own handler that extends AbstractHandler
this writes to the screen saying when an event has transpired (i.e. 30 seconds have passed)
If two people connect to this page, they each see a print out every minute (that is it switches back and forth letting each person know when every other event has transpired)
If 3 people connect, only two can stay connected and the third just spins getting no output to the screen
I have not set up an Connectors of my own since my attempts to do so have been unsuccessful and i'm not sure how I understand if that is the solution to my problem.
Any help would be much appreciated and if anybody has some idea but needs some clarification on what I am doing I would be glad to give more details.
Thanks!
Handler code:
#Override
public void handle(String target, Request request, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException, ServletException
{
httpServletResponse.setContentType("text/html;charset=utf-8");
httpServletResponse.setStatus(HttpServletResponse.SC_OK);
request.setContextPath("/time");
request.setHandled(true);
while (true) {
synchronized(Main.list) {
while (!Main.list.isEmpty()) {
Double time = Main.list.get(0);
httpServletResponse.getWriter().println("<h1>The time now is " + time + "</h1>");
httpServletResponse.flushBuffer();
Main.list.remove(0);
}
try {
Main.list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
So the list object is a static ArrayList defined in the Main class that I wake up (i.e. notify) every 30 seconds. Hopefully this helps someone understand more what I am talking about as i'm not sure what I could change in the handler...
How are you feeding clients into your handler? Browsers have limits to the number of connections are made to to a particular host, perhaps your seeing that.
there is nothing intrinsically wrong that handler code aside from it being a generally odd thing to see in a handler
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'm working on a websocket implementation that collects data from several (around 10) android clients.
So I have created a classic ServerEndpoint running currently on localhost and on client side an app that opens up a connection to the ServerEndpoint and sends sensor data every 500ms.
The whole thing works fine and on time if I use just one client.
However if I use multiple clients, they send their messages all on time, but the ServerEndpoints onMessage is called at random times. It looks like it "queues" messages from a clients for several seconds, and then fires the onMessage method 5 times in a row. I would need it always on the exact time however. Can I force this?
No errors or exceptions showing up.
This is the very basic server side:
#ServerEndpoint("/ServerEndpoint")
public class ServerEndpoint {
static Set<Session> connections = Collections.synchronizedSet(new HashSet<Session>());
#OnOpen
public void handleOpen(Session userSession){
log("opened session: "+ userSession);
connections.add(userSession);
}
#OnMessage
public void handleMessage(String message, Session userSession) throws IOException{
String userName = (String) userSession.getUserProperties().get("username");
log("received message from: "+ userName+": "+Calendar.getInstance().get(Calendar.SECOND)+":"+Calendar.getInstance().get(Calendar.MILLISECOND)+ " "+ message );
....
}
#OnClose
public void handleClose(Session userSession){
log("closed session: "+userSession);
connections.remove(userSession);
}
I guess I miss some configuration option of the ServerEndpoint or something. Does someone know what causes this behavior and how to solve it?
Alright got it. The issue was Tomcat 7 which has obviously some issues with websockets. Using Tomcat 8, it works now without any queues or big delay. Also other minor errors and connection problems were solved by the update and it seems to be much more stable.
Maybe this helps someone facing similar problems.
I'm currently in the progress of working on a telephone application, and for easy portability I'm making use of Unity3D. The application's design looks nice and crisp and scales well into all of my target resolutions, but the networking is giving me an issue.
I'm using Java for the server backend, and I'm using JDBC to mananage database connections. The problem is that this application is sure to have a few thousand users at minimum (Based on my current following, blogs, and marketing techniques) and I would like to make sure that I'm doing this correctly to avoid any lockups from SQL being used at the same time.
This application pulls everything that is needed from the database. For security and glitch prevention reasons if the database cannot be connected the server lets the client(application) know that there was an error.
Here's what I'm worried about: When a user logs in a few things are done almost instantly. The database is checked for their login credentials, if it's successful the client then loads the next stage of the application then sends a packet to the server. The server then grabs more information from the server (This is done through a total of three queries in the shortest form I can possibly come up with.) However; What happens if a 2-300 people are logging in, 3-400 are spending tokens (Requires db calls) and 2-300 are requesting database data elsewhere. That's around 1,000 requested database calls coming in.
I don't want the application to seem really laggy.
Here's how I'm currently handling it after a little research, but it doesn't feel necessarily right. Looking for advice and corrections. (decodeTCP is called when a packet with the header id of X is received.)
public void decodeTcp(Session session) throws IOException {
try {
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
ScheduledFuture<?> scheduledFuture = scheduledExecutorService.schedule(new Callable<Object>() {
public Object call() throws Exception {
return Database.getSingleton().fetch((User)session.getAttachment());
}
}, 0, TimeUnit.SECONDS);
int results = (int) scheduledFuture.get();scheduledFuture.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
Where Database#fetch(Object) returns an int.
My deployed server has sometimes long response times, while working and developing at localhost all calls are really fast.
This has made my application enter unexpected behaviour once deployed a few times due to problems with resource loading taking too long.
I'd like to simulate in my local tests the bad connection with my real server, therefore I want to add a random delay to every request-response and my first thought was to use Thread.sleep in the servlet:
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//add delay before processing request
if (DELAY > 0){
int delay;
if (RANDOMIZE){
delay = Random.nextInt(DELAY);
} else {
delay = DELAY;
}
try {
Thread.sleep(delay);
} catch (InterruptedException e1) {
logger.error(e1);
}
}
...
However I have read that one should not use Thread.sleep() inside a servlet, but the context of such discouragement and their solutions are drastically different from my case, can I use thread.sleep() in this context?
EDIT: This is of course only for local and for the client to be strained a bit in the local tests... I just want to simulate the bad network I've encountered in reality!
I think this whole approach is flawed. I wouldn't introduce a random delay (how are you going to repeat test cases?). You can introduce a Thread.sleep(), but I wouldn't. Would this be in your production code ? Is it configurable ? What happens if it's accidentlally turned on in production ?
I would rather set up a test server with the exact characteristics of your production environment. That way you can not only debug effectively, but build a regression test suite that will allow you to develop effectively, knowing how the application will perform in production.
Perhaps the one concession to the above is to introduce network delays (as appropriate) between client and server if your users are geographically diverse. That's often done using a hardware device on the network and wouldn't affect your code or configuration.
I did this to get delay :
response.setContentType("text/html;charset=UTF-8");
try (PrintWriter out = response.getWriter()) {
out.println("<meta http-equiv=\"Refresh\" content=\"3;url=home.jsp/\">");
}
Remember that in content=\"3;url=home.jsp/\", 3 is the delay seconds and home.jsp is the page you want to go to after the given seconds.
How does async JMS work? I've below sample code:
public class JmsAdapter implements MessageListener, ExceptionListener
{
private ConnectionFactory connFactory = null;
private Connection conn = null;
private Session session = null;
public void receiveMessages()
{
try
{
this.session = this.conn.createSession(true, Session.SESSION_TRANSACTED);
this.conn.setExceptionListener(this);
Destination destination = this.session.createQueue("SOME_QUEUE_NAME");
this.consumer = this.session.createConsumer(destination);
this.consumer.setMessageListener(this);
this.conn.start();
}
catch (JMSException e)
{
//Handle JMS Exceptions Here
}
}
#Override
public void onMessage(Message message)
{
try
{
//Do Message Processing Here
//Message sucessfully processed... Go ahead and commit the transaction.
this.session.commit();
}
catch(SomeApplicationException e)
{
//Message processing failed.
//Do whatever you need to do here for the exception.
//NOTE: You may need to check the redelivery count of this message first
//and just commit it after it fails a predefined number of times (Make sure you
//store it somewhere if you don't want to lose it). This way you're process isn't
//handling the same failed message over and over again.
this.session.rollback()
}
}
}
But I'm new to Java & JMS. I'll probably consume messages in onMessage method. But I don't know how does it work exactly.
Do I need to add main method in JmsAdapter class? After adding main method, do I need to create a jar & then run the jar as "java -jar abc.jar"?
Any help is much appreciated.
UPDATE: What I want to know is that if I add main method, should I simply call receiveMessages() in main? And then after running, will the listener keep on running? And if there are messages, will it retrieve automatically in onMessage method?
Also, if the listener is continuously listening, doesn't it take CPU??? In case of threads, when we create a thread & put it in sleep, the CPU utilization is zero, how doe it work in case of listener?
Note: I've only Tomcat server & I'll not be using any jms server. I'm not sure if listener needs any specific jms server such as JBoss? But in any case, please assume that I'll not be having anything except tomcat.
Thanks!
You need to learn to walk before you start trying to run.
Read / do a tutorial on Java programming. This should explain (among other things) how to compile and run a Java program from the command line.
Read / do a tutorial on JMS.
Read the Oracle material on how to create an executable JAR file.
Figure out what it is you are trying to do ... and design your application.
Looking at what you've shown and told us:
You could add a main method to that class, but to make an executable JAR file, you've got to create your JAR file with a manifest entry that specifies the name of the class with the main method.
There's a lot more that you have to do before that code will work:
add code to (at least) log the exceptions that you are catching
add code to process the messages
add code to initialize the connection factory and connection objects
And like I said above, you probably need some kind of design ... so that you don't end up with everything in a "kitchen sink" class.
if I add main method, should I simply call receiveMessages() in main?
That is one approach. But like I said, you really need to design your application.
And then after running, will the listener keep on running?
It is not entirely clear. It should keep running as long as the main thread is alive, but it is not immediately obvious what happens when your main method returns. (It depends on whether the JMS threads are created as daemon threads, and that's not specified.)
And if there are messages, will it retrieve automatically in onMessage method?
It would appear that each message is retrieved (read from the socket) before your onMessage method is called.
Also, if the listener is continuously listening, doesn't it take CPU???
Not if it is implemented properly.
In case of threads, when we create a thread & put it in sleep, the CPU utilization is zero, how doe it work in case of listener?
At a certain level, a listener thread will make a system call that waits for data to arrive on a network socket. I don't know how it is exactly implemented, but this could be as simple as an read() call on the network socket's InoutStream. No CPU is used by a thread while it waits in a blocking system call.
This link looks like a pretty good place with examples using Oracle AQ. There's an examples section that tells you how to setup the examples and run them. Hopefully this can help.
Link to Oracle Advanced Queueing