retrofit spring boot not responding - spring

I have a server in spring boot, which is running on port 8080.
Now I'm trying to call rest api in my android application using retrofit2.
Here is what I have implemented:
final TextView textView=findViewById(R.id.t1);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://localhost:8080/")
.addConverterFactory(GsonConverterFactory.create())
.build();
JsonPlaceHolderApi jsonPlaceHolderApi = retrofit.create(JsonPlaceHolderApi.class);
Call<TC> call = jsonPlaceHolderApi.getPosts();
call.enqueue(new Callback<TC>() {
#Override
public void onResponse(Call<TC> call, Response<TC> response) {
textView.setText(response.toString());
if (!response.isSuccessful()) {
return;
}
TC posts = response.body();
textView.setText(posts.toString());
}
#Override
public void onFailure(Call<TC> call, Throwable t) {
}
});
I can surly say that, it's not working as my api is not even being called. As the hello world screen remains as it is.
And in my server I have logger, which doesn't log anything, so it doesn't get called.
Here is my CORS:
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry
.addMapping("*")
.allowedOrigins("*");
}
};
}

The problem is with the word localhost.
As for debugging purpose I'm connecting the android device with my PC so my android device can't connect to localhost as it is just an alias of my IP address.
To resolve this, I opened up CMD and wrote ipconfig, by this command I can see all details related to IP.
And here it shows my IPv4 address as $.$.$.$. I just replaced the localhost with that $.$.$.$.
Now everything is working fine.

Any ideas how to make it work with Asp.net core. I just test it wih my local machine ip address and work perfectly.
Unfortunately, not the case with Asp.net core.
aAndroid + Retrofit + Asp.net API "java.security.cert.CertPathValidatorException: Trust anchor for certification path not found."

Related

Spring Boot + Sockjs client offline connecting issues

I'm trying to connect a Spring Boot Stomp Server with multiple sockjs clients offline but I get the warning
Websocket is closed before the connection is established
followed by
GET http://192.168.1.45:8080/socket/327/si5osugt/jsonp?c=jp.a3xdefl net::ERR_ABORTED 404 (Not Found)
I'm using Spring Boot Version 2.1.2 with the spring-boot-starter-websocket package on the backend side and on the frontend side I'm using Angular 6 with sockjs-client version 1.3.0. Frontend and backend are both running on port 8080
I'm getting some errors while turning the internet down. If the internet is turned off the iframe tries to reach to https://cdn.jsdelivr.net/npm/sockjs-client#1/dist/sockjs.js.
I managed by configuring stomp server on the backend to set the client library by adding .setClientLibraryUrl to a absolute path which is offline reachable.
registry.addEndpoint("/socket").setAllowedOrigins("*").withSockJS).setClientLibraryUrl("http://192.168.1.45/dist/sockjs.min.js");
and get a 200 OK on http://192.168.1.45/dist/sockjs.min.js
Spring Boot:
WebSocketConfiguration (extends AbstractWebSocketMessageBrokerConfigurer)
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/socket")
.setAllowedOrigins("*")
.withSockJS().setClientLibraryUrl("http://192.168.1.45/dist/sockjs.min.js");
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
MessageBrokerRegistry messageBrokerRegistry = registry.setApplicationDestinationPrefixes("/app");
messageBrokerRegistry.enableSimpleBroker( "/test", "/test2"
);
}
WebSocketController
private final SimpMessagingTemplate template;
#Autowired
WebSocketController(SimpMessagingTemplate template){
this.template=template;
}
#MessageMapping("/send/message")
public void onReceivedMessage( String destination , String message){
this.template.convertAndSend(destination , message);
}
public void convertAndSend(String url, Object o){
this.template.convertAndSend(url, o);
}
Angular 6:
TestComponet
ngAfterViewInit() {
let ws = new SockJS('http://192.168.1.45:8080/socket');
this.stompClient = Stomp.over(ws);
let that = this;
that.stompClient.subscribe("/test", (message) => {
if (message.body) {
console.log(message.body);
}
});
that.stompClient.subscribe("/test2", (message) => {
if (message.body) {
console.log(message.body);
}
});
}
I thought it would work by just adding the sockjs client lib to an offline reachable path but I get the warning
Websocket is closed before the connection is established
followed by
"GET http://192.168.1.45:8080/socket/327/si5osugt/jsonp?c=jp.a3xdefl net::ERR_ABORTED 404 (Not Found)"
The library works with an internet connection perfectly fine, but I need it to work with both situations online and offline.
I had the same issue, and I fixed it by removing SockJs.
So now I'm currently using only Stomp-Websockets.
Changes in SpringBoot-Service(WebsocketConfiguration):
registry.addEndpoint("/justStomp").setAllowedOrigins("*");
I removed the .withSockJS() and .setClientLibraryUrl(../sockjs.min.js)
Changes in my Javascript-Code to connect to the websocket:
const stompClient = Stomp.client(`ws://localhost:8080/justStomp`);
stompClient.heartbeat.outgoing = 0;
stompClient.heartbeat.incoming = 0;
stompClient.connect({ name: 'test' }, frame => this.stompSuccessCallBack(frame, stompClient), err => this.stompFailureCallBack(err));
Instead of using Stomp.over(sockjs) I use the Stomp.client Method to directly connect to the websocket-url.
I have a rabbitMQ in the background with stomp-plugin, and this only works properly with the 2 heartbeat-settings. see here RabbitMQ Web STOMP without SockJS

SockJS + Stomp + SpringBoot = Issue

I have an application with a page that subscribe a websocket endpoint with this:
var socket = new SockJS("/hello");
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
stompClient.subscribe('/topic/nextticket', function (ws_response) {
var data = JSON.parse(ws_response.body);
....
});
});
This app run on Raspberry and all works fine when the raspberry is connected on internet. But in a local network (no Internet) I have this
My backend conf is:
#Configuration
#PropertySource("file:/etc/app.properties")
#EnableWebSocketMessageBroker
class MessageBroker extends AbstractWebSocketMessageBrokerConfigurer {
#Autowired
Environment env
#Override
void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic")
config.setApplicationDestinationPrefixes("/app")
}
#Override
void registerStompEndpoints(StompEndpointRegistry registry) {
def ip = env.getProperty("kiosk.ip") ? env.getProperty("kiosk.ip") as String : "192.168.1.90"
registry.addEndpoint("/hello")
.setAllowedOrigins("*")
.withSockJS()
.setClientLibraryUrl("http://${ip}:8080/js/sockjs.js")
}
}
I don't understand why have a CORS (I suppose) problem.. And the page reload forever.
Thanks in advance
Luis
I had this CORS behaviour in my application whenever I used a specific IP.
application.properties
server.address: 192.168.1.90
After removing server.address from the application.properties the application worked as expected. If somebody knows the cause of this please let me know. I would have expected that
registry.setAllowedOrigins("*")
would remove all CORS behaviour as document here

WebSocket can connect to local server, but can't send or receive

I'm working on setting up a websocket between two local servers for development.
On one end I have my Ionic app running on http://localhost:8100/
On the other end I have a Spring backend running on http://localhost:9080/ (or http://127.0.0.1:9080)
Connection has been established, so next up I want to send a message to the websocket with a token (I know this can be send along when the connection is set up in SockJS 1.1.0, but I am currently using 0.3.4)
However my code in the backend doesn't seem to respond, I am wondering if my IP configuration is correct. I followed a tutorial and got this working in another project.
Anyone with more experience that knows if the url in the subscribe function also needs to be prefixed with 'localhost' or an IP adrress? I know the websocket changes from http:// to ws:// so I suppose when this is the case I need to prefix it with something like: ws://localhost:9080/...
Anyway, here's my code:
WebSocet Service :
function init() {
var socket = new SockJS('http://127.0.0.1:9080/ws-notification');
stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
console.log('Connected: ' + frame);
/**
* Subscribe at /ws-topic/greetings url to catch messages
*/
stompClient.subscribe('/ws-topic/greetings', function(greeting){
notify(JSON.parse(greeting.body).content);
});
parseAuthentication();
});
}
function parseAuthentication(){
stompClient.send("/ws-app/ws-notification",{},JSON.stringify({ 'token': authenticationService.isAuthenticated() }));
}
function disconnect() {
if (stompClient != null) {
stompClient.disconnect();
}
// setConnected(false);
console.log("Disconnected");
}
function notify(message){
console.log("NOTIFY: "+message);
}
The WebSocket Config :
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws-notification").setAllowedOrigins("*").withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry config){
config.enableSimpleBroker("/ws-topic");
config.setApplicationDestinationPrefixes("/ws-app");
}
}
My Controllerfunction :
#MessageMapping("/ws-notification")
#SendTo("/ws-topic/greetings")
public Notify greeting(Notify notify) throws InterruptedException {
Thread.sleep(1000);
return new Notify("Hello, your token is :" + notify.getWsToken());
}
Notice that I only specify the IP adress when I set up the connection in the init() function, tried to prefix the other url's with ws://127.0.0.1:... but no luck!
I found the answer!
The problem was that there was no default contructor method in the models I used to send the data.
This was also not implemented or mentioned in the Spring WebSocket Tutorial

Disconnect client session from Spring websocket stomp server

I've searched quite a bit and been unable to find this: Is there a way that a spring websocket stomp server can disconnect a client based on the sessionId (or really based on anything at all)?
It seems to me that once a client connects to a server there is nothing that allows the server to disconnect the client.
Actually using some workarounds you can achieve what you want.
For that you should do:
Use java configuration (not sure if it is possible with XML config)
Extend your config class from WebSocketMessageBrokerConfigurationSupport and implement WebSocketMessageBrokerConfigurer interface
Create custom sub-protocol websocket handler and extend it from SubProtocolWebSocketHandler class
In your custom sub-protocol websocket handler override afterConnectionEstablished method and you will have access to WebSocketSession :)
I've created sample spring-boot project to show how we can disconnect client session from server side:
https://github.com/isaranchuk/spring-websocket-disconnect
You can also disconnect session by implementing a custom WebSocketHandlerDecorator:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig<S extends ExpiringSession> extends AbstractSessionWebSocketMessageBrokerConfigurer<S> {
#Override
public void configureWebSocketTransport(final WebSocketTransportRegistration registration) {
registration.addDecoratorFactory(new WebSocketHandlerDecoratorFactory() {
#Override
public WebSocketHandler decorate(final WebSocketHandler handler) {
return new WebSocketHandlerDecorator(handler) {
#Override
public void afterConnectionEstablished(final WebSocketSession session) throws Exception {
session.close(CloseStatus.NOT_ACCEPTABLE);
super.afterConnectionEstablished(session);
}
};
}
});
super.configureWebSocketTransport(registration);
}
#Override
protected void configureStompEndpoints(final StompEndpointRegistry registry) {
registry.addEndpoint("/home")
.setHandshakeHandler(new DefaultHandshakeHandler(
new UndertowRequestUpgradeStrategy() // If you use undertow
// new JettyRequestUpgradeStrategy()
// new TomcatRequestUpgradeStrategy()
))
.withSockJS();
}
}
As far as I know the API doesn't provide what you are looking for, on server-side you can only detect disconnect events. If you want to disconnect a certain client I think you must go for a litte workaround, e.g. this one:
Write a client-side javascript function that is able to trigger a disconnect
As soon as your client is connected to the server, generate a client ID in your javascript and send it to the server. Remember the ID on the client, you'll need it in step (4).
At the time you want the server to disconnect the connection to the specific client (identified by the ID), send a message containing the ID back to the client.
Now your client javascript evaluates the message send from the server and decides to call the disconnect function you wrote in step (1).
Your client disconnects itself.
The workaround is a bit cumbersome but it'll work.
I relied on the idea of #Dániel Kis and implemented the websocket session management with the key point of storing websocket sessions for authenticated users in Singleton-like object.
// WebSocketConfig.java
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
registration.addDecoratorFactory(new WebSocketHandlerDecoratorFactory() {
#Override
public WebSocketHandler decorate(final WebSocketHandler handler) {
return new WebSocketHandlerDecorator(handler) {
#Override
public void afterConnectionEstablished(final WebSocketSession session) throws Exception {
// We will store current user's session into WebsocketSessionHolder after connection is established
String username = session.getPrincipal().getName();
WebsocketSessionHolder.addSession(username, session);
super.afterConnectionEstablished(session);
}
};
}
});
}
}
Class to store websocket users' sessions WebsocketSessionHolder. I use 'synchronized' blocks for thread safety. Actually this blocks are not expensive operations because each of methods (addSession and closeSessions) are used not so often (On establishing and terminating connection). No need to use ConcurrentHashMap or SynchronizedMap here because we perform bunch of operations with the list in these methods.
// WebsocketSessionHolder.java
public class WebsocketSessionHolder {
static {
sessions = new HashMap<>();
}
// key - username, value - List of user's sessions
private static Map<String, List<WebSocketSession>> sessions;
public static void addSession(String username, WebSocketSession session)
{
synchronized (sessions) {
var userSessions = sessions.get(username);
if (userSessions == null)
userSessions = new ArrayList<WebSocketSession>();
userSessions.add(session);
sessions.put(username, userSessions);
}
}
public static void closeSessions(String username) throws IOException
{
synchronized (sessions) {
var userSessions = sessions.get(username);
if (userSessions != null)
{
for(var session : userSessions) {
// I use POLICY_VIOLATION to indicate reason of disconnecting for a client
session.close(CloseStatus.POLICY_VIOLATION);
}
sessions.remove(username);
}
}
}
}
And the final touch - terminating (disconnecting) specified user websocket sessions ("ADMIN" in the example), say in some Controller
//PageController.java
#Controller
public class PageController {
#GetMapping("/kill-sessions")
public void killSessions() throws Exception {
WebsocketSessionHolder.closeSessions("ADMIN");
}
}
In case of xml configuration you can use <websocket:decorator-factories> in the <websocket:transport> of your <websocket:message-broker>.
Create custom WebSocketHandlerDecorator and WebSocketHandlerDecoratorFactory which implement decorate method.
This may seem brief but I am not certain what the implementation would look like in your case. But, I think there are some circumstances that would warrant this workaround/solution:
Set a timeout on the back-end (say 30 seconds):
This is how you would do it with Spring Boot Websocket (and Tomcat):
#Bean
public ServletServerContainerFactoryBean websocketContainer() {
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
container.setMaxSessionIdleTimeout(MAX_SESSION_IDLE_TIMEOUT);
return container;
}
If you want to keep the session open - continue to send messages or else actively send ping/pongs. In the case that you want the session to disconnect, stop the ping/pong interaction somewhere suitable in you application.
Of course, if you are wanting to disconnect immediately, this doesn't seem to be an appropriate solution. But if you are simply trying to reduce the number of active connections, ping/pong may be a good fit since it keeps a session open only so long as messages are actively being sent, preventing the session from being closed prematurely.
first you have to introduce a class as your User class by inheritance then use it like this:
if (userObject instanceof User) {
User user = (User) userObject;
if (user.getId().equals(userDTO.getId())) {
for (SessionInformation information : sessionRegistry.getAllSessions(user, true)) {
information.expireNow();
}
}
}

RMI very slow is client and server are not in the same machine

i have a strange problem. I developed client-server application with Java RMI, and in the localhost work very fine, also work very well if i put the client and server on two different MacBook Pro, but work very very slowly if i try to put the client and the server on two computer that are not macbook pro. I have this problem only if i try to send a reference of the client to the server with invocation of a remote method.
This is my code
SERVER:
public class Server{
public static void main(String [] args){
try
{
Server_Impl server=new Server_Impl();
Registry reg=LocateRegistry.createRegistry(1099);
reg.bind("Server",server);
if(new Scanner(System.in).nextInt()==-1){
System.exit(0);
}
}
catch (RemoteException e){e.printStackTrace( );}
catch (AlreadyBoundException e) {e.printStackTrace( );}
}
}
CLIENT
public class Client{
public static Interfaccia_Server Server;
public static void main(String [] args){
try{
Registry reg=LocateRegistry.getRegistry("10.0.1.5",1099);
Server = (Interfaccia_Server) reg.lookup("Server");
Client_Impl c= new Client_Impl(Server);
Server.connect_client(c);
c.check_action();
}
catch(Exception e){
}
}
}
All of the code work, but very very slow if client and server are not on the same machine, or on a apple mac computer.
If i remove this line of code from the client all work very well anywhere, but i need the reference of the client in the server
Server.connect_client(c);
I have no idea about, please help me

Resources