Paasing authentication header to javax.websocket ClientEndpoint - spring-boot

I am trying to connect to websocket server endpoint using below code but I am not able to resolve container.connectToServer(this, cec, uri); this. This method is not able to take my class as Endpoint class. It's a spring boot project. If I don't pass config then it accepts but then it fails to connect to server and return 401. I have tried many online links but failed to resolve this issue. Need help in how to fix it.
#ClientEndpoint
public class TestClassEndpoint {
private Session userSession = null;
public TestClassEndpoint(URI uri) {
try {
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
ClientEndpointConfig cec = ClientEndpointConfig.Builder
.create().configurator(new ClientEndpointConfig.Configurator() {
public void beforeRequest(Map<String, List<String>> headers) {
System.out.println("Setting user cookie in beforeRequest ...");
headers.put("Authorization", Arrays.asList("Basic base64encodedString"));
}
}).build();
container.connectToServer(this, cec, uri);
} catch (Exception e) {
e.printStackTrace();
}
}
#OnOpen
public void onOpen(Session session) {
this.userSession = session;
System.out.println("New connection established");
}
#OnMessage
public void onMessage(String message, Session session) {
System.out.println(message);
}
#OnClose
public void onClose(Session userSession, CloseReason reason) {
this.userSession = null;
System.out.println("connection closed");
}
#OnError
public void onError(Throwable t) {
}
private void sendMessage(ByteBuffer buffer) {
this.userSession.getAsyncRemote().sendBinary(buffer);
}
}
Main class
#SpringBootApplication
public class MainApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(TwilioPocApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
URI uri = UriComponentsBuilder.fromUriString("server_url").build().toUri();
new TestClassEndpoint(uri);
}
}

Related

Spring websocket establishing connection is stuck at 'opening connection'

I am using spring-boot-websocket (spring-boot version 1.5.10) in my project. I have configured it as below,
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends WebSocketMessageBrokerConfigurationSupport
implements WebSocketMessageBrokerConfigurer {
#Value( "${rabbitmq.host}" )
private String rabbitmqHost;
#Value( "${rabbitmq.stomp.port}" )
private int rabbitmqStompPort;
#Value( "${rabbitmq.username}" )
private String rabbitmqUserName;
#Value( "${rabbitmq.password}" )
private String rabbitmqPassword;
#Override
public void configureMessageBroker( MessageBrokerRegistry registry )
{
registry.enableStompBrokerRelay("/topic", "/queue").setRelayHost(rabbitmqHost).setRelayPort(rabbitmqStompPort)
.setSystemLogin(rabbitmqUserName).setSystemPasscode(rabbitmqPassword);
registry.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints( StompEndpointRegistry stompEndpointRegistry )
{
stompEndpointRegistry.addEndpoint("/ws").setAllowedOrigins("*").withSockJS();
}
#Bean
#Override
public WebSocketHandler subProtocolWebSocketHandler()
{
return new CustomSubProtocolWebSocketHandler(clientInboundChannel(), clientOutboundChannel());
}
#Override
public void configureWebSocketTransport( WebSocketTransportRegistration registry )
{
super.configureWebSocketTransport(registry);
}
#Override
public boolean configureMessageConverters( List<MessageConverter> messageConverters )
{
return super.configureMessageConverters(messageConverters);
}
#Override
public void configureClientInboundChannel( ChannelRegistration registration )
{
super.configureClientInboundChannel(registration);
}
#Override
public void configureClientOutboundChannel( ChannelRegistration registration )
{
super.configureClientOutboundChannel(registration);
}
#Override
public void addArgumentResolvers( List<HandlerMethodArgumentResolver> argumentResolvers )
{
super.addArgumentResolvers(argumentResolvers);
}
#Override
public void addReturnValueHandlers( List<HandlerMethodReturnValueHandler> returnValueHandlers )
{
super.addReturnValueHandlers(returnValueHandlers);
}
}
public class CustomSubProtocolWebSocketHandler extends SubProtocolWebSocketHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(CustomSubProtocolWebSocketHandler.class);
#Autowired
private UserCommons userCommons;
CustomSubProtocolWebSocketHandler(MessageChannel clientInboundChannel,
SubscribableChannel clientOutboundChannel) {
super(clientInboundChannel, clientOutboundChannel);
}
#Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
LOGGER.info("************************************************************************************************************************New webSocket connection was established: {}", session);
String token = session.getUri().getQuery().replace("token=", "");
try
{
String user = Jwts.parser().setSigningKey(TokenConstant.SECRET)
.parseClaimsJws(token.replace(TokenConstant.TOKEN_PREFIX, "")).getBody().getSubject();
Optional<UserModel> userModelOptional = userCommons.getUserByEmail(user);
if( !userModelOptional.isPresent() )
{
LOGGER.error(
"************************************************************************************************************************Invalid token is passed with web socket request");
throw new DataException(GeneralConstants.EXCEPTION, "Invalid user", HttpStatus.BAD_REQUEST);
}
}
catch( Exception e )
{
LOGGER.error(GeneralConstants.ERROR, e);
}
super.afterConnectionEstablished(session);
}
#Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
LOGGER.error("************************************************************************************************************************webSocket connection was closed");
LOGGER.error("Reason for closure {} Session: {} ", closeStatus.getReason(),session.getId() );
super.afterConnectionClosed(session, closeStatus);
}
#Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
LOGGER.error("************************************************************************************************************************Connection closed unexpectedly");
LOGGER.error(GeneralConstants.ERROR, exception);
super.handleTransportError(session, exception);
}
}
From the client-side, I am creating a SockJS object to establish the connection,
let url = `/ws?token=${localStorage.getItem("access_token")}`;
// Web Socket connection
/* eslint-disable */
let sockJS = new SockJS(url);
let stompClient = Stomp.over(sockJS);
debugger
this.setState({
stompObject : stompClient,
});
But the connection is not getting established consistently, most of the times it is stuck at Opening the connection, in the backend log, I can see the connection getting established and a session is created. But, in the browser console, I can see client-side sending message to the server but the server is not acknowledging the message.
Sometimes, when I refresh the browser for 10-15 times, the connection is getting established successfully. Is there any mistake in my configuration?
Thank You.
Given that you can "hit refresh 10 or 15 times and then get a connection," I'm curious if you dealing with a cookie issue? I know Chrome is famous for that sort of thing. Anyway close out all browser windows and stop the browser, then start the browser, and tell it to clear browsing history and then attempt the connection. Also, be SURE you read the version of the spring-boot docs for the version of spring-boot you are that you are actually using, and also specify the SB version in your questions and when looking for answers.

ServerEnpoint change port

I would like to set the port number of my serverEnPoint.
Here is my server socket:
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
#ServerEndpoint("/myEndPoint")
public class MyEndPoint {
private static Session session;
#OnOpen
public void onOpen(Session s) throws IOException {
session = s;
}
#OnMessage
public String echo(String message) {
return message + " (from your server)";
}
#OnError
public void onError(Throwable t) {
t.printStackTrace();
}
public static void sendMessage(String message){
try {
session.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
}
I ask how to do that because my server needs to open a websocket but still allow REST API.
I am assuming that the websocket port by default is the same as REST and this is why my client does not connect. If you have other solution let me know.
Thanks

Session management in a Neo4J Flink sink

I am developing a data analytics app with Apache Flink and Neo4J (Community Edition).
In this application, the Flink sink must save/update relations in Neo4J.
Which is the best way for Neo4J session management, and why?
First implementation:
public class MySink extends RichSinkFunction<Link> {
private DbConfiguration dbconfig;
private Driver driver;
#Override
public void open(Configuration parameters) throws Exception {
this.driver = Neo4JManager.open(this.dbconfig);
}
#Override
public void close() throws Exception {
this.driver.close();
}
#Override
public void invoke(Link link) throws Exception {
Session session = this.driver.session();
Neo4JManager.saveLink(session, link);
session.close();
}
}
Second implementation:
public class MySink extends RichSinkFunction<Link> {
private DbConfiguration dbconfig;
private Driver driver;
private Session session;
#Override
public void open(Configuration parameters) throws Exception {
this.driver = Neo4JManager.open(this.dbconfig);
this.session = driver.session();
}
#Override
public void close() throws Exception {
this.session.close();
this.driver.close();
}
#Override
public void invoke(Link link) throws Exception {
Neo4JManager.saveLink(this.session, link);
}
}
In both implementations, the following functions have been used:
public class Neo4JManager {
public static Driver open(DbConfiguration dbconf) {
AuthToken auth = AuthTokens.basic(dbconf.getUsername(), dbconf.getPassword());
Config config = Config.build().withEncryptionLevel(Config.EncryptionLevel.NONE ).toConfig();
return GraphDatabase.driver(dbconf.getHostname(), auth, config);
}
public static void saveLink(Session session, Link link) {
Value params = parameters("x", link.x, "y", link.y);
session.run('CREATE (Person {id:{x}}-[FOLLOWS]->(Person {id:{y}}))'
}
}
Thank you.

How to do unit test websocket with embedded jetty?

I want to write Junit UT case for my websocket serverendpoint code using embedded Jetty.
i tried things explained in below link:
JUnit test with javax.websocket on embedded Jetty throws RejectedExecutionException: NonBlockingThread
I want to test my onMessage callback for websocket.
If i dont use server.join() method then the connection closes as soon as it opens.
If i use server.join() method nothing happens after joining.
Below is My code.
Server startup code::
public class EmbeddedJettyServer {
private final int port;
private Server server;
public EmbeddedJettyServer(int port) {
this.port = port;
}
public void start() throws Exception {
server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(8080);
server.addConnector(connector);
// Setup the basic application "context" for this application at "/"
// This is also known as the handler tree (in jetty speak)
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
server.setHandler(context);
try {
// Initialize javax.websocket layer
ServerContainer wscontainer = WebSocketServerContainerInitializer.configureContext(context);
// Add WebSocket endpoint to javax.websocket layer
wscontainer.addEndpoint(WebSocketServer.class);
System.out.println("Begin start");
server.start();
server.dump(System.err);
server.join();
} catch (Throwable t) {
t.printStackTrace(System.err);
}
}
public void stop() throws Exception {
server.stop();
LOGGER.info("Jetty server stopped");
}
public URI getWebsocketUri(Class<WebSocketServer> class1) {
return server.getURI();
}
}
Client Code:
#ClientEndpoint()
public class WebSocketClientJetty {
WebSocketContainer container;
public Session connect(URI uri) throws Exception {
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
try {
// Attempt Connect
Session session = container.connectToServer(WebSocketClientJetty.class,uri);
// return container.connectToServer(WebSocketClientJetty.class, uri);
session.getBasicRemote().sendText("Hello");
// Close session
// session.close();
return session;
} finally {
}
}
public void stop() throws Exception{
if (container instanceof LifeCycle) {
((LifeCycle) container).stop();
}
}
#OnOpen
public void onWebSocketConnect(Session sess)
{
System.out.println("Socket Connected: " + sess);
}
#OnMessage
public void onWebSocketText(String message)
{
System.out.println("Received TEXT message: " + message);
}
#OnClose
public void onWebSocketClose(CloseReason reason)
{
System.out.println("Socket Closed: " + reason);
}
#OnError
public void onWebSocketError(Throwable cause)
{
cause.printStackTrace(System.err);
}
}
Serverendpoint code:
#ServerEndpoint(value = "/echo",
encoders={JsonEncoder.class})
public class WebSocketServer {
private static final Logger LOGGER =
#OnOpen
public void onOpen(Session session){
System.out.println("onopen");
some code....
}
#OnMessage
public void onMessage(String message, Session session) throws IOException{
System.out.println("onmessage");
....
}
#OnClose
public void onClose(Session session){
System.out.println("onClose");
...
}
}
Ut case:
public class WebSocketJettyTest {
private static EmbeddedJettyServer server;
#ClassRule
public static final ExternalResource integrationServer = new ExternalResource() {
#Override
protected void before() throws Throwable {
System.out.println("Starting...");
server = new EmbeddedJettyServer(8080);
server.start();
System.out.println("Started");
}
};
#Before
public void setUp() throws Exception {
}
#After
public void shutdown() throws Exception {
server.stop();
}
#Test
public void testSocket() throws Exception {
/*URI uri = server.getWebsocketUri(WebSocketServer.class);*/
URI uri = URI.create("ws://localhost:8080/echo");
WebSocketClientJetty client = new WebSocketClientJetty();
Session session = client.connect(uri);
session.getBasicRemote().sendText("hello");
Thread.sleep(6000);
client.stop();
}
}
Drop the call to
server.join();
That just makes the current thread wait until the server thread stops.
Which is making it difficult for you.

Websocket : Is it possible to know from the program what is the reason for onClose being called

I have a Sample WebSocket Program whown below which works fine
When ever the user closes the browser or if there is any excetion Or any disconnect , the onClose Method is
being called
My question is that , Is it possible to know from the program what is the reason for onClose being called ??
Please share your views , Thanks for reading .
public class Html5Servlet extends WebSocketServlet {
private AtomicInteger index = new AtomicInteger();
private static final List<String> tickers = new ArrayList<String>();
static{
tickers.add("ajeesh");
tickers.add("peeyu");
tickers.add("kidillan");
tickers.add("entammo");
}
/**
*
*/
private static final long serialVersionUID = 1L;
public WebSocket doWebSocketConnect(HttpServletRequest req, String resp) {
//System.out.println("doWebSocketConnect");
return new StockTickerSocket();
}
protected String getMyJsonTicker() throws Exception{
return "";
}
public class StockTickerSocket implements WebSocket.OnTextMessage{
private Connection connection;
private Timer timer;
#Override
public void onClose(int arg0, String arg1) {
System.out.println("onClose called!"+arg0);
}
#Override
public void onOpen(Connection connection) {
//System.out.println("onOpen");
this.connection=connection;
this.timer=new Timer();
}
#Override
public void onMessage(String data) {
//System.out.println("onMessage");
if(data.indexOf("disconnect")>=0){
connection.close();
timer.cancel();
}else{
sendMessage();
}
}
public void disconnect() {
System.out.println("disconnect called");
}
public void onDisconnect()
{
System.out.println("onDisconnect called");
}
private void sendMessage() {
if(connection==null||!connection.isOpen()){
//System.out.println("Connection is closed!!");
return;
}
timer.schedule(new TimerTask() {
#Override
public void run() {
try{
//System.out.println("Running task");
connection.sendMessage(getMyJsonTicker());
}
catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}, new Date(),5000);
}
}
}
The signature for onClose is the following ...
#Override
public void onClose(int closeCode, String closeReason) {
System.out.println("onClose called - statusCode = " + closeCode);
System.out.println(" reason = " + closeReason);
}
Where int closeCode is any of the registered Close Status Codes.
And String closeReason is an optional (per protocol spec) close reason message.

Resources