Below is the example i tried for websocket,
import java.io.IOException;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
#ServerEndpoint("/socket")
public class ExampleWebSocket {
private static Queue<Session> queue = new ConcurrentLinkedQueue<Session>();
#OnMessage
public void onMessage(Session session, String msg) {
try {
System.out.println("received msg "+msg+" from "+session.getId());
ExecutorService executorService = Executors
.newFixedThreadPool(1);
ThreadClass newThread = new ThreadClass(session); // a thread class which is going to perform async operations
Future<String> fut = executorService.submit(newThread);
int i =10;
while(fut.isDone()){
if(i > 50){
fut.cancel(true);
return;
}
Thread.sleep(1000);
i++;
}
executorService.shutdown();
} catch (Exception e) {
e.printStackTrace();
}
}
#OnOpen
public void open(Session session) {
queue.add(session);
System.out.println("New session opened: "+session.getId());
}
#OnError
public void error(Session session, Throwable t) {
queue.remove(session);
System.err.println("Error on session "+session.getId());
}
#OnClose
public void closedConnection(Session session) throws IOException {
queue.remove(session);
System.out.println("session closed: "+session.getId());
}
}
I added the below dependency in my jar,
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
</dependency>
For this example, i am always getting 404 when i tried to hit from browser.
Our project also runs with spring 3.2. Do i have to add this class config in any xml files like we.xml.. I am totally stuck here.
Also i tried by adding <scope>provided</scope> in the dependency of javax.websocket-api then deployment getting failed with class not found exception.
Websocket is not supported by servers of lower version.
Below RUL provide us the list of websocket supported web servers.
https://github.com/Atmosphere/atmosphere/wiki/Supported-WebServers-and-Browsers
Related
I am building notification system using spring boot and websocket, I used ActiveMQ to keep Queues for offlines users, it's working perfect.
I need to edit some configuration like queue time to live, keep message in queue until user read it, I don't know how can configure it?
The below is its implementation:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
/*config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");*/
config
.setApplicationDestinationPrefixes("/app")
.setUserDestinationPrefix("/user")
.enableStompBrokerRelay("/topic","/queue","/user")
.setRelayHost("localhost")
.setRelayPort(61613)
.setClientLogin("guest")
.setClientPasscode("guest");
}
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/websocket").withSockJS();
}
}
And:
#Service
public class NotificationWebSocketService {
#Autowired
private SimpMessagingTemplate messagingTemplate;
public void initiateNotification(WebSocketNotification notificationData) throws InterruptedException {
messagingTemplate.convertAndSendToUser(notificationData.getUserID(), "/reply", notificationData.getMessage());
}
}
After invoke NotificationWebSocketService it will create queue "/user/Johon/reply" in activemq contains message when user subscribe in this queue message will received.
How can configure queue time to live , keep message in queue until user read it?
Unit-test to illustrate how to set up expiration of message in user queue.
Required tomcat-embedded, spring-messaging, and active-mq
import org.apache.catalina.Context;
import org.apache.catalina.Wrapper;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.startup.Tomcat;
import org.apache.coyote.http11.Http11NioProtocol;
import org.apache.tomcat.util.descriptor.web.ApplicationListener;
import org.apache.tomcat.websocket.server.WsContextListener;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.messaging.simp.stomp.*;
import org.springframework.messaging.support.ChannelInterceptorAdapter;
import org.springframework.web.SpringServletContainerInitializer;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import org.springframework.web.socket.WebSocketHttpHeaders;
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.messaging.WebSocketStompClient;
import org.springframework.web.socket.sockjs.client.SockJsClient;
import org.springframework.web.socket.sockjs.client.WebSocketTransport;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import static java.util.concurrent.TimeUnit.SECONDS;
public class Test48402361 {
private static final Logger logger = LoggerFactory.getLogger(Test48402361.class);
private static TomcatWebSocketTestServer server = new TomcatWebSocketTestServer(33333);
#BeforeClass
public static void beforeClass() throws Exception {
server.deployConfig(Config.class);
server.start();
}
#AfterClass
public static void afterClass() throws Exception {
server.stop();
}
#Test
public void testUser() throws Exception {
WebSocketStompClient stompClient = new WebSocketStompClient(new SockJsClient(Collections.singletonList(new WebSocketTransport(new StandardWebSocketClient()))));
BlockingQueue<String> blockingQueue = new LinkedBlockingQueue<>();
StompSession session = stompClient
.connect("ws://localhost:" + server.getPort() + "/test", new WebSocketHttpHeaders(), new StompSessionHandlerAdapter() {
})
.get();
// waiting until message 2 expired
Thread.sleep(3000);
session.subscribe("/user/john/reply", new StompFrameHandler() {
#Override
public Type getPayloadType(StompHeaders headers) {
return byte[].class;
}
#Override
public void handleFrame(StompHeaders headers, Object payload) {
String message = new String((byte[]) payload);
logger.debug("message: {}, headers: {}", message, headers);
blockingQueue.add(message);
}
});
String message = blockingQueue.poll(1, SECONDS);
Assert.assertEquals("1", message);
message = blockingQueue.poll(1, SECONDS);
Assert.assertEquals("3", message);
}
public static class Config extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { Mvc.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
#Configuration
#EnableWebSocketMessageBroker
public static class Mvc extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
stompEndpointRegistry.addEndpoint("/test")
.withSockJS()
.setWebSocketEnabled(true);
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableStompBrokerRelay("/user").setRelayHost("localhost").setRelayPort(61614);
}
#Autowired
private SimpMessagingTemplate template;
#Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.setInterceptors(new ChannelInterceptorAdapter() {
#Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor sha = StompHeaderAccessor.wrap(message);
switch (sha.getCommand()) {
case CONNECT:
// after connect we send 3 messages to user john, one will purged after 2 seconds.
template.convertAndSendToUser("john", "/reply", "1");
Map<String, Object> headers = new HashMap<>();
headers.put("expires", System.currentTimeMillis() + 2000);
template.convertAndSendToUser("john", "/reply", "2", headers);
template.convertAndSendToUser("john", "/reply", "3");
break;
}
return super.preSend(message, channel);
}
});
}
}
public static class TomcatWebSocketTestServer {
private static final ApplicationListener WS_APPLICATION_LISTENER =
new ApplicationListener(WsContextListener.class.getName(), false);
private final Tomcat tomcatServer;
private final int port;
private Context context;
public TomcatWebSocketTestServer(int port) {
this.port = port;
Connector connector = new Connector(Http11NioProtocol.class.getName());
connector.setPort(this.port);
File baseDir = createTempDir("tomcat");
String baseDirPath = baseDir.getAbsolutePath();
this.tomcatServer = new Tomcat();
this.tomcatServer.setBaseDir(baseDirPath);
this.tomcatServer.setPort(this.port);
this.tomcatServer.getService().addConnector(connector);
this.tomcatServer.setConnector(connector);
}
private File createTempDir(String prefix) {
try {
File tempFolder = File.createTempFile(prefix + '.', "." + getPort());
tempFolder.delete();
tempFolder.mkdir();
tempFolder.deleteOnExit();
return tempFolder;
} catch (IOException ex) {
throw new RuntimeException("Unable to create temp directory", ex);
}
}
public int getPort() {
return this.port;
}
#SafeVarargs
public final void deployConfig(Class<? extends WebApplicationInitializer>... initializers) {
this.context = this.tomcatServer.addContext("", System.getProperty("java.io.tmpdir"));
// Add Tomcat's DefaultServlet
Wrapper defaultServlet = this.context.createWrapper();
defaultServlet.setName("default");
defaultServlet.setServletClass("org.apache.catalina.servlets.DefaultServlet");
this.context.addChild(defaultServlet);
// Ensure WebSocket support
this.context.addApplicationListener(WS_APPLICATION_LISTENER);
this.context.addServletContainerInitializer(
new SpringServletContainerInitializer(), new HashSet<>(Arrays.asList(initializers)));
}
public void start() throws Exception {
this.tomcatServer.start();
}
public void stop() throws Exception {
this.tomcatServer.stop();
}
}
}
"stompClient.subscribe('/user/Johon/reply' --> '/user/Johon/reply' is a topic and not a queue.
If your Stomp client is not connected to the topic '/user/Johon/reply' he will loose every message sent to that topic.
So your solutions are :
convert your topic '/user/Johon/reply' to a queue, so the message remains on the queue indefinitely or until the server end-processes the message.
use Retroactive Consumer & Subscription Recovery Policy
A retroactive consumer is just a regular JMS Topic consumer who
indicates that at the start of a subscription every attempt should be
used to go back in time and send any old messages (or the last message
sent on that topic) that the consumer may have missed.
http://activemq.apache.org/retroactive-consumer.html
The subscription recovery policy allows you to go back in time when
you subscribe to a topic.
http://activemq.apache.org/subscription-recovery-policy.html
Use Durable Subscribers
Durable topic subscribers that are offline for a long period of time
are usually not desired in the system. The reason for that is that
broker needs to keep all the messages sent to those topics for the
said subscribers. And this message piling can over time exhaust broker
store limits for example and lead to the overall slowdown of the
system.
http://activemq.apache.org/manage-durable-subscribers.html
Durable Subscribers with Stomp :
http://activemq.apache.org/stomp.html#Stomp-ActiveMQExtensionstoSTOMP
CONNECT client-id string Specifies the JMS clientID which is used in
combination with the activemq.subcriptionName to denote a durable
subscriber.
some explanations about TTL
A client can specify a time-to-live value in milliseconds for each
message it sends. This value defines a message expiration time that is
the sum of the message's time-to-live and the GMT when it is sent (for
transacted sends, this is the time the client sends the message, not
the time the transaction is committed).
the default time to live is 0, so the message remains on the queue
indefinitely or until the server end-processes the message
UPDATE
if you want to use external ActiveMQ Broker
remove #EnableWebSocketMessageBroker and add to your activemq.xml below connector and restart the broker.
<transportConnector name="stomp" uri="stomp://localhost:61613"/>
if you want to embedd ActiveMQ Broker, add bean to you WebSocketConfig :
#Bean(initMethod = "start", destroyMethod = "stop")
public BrokerService broker() throws Exception {
final BrokerService broker = new BrokerService();
broker.addConnector("stomp://localhost:61613");
return broker;
}
and required dependencies
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-stomp</artifactId>
</dependency>
full examples
Spring Boot WebSocket with embedded ActiveMQ Broker
http://www.devglan.com/spring-boot/spring-boot-websocket-integration-example
Out of curiosity I'd like to build a simple websockets tyrus server chat project with javac and libraries in -classpath.
Yes, I know that this is not the standard way (mvn is), but I'm doing it as a proof of concept. I manage to get project built but it throws a NullPointerException
Code is:
ChatMain.java:
package chat;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
import javax.websocket.DeploymentException;
import org.glassfish.tyrus.server.Server;
public class ChatMain {
public static void main(String[] args) throws DeploymentException,
IOException {
Map<String, Object> properties = Collections.emptyMap();
Server server = new Server("localhost", 8080, "/ws", properties,
ChatEndPoint.class);
System.out.println(server);
try {
server.start();
System.in.read();
} finally {
server.stop();
}
}
}
ChatEndPoint.java:
package chat;
import java.io.IOException;
import java.util.Map;
import java.util.HashMap;
import java.util.Collections;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import org.json.*;
#ServerEndpoint("/chat")
public class ChatEndPoint {
private static Map<String, Session> peers = Collections.synchronizedMap(new HashMap<String, Session>());
#OnOpen
public void onOpen(Session peer) {
System.out.println("onOpen");
}
#OnMessage
public void onMessage(String message, Session peer) throws IOException {
System.out.println("onMessage");
JSONObject json = new JSONObject(message);
String nick = (String) json.get("nick");
boolean newClient = json.has("action") && ((String) json.get("action")).equals("add");
synchronized(peers) {
// Iterate over the connected sessions
// and broadcast the received message
for (Map.Entry<String, Session> entry : peers.entrySet()) {
if (newClient) {
JSONObject json1 = new JSONObject(json, new String[] { "action" }).put("nick", entry.getKey());
peer.getBasicRemote().sendText(json1.toString());
}
entry.getValue().getBasicRemote().sendText(message);
}
}
if (newClient)
peers.put(nick, peer);
}
#OnClose
public void onClose(Session peer) {
System.out.println("onClose");
peers.values().remove(peer);
}
}
javac line:
javac -cp chat/javax.websocket-api-1.1.jar:chat/tyrus-server-1.12.jar:chat/tyrus-spi-1.12.jar:chat/tyrus-core-1.12.jar:chat/grizzly-framework-2.3.22.jar:chat/grizzly-http-server-2.3.22.jar:chat/tyrus-container-grizzly-server-1.12.jar:chat/json.jar: chat/ChatMain.java
java line:
java -cp chat/javax.websocket-api-1.1.jar:chat/tyrus-server-1.12.jar:chat/tyrus-spi-1.12.jar:chat/tyrus-core-1.12.jar:chat/grizzly-framework-2.3.22.jar:chat/grizzly-http-server-2.3.22.jar:chat/tyrus-container-grizzly-server-1.12.jar:chat/json.jar: chat.ChatMain
runtime error:
Exception in thread "main" java.lang.NullPointerException
at org.glassfish.tyrus.container.grizzly.server.GrizzlyServerContainer$1.stop(GrizzlyServerContainer.java:228)
at org.glassfish.tyrus.server.Server.stop(Server.java:231)
at chat.ChatMain.main(ChatMain.java:23)
I understand that this can be done
Interestingly, more libraries are needed. If I include all libraries in websocket-ri-archive-1.12.zip bundle, it works well. Definitely, a builder is the way to go
I am using Spring and Spring Security and want to use spring-session-data-redis with RedisHttpSessionConfiguration to enable storing session IDs on redis (so clients wont loose their sessions when webapp fails and switched over to another server).
My question, what happens when Redis server is down?
Will spring be able to continue to work by storing session in memory until Redis is back up? Is there a way to configure this as so?
I am using Redis on AWS ElastiCache, and Failover can take several minutes before replacement primary node is configured on the DNS.
As far as I can see, you will need to provide an implementation of CacheErrorHandler ( javadoc).
You can do this by providing a Configuration instance, that implements CachingConfigurer, and overrides the errorHandler() method.
For example:
#Configuration
#Ena1bleCaching
public class MyApp extends SpringBootServletInitializer implements CachingConfigurer {
#Override
public CacheErrorHandler errorHandler() {
return MyAppCacheErrorHandler();
}
}
Exactly HOW you will then provide uninterrupted service is not clear to me - without duplicating the current sessions in your failover cache, it seems impossible.
If you are using ElasticCache, is it not possible to have AWS handle a replicated setup for you, so that if one node goes doen, the other can take over?
I've managed to implement a fail-over mechanism to an in-memory session whenever Redis is unreachable. Unfortunately this can't be done just by a Spring property, so you have to implement your custom SessionRepository and configuring it to be used the SessionRepositoryFilter which will fail-over to the in-memory cache whenever Redis is unreachable .
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Primary;
import org.springframework.session.MapSession;
import org.springframework.session.Session;
import org.springframework.session.SessionRepository;
import org.springframework.stereotype.Component;
#Component("customSessionRepository")
#Primary
public class CustomFailoverToMapSessionRepository implements SessionRepository {
private static final Logger LOGGER = LoggerFactory.getLogger(CustomFailoverToMapSessionRepository.class);
private GuavaBasedSessionRepository guavaBasedSessionRepository;
private SessionRepository sessionRepository;
public CustomFailoverToMapSessionRepository(SessionRepository sessionRepository, GuavaBasedSessionRepository guavaBasedSessionRepository) {
this.sessionRepository = sessionRepository;
this.guavaBasedSessionRepository = guavaBasedSessionRepository;
}
#Override
public Session createSession() {
Session session = null;
MapSession mapSession = guavaBasedSessionRepository.createSession();
try {
session = sessionRepository.createSession();
mapSession = toMapSession(session);
} catch (Exception e) {
LOGGER.warn("Unexpected exception when trying to create a session will create just an in memory session", e);
}
return session == null ? mapSession : session;
}
#Override
public void save(Session session) {
try {
if (!isOfMapSession(session)) {
sessionRepository.save(session);
}
} catch (Exception e) {
LOGGER.warn("Unexpected exception when trying to save a session with id {} will create just an in memory session", session.getId(), e);
}
guavaBasedSessionRepository.save(toMapSession(session));
}
#Override
public Session findById(String id) {
try {
return sessionRepository.findById(id);
} catch (Exception e) {
LOGGER.warn("Unexpected exception when trying to lookup a session with id {}", id, e);
return guavaBasedSessionRepository.findById(id);
}
}
#Override
public void deleteById(String id) {
try {
try {
guavaBasedSessionRepository.deleteById(id);
} catch (Exception e) {
//ignored
}
sessionRepository.deleteById(id);
} catch (Exception e) {
LOGGER.warn("Unexpected exception when trying to delete a session with id {}", id, e);
}
}
private boolean isOfMapSession(Session session) {
return session instanceof MapSession;
}
private MapSession toMapSession(Session session) {
final MapSession mapSession = guavaBasedSessionRepository.createSession();
if (session != null) {
mapSession.setId(session.getId());
mapSession.setCreationTime(session.getCreationTime());
mapSession.setLastAccessedTime(session.getLastAccessedTime());
mapSession.setMaxInactiveInterval(session.getMaxInactiveInterval());
session.getAttributeNames()
.forEach(attributeName -> mapSession.setAttribute(attributeName, session.getAttribute(attributeName)));
}
return mapSession;
}
Implement the in-memory cache session repository using Guava
import com.google.common.annotations.VisibleForTesting;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.session.MapSession;
import org.springframework.session.Session;
import org.springframework.session.SessionRepository;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
#Component("guavaBasedSessionRepository")
public class GuavaBasedSessionRepository implements SessionRepository<MapSession> {
private Cache<String, Session> sessionCache;
#Value("${session.local.guava.cache.maximum.size}")
private int maximumCacheSize;
#Value("${redis.session.keys.timeout}")
private long sessionTimeout;
#PostConstruct
void init(){
sessionCache = CacheBuilder
.newBuilder()
.maximumSize(maximumCacheSize)
.expireAfterWrite(sessionTimeout, TimeUnit.MINUTES)
.build();
}
#Override
public void save(MapSession session) {
if (!session.getId().equals(session.getOriginalId())) {
this.sessionCache.invalidate(session.getOriginalId());
}
this.sessionCache.put(session.getId(), new MapSession(session));
}
#Override
public MapSession findById(String id) {
Session saved = null;
try {
saved = this.sessionCache.getIfPresent(id);
} catch (Exception e){
//ignored
}
if (saved == null) {
return null;
}
if (saved.isExpired()) {
deleteById(saved.getId());
return null;
}
return new MapSession(saved);
}
#Override
public void deleteById(String id) {
this.sessionCache.invalidate(id);
}
#Override
public MapSession createSession() {
MapSession result = new MapSession();
result.setMaxInactiveInterval(Duration.ofSeconds(sessionTimeout));
return result;
}
Configure Spring to use the custom SessionRepository
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.session.Session;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.session.web.http.CookieHttpSessionIdResolver;
import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.SessionRepositoryFilter;
import javax.annotation.PostConstruct;
#EnableRedisHttpSession
#Configuration
public class CustomSessionConfig {
private CookieHttpSessionIdResolver defaultHttpSessionIdResolver = new CookieHttpSessionIdResolver();
#Autowired
private CookieSerializer cookieSerializer;
#PostConstruct
public void init(){
this.defaultHttpSessionIdResolver.setCookieSerializer(cookieSerializer);
}
#Bean
#Primary
public <S extends Session> SessionRepositoryFilter<? extends Session> sessionRepositoryFilter(CustomFailoverToMapSessionRepository customSessionRepository) {
SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter<>(customSessionRepository);
sessionRepositoryFilter.setHttpSessionIdResolver(this.defaultHttpSessionIdResolver);
return sessionRepositoryFilter;
}
I am new to Socket Programming and very well know that i am making a silly mistake. Unfortunately not able to figure out as to what is going on. I have created a basic multi Client-Server system using Java socket on same machine(shouldn't make any difference), however to my surprise either i am able to only
Send Message from Server to Client and then read it on Client.
OR
Send Message from Client to Server and then read it on Server.
What i am not able to achieve is
Send Message from Server to Client and then read it on Client.
AND
Send Message from Client to Server and then read it on Server.
I am attaching my code.
import java.io.IOException;
import java.net.ServerSocket;
public class ServerSocketMain {
public static void main(String[] args) throws IOException {
#SuppressWarnings("resource")
ServerSocket serverSocket = new ServerSocket(1234);
while(true){
System.out.println("Server Waiting for Client to Connect ....");
Thread thread = new Thread(new ServerReaderWriter(serverSocket.accept()));
System.out.println("Client connected....");
thread.start();
}
}
}
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
public class ServerReaderWriter implements Runnable {
private Socket socket;
public ServerReaderWriter(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
try {
readFromClient();
writeToClient();
} catch (IOException e) {
e.printStackTrace();
}
}
private void writeToClient() throws IOException {
DataOutputStream writeToClient = new DataOutputStream(this.socket.getOutputStream());
writeToClient.writeBytes("Communication from Client Thread "
+ Thread.currentThread().getName() + "\n");
}
private void readFromClient() throws IOException {
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(
this.socket.getInputStream()));
System.out.println("Client Communication : " + inFromClient.readLine());
}
}
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ClientSocketMain {
public static void main(String[] args) throws UnknownHostException, IOException {
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
executorService.submit(new ClientReaderWriter(new Socket("localhost", 1234)));
}
executorService.shutdown();
}
}
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
public class ClientReaderWriter implements Runnable {
private Socket socket;
public ClientReaderWriter(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
try {
readFromServer(socket.getInputStream());
writeToServer(socket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private void writeToServer(OutputStream outputStream) throws IOException {
DataOutputStream writeToServer = new DataOutputStream(outputStream);
writeToServer.writeBytes("Communication from Client Thread "
+ Thread.currentThread().getName() + "\n");
}
private void readFromServer(InputStream inputStream) throws IOException {
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(
inputStream));
System.out.println(inFromServer.readLine());
}
}
I am just wondering if my client socket closes even before read and write operations are done..not sure just guessing out loud. please help!!
As it turned out...i was making a silly mistake....Ordering is very important in the code snippet that i had shared above and i was ignoring the fact.
readFromClient();
writeToClient();
readFromServer(socket.getInputStream());
writeToServer(socket.getOutputStream());
In the above scenario both server and client are trying to read...instead one should be writing and other reading. So all i needed to do was change the order
writeToClient();
readFromClient();
readFromServer(socket.getInputStream());
writeToServer(socket.getOutputStream());
Spring JMS is working against me, as the title say I get a NoClassDefFoundError, below you find the code.
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Queue;
import javax.jms.Session;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.JmsTemplate102;
import org.springframework.jms.core.MessageCreator;
public class JMSQueueSender {
private JmsTemplate jmsTemplate;
private Queue queue;
public void setConnectionFactory(ConnectionFactory cf) {
this.jmsTemplate = new JmsTemplate102(cf, false);
}
public void setQueue(Queue queue) {
this.queue = queue;
}
public void simpleSend() throws Exception {
this.jmsTemplate.send(this.queue, new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage("hello queue world");
}
});
}
}
This is also the example code, I have a working code with IBM, but I'm trying to change it for a Spring JMS, but it isn't working. Can someone help me.
I guess you need to add spring-tx.jar (or org.springframework.transaction-*.jar with new style of names) to the classpath.
Try checking your JAVA_HOME and CLASSPATH settings.