I've started this multi chat thread alert system and I've successfully gotten multiple clients on the server, but when broadcasting the message to everyone, it only interacts with the initial client sending the message and the sever only, the other client does not receive the message.
Here are the codes I'm working with
Client 1
package popup;
import java.io.*;
import java.net.*;
import javax.swing.*;
public class ClientJFrame extends javax.swing.JFrame {
static Socket s;
static DataInputStream din;
static DataOutputStream dout;
public ClientJFrame() {
super("Client 1");
initComponents();
}
private void alertButtonActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
try {
String msgout = "Alert client 1\n";
dout.writeUTF(msgout);
} catch (Exception e) {
}
}
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new ClientJFrame().setVisible(true);
}
});
try {
s = new Socket("127.0.0.1", 111);
din = new DataInputStream(s.getInputStream());
dout = new DataOutputStream(s.getOutputStream());
String msgin = "";
while (true) {
msgin = din.readUTF();
messageArea.append(msgin);
JOptionPane.showMessageDialog(null, "BITCH WE ON FIRE");
s.close();
System.exit(0);
}
} catch (Exception e) {
}
}
// Variables declaration - do not modify
private javax.swing.JButton alertButton;
private javax.swing.JScrollPane jScrollPane1;
private static javax.swing.JTextArea messageArea;
// End of variables declaration
}
Server
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
public class TestJFrame extends javax.swing.JFrame {
static ServerSocket listener;
static Socket s;
private static final int PORT = 111;
public TestJFrame() {
super("Main");
initComponents();
}
public static class Handler extends Thread {
private final Socket socket;
private DataInputStream in;
private DataOutputStream out;
public Handler(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
try {
in = new DataInputStream(socket.getInputStream());
messageArea.append("in\n");
out = new DataOutputStream(socket.getOutputStream());
messageArea.append("Out\n");
} catch (IOException e) {
}
while (true) {
try {
String input = in.readUTF();
messageArea.append(input);
out.writeUTF("We on Fire!!!\n");
} catch (IOException ex) {
Logger.getLogger(TestJFrame.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
public static void main(String args[]) throws IOException, InterruptedException {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new TestJFrame().setVisible(false);
createAndShowGUI();
}
});
listener = new ServerSocket(PORT);
try {
while (true) {
new Handler(listener.accept()).start();
}
} finally {
listener.close();
}
}
// Variables declaration - do not modify
private javax.swing.JButton alertButton;
private javax.swing.JScrollPane jScrollPane1;
private static javax.swing.JTextArea messageArea;
// End of variables declaration
}
When a client connects to the server, add him to a list, so you always know who's connected. The same goes for when he disconnects.
When a client sends a message, process it however you want, then iterate over the list of connected clients and send them the message.
Take a look at the observer pattern, I think it will help for your project.
Related
I need to establish connection between client websocket threw my backend on spring java to another websocket where my backend is a client, I established connection as client but can't figure out how to send it back as soon as my client send me message,
My Client Endpoint works as I need
#Service
#ClientEndpoint
public class ClientEndpoint {
Session userSession = null;
private MessageHandler messageHandler;
public WbsClientEndpoint(#Value("${url}") String url) {
try {
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
container.connectToServer(this, new URI(url));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
#OnOpen
public void onOpen(Session userSession) {
System.out.println("opening web socket");
this.userSession = userSession;
}
#OnClose
public void onClose(Session userSession, CloseReason reason) {
System.out.println("closing web socket");
this.userSession = null;
}
#OnMessage
public void onMessage(String message) {
if (this.messageHandler != null) {
this.messageHandler.handleMessage(message);
}
}
public void addMessageHandler(MessageHandler msgHandler) {
this.messageHandler = msgHandler;
}
public void sendMessage(String message) {
this.userSession.getAsyncRemote().sendText(message);
}
public interface MessageHandler {
void handleMessage(String message);
}
}
and example of method when I send my message as client, it does what I need but now I only printing the message cause cannot connect it to my message handler:
#Override
public void addDevice(DeviceTransfer deviceTransfer) {
clientEndPoint.addMessageHandler(message -> {
System.out.println("Response: " + message);
});
clientEndPoint.sendMessage(JSON.toJSONString(deviceTransfer));
}
Also I wrote a websockethandler for messages that comes to my backend:
#Component
public class WebSocketHandler extends AbstractWebSocketHandler {
#Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException {
System.out.println("New Text Message Received" + message + " ___ " + session);
String clientMessage = message.getPayload();
if (clientMessage.startsWith("/addDevice")) {
//Here I don't know how to send this clientMessage and wait for result from my addDevice method to return it back
}
}
}
And I need to connect both of the realizations to establish connection in real time.
When client sends message to me I must send this message to another server as client.
My client code on JavaScript as example, when I press button it establish connection to my web socket and send my message:
const connectBtn = document.getElementById('connect');
if (connectBtn) {
connectBtn.addEventListener('click', function () {
window.socket1 = new WebSocket("ws://localhost:8081/ws");
socket1.onopen = function(e) {
console.log("[open]");
socket1.send(JSON.stringify({"command": "subscribe","identifier":"{\"channel\":\"/topic/addDevice\"}"}))
};
socket1.onmessage = function(event) {
console.log(`[message]: ${event.data}`);
};
socket1.onclose = function(event) {
if (event.wasClean) {
console.log(`[close],code=${event.code}reason=${event.reason}`);
} else {
console.log('[close]');
}
};
socket1.onerror = function(error) {
console.log(`[error] ${error.message}`);
};
});
}
It seems to me like you need to keep track of your ClientEndpoint instances:
public class ClientEndpoint {
private HashSet<ClientEndpoint> endpoints = new HashSet<>();
// or perhaps a HashMap using `userSession.id` or similar
private HashMap<string, ClientEndpoint> userToEndpoint = new HahsMap<>();
#OnOpen
public void onOpen(Session userSession) {
System.out.println("opening web socket");
this.userSession = userSession;
this.endpoints.add(this);
this.userToEndpoint.put(userSession.id, this);
}
#OnClose
public void onClose(Session userSession, CloseReason reason) {
System.out.println("closing web socket");
this.endpoints.remove(this);
this.userToEndpoint.delete(userSession.id);
this.userSession = null;
}
}
You can use endpoints/userToEndpoint to find all connected clients, perhaps filter by which rooms they're in (I assume that's what you're trying to accomplish with that subscribe command), and do whatever you want with that information. E.g. a broadcast to everyone except the sender:
for (ClientEnpoint endpoint : this.endpoints) {
if (endpoint == sender) continue; // Don't send to sender
endpoint.sendMessage("message");
}
while signing up, I am unable to get the response code and error message so can you help me?
This is My Interface
public interface SignupAPI {
#FormUrlEncoded
#POST("users")
Call<ResponseBody> createUser(
#Field("email") String email,
#Field("password") String password,
#Field("role") String role
);
}
This is Java Class
public class SignupClient {
private static final String BASE_URL = "http://74.207.233.160/api/v1/";
private static SignupClient mInstance;
private Retrofit retrofit;
private SignupClient(){
retrofit = new Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create()).build();
}
public static synchronized SignupClient getmInstance(){
if (mInstance == null){
mInstance = new SignupClient();
}
return mInstance;
}
public SignupAPI getApi(){
return retrofit.create(SignupAPI.class);
}
}
This Is Signup Activity
progressBar.setVisibility(View.VISIBLE);
Call<ResponseBody> call = SignupClient.getmInstance().getApi().createUser(email, password,role);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.isSuccessful()){
progressBar.setVisibility(View.GONE);
Toast.makeText(SignupActivity.this, "Account Sucessfully Created", Toast.LENGTH_SHORT).show();
}else {
try {
progressBar.setVisibility(View.GONE);
JSONObject jsonError = new JSONObject(response.errorBody().string());
Toast.makeText(SignupActivity.this, jsonError.getString("errors"),Toast.LENGTH_SHORT).show();
} catch (JSONException e) {
progressBar.setVisibility(View.GONE);
e.printStackTrace();
} catch (IOException e) {
progressBar.setVisibility(View.GONE);
e.printStackTrace();
}
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Toast.makeText(SignupActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
}
I am not able to get error message and also response code so please help me to get it.
Here is the Postman PostMan API
Here I have written how you can get HTTP code from both success response and error response.
#Override
public void onResponse(Call<T> call, Response<T> response) {
int statusCode = response.code();
}
#Override
public void onFailure(Call<T> call, Throwable t) {
if (new Exception(t) instanceof HttpException) {
int statusCode = ((HttpException) t).getStatusCode();
else {
// unknown error
}
}
I'm using Ember for front-end and Java for back-end. On typing localhost:8080, I need to show the Ember homepage index.html. Previously, I used Node.js and the below line did the trick
res.sendfile('./public/index.html');
Now on shifting to Java, I'm unable to achieve the same result. I tried the below code.
public static void main(String[] args) throws Exception
{
HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
server.createContext("/", new HHandler());
server.createContext("/getbookarray", new MyHandler());
server.setExecutor(null); // creates a default executor
server.start();
}
static class HHandler implements HttpHandler
{
#Override
public void handle(HttpExchange t) throws IOException
{
File file = new File("..\\public\\index.html");
String response = FileUtils.readFileToString(file);
String encoding = "UTF-8";
t.getResponseHeaders().set("Content-Type", "text/html; charset=" + encoding);
t.getResponseHeaders().set("Accept-Ranges", "bytes");
t.sendResponseHeaders(200, response.length());
OutputStream os = t.getResponseBody();
os.write(response.getBytes("UTF-8"));
os.close();
}
}
But, unfortunately I'm getting the below error on trying to load the home page.
"Uncaught SyntaxError: Unexpected token <"
The same Ember application when processed using Node.js works fine. I guess I'm not sending the HTTP response properly. Any help is appreciated.
Maybe you have an issue with the path of your file. Also notice that the readFileToString is deprecated.
Here is a working server that will send your index.html to your frontend.
import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import org.apache.commons.io.FileUtils;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
public class myServer {
public static void main(String[] args) throws Exception {
System.out.println("server ...");
HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
server.createContext("/", new HHandler());
//server.createContext("/getbookarray", new HHandler());
//server.setExecutor(null); // creates a default executor
server.start();
//server.getExecutor();
}
static class HHandler implements HttpHandler {
#Override
public void handle(HttpExchange t) throws IOException {
Headers h = t.getResponseHeaders();
String line;
String resp = "";
try {
File newFile = new File("src/index.html");
System.out.println("*****lecture du fichier*****");
System.out.println("nom du fichier: " + newFile.getName());
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(newFile)));
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
resp += line;
}
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
h.add("Content-Type", "application/json");
t.sendResponseHeaders(200, resp.length());
OutputStream os = t.getResponseBody();
os.write(resp.getBytes());
os.close();
}
}
}
You can use the lightweight server nanoHttpd. With the following code you can send your index.html file to your frontend also.
import fi.iki.elonen.NanoHTTPD;
import java.io.*;
public class App extends NanoHTTPD {
public App() throws IOException {
super(8080);
start(NanoHTTPD.SOCKET_READ_TIMEOUT, false);
System.out.println("\nRunning! Point your browsers to http://localhost:8080/ \n");
}
public static void main(String[] args) {
try {
new App();
} catch (IOException ioe) {
System.err.println("Couldn't start server:\n" + ioe);
}
}
#Override
public Response serve(NanoHTTPD.IHTTPSession session) {
File newFile = new File("src/index.html");
System.out.println("*****lecture du fichier*****");
System.out.println("nom du fichier: " + newFile.getName());
String line;
String reponse = "";
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(newFile)));
while ((line = bufferedReader.readLine()) != null){
reponse += line;
}
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
return newFixedLengthResponse(reponse);
}
}
I'm trying to do a connection between a server in Java and a JavaScript client but I'm getting this error on client side:
WebSocket connection to 'ws://127.0.0.1:4444/' failed: Connection closed before receiving a handshake response
It maybe stays on OPENNING state because the connection.onopen function is never called. The console.log('Connected!') isn't being called.
Could someone let me know what is going wrong here?
Server
import java.io.IOException;
import java.net.ServerSocket;
public class Server {
public static void main(String[] args) throws IOException {
try (ServerSocket serverSocket = new ServerSocket(4444)) {
GameProtocol gp = new GameProtocol();
ServerThread player= new ServerThread(serverSocket.accept(), gp);
player.start();
} catch (IOException e) {
System.out.println("Could not listen on port: 4444");
System.exit(-1);
}
}
}
ServerThread
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class ServerThread extends Thread{
private Socket socket = null;
private GameProtocol gp;
public ServerThread(Socket socket, GameProtocol gp) {
super("ServerThread");
this.socket = socket;
this.gp = gp;
}
public void run() {
try (
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
) {
String inputLine, outputLine;
while ((inputLine = in.readLine()) != null) {
outputLine = gp.processInput(inputLine);
System.out.println(outputLine);
}
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
GameProtocol
public class GameProtocol {
public String processInput(String theInput) {
String theOutput = null;
theOutput = theInput;
return theOutput;
}
}
Client
var connection = new WebSocket('ws://127.0.0.1:4444');
connection.onopen = function () {
console.log('Connected!');
connection.send('Ping'); // Send the message 'Ping' to the server
};
// Log errors
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
};
// Log messages from the server
connection.onmessage = function (e) {
console.log('Server: ' + e.data);
};
To start with, both your code looks identical the Java and JavaScript one. Both work for what they are design to, but the facts is that you are trying to connect a WebSocket client to a socket server.
As I know they are two different things regarding this answer.
I have never tried it your way. That said if I have a network application that use socket than it would be pure client/server socket, and if it was a web application than I would use WebSocket on both side as well.
So far so good..
To make this work, this answer suggests to use any available WebSocket on server side and your problem is solved.
I am using WebSocket for Java and here is a sample implementation that I have tested with your client code and it works, both on client and server side.
import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;
import java.net.InetSocketAddress;
import java.util.HashSet;
import java.util.Set;
public class WebsocketServer extends WebSocketServer {
private static int TCP_PORT = 4444;
private Set<WebSocket> conns;
public WebsocketServer() {
super(new InetSocketAddress(TCP_PORT));
conns = new HashSet<>();
}
#Override
public void onOpen(WebSocket conn, ClientHandshake handshake) {
conns.add(conn);
System.out.println("New connection from " + conn.getRemoteSocketAddress().getAddress().getHostAddress());
}
#Override
public void onClose(WebSocket conn, int code, String reason, boolean remote) {
conns.remove(conn);
System.out.println("Closed connection to " + conn.getRemoteSocketAddress().getAddress().getHostAddress());
}
#Override
public void onMessage(WebSocket conn, String message) {
System.out.println("Message from client: " + message);
for (WebSocket sock : conns) {
sock.send(message);
}
}
#Override
public void onError(WebSocket conn, Exception ex) {
//ex.printStackTrace();
if (conn != null) {
conns.remove(conn);
// do some thing if required
}
System.out.println("ERROR from " + conn.getRemoteSocketAddress().getAddress().getHostAddress());
}
}
On your main method just:
new WebsocketServer().start();
You might need to manipulate your code to fit it with this implementation, but that should be part of the job.
Here is the test output with 2 tests:
New connection from 127.0.0.1
Message from client: Ping
Closed connection to 127.0.0.1
New connection from 127.0.0.1
Message from client: Ping
here is WebSocket maven configuration, otherwise download the JAR file/s manually and import it in your IDE/development environment:
<!-- https://mvnrepository.com/artifact/org.java-websocket/Java-WebSocket -->
<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
<version>1.3.0</version>
</dependency>
Link to WebSocket.
I am developing a spring boot web application(My first Application) and it works fine when I deploy it in the embedded tomcat server.But when I deploy it in the standalone Tomcat server it cannot accesss the database.I am using Rest WebService to pass the data to the front end and my url will be look like
http://localhost:8080/day_demand?day=3
But in my standalone server when I access
http://localhost:8080/WebApp/day_demand?day=3 (WebApp is my project name)
The connection to the database is made by the below code:
private Connection connectToDatabaseOrDie()
{
Connection conn = null;
try
{
Class.forName("org.postgresql.Driver");
String url = "jdbc:postgresql://localhost:5432/data_base";
conn = DriverManager.getConnection(url,"user", "password");
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
System.exit(1);
}
catch (SQLException e)
{
e.printStackTrace();
System.exit(2);
}
return conn;
}
private void populateListOfTopics(Connection conn, List<State> listOfBlogs,Timestamp start_time,Timestamp end_time,int zone_id)
{
try
{
String sql= "SELECT * FROM public.table where time >= ? and time <= ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setTimestamp(1,start_time);
pstmt.setTimestamp(2,end_time);
ResultSet rs = pstmt.executeQuery();
while ( rs.next() )
{
State blog = new State();
blog.year = rs.getInt ("year");
blog.month=rs.getInt ("month");
blog.day = rs.getInt ("day");
blog.hour = rs.getInt ("hour");
listOfBlogs.add(blog);
}
rs.close();
pstmt.close();
conn.close();
}
catch (SQLException se) {
System.err.println("Threw a SQLException creating the list of state.");
System.err.println(se.getMessage());
} catch (Exception e) {
System.out.println("Err");
e.printStackTrace();
}
}
I cannot able to access the data.Any help is appreciated.
You need to do the below steps:
1) In pom.xml file , make scope as provided for embedded server
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
<scope>provided</scope>
</dependency>
or
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
2) In pom.xml file, make packaging as war
<packaging>war</packaging>
3) Extend SpringBootServletInitializer class in your Application.class
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
#SpringBootApplication
#Configuration
#ComponentScan
#EnableAutoConfiguration
public class Application extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
private static Class<Application> applicationClass = Application.class;
}
4) Take the war from target folder and deploy it to External tomcat
and start the server.You will see logs as below :
5) Hit the URL somewhat like below :
http://localhost:8080/SpringBootExamples-0.0.1-SNAPSHOT/persons/1
SpringBootExamples-0.0.1-SNAPSHOT = Context path
Same as Extracted folder name in External Tomcat Server
#john
I have twisted your code as per my Database and im able to get the data from db.Im using mysql.
Here is the code:
#RestController
public class PersonController {
#Autowired
private PersonRepository personRepository;
#RequestMapping(value = "/persons/{id}", method = RequestMethod.GET,produces={MediaType.APPLICATION_XML_VALUE},headers = "Accept=application/xml")
public ResponseEntity<?> getPersonDetails(#PathVariable Long id, final HttpServletRequest request)throws Exception {
System.out.println("Before");
ConnectionManager cm=new ConnectionManager();
Person personResponse=cm.populateListOfTopics();
System.out.println("personResponse"+personResponse);
return ResponseEntity.ok(personResponse);
}
}
Connection Class:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.List;
public class ConnectionManager {
private Connection connectToDatabaseOrDie()
{
Connection conn = null;
try
{
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/master?createDatabaseIfNotExist=false";
conn = DriverManager.getConnection(url,"root", "mysql");
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
System.exit(1);
}
catch (SQLException e)
{
e.printStackTrace();
System.exit(2);
}
return conn;
}
public Person populateListOfTopics()
{
Person person=new Person();
try
{
Connection conn = ConnectionManager.this.connectToDatabaseOrDie();
String sql= "SELECT * FROM master.person WHERE ID = 1";
PreparedStatement pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery();
while (rs.next())
{
person.setFirst_name(rs.getString("FIRST_NAME"));
}
rs.close();
pstmt.close();
conn.close();
}
catch (SQLException se) {
System.err.println("Threw a SQLException creating the list of state.");
System.err.println(se.getMessage());
} catch (Exception e) {
System.out.println("Err");
e.printStackTrace();
}
return person;
}
}