Passing data (other than payload) via websockets - java

Once the websocket session has been established, is it possible to pass data other than using session.getAsyncRemote().sendText(**)) across the session?
I am using
javax.websocket.* as ClientEndpoint
and spring-websocket for server.
I have tried using:
session.getRequestParameterMap().putAll(bMap); //This gives me exception
session.getPathParameters().putAll(aMap); //This gives me exception
session.getUserProperties().put("dataE", "dataF");; //This goes through fine
And I am not able to see the data on server side:
Map<String, Object> aMap = stStandard.getNativeSession().getUserProperties();
This map comes as blank on server side.Please let me know if more information is needed. Here is my code:
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.websocket.ClientEndpoint;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
#ClientEndpoint
public class TestSpring {
#OnMessage
public void onMessage(String message, Session session) throws IOException,
InterruptedException {
Map aMap = new HashMap();
aMap.put("dataA", "dataB");
try {
session.getPathParameters().putAll(aMap);
} catch (Exception e) {
e.printStackTrace();
}
Map bMap = new HashMap();
List<String> bList = new ArrayList<String>();
bList.add("dataC");
try {
bMap.put("dataD", bList);
session.getRequestParameterMap().putAll(bMap);
} catch (Exception e) {
e.printStackTrace();
}
try {
session.getUserProperties().put("dataE", "dataF");
} catch (Exception e) {
e.printStackTrace();
}
session.getAsyncRemote().sendText("Data to be sent");
}
#OnOpen
public void onOpen() {
System.out.println("Client connected");
}
#OnClose
public void onClose() {
System.out.println("Connection closed");
}
}
import java.util.List;
import java.util.Map;
import org.springframework.web.socket.BinaryMessage;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketExtension;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.adapter.standard.StandardWebSocketSession;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;
import com.sap.websocket.inMemoryWebSockets.KeepInMemoryWebSockets;
public class WebsocketEndPoint extends AbstractWebSocketHandler {
#Override
protected void handleTextMessage(WebSocketSession session,
TextMessage message) throws Exception {
session.getHandshakeHeaders();
StandardWebSocketSession stStandard = (StandardWebSocketSession) session;
try {
Map<String, Object> aMap = stStandard.getNativeSession()
.getUserProperties();
} catch (Exception e) {
e.printStackTrace();
}
TextMessage binaryMessage = new TextMessage(new String(
"Hello Client. This is message sent from server"));
session.sendMessage(binaryMessage);
}
#Override
protected void handleBinaryMessage(WebSocketSession session,
BinaryMessage message) throws Exception {
}
}

Related

Download image with json data (retrofit2 android)

I want download image but url image is not direct and should send additional data like that :
url : http://example.com/download
data :
{
"phoneNumber":"9199191",
"token":"1KAwqCxCdQUjTvTK9EtT7N",
"fileName":"632_macbook_pro.jpg"
}
and server callback data image In the form of base64
i use this codes but server return 500 code :
restservice :
#POST("download")
Call<ResponseBody> getImage(
#Body JsonObject data,
#HeaderMap Map<String, String> headers
);
Java code:
JsonObject params = new JsonObject();
params.addProperty("phoneNumber",settingMain.getPhoneNum());
params.addProperty("token",settingMain.getSecureLogin());
params.addProperty("fileName",fileName);
Call<ResponseBody> myCall = restService.getImage(params, UrlController.AddHeadersDownload(fileName));
myCall.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> responseObj) {
try {
Log.e("DownloadCode",responseObj.code()+"");
if (responseObj.isSuccessful() && responseObj.code()==200) {
} catch (JSONException e) {
e.printStackTrace();
Log.e("JSONException",e.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
});
This is a little example showing how to download the Retrofit JAR file. You can adapt it to your needs.
This is the interface:
import com.squareup.okhttp.ResponseBody;
import retrofit.Call;
import retrofit.http.GET;
import retrofit.http.Path;
interface RetrofitDownload {
#GET("/maven2/com/squareup/retrofit/retrofit/2.0.0-beta2/{fileName}")
Call<ResponseBody> downloadRetrofit(#Path("fileName") String fileName);
}
And this is a Java class using the interface:
import com.google.common.io.Files;
import com.squareup.okhttp.ResponseBody;
import retrofit.Call;
import retrofit.Callback;
import retrofit.Response;
import retrofit.Retrofit;
import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String... args) {
Retrofit retrofit = new Retrofit.Builder().
baseUrl("http://repo1.maven.org").
build();
RetrofitDownload retrofitDownload = retrofit.create(RetrofitDownload.class);
Call<ResponseBody> call = retrofitDownload.downloadRetrofit("retrofit-2.0.0-beta2.jar");
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Response<ResponseBody> response, Retrofit retrofitParam) {
File file = new File("retrofit-2.0.0-beta2.jar");
try {
file.createNewFile();
Files.asByteSink(file).write(response.body().bytes());
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onFailure(Throwable t) {
}

JMS-Websocket - delayed message delivery

This application receives & forwards messages from database events to client applications. Messages are immediately delivered when the client browser has a web socket session.
However, when no web socket session exists and a message is sent by the JMSProducer into the Destination "jms/notificationQueue" in QueueSenderSessionBean, the message is immediately consumed in NotificationEndpoint. This is not my intent.
My intent is for the queue to retain the message until the user connects to NotificationEndpoint. If the user is not connected to the NotificationEndpoint, I think there should be no instance of NotificationEndpoint created to receive the message.
How do I delay the JMSConsumer consuming the message from the queue?
Overview - TomEE Plus 8.0.0-M1 project
Application receives notification in a NotificationServlet
HttpServletRequest
String message is put into JMS Queue by QueueSenderSessionBean injected into NotificationServlet
NotificationMessageDrivenBean implements MessageListener to listen to the JMS Queue
An Event annotated with #NotificationServletJMSMessage is fired from NotificationMessageDrivenBean for an Observer in
NotificationEndpoint method onJMSMessage.
NotificationEndpoint uses PushContext which gathers all websocket sessions to deliver the message to the user
In PushContext.send, if any websocket sessions with a user uuid property matching the message user uuid property, the message is
delivered to each websocket session.
My understanding of #ServerEndpoint is that "each new WS session gets its own instance." Notify only specific user(s) through WebSockets, when something is modified in the database
Sources: the above link from https://stackoverflow.com/users/157882/balusc
and https://blogs.oracle.com/theaquarium/integrating-websockets-and-jms-with-cdi-events-in-java-ee-7-v2
WEB-INF/resources.xml
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<Resource id="jmsConnectionFactory" type="javax.jms.ConnectionFactory">
connectionMaxIdleTime = 15 Minutes
connectionMaxWaitTime = 5 seconds
poolMaxSize = 10
poolMinSize = 0
resourceAdapter = Default JMS Resource Adapter
transactionSupport = xa
</Resource>
</resources>
NotificationServlet.java
import java.io.IOException;
import java.util.UUID;
import javax.annotation.Resource;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.jms.Queue;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
#WebServlet("/notifications")
public class NotificationServlet extends HttpServlet
{
#Resource(name = "jms/notificationQueue")
private Queue _notificationQueue;
#Inject
private QueueSenderSessionBean _queueSessionSenderBean;
#Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException,
IOException
{
try
{
String notificationJson =
extractNotificationJson(request);
if (notificationJson != null)
{
_queueSessionSenderBean.sendMessage(
"notification="
+ notificationJson);
}
}
catch (Exception e)
{
e.printStackTrace();
// handle exception
}
}
public String extractNotificationJson(HttpServletRequest request)
throws IOException
{
if(request.getParameter("notification") != null)
{
String[] notificationString =
request.getParameterValues("notification");
return notificationString[0];
}
return null;
}
}
QueueSenderSessionBean.java
import javax.annotation.Resource;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.inject.Named;
import javax.jms.DeliveryMode;
import javax.jms.JMSConnectionFactory;
import javax.jms.JMSContext;
import javax.jms.JMSException;
import javax.jms.JMSProducer;
import javax.jms.Queue;
import javax.jms.TextMessage;
import org.json.JSONObject;
#Named
#LocalBean
#Stateless
public class QueueSenderSessionBean
{
#Resource(mappedName = "jms/notificationQueue")
private Queue _notificationQueue;
#Inject
#JMSConnectionFactory("jmsConnectionFactory")
private JMSContext _jmsContext;
// Static Methods
// Member Methods
public void sendMessage(String message)
{
try
{
JMSProducer messageProducer =
_jmsContext.createProducer();
messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT);
String userProperty = "someValue";
TextMessage textMessage = _jmsContext.createTextMessage(message);
textMessage.setStringProperty("userProperty", userProperty);
messageProducer.send(_notificationQueue, textMessage);
}
catch (JMSException e)
{
e.printStackTrace();
// handle jms exception
}
}
}
Qualifier NotificationServletJMSMessage.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})
public #interface NotificationServletJMSMessage
{
}
NotificationMessageDrivenBean.java
import javax.ejb.MessageDriven;
import javax.enterprise.event.Event;
import javax.inject.Inject;
import javax.inject.Named;
import javax.jms.Message;
import javax.jms.MessageListener;
#Named
#MessageDriven(mappedName = "jms/notificationQueue")
public class NotificationMessageDrivenBean implements MessageListener
{
#Inject
#NotificationServletJMSMessage
Event<Message> jmsEvent;
#Override
public void onMessage(Message message)
{
jmsEvent.fire(message);
}
}
PushContext.java
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.jms.JMSConsumer;
import javax.jms.JMSContext;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Queue;
import javax.jms.TextMessage;
import javax.websocket.Session;
#ApplicationScoped
public class PushContext
{
#Inject
private JMSContext _jmsContext;
#Resource(mappedName = "jms/notificationQueue")
private Queue _notificationQueue;
private Map<String, Set<Session>> _sessions;
#PostConstruct
public void init()
{
_sessions = new ConcurrentHashMap<>();
}
public void add(Session session, String userUuid)
{
_sessions.computeIfAbsent(userUuid,
value -> ConcurrentHashMap.newKeySet()).add(session);
}
void remove(Session session)
{
_sessions.values().forEach(value -> value.removeIf(e -> e.equals(session)));
}
public void send(Set<String> userUuids, Message message) throws JMSException
{
String userUuid = message.getStringProperty("userUuid");
userUuids.add(userUuid);
Set<Session> userSessions;
synchronized(_sessions)
{
userSessions = _sessions.entrySet().stream()
.filter(e -> userUuids.contains(e.getKey()))
.flatMap(e -> e.getValue().stream())
.collect(Collectors.toSet());
}
for (Session userSession : userSessions)
{
if (userSession.isOpen())
{
userSession.getAsyncRemote().sendText(((TextMessage) message).getText());
}
}
}
public void removeSession(Session session)
{
String userUuid = (String)session.getUserProperties().get("userUuid");
_sessions.remove(userUuid, session);
}
}
NotificationEndpoint.java
import java.io.IOException;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
import javax.inject.Named;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.websocket.CloseReason;
import javax.websocket.EndpointConfig;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
#Named
#ServerEndpoint(value="/notificationEndpoint/{tokenId}")
public class NotificationEndpoint
{
private static final Set<Session> SESSIONS =
Collections.synchronizedSet(new HashSet<Session>());
private QueueSenderSessionBean _senderBean;
#Inject
private PushContext _pushContext;
#Inject
public NotificationEndpoint(QueueSenderSessionBean senderBean)
{
_senderBean = senderBean;
}
#OnOpen
public void onOpen(Session session,
EndpointConfig configurator,
#PathParam(value = "tokenId") String userUuidString)
{
session.getUserProperties().put("userUuid", userUuidString);
_pushContext.add(session, userUuidString);
}
#OnMessage
public void onMessage(String message, Session session)
throws IOException
{
System.out.println("Message received: " + message);
_senderBean.sendMessage(message);
}
#OnClose
public void onClose(CloseReason reason, Session session)
{
System.out.println(
"Closing 'notificatioEndpoint due to "
+ reason.getReasonPhrase());
try
{
session.close();
}
catch (IOException e)
{
e.printStackTrace();
}
_pushContext.removeSession(session);
}
#OnError
public void error(Session session, Throwable t)
{
t.printStackTrace();
}
public static void sendToAllClients(String message)
{
synchronized (SESSIONS)
{
for (Session session : SESSIONS)
{
if (session.isOpen())
{
session.getAsyncRemote().sendText(message);
}
}
}
}
public void onJMSMessage(#Observes #NotificationServletJMSMessage Message message)
{
Set<String> userUuids = new HashSet<String>();
try
{
_pushContext.send(userUuids, message);
}
catch (JMSException ex)
{
ex.printStackTrace();
Logger.getLogger(NotificationEndpoint.class.getName()).
log(Level.SEVERE, null, ex);
}
}
}
Thank you,
Ted S
Delayed message delivery accomplished inspired by the solution here.
The solution was using a local queue to hold messages if the user was not connected to the web socket, then when connected, moving messages from the local queue to a remote queue which gets received/consumed immediately using the MessageDrivenBean.
Also, instead of listening for messages from the database (Postgresql) with a Web Servlet, I changed my DB trigger to NOTIFY and started an asynchronous listener using the pgjdbc-ng driver and the Postgresql LISTEN/NOTIFY pattern described here.
NotificationListener.java
#Stateless
public class NotificationListener extends Thread
{
#Inject
private QueueSenderSessionBean _queueSessionSenderBean;
#Override
public void run()
{
listenToNotifications();
}
public void listenToNotifications()
{
PGNotificationListener listener = new PGNotificationListener()
{
public void notification(int processId, String channelName, String payload)
{
System.out.println("Received notification from: "
+ channelName + ", "
+ payload);
_queueSessionSenderBean.sendMessage(payload);
}
};
PGDataSource dataSource = new PGDataSource();
dataSource.setHost("localhost");
dataSource.setDatabase("db");
dataSource.setPort(5432);
dataSource.setUser("user");
dataSource.setPassword("pass");
try(PGConnection connection =
(PGConnection) dataSource.getConnection())
{
Statement statement = connection.createStatement();
statement.execute("LISTEN notifications");
statement.close();
connection.addNotificationListener(listener);
while (true)
{
if (Thread.currentThread().isInterrupted())
{
break;
}
}
}
catch (Exception e)
{
// TODO: handle exception
e.printStackTrace();
}
}
}
NotificationStarter.java
#Singleton
#Startup
public class NotificationsStarter
{
#EJB
private NotificationListener _listener;
#PostConstruct
public void startListener()
{
_listener.start();
}
#PreDestroy
public void shutdown()
{
_listener.interrupt();
}
}
PushContext.java
#ApplicationScoped
public class PushContext
{
#Resource(mappedName = "jms/localNotificationQueue")
private Queue _localNotificationQueue;
#Resource(mappedName = "jms/remoteNotificationQueue")
private Queue _remoteNotificationQueue;
private Map<String, Set<Session>> _sessions;
#PostConstruct
public void init()
{
_sessions = new ConcurrentHashMap<>();
}
public void add(Session session, String userUuid)
{
_sessions.computeIfAbsent(userUuid,
value -> ConcurrentHashMap.newKeySet()).add(session);
}
void remove(Session session)
{
_sessions.values().forEach(value -> value.removeIf(e -> e.equals(session)));
}
public void send(Set<String> userUuids, Message message) throws JMSException
{
String userUuid = message.getStringProperty("userUuid");
userUuids.add(userUuid);
Set<Session> userSessions;
synchronized(_sessions)
{
userSessions = _sessions.entrySet().stream()
.filter(e -> userUuids.contains(e.getKey()))
.flatMap(e -> e.getValue().stream())
.collect(Collectors.toSet());
for (Session userSession : userSessions)
{
if (userSession.isOpen())
{
userSession.getAsyncRemote().sendText(((TextMessage) message).getText());
}
}
}
}
public void removeSession(Session session)
{
String userUuid = (String)session.getUserProperties().get("userUuid");
_sessions.remove(userUuid, session);
}
public Boolean userHasWebSocketSession(String userUuid)
{
Boolean sessionOpen = false;
Set<String> userUuids = new HashSet<String>();
userUuids.add(userUuid);
Set<Session> userSessions;
synchronized(_sessions)
{
userSessions = _sessions.entrySet().stream()
.filter(e -> userUuids.contains(e.getKey()))
.flatMap(e -> e.getValue().stream())
.collect(Collectors.toSet());
}
for (Session userSession : userSessions)
{
if (userSession.isOpen())
{
sessionOpen = true;
break;
}
}
return sessionOpen;
}
}
QueueSenderSessionBean.java
#Named
#LocalBean
#Stateless
public class QueueSenderSessionBean
{
#Resource(mappedName = "jms/localNotificationQueue")
private Queue _localNotificationQueue;
#Resource(mappedName = "jms/remoteNotificationQueue")
private Queue _remoteNotificationQueue;
#Inject
#JMSConnectionFactory("jmsConnectionFactory")
private JMSContext _jmsContext;
#Inject
PushContext _pushContext;
public void sendMessage(String message)
{
JMSProducer messageProducer =
_jmsContext.createProducer();
messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT);
try
{
String userProperty = "someValue";
TextMessage textMessage = _jmsContext.createTextMessage(message);
textMessage.setStringProperty("userProperty", userProperty );
Boolean userIsConnected =
_pushContext.userHasWebSocketSession(userUuid);
if (!userIsConnected)
{
messageProducer.send(_localNotificationQueue, textMessage);
}
else
{
messageProducer.send(_remoteNotificationQueue, textMessage);
}
}
catch (JMSException e)
{
e.printStackTrace();
}
}
}
NotificationMessageDrivenBean.java is now listening to only the remote queue
#Named
#MessageDriven(mappedName = "jms/remoteNotificationQueue")
public class NotificationMessageDrivenBean implements MessageListener
{
#Inject
#NotificationServletJMSMessage
Event<Message> jmsEvent;
#Override
public void onMessage(Message message)
{
jmsEvent.fire(message);
}
}
New QueueReceiverSessionBean.java is used to receive/consume messages from the localNotificationQueue and places them in the remoteNotificationQueue whenever the user connects to NotificationEndpoint web socket.
#Named
#LocalBean
#Stateless
public class QueueReceiverSessionBean
{
#Resource(mappedName = "jms/localNotificationQueue")
private Queue _localNotificationQueue;
#Resource(mappedName = "jms/remoteNotificationQueue")
private Queue _remoteNotificationQueue;
#Inject
#JMSConnectionFactory("jmsConnectionFactory")
private JMSContext _jmsContext;
public void receiveQueuedMessages(String userUuidString) throws JMSException
{
Set<String> userUuids =
new HashSet<String>();
userUuids.add(userUuidString);
JMSConsumer messageConsumer =
_jmsContext.createConsumer(_localNotificationQueue,
"userProperty='someValue'",
true);
JMSProducer messageProducer =
_jmsContext.createProducer();
Message localMessage =
messageConsumer.receive(10);
while(localMessage != null)
{
TextMessage textMessage =
_jmsContext.createTextMessage(((TextMessage) localMessage).getText());
textMessage.setStringProperty("userUuid", userUuidString);
messageProducer.send(_remoteNotificationQueue, textMessage);
localMessage.acknowledge();
localMessage =
messageConsumer.receive(10);
}
messageConsumer.close();
}
public void sendMessage(String message)
{
JMSProducer messageProducer =
_jmsContext.createProducer();
messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT);
try
{
if (message.startsWith("notification"))
{
String messageJson = message.substring(message.indexOf("=") + 1);
JSONObject notificationJson =
new JSONObject(messageJson);
String userUuid = notificationJson.getString("receivinguseruuid");
TextMessage textMessage = _jmsContext.createTextMessage(message);
textMessage.setStringProperty("userUuid", userUuid);
messageProducer.send(_remoteNotificationQueue, textMessage);
}
}
catch (JMSException e)
{
e.printStackTrace();
}
}
}
NotificationEndpoint.java
#Named
#ServerEndpoint(value="/notificationEndpoint/{tokenId}")
public class NotificationEndpoint implements Serializable
{
private static final long serialVersionUID = 1L;
private static final Set<Session> SESSIONS =
Collections.synchronizedSet(new HashSet<Session>());
private QueueReceiverSessionBean _senderBean;
#Inject
private PushContext _pushContext;
#Inject
public NotificationEndpoint(QueueReceiverSessionBean senderBean)
{
_senderBean = senderBean;
}
#OnOpen
public void onOpen(Session session,
EndpointConfig configurator,
#PathParam(value = "tokenId") String userUuidString)
{
session.getUserProperties().put("userUuid", userUuidString );
_pushContext.add(session, userUuidString);
try
{
_senderBean.receiveQueuedMessages(userUuidString);
}
catch (JMSException e)
{
e.printStackTrace();
}
}
#OnMessage
public void onMessage(String message, Session session)
throws IOException
{
_senderBean.sendMessage(message);
}
#OnClose
public void onClose(CloseReason reason, Session session)
{
try
{
session.close();
}
catch (IOException e)
{
e.printStackTrace();
}
_pushContext.removeSession(session);
}
#OnError
public void error(Session session, Throwable t)
{
t.printStackTrace();
}
public static void sendToAllClients(String message)
{
synchronized (SESSIONS)
{
for (Session session : SESSIONS)
{
if (session.isOpen())
{
session.getAsyncRemote().sendText(message);
}
}
}
}
public void onJMSMessage(#Observes #NotificationServletJMSMessage Message message)
{
Set<String> userUuids = new HashSet<String>();
try
{
_pushContext.send(userUuids, message);
}
catch (JMSException ex)
{
ex.printStackTrace();
Logger.getLogger(NotificationEndpoint.class.getName()).
log(Level.SEVERE, null, ex);
}
}
}
Note: This code was used in the TomEE 8.0 container. Injecting JMSContext into the EJBs uncovered a bug in TomEE where the container fails to release the JMSConnection resource. Issue has been added to TomEE issues tracker

Sending XML message to JMS queue

am working with a project in which I am trying to call a Servlet that will push XML message to a JMS queue running in my local machine, using java code. You can find the actual Servlet code below, which actually sends the message to the queue.
import java.io.IOException;
import java.io.PrintWriter;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MessageSender
extends HttpServlet
{
private static final long serialVersionUID = 1L;
static PrintWriter out;
public static final String CNN_FACTORY = "jms/alert/connectionFactory";
public static final String QUEUE_NAME = "jms/alert/amlScreenQueue";
public static String currentQueueName;
public static String JMSConnectionFactory;
private QueueConnection qcon;
private QueueSession qsession;
private static QueueSender qsender;
private Queue queue;
private static ObjectMessage om;
private static MessageProducer messageProducer;
public MessageSender() {}
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
try
{
String JMSQueueName = request.getParameter("JMSQueueName");
currentQueueName = JMSQueueName;
JMSConnectionFactory = request.getParameter("JMSConnectionFactory");
out = response.getWriter();
InitialContext ic = getInitialContext();
init(ic, JMSQueueName);
doPost(request, response);
}
catch (Exception e) {
e.printStackTrace();
}
}
public void init(Context ctx, String queueName)
throws NamingException, JMSException
{
QueueConnectionFactory qconFactory = (QueueConnectionFactory)ctx.lookup(JMSConnectionFactory);
this.qcon = qconFactory.createQueueConnection();
this.qsession = this.qcon.createQueueSession(false, 1);
queue = ((Queue)ctx.lookup(queueName));
QueueConnection qcon = qconFactory.createQueueConnection();
qcon.start();
QueueSession qsession = qcon.createQueueSession(false, 1);
qsender = qsession.createSender(queue);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
String textMessage = request.getParameter("textMessage");
try
{
TextMessage msg = qsession.createTextMessage(textMessage);
msg.setStringProperty("JMSXGroupID", "1");
msg.setIntProperty("JMSXGroupSeq", 1);
msg.setBooleanProperty("JMS_IBM_Last_Msg_In_Group", false);
qsender.send(msg);
out.println("Message sent to queue " + currentQueueName);
out.println("");
out.println(msg.getText());
}
catch (JMSException e)
{
e.printStackTrace();
out.println(e.getErrorCode());
try
{
qsender.close();
qcon.close();
}
catch (JMSException e) {
e.printStackTrace();
}
}
finally
{
try
{
qsender.close();
qcon.close();
}
catch (JMSException e) {
e.printStackTrace();
}
}
}
private static InitialContext getInitialContext() throws NamingException
{
return new InitialContext();
}
}
This is the java code that I am using to call the servlet,
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map.Entry;
public class SendMessage {
public static void main(String[] args) throws URISyntaxException{
String line;
StringBuffer buffer = new StringBuffer();
String data = null;
try
{
String filePath = "data/payload.xml";
File dataFile = new File(filePath);
if(dataFile.exists()){
data = new String(Files.readAllBytes(Paths.get(filePath)));
}else{
System.out.println("Not Available");
}
String localUrl = "http://localhost:8080/SimulationTool/MessageSender";
String params = "JMSQueueName=jms/alert/amlScreenQueue&"
+ "JMSConnectionFactory=jms/alert/connectionFactory&"
+ "textMessage=" + data;
System.out.println("PARAMS:::" + params);
URL url = new URL(localUrl);
System.out.println("URL FOUND:::" + url.toURI());
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
conn.connect();
System.out.println("Response Code:::" + ((HttpURLConnection)conn).getResponseCode());
BufferedWriter out = new BufferedWriter( new OutputStreamWriter( conn.getOutputStream() ));
out.write(params);
out.flush();
out.close();
// Response code
System.out.println("Response Code:::" + ((HttpURLConnection)conn).getResponseCode());
// Response values
for (Entry<String, List<String>> header : ((HttpURLConnection)conn).getHeaderFields().entrySet()) {
System.out.println(header.getKey() + "=" + header.getValue());
}
BufferedReader in = new BufferedReader( new InputStreamReader( conn.getInputStream() ) );
String response;
while ( (response = in.readLine()) != null ) {
System.out.println( response );
}
in.close();
}
catch ( MalformedURLException ex ) {
ex.printStackTrace();
}
catch ( IOException ex ) {
ex.printStackTrace();
}
}
}
The problem is its failing with below exception,
Response Code:::200
java.net.ProtocolException: Cannot write output after reading input.
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream0(HttpURLConnection.java:1312)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1291)
at servlettests.SendMessage.main(SendMessage.java:63)
Its shows response code as 200, so the connection was successful but it fails while getting the outputstream, which is being created to send message to the queue. Pls help me on resolving this issue.

Java Websocket closes immediately

I am trying to use TooTallNate's Java-Websocket to connect to OkCoin. I found this simple code example somewhere, but I can't get it to work. The connection is immediately closed and so the call mWs.send(...) throws a WebsocketNotConnectedException. I can't figure out why; so far I have found a number of similar questions, none of which have an answer.
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.json.JSONObject;
import java.net.URI;
import java.net.URISyntaxException;
public class TestApp {
public static void main(String[] args) {
try {
URI uri = new URI("wss://real.okcoin.cn:10440/websocket/okcoinapi");
final WebSocketClient mWs = new WebSocketClient(uri) {
#Override
public void onMessage(String message) {
JSONObject obj = new JSONObject(message);
}
#Override
public void onOpen(ServerHandshake handshake) {
System.out.println("opened connection");
}
#Override
public void onClose(int code, String reason, boolean remote) {
System.out.println("closed connection");
}
#Override
public void onError(Exception ex) {
ex.printStackTrace();
}
};
mWs.connect();
JSONObject obj = new JSONObject();
obj.put("event", "addChannel");
obj.put("channel", "ok_btccny_ticker");
mWs.send(obj.toString());
} catch (URISyntaxException e) {
System.err.println("URI not formatted correctly");
}
}
}
Use mWs.connectBlocking() instead of mWs.connect() with this it will not close automatically.
See

Character encoding in com.sun.net.httpserver

I'm trying to write a mock HTTP server for unit tests, I'm using the com.sun.net.httpserver classes for that.
I'm having problem with the encoding of the URL: the query parameters are ISO-8859-1 encoded, but the URI that is passed to the handler (via HttpExchange) is not.
As I can't change the encoding of the original server, I was wondering if there was a way to tell the HttpServer which encoding to use when decoding the URL.
Thanks in advance.
Here is a test program:
package test34;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLEncoder;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Main {
public static void main(String[] args) {
try {
MockServer mock = new MockServer();
mock.start(8642);
URL url = new URL("http://localhost:8642/?p="
+ URLEncoder.encode("téléphone", "ISO-8859-1"));
System.out.println(url);
InputStream in = url.openStream();
while (in.read() > 0) {
}
in.close();
mock.stop();
System.out.println(mock.getLastParams().get("p"));
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
And here is the code of the mock server:
package test34;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
public class MockServer {
private HttpServer httpServer;
private Map<String, String> params;
public void start(int port) {
if (httpServer == null) {
try {
InetSocketAddress addr = new InetSocketAddress(port);
httpServer = HttpServer.create(addr, 0);
httpServer.createContext("/", new HttpHandler() {
#Override
public void handle(HttpExchange exchange) throws IOException {
try {
handleRoot(exchange);
} catch (RuntimeException e) {
throw e;
} catch (IOException e) {
throw e;
}
}
});
httpServer.setExecutor(Executors.newFixedThreadPool(1));
httpServer.start();
} catch (IOException e) {
throw new RuntimeException(e.getMessage());
}
}
}
public void stop() {
if (httpServer != null) {
httpServer.stop(10);
httpServer = null;
}
}
public Map<String, String> getLastParams() {
Map<String, String> result = new HashMap<String, String>();
if (params != null) {
result.putAll(params);
}
return result;
}
private void handleRoot(HttpExchange exchange) throws IOException {
URI uri = exchange.getRequestURI();
params = parseQuery(uri.getQuery());
Headers responseHeaders = exchange.getResponseHeaders();
responseHeaders.set("Content-Type", "text/plain;charset=ISO-8859-1");
exchange.sendResponseHeaders(200, 0);
OutputStream stream = exchange.getResponseBody();
try {
Writer writer = new OutputStreamWriter(stream, "ISO-8859-1");
try {
PrintWriter out = new PrintWriter(writer);
try {
out.println("OK");
} finally {
out.close();
}
} finally {
writer.close();
}
} finally {
stream.close();
}
}
private static Map<String, String> parseQuery(String qry)
throws IOException {
Map<String, String> result = new HashMap<String, String>();
if (qry != null) {
String defs[] = qry.split("[&]");
for (String def : defs) {
int ix = def.indexOf('=');
if (ix < 0) {
result.put(def, "");
} else {
String name = def.substring(0, ix);
String value = URLDecoder.decode(
def.substring(ix + 1), "ISO-8859-1");
result.put(name, value);
}
}
}
return result;
}
}
The javadoc of HttpExchange.getQueryString() says it returns "undecoded query string of request URI, or null if the request URI doesn't have one."
If it's not decoded, and since http headers have to be in 7 bit ASCII (ietf.org/rfc/rfc2616.txt) , then you can decode later with URLDecoder.decode(... "ISO-8859-1");

Categories