In the server end, I use Spring-websocket, Handshake as follow:
public class WebsocketEndPoint extends TextWebSocketHandler {
#Override
protected void handleTextMessage(WebSocketSession session,
TextMessage message) throws Exception {
System.out.println("start to translate data!");
super.handleTextMessage(session, message);
for (int i = 0; i <= 1000; i++) {
session.sendMessage(new TextMessage("push message " + i));
Thread.sleep(2000);
}
session.sendMessage(message);
}
#Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
System.out.println("Connection Established!");
}
#Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
System.out.println("Connection Closed!");
}
}
springmvc.xml as follow:
<mvc:default-servlet-handler/>
<bean id="websocket" class="com.yyp.mvc.controller.WebsocketEndPoint" />
<websocket:handlers>
<websocket:mapping path="/websocket" handler="websocket" />
<websocket:handshake-interceptors>
<bean class="com.yyp.mvc.controller.HandshakeInterceptor" />
</websocket:handshake-interceptors>
</websocket:handlers>
In the client, my html as follow:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
</head>
<body>
<button onclick="closeSocket()">stop socket</button>
<script>
var wsServer = 'ws://localhost:8080/websocket';
var websocket = new WebSocket(wsServer);
websocket.onopen = function (evt) { onOpen(evt) };
websocket.onclose = function (evt) { onClose(evt) };
websocket.onmessage = function (evt) { onMessage(evt) };
websocket.onerror = function (evt) { onError(evt) };
function onOpen(evt) {
console.log("Connected to WebSocket server.");
websocket.send('hello');
}
function onClose(evt) {
console.log("Disconnected");
}
function onMessage(evt) {
console.log('Retrieved data from server: ' + evt.data);
}
function onError(evt) {
console.log('Error occured: ' + evt.data);
}
function closeSocket (argument) {
console.log("close socket");
websocket.close();
websocket=null;
}
</script>
</body>
</html>
Finally, I could get log like this in the server:
before shakeHands
after shakeHands
Connection Established!
start to translate data!
Why couldn't get the "Connection Closed!" log after I click the "stop socket" button or how can I process the connection close information form the client?
Related
I want to send an WebSocket Message when received socket message, but it won't work.
I tried to call an method, but it seems it doesn't send a message to its subscribers even if it has #SendTo annotation.
Isn't calling a method directly have to be sending a message to its subscribers?
here are my codes that I tried.
Greetings.class
#NoArgsConstructor
#Getter
#Setter
public class Greeting {
private InCarOutcarVisitor inCarOutcarVisitor;
private InAndOutPeriods inAndOutPeriods;
public Greeting(InCarOutcarVisitor inCarOutcarVisitor){
this.inCarOutcarVisitor = inCarOutcarVisitor;
}
public Greeting(InAndOutPeriods inAndOutPeriods){
this.inAndOutPeriods = inAndOutPeriods;
}
}
GreetingController.class
#Controller
public class GreetingController {
#Autowired
SidebarInfoService sidebarInfoService;
#MessageMapping("/hello")
#SendTo("/topic/greetings")
public InCarOutcarVisitor inCarOutcarVisitor() {
Integer incarCounting = Math.toIntExact(sidebarInfoService.getIncarCounting());
Integer outcarCounting = Math.toIntExact(sidebarInfoService.getOutcarCounting());
Integer visitorCounting = Math.toIntExact(sidebarInfoService.getVisitorCounting());
return new InCarOutcarVisitor(incarCounting,outcarCounting,visitorCounting);
}
}
WebSocketConfig.class
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/gs-guide-websocket").withSockJS();
}
}
ParkingApplication.class
public class ParkingApplication {
private static GreetingController sGreetingController;
#Autowired
GreetingController greetingController;
#PostConstruct
public void init(){
ParkingApplication.sGreetingController = greetingController;
}
public static void main(String[] args) throws IOException {
SpringApplication.run(ParkingApplication.class, args);
Socket socket = null; //Client와 통신하기 위한 Socket
ServerSocket server_socket = null; //서버 생성을 위한 ServerSocket
BufferedReader in = null; //Client로부터 데이터를 읽어들이기 위한 입력스트림
PrintWriter out = null; //Client로 데이터를 내보내기 위한 출력 스트림
boolean isPortUsedIdentifier = false;
try {
server_socket = new ServerSocket(9999);
} catch (IOException e) {
System.out.println("해당 포트는 사용중입니다.");
isPortUsedIdentifier = true;
}
if(!isPortUsedIdentifier) {
try {
while (true) {
System.out.println("Server Open!!");
socket = server_socket.accept(); //서버 생성 , Client 접속 대기
in = new BufferedReader(new InputStreamReader(socket.getInputStream())); //입력스트림 생성
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))); //출력스트림 생성
char[] readData = new char[1];
int chk = in.read(readData, 0, 1); //Client로부터 데이터를 읽어옴
System.out.println("Client로 부터 온 메세지 : " + chk);
out.write(String.valueOf(chk));
if(chk == 1){
System.out.println("checker");
sGreetingController.inCarOutcarVisitor();
}
out.flush();
socket.close();
}
} catch (IOException e) {
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
app.js
var stompClient = null;
connect();
setTimeout(sendName, 1000);
function setConnected(connected) {
$("#connect").prop("disabled", connected);
$("#disconnect").prop("disabled", !connected);
if (connected) {
$("#conversation").show();
}
else {
$("#conversation").hide();
}
$("#greetings").html("");
}
function connect() {
var socket = new SockJS('/gs-guide-websocket');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/greetings', function (greeting) {
showGreeting(JSON.parse(greeting.body));
});
});
}
function disconnect() {
if (stompClient !== null) {
stompClient.disconnect();
}
setConnected(false);
console.log("Disconnected");
}
function sendName() {
stompClient.send("/app/hello", {}, JSON.stringify({'name': $("1").val()}));
}
function showGreeting(message) {
$("#greetings").append("<tr><td>" + message['incar'] + "</td></tr>");
}
$(function () {
$("form").on('submit', function (e) {
e.preventDefault();
});
$( "#connect" ).click(function() { connect(); });
$( "#disconnect" ).click(function() { disconnect(); });
$( "#send" ).click(function() { sendName(); });
});
I'm new to Spring and this maybe a basic task but after I've set up spring boot with stomp websocket, an interactive web page is accomplished and I can push a json object to a client webpage but my goal is to refresh the client/user's page only, I don't need a json transfer.
I just want to refresh the user's page after admin has logged him out.
this is my app.js
var stompClient = null;
function setConnected(connected) {
$("#connect").prop("disabled", connected);
$("#disconnect").prop("disabled", !connected);
if (connected) {
$("#conversation").show();
} else {
$("#conversation").hide();
}
$("#greetings").html("");
}
function connect() {
var socket = new SockJS('/vira-websocket');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
setConnected(true);
stompClient.subscribe('/topic/greetings', function (greeting) {
showGreeting(JSON.parse(greeting.body).content);
});
});
}
function disconnect() {
if (stompClient !== null) {
stompClient.disconnect();
}
setConnected(false);
}
function sendName() {
stompClient.send("/app/hello", {}, JSON.stringify({'name': $("#name").val()}));
}
$(function () {
$( "form" ).on('submit', function (e) {e.preventDefault();});
$( "#connect" ).click(function() { connect(); });
$( "#disconnect" ).click(function() { disconnect(); });
$( "#send" ).click(function() { sendName(); });
});
my config
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/vira-websocket").withSockJS();
}
}
and controller
#Controller
public class GreetingController {
#MessageMapping("/hello")
#SendTo("/topic/greetings")
public Greeting greeting(HelloMessage message) throws Exception {
Thread.sleep(3000); // simulated delay
return new Greeting("Hello, " + message.getName() + "!");
}
}
I'm not sure I fully understand your question but if you want to refresh the page instead of pushing a json just replace location.reload(); with the callback of subscribe function which is the second argument.
function connect() {
var socket = new SockJS('/vira-websocket');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
setConnected(true);
stompClient.subscribe('/topic/greetings', location.reload());
});
}
according to the documentation The client will send a STOMP
SUBSCRIBE frame to the server and register the callback. Every time
the server send a message to the client, the client will in turn call
the callback with a STOMP Frame object corresponding to the message:
which means your refresh will be called after you sent a push to the subscribed users.
I need to start a drawable animation when my text to speech is starting and stop this one when the text to speech is over, but i can't stop the animation.
Code:
tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
int result = tts.setLanguage(Locale.US);
if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
Log.e("TTS", "This Language is not supported");
}
} else {
Log.e("TTS", "Initilization Failed!");
}
}
});
private void speak(String text){
animation.start();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
tts.speak(text, TextToSpeech.QUEUE_FLUSH, null, null);
}else{
tts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
}
}
and here my animationdrawable xml
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/selected" android:oneshot="false" >
<item android:drawable="#drawable/face_1a_mini" android:duration="250" />
<item android:drawable="#drawable/face_1b_mini" android:duration="250" />
<item android:drawable="#drawable/face_1c_mini" android:duration="250" />
<item android:drawable="#drawable/face_1d_mini" android:duration="250" />
</animation-list>
You have to add the Utterance Id to the speak method
tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
int result = tts.setLanguage(Locale.US);
if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
Log.e("TTS", "This Language is not supported");
}
textToSpeech.setOnUtteranceProgressListener(new UtteranceProgressListener() {
#Override
public void onStart(String utteranceId) {
Log.i("TextToSpeech","On Start");
animation.start();
}
#Override
public void onDone(String utteranceId) {
Log.i("TextToSpeech","On Done");
animation.stop();
}
#Override
public void onError(String utteranceId) {
}
});
} else {
Log.e("TTS", "Initilization Failed!");
}
}
});
private void speak(String text){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
tts.speak(text, TextToSpeech.QUEUE_FLUSH, null, TextToSpeech.ACTION_TTS_QUEUE_PROCESSING_COMPLETED);
}
}
You must wrap it with while(tts.isSpeaking())
example :
while(tts.isSpeaking())
{
Animation animation1 =
AnimationUtils.loadAnimation(this,R.anim.fadein);
view.startAnimation(animation1);
}
start your animation on start of utterance and stop when utterance is done.
t1 = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
if (status != TextToSpeech.ERROR) {
t1.setLanguage(Locale.UK);
t1.setOnUtteranceProgressListener(new UtteranceProgressListener() {
#Override
public void onStart(String utteranceId) {
}
#Override
public void onDone(String utteranceId) {
if(utteranceId.equals("finish")){
finish();
}
}
#Override
public void onError(String utteranceId) {
}
});
}
}
});
in the below code my arrayList will be empty after JsonArrayRequest block.
I set break point at this line: "int size = arrayList.size();"
every thing is OK until "while" loop finishes. after that allayList is empty.
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(Request.Method.GET, json_url,(String) null,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
int count=0;
int responseLength = response.length();
responseLength--;
while (count<responseLength)
{
try {
JSONObject jsonObject = response.getJSONObject(count);
Contact contact = new Contact(jsonObject.getString("title"),
jsonObject.getString("email"),
jsonObject.getString("description"),
jsonObject.getString("date"),
jsonObject.getBoolean("status"));
arrayList.add(contact);
int size = arrayList.size();
count++;
} catch (JSONException e) {
e.printStackTrace();
}
}
int size = arrayList.size();
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(context,"Error....",Toast.LENGTH_SHORT).show();
error.printStackTrace();
}
}
);
int size = arrayList.size();
VolleySingleton.getmInstance(context).addToRequestQueue(jsonArrayRequest);
return arrayList;
I will show what i did using CallBack interface:
in onCreate() method:
recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
recyclerView.setHasFixedSize(true);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(linearLayoutManager);
BackgroundTask backgroundTask = new BackgroundTask(this);
backgroundTask.getContacts(new BackgroundTask.arrayListCallBack() {
#Override
public void onSuccess(ArrayList<Contact> contacts) {
RecyclerView.Adapter adapter = new RecyclerAdapter(MainActivity.this, contacts);
recyclerView.setAdapter(adapter);
}
#Override
public void onFail(String error) {
Toast.makeText(MainActivity.this, error, Toast.LENGTH_LONG).show();
}
});
and in the BackgroundTask class:
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(Request.Method.POST, server_url, new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
int count = 0;
while (count < response.length()) {
try {
JSONObject jsonObject = response.getJSONObject(count);
Contact contact = new Contact(jsonObject.getString("name"), jsonObject.getString("section"));
contacts.add(contact);
Log.d("process request", "....."+jsonObject.getString("name"));
count++;
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(context, e.getMessage()+"\nError in Response", Toast.LENGTH_LONG).show();
}
callBack.onSuccess(contacts);
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
Toast.makeText(context, error.getMessage()+"\nError in Connection", Toast.LENGTH_LONG).show();
callBack.onFail("There's error ...");
}
});
MySingleton.getInstance(context).addToRequestQueue(jsonArrayRequest);
}
public interface arrayListCallBack {
void onSuccess(ArrayList<Contact> contacts);
void onFail(String error);
}
I'm trying to make a real basic Websocket example work on standalone Jetty, but i'm stuck on a NullPointerException.
Here are my 2 server classes:
#WebServlet("/MyWebSocketServlet")
public class MyWebSocketServlet extends WebSocketServlet {
#Override
public void configure(WebSocketServletFactory factory) {
factory.register(MyWebSocket.class);
}
}
#WebSocket
public class MyWebSocket{
#OnWebSocketConnect
public void onConnect(Session session){
System.out.println("MyWebSocket.onConnect()");
}
#OnWebSocketMessage
public void onText(String msg) {
System.out.println("MyWebSocket.onText()");
}
#OnWebSocketClose
public void onClose(int statusCode, String reason) {
System.out.println("MyWebSocket.onClose()");
}
}
I try to establish communication through JavaScript in Chrome:
<script type="text/javascript">
var echoSocket = new WebSocket(
"ws://localhost:8080/JettyWebsocketsTest/MyWebSocketServlet"
);
echoSocket.onopen = function(e) {
console.log("onopen()");
echoSocket.send("Hello");
}
echoSocket.onmessage = function(e) {
console.log("msg received");
};
</script>
Unfortunately the connection won't establish and instead this NullPointerException is thrown:
java.lang.NullPointerException
at org.eclipse.jetty.websocket.server.WebSocketServerFactory.upgrade(WebSocketServerFactory.java:400)
at org.eclipse.jetty.websocket.server.WebSocketServerFactory.acceptWebSocket(WebSocketServerFactory.java:168)
at org.eclipse.jetty.websocket.servlet.WebSocketServlet.service(WebSocketServlet.java:160)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:558)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:489)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:119)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:520)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:233)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:972)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:417)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:192)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:906)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:117)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:110)
at org.eclipse.jetty.server.Server.handle(Server.java:350)
at org.eclipse.jetty.server.HttpConnection.handleRequest(HttpConnection.java:442)
at org.eclipse.jetty.server.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:910)
at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:565)
at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:217)
at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:46)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:545)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:43)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:598)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:533)
at java.lang.Thread.run(Thread.java:722)
These lines in WebSocketServerFactory throw that Exception:
HttpConnection http = HttpConnection.getCurrentConnection();
EndPoint endp = http.getEndPoint();
What can i do for an available HttpConnection?