I have a camel route with a splitter (using streaming) that sends messages to a seda queue to be processed. When I'm trying to stop the application gently, the seda queue doesn't stop immediately, it is processing all the messages before finally shutting down.
What can I do to stop it right away?
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.builder.ExpressionBuilder;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.main.Main;
public class MySedaShutdownTest extends RouteBuilder {
#Override
public void configure() throws Exception {
onException(Exception.class)
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
System.out.println("exception");
}
});
from("timer:myTimer?repeatCount=1")
.split(ExpressionBuilder.beanExpression(new MySplitter(), "myIterator"))
.streaming()
.to("seda:mySeda");
from("seda:mySeda")
.throttle(1)
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
System.out.println("processing: " + exchange.getIn().getBody()
+ "; app status: " + exchange.getContext().getStatus());
}
});
}
public static class MySplitter {
public Iterator<String> myIterator() {
List<String> values = new ArrayList<String>();
for (int i = 0; i < 10; i++) {
values.add("string nr : " + i);
}
System.out.println("in myIterator");
return values.iterator();
}
}
public static void main(String[] a) throws Exception {
final Main main = new Main();
new Thread(new Runnable() {
#Override
public void run() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
System.out.println("invoking shutdown");
main.shutdown();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
System.out.println("starting app");
main.enableHangupSupport();
main.addRouteBuilder(new MySedaShutdownTest());
main.run();
}
}
There is a purgeQueue method on the SedaEndpoint. So you can get the endpoint and call this method. You can also access it from JMX.
A bit related we have this ticket for improvement
https://issues.apache.org/jira/browse/CAMEL-5911
And I logged a ticket for this
https://issues.apache.org/jira/browse/CAMEL-6405
Just add string below as first line of your configure() method:
getContext().getShutdownStrategy().setTimeout(1);
It will reduce shutdown timeout from 300 seconds (default) to 1
See more info on controlling start-up and shutdown of routes.
Related
I implemented SignalR Java Client in my Android Project. It works well on Android Versions 6 to 11 but fails on Android 12, I'm getting this error only on Android 12 java.net.SocketException: Socket closed [Ljava.lang.StackTraceElement;#e95116d, here is my code:
import android.content.Context;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.microsoft.signalr.HubConnection;
import com.microsoft.signalr.HubConnectionBuilder;
import com.microsoft.signalr.OnClosedCallback;
import org.json.JSONObject;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
import timber.log.Timber;
public class SignalRChatService {
Timer timer = new Timer();
public void startTimer()
{
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
// Your code here
Timer_Elapsed();
}
}, 1000, 2000);
}
private void Timer_Elapsed()
{
try
{
module.checkNetwork(context);
if(!Connected)
{
Init();
}
}
catch (Exception e)
{
Connected = false;
}
}
private HubConnection _connection;
public boolean Connected;
public String instanceName;
public int instanceProfileId;
private boolean connecting;
private SignalRMessageReceivedEvents signalRMessageReceivedEvents;
private final Gson gson;
private final Context context;
public SignalRChatService(Context context, String instanceName, int instanceProfileId, SignalRMessageReceivedEvents signalRMessageReceivedEvents) {
this.instanceName = instanceName;
this.instanceProfileId = instanceProfileId;
this.connecting = false;
this.context = context;
this.signalRMessageReceivedEvents = signalRMessageReceivedEvents;
gson = new GsonBuilder().setPrettyPrinting().create();
}
public void Stop()
{
try
{
_connection.stop();
}
catch(Exception ignored)
{}
}
public void Init()
{
if (connecting)
{
return;
}
try
{
connecting = true;
_connection = HubConnectionBuilder.create("https://" + instanceName.trim().toLowerCase() + ".com").build();
try
{
_connection.start();
Connected = true;
}
catch (Exception e)
{
Connected = false;
Timber.e("SignalR Push connect: %s", e.getLocalizedMessage());
return;
}
_connection.on("Message", (message) ->
{
try
{
// Separate this code affterwads
JSONObject messageObject = new JSONObject(message);
String Messagetype = (String) messageObject.get("messageType");
HandleWebSocketMessage(Messagetype, message);
}
catch (Exception ignored)
{
}
}, String.class);
_connection.onClosed(new OnClosedCallback() {
#Override
public void invoke(Exception exception) {
handleClosed();
}
});
}
catch (Exception ignored)
{
}
finally
{
connecting = false;
startTimer();
}
}
private void handleClosed()
{
try
{
TimeUnit.MILLISECONDS.sleep(100);
}
catch (Exception ignored)
{
}
Init();
}
}
I've tried upgrading to the latest version of SignalR Java Client
implementation "com.microsoft.signalr:signalr:6.0.3"
and it is still not working. It just wont receive any Signal.
I am trying to do long polling in a struts web application. I start an AsyncContext inside an ActionSupport action method, do some time-consuming work async, and then would like to send the SUCCESS response to struts.
I know that I can do PrintWriter pw = asyncContext.getResponse().getWriter(); and write a raw response, but I would like to somehow signal struts to proceed with the predefined result in struts.xml. Is this possible?
<action name="myAction" method="action1" class="myActionClass">
<result name="success" type="redirectAction">
/pages/myPage.jsp <!-- I want to run this from async --->
</result>
</action>
In non-async action I can simply return SUCCESS and struts takes care of everything, but I am having trouble with achieving a similar effect with async action. This is what I have so far:
public void action1() {
HttpServletRequest req = ServletActionContext.getRequest();
HttpServletResponse res = ServletActionContext.getResponse();
final AsyncContext asyncContext = req.startAsync(req, res);
asyncContext.start(new Runnable() {
public void run() {
// Some time-consuming polling task is done here
asyncContext.complete();
// Can I somehow proceed to predefined struts result from here?
}
});
}
Currently it seems cannot be done clearly. I am working if I can import this support to Struts but for now, I have a hack which works. I extended StrutsExecuteFilter as below:
package me.zamani.yasser.ww_convention.utils;
import org.apache.struts2.dispatcher.PrepareOperations;
import org.apache.struts2.dispatcher.filter.StrutsExecuteFilter;
import org.apache.struts2.dispatcher.filter.StrutsPrepareFilter;
import org.apache.struts2.dispatcher.mapper.ActionMapping;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
/**
* Created by user on 8/31/2017.
*/
public class MYStrutsAsyncExecuteFilter extends StrutsExecuteFilter {
public final int REQUEST_TIMEOUT = 240000;//set your desired timeout here
private ExecutorService exe;
#Override
public void init(FilterConfig filterConfig) throws ServletException {
int size = 41;//set your desired pool size here
exe = Executors.newFixedThreadPool(
size,
new ThreadFactory() {
public Thread newThread(Runnable r) {
return new Thread(r, "My Struts Async Processor");
}
}
);
super.init(filterConfig);
}
#Override
public void doFilter(final ServletRequest req, final ServletResponse res, final FilterChain chain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) req;
final HttpServletResponse response = (HttpServletResponse) res;
if (excludeUrl(request)) {
chain.doFilter(request, response);
return;
}
// This is necessary since we need the dispatcher instance, which was created by the prepare filter
if (execute == null) {
lazyInit();
}
final ActionMapping mapping = prepare.findActionMapping(request, response);
//if recursion counter is > 1, it means we are in a "forward", in that case a mapping will still be
//in the request, if we handle it, it will lead to an infinite loop, see WW-3077
final Integer recursionCounter = (Integer) request.getAttribute(PrepareOperations.CLEANUP_RECURSION_COUNTER);
if (mapping == null || recursionCounter > 1) {
boolean handled = execute.executeStaticResourceRequest(request, response);
if (!handled) {
chain.doFilter(request, response);
}
} else {
/* I ADDED THESE */
final AsyncContext context = req.startAsync();
context.setTimeout(REQUEST_TIMEOUT);
context.addListener(new AsyncListener() {
public void onComplete(AsyncEvent asyncEvent) throws IOException {
}
public void onTimeout(AsyncEvent asyncEvent) throws IOException {
context
.getResponse()
.getWriter().write("Request Timeout");
}
public void onError(AsyncEvent asyncEvent) throws IOException {
context
.getResponse()
.getWriter().write("Processing Error");
}
public void onStartAsync(AsyncEvent asyncEvent) throws IOException {
}
});
exe.execute(new ContextExecution(context, mapping));
}
}
private boolean excludeUrl(HttpServletRequest request) {
return request.getAttribute(StrutsPrepareFilter.class.getName() + ".REQUEST_EXCLUDED_FROM_ACTION_MAPPING") != null;
}
#Override
public void destroy() {
exe.shutdown();
super.destroy();
}
class ContextExecution implements Runnable {
final AsyncContext context;
ActionMapping mapping;
public ContextExecution(AsyncContext context, ActionMapping mapping) {
this.context = context;
this.mapping=mapping;
}
public void run() {
try {
execute.executeAction((HttpServletRequest) context.getRequest(),
(HttpServletResponse) context.getResponse(), mapping);
context.complete();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
then
<filter>
<filter-name>struts2asyncexecute</filter-name>
<filter-class>me.zamani.yasser.ww_convention.utils.MYStrutsAsyncExecuteFilter</filter-class>
<async-supported>true</async-supported>
</filter>
then put your desired async actions in a specific package and exclude them from Strut's original filter but map them to above filter in your web.xml.
I'm working to improve this to be more configurable and clear then import to Struts.
Could you please test in your app? and please feel free to let me know any idea.
Look at this example:
package sample;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.stage.Stage;
public class Main extends Application {
//NOTICE: This is class in **other file** (here is just for example)
private static class MyService extends Service {
#Override
protected Task createTask() {
return new Task() {
#Override
protected Object call() throws Exception {
System.out.println("Service: START");
while(true) {
System.out.println("Service: ITERATION");
// Thread.sleep(3000); // This raise InterruptedException after cancel, but how about such code (it won't raise exception):
for(long i = 0; i < 1_000_000_000; i++) {
}
if (isCancelled())
break;
}
System.out.println("Service: END");
return null;
}
};
}
}
#Override
public void start(Stage primaryStage) throws Exception {
MyService myService = new MyService();
myService.start();
Thread.sleep(5000);
myService.cancel();
System.out.println(myService.getState()); // Here is `CANCELLED` already but task isn't finished yet.
// <--- How to wait cancellation of Task here?
System.out.println("This command must be called after `Service: END`");
Platform.exit();
}
public static void main(String[] args) {
launch(args);
}
}
As you known call of Service#cancel doesn't wait cancellation of Task. So, I want to block main thread and await cancellation of Task. How can I do it?
P.S.
Looks like Service doesn't provide any callback/event handler to check real cancellation of Task. Is it right?
By default, Service.cancel() interrupts the Task. So an InterruptedException must be raised and your task will be terminated (forcefully).
One thing you could do is to store the created task in a global variable in your MyService class and override the cancel method like this:
class MyService extends Service {
private Task t;
#Override
public boolean cancel() {
if (t != null) {
return t.cancel(false);
} else {
return false;
}
}
#Override
protected Task createTask() {
t = new Task() { /* ... */ };
return t;
}
}
The rest will be easy. Add a change listener to the service state property (or use setOnCanceled() method) and do whatever you want to do after the state change, in the callback.
Never block the FX Application Thread.
The Service class does indeed define a setOnCancelled(...) method, which you use to register a callback:
myService.setOnCancelled(event -> {
System.out.println("Service was cancelled");
});
Note that when you cancel a Service, it will interrupt the thread if it is blocked. So if you don't catch the InterruptedException it will not exit the call method normally. This is why you don't see the "END" message.
Full example code:
import javafx.animation.PauseTransition;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.stage.Stage;
import javafx.util.Duration;
public class ServiceCancellationTest extends Application {
//NOTICE: This is class in **other file** (here is just for example)
private static class MyService extends Service<Void> {
#Override
protected Task<Void> createTask() {
return new Task<Void>() {
#Override
protected Void call() throws Exception {
System.out.println("Service: START");
while(! isCancelled()) {
System.out.println("Service: ITERATION");
try {
Thread.sleep(3000);
} catch (InterruptedException interrupted) {
System.out.println("Task interrupted");
}
if (isCancelled())
break;
}
System.out.println("Service: END");
return null;
}
};
}
}
#Override
public void start(Stage primaryStage) throws Exception {
MyService myService = new MyService();
myService.start();
myService.setOnCancelled(event -> {
System.out.println("In cancelled callback: "+myService.getState()); // Here is `CANCELLED` already but task isn't finished yet.
});
// You should never block the FX Application Thread. To effect a pause,
// use a pause transition and execute the code you want in its
// onFinished handler:
PauseTransition pause = new PauseTransition(Duration.seconds(5));
pause.setOnFinished(event -> {
myService.cancel();
System.out.println("After calling cancel: "+myService.getState());
System.out.println("This command must be called after `Service: END`");
Platform.exit();
});
pause.play();
}
public static void main(String[] args) {
launch(args);
}
}
We have a servlet as follows:
public class CacheRefresher extends HttpServlet {
private static final long START_TIMEOUT = 120*1000;
public void init(ServletConfig servletConfig) throws ServletException {
super.init(servletConfig);
new Thread(new Worker()).start();
}
private class Worker implements Runnable {
public Worker() { }
public void run() {
try {
Thread.sleep(START_TIMEOUT);
} catch (InterruptedException e) {
}
while(true) {
MyService myService = null;
try {
myService = ServiceFactory.getInstance().getMyService();
myService.doSomething();
} catch (Exception ex){
ex.printStackTrace();
}finally {
ServiceFactory.getInstance().releaseMyService(myService);
}
try {
Thread.sleep(timeout);
} catch (InterruptedException e) {
}
}
}
}
}
Its purpose is to periodically call a service. There will only be a single instance of this Servlet, which will be created on server startup. MyService is an EJB.
How bad is this? I know spawning threads from EJBs is not allowed, but what about the other way around? What will happen on server shutdown?
Conceptualy i dont see a problem with invoking ejb methods from multiple threads (even if you created the threads yourself). For the ejb-container that will be just another client among others.
From your example it looks like the soul purpose of you servlet is to start a bunch of timers. If you can use ejb 3.1, there is java ee standard way to do that.
First a Singleton ejb that launches the timers on startup
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.ejb.Singleton;
import javax.ejb.Startup;
#Singleton
#Startup
public class SingletonBean {
#EJB
LabBean labBean;
#PostConstruct
public void init() {
long interval = 4000;
long initialExpiration = 2000;
labBean.startTimer(initialExpiration, interval, "MyTimer");
}
}
Then a SLSB that handles the timeout:
import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerConfig;
import javax.ejb.TimerService;
#Stateless
public class LabBean {
#Resource
protected TimerService timerService;
#Timeout
public void timeoutHandler(Timer timer) {
String name = timer.getInfo().toString();
System.out.println("Timer name=" + name);
}
public void stopTimer(String name) {
for (Object o : this.timerService.getTimers())
if (((Timer) o).getInfo().toString().startsWith(name)){
((Timer)o).cancel();
}
}
public void startTimer(long initialExpiration, long interval, String name){
stopTimer(name);
TimerConfig config = new TimerConfig();
config.setInfo(name);
config.setPersistent(false);
timerService.createIntervalTimer(initialExpiration, interval, config);
}
}
I have written a Netty server which sends asynchronous messages. The server is working as expected.
I can telnet to the server with a couple of telnet sessions and the asynchronous messages gets written out.
I have written a Netty Client but the client seems to be event driven and not asynchronous. On the server when the client connects; the server writes back to the client "Welcome" and the messages get handled in the client by the messageReceived event, any asynchronous event does not fire any event within the SimpleChannelHandler.
Question: How do I get the Netty client to pick up asynchronous message/events? At the moment it is event driven.
Just to add, the client is the Netty Telnet client.[http://netty.io/docs/stable/xref/org/jboss/netty/example/telnet/package-summary.html]
The Server Code
//---------Server code---------------
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
public class TestServer {
private final ServerBootstrap clientServerBootstrap;
private EchoServerFactory echoServerFactory;
private Channel appChannel;
public TestServer() {
this.clientServerBootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool()));
this.clientServerBootstrap.setOption("child.tcpNoDelay", true);
}
public static void main(String[] args) {
try {
TestServer test = new TestServer();
test.start();
for(int i = 0; i < 100; i++) {
long time = System.currentTimeMillis()+1000;
String data = "setPhase();d(1,1,2.2342,"+time+");";
System.out.println(data);
test.write(data);
Thread.sleep(1000);
}
} catch(Exception ex) {
ex.printStackTrace();
}
}
public void start() {
echoServerFactory = new EchoServerFactory();
clientServerBootstrap.setPipelineFactory(echoServerFactory);
InetSocketAddress isaApp = new InetSocketAddress("127.0.0.1", 9090);
appChannel = clientServerBootstrap.bind(isaApp);
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
public void run() {
stop();
}
}));
}
public void write(String message) throws Exception {
echoServerFactory.write(message);
}
public void stop() {
clientServerBootstrap.releaseExternalResources();
}
}
//---------------Factory----------------------------
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder;
import org.jboss.netty.handler.codec.frame.Delimiters;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;
public class EchoServerFactory implements ChannelPipelineFactory {
EchoServerHandler handler = new EchoServerHandler();
public EchoServerHandler getHandler() {
return handler;
}
public void write(String message) throws Exception {
handler.write(message);
}
public ChannelPipeline getPipeline() throws Exception {
// Create a default pipeline implementation.
ChannelPipeline pipeline = org.jboss.netty.channel.Channels.pipeline();
// Add the text line codec combination first,
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
// and then business logic.
pipeline.addLast("handler", handler);
return pipeline;
}
}
//---------------Handler----------------------------
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ChildChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.jboss.netty.channel.WriteCompletionEvent;
import org.jboss.netty.channel.group.ChannelGroup;
import org.jboss.netty.channel.group.DefaultChannelGroup;
public class EchoServerHandler extends SimpleChannelHandler {
private static final Logger logger = Logger.getLogger(EchoServerHandler.class.getName());
static final ChannelGroup channels = new DefaultChannelGroup();
public void write(String message) throws Exception {
channels.write(message);
}
#Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
Channel channel = e.getChannel();
channels.add(channel);
channel.write("Welcome\n\n");
}
#Override
public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
// Unregister the channel from the global channel list
// so the channel does not receive messages anymore.
//channels.remove(e.getChannel());
}
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
// Send back the received message to the remote peer.
System.out.println("------------------------->"+e.getMessage());
Channel ch = e.getChannel();
ChannelFuture f = ch.write(e.getMessage());
/* f.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) {
Channel ch = future.getChannel();
System.out.println("Completed : "+ch.isOpen());
}
});*/
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
// Close the connection when an exception is raised.
logger.log(
Level.WARNING,
"Unexpected exception from downstream.",
e.getCause());
e.getChannel().close();
}
}
The Client Code
//---------------- Client Code -------------------
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jfree.ui.RefineryUtilities;
/**
* Simplistic telnet client.
*/
public class TelnetClient {
private final String host;
private final int port;
public TelnetClient(String host, int port) {
this.host = host;
this.port = port;
}
public void run() throws IOException {
// Configure the client.
ClientBootstrap bootstrap = new ClientBootstrap(
new NioClientSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool()));
// Configure the pipeline factory.
bootstrap.setPipelineFactory(new TelnetClientPipelineFactory());
bootstrap.setOption("tcpNoDelay", true);
// Start the connection attempt.
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
// Wait until the connection attempt succeeds or fails.
Channel channel = future.awaitUninterruptibly().getChannel();
if (!future.isSuccess()) {
future.getCause().printStackTrace();
bootstrap.releaseExternalResources();
return;
}
// Read commands from the stdin.
ChannelFuture lastWriteFuture = null;
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
for (;;) {
String line = in.readLine();
if (line == null) {
break;
}
// Sends the received line to the server.
lastWriteFuture = channel.write(line + "\r\n");
// If user typed the 'bye' command, wait until the server closes
// the connection.
if (line.toLowerCase().equals("bye")) {
channel.getCloseFuture().awaitUninterruptibly();
break;
}
}
// Wait until all messages are flushed before closing the channel.
if (lastWriteFuture != null) {
lastWriteFuture.awaitUninterruptibly();
}
// Close the connection. Make sure the close operation ends because
// all I/O operations are asynchronous in Netty.
channel.close().awaitUninterruptibly();
// Shut down all thread pools to exit.
bootstrap.releaseExternalResources();
}
public static void main(String[] args) throws Exception {
try {
// Parse options.
String host = "127.0.0.1";
int port = 9090;
new TelnetClient(host, port).run();
} catch(Exception ex) {
ex.printStackTrace();
}
}
}
//---------------- Client Factory -------------------
import static org.jboss.netty.channel.Channels.*;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder;
import org.jboss.netty.handler.codec.frame.Delimiters;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;
/**
* Creates a newly configured {#link ChannelPipeline} for a new channel.
*/
public class TelnetClientPipelineFactory implements ChannelPipelineFactory {
public ChannelPipeline getPipeline() throws Exception {
// Create a default pipeline implementation.
ChannelPipeline pipeline = pipeline();
// Add the text line codec combination first,
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(1118192, Delimiters.lineDelimiter()));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
// and then business logic.
pipeline.addLast("handler", new TelnetClientHandler2());
return pipeline;
}
}
//----------------- Client handler -------------------
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ChildChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
import org.jboss.netty.channel.WriteCompletionEvent;
/**
* Handles a client-side channel.
*/
public class TelnetClientHandler extends SimpleChannelHandler {
private static final Logger logger = Logger.getLogger(TelnetClientHandler.class.getName());
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
System.out.println("messageReceived");
String message = (String) e.getMessage();
parseMessage(message);
}
private void parseMessage(String message) {
try {
System.out.println("Messatge --> "+message);
} catch (Exception ex) {
ex.printStackTrace();
}
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
System.out.println(e.getCause());
logger.log(Level.WARNING,"Unexpected exception from downstream.", e.getCause());
e.getChannel().close();
}
}
Since you are using delimiter based frame decoder in the Netty Client App, it expects the delimiter at end of each message, but it looks like the server is not sending message with delimiter.
String data = "setPhase();d(1,1,2.2342,"+time+");";
System.out.println(data);
test.write(data);
after above messages are sent, frame decoder is keep waiting even after it received many messages. It works in telnet because, telnet session expects one character at a time. You have done it correctly only for the first message.
channel.write("Welcome\n\n");