Giter VIP home page Giter VIP logo

wasync's Introduction

wAsync: A WebSockets/HTTP Client Library for Asynchronous Communication

wAsync is a Java based library allowing asynchronous communication with any WebServer supporting the WebSocket or Http Protocol. wAsync can be used with Node.js, Android, Atmosphere or any WebSocket Framework. To get started, read this super simple Tutorial or read the FAQ

You can browse the javadoc or browse our samples.

You can download the jar or use Maven

          <dependency>
              <groupId>org.atmosphere</groupId>
              <artifactId>wasync</artifactId>
              <version>3.0.2</version>
          </dependency>

As simple as

        Client client = ClientFactory.getDefault().newClient();

        RequestBuilder request = client.newRequestBuilder()
                .method(Request.METHOD.GET)
                .uri("http://async-io.org")
                .encoder(new Encoder<String, Reader>() {        // Stream the request body
                    @Override
                    public Reader encode(String s) {
                        return new StringReader(s);
                    }
                })
                .decoder(new Decoder<String, Reader>() {
                    @Override
                    public Reader decode(Event type, String s) {
                        return new StringReader(s);
                    }
                })
                .transport(Request.TRANSPORT.WEBSOCKET)                        // Try WebSocket
                .transport(Request.TRANSPORT.LONG_POLLING);                    // Fallback to Long-Polling

        Socket socket = client.create();
        socket.on(new Function<Reader>() {
            @Override
            public void on(Reader r) {
                // Read the response
            }
        }).on(new Function<IOException>() {

            @Override
            public void on(IOException ioe) {
                // Some IOException occurred
            }

        }).open(request.build())
            .fire("echo")
            .fire("bong");

Life cycle of the underlying Socket can easily be implemented as well

           Socket socket = client.create();
           socket.on(Event.CLOSE.name(), new Function<String>() {
               @Override
               public void on(String t) {
               }
           }).on(Event.REOPENED.name(), new Function<String>() {
               @Override
               public void on(String t) {
               }
           }).on(new Function<IOException>() {
               @Override
               public void on(IOException ioe) {
                   ioe.printStackTrace();
               }
           }).on(Event.OPEN.name(), new Function<String>() {
               @Override
               public void on(String t) {
               }
           }).open(request.build());

You can also use the specialized clients. For example, to transparently enable Atmosphere's Protocol

       AtmosphereClient client = ClientFactory.getDefault().newClient(AtmosphereClient.class);

       RequestBuilder request = client.newRequestBuilder()
    		   .method(Request.METHOD.GET)
    		   .uri(targetUrl + "/suspend")
               .trackMessageLength(true)
    		   .transport(Request.TRANSPORT.LONG_POLLING);

or if you want to serialize the fire() method call so events are asynchronously sent in the order the fire method is called

        SerializedClient client = ClientFactory.getDefault().newClient(SerializedClient.class);

        SerializedOptionsBuilder b = client.newOptionsBuilder();
        b.serializedFireStage(new DefaultSerializedFireStage());

        RequestBuilder request = client.newRequestBuilder()
                .method(Request.METHOD.GET)
                .uri(targetUrl + "/suspend")
                .transport(Request.TRANSPORT.WEBSOCKET);

        Socket socket = client.create(b.build());

By default, the FunctionResolver will associate the Decoder's type will be used to invoke the appropriate Function, if defined. For example,

   Decoder<String, POJO> d = new Decoder<String, POJO>() {
             @Override
             public POJO decode(Event type, String s) {
                 if (type.equals(Event.MESSAGE)) {
                    return new POJO(s);
                 } else {
                    return s;
                 }
             }
         }

will be associated to

   Function<String> f = new Function<POJO>() {
             @Override
             public void on(POJO t) {

             }
        }

You can also implement your own FunctionResolver to associate the Function with Decoder

         Socket socket = client.create();
         socket.on("myEvent", new Function<Reader>() { ...}

where myEvent could be read from the response's body.

Want to write an Android Client? See

Build Status

Build Status

[Analytics]

wasync's People

Contributors

bartfaitamas avatar dependabot[bot] avatar jfarcand avatar khernyo avatar pdegol avatar r-bhuvan avatar ratsam avatar ricardojlrufino avatar sakno avatar seamusmac avatar slovdahl avatar super-nimbus avatar thabach avatar vinodsral avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wasync's Issues

Socket status should be updated when a response is received from server

I'm doing a simple test. do a Get (without suspend) and received the response HELLO from the server. When I check the status on the socket, the status is still at INIT.

I was expecting another status like : OPEN or CONNECTED.

here my testcase

package com.jerabi.socketio.core;

import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;

import java.io.IOException;
import java.net.ServerSocket;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

import org.atmosphere.cpr.AtmosphereHandler;
import org.atmosphere.cpr.AtmosphereResource;
import org.atmosphere.cpr.AtmosphereResourceEvent;
import org.atmosphere.nettosphere.Config;
import org.atmosphere.nettosphere.Nettosphere;
import org.atmosphere.wasync.Client;
import org.atmosphere.wasync.ClientFactory;
import org.atmosphere.wasync.Function;
import org.atmosphere.wasync.Request;
import org.atmosphere.wasync.RequestBuilder;
import org.atmosphere.wasync.Socket;
import org.atmosphere.wasync.Socket.STATUS;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class EchoTest {

    public Nettosphere server;
    public String targetUrl;
    public static final Logger logger = LoggerFactory.getLogger(EchoTest.class);
    public int port;

    public int findFreePort() throws IOException {
        ServerSocket socket = null;

        try {
            socket = new ServerSocket(0);

            return socket.getLocalPort();
        } finally {
            if (socket != null) {
                socket.close();
            }
        }
    }

    @After
    public void tearDownGlobal() throws Exception {
        if (server != null && server.isStarted()) {
            server.stop();
        }
    }

    @Before
    public void start() throws IOException {
        port = findFreePort();
        targetUrl = "http://127.0.0.1:" + port;
    }


    @Test
    public void basicHelloTest() throws Exception {
        final CountDownLatch l = new CountDownLatch(1);

        Config config = new Config.Builder()
                .port(port)
                .host("127.0.0.1")
                .resource("/suspend", new AtmosphereHandler() {

                    private final AtomicBoolean b = new AtomicBoolean(false);

                    @Override
                    public void onRequest(AtmosphereResource r) throws IOException {
                        r.getResponse().getWriter().print("HELLO");
                        // at this point, I think Socket should have a STATUS other than INIT when it reads the response in the socket.on(...)
                    }

                    @Override
                    public void onStateChange(AtmosphereResourceEvent r) throws IOException {
                    }

                    @Override
                    public void destroy() {

                    }
                }).build();

        server = new Nettosphere.Builder().config(config).build();
        assertNotNull(server);
        server.start();

        final CountDownLatch latch = new CountDownLatch(1);
        final AtomicReference<String> response = new AtomicReference<String>();
        Client client = ClientFactory.getDefault().newClient();

        RequestBuilder request = client.newRequestBuilder()
                .method(Request.METHOD.GET)
                .uri(targetUrl + "/suspend")
                .transport(Request.TRANSPORT.LONG_POLLING);

        Socket socket = client.create();

        socket.on(new Function<String>() {
            @Override
            public void on(String t) {
// the status should have been updated to something else than INIT
                response.set(t);
                latch.countDown();
            }
        }).on(new Function<Throwable>() {

            @Override
            public void on(Throwable t) {
                t.printStackTrace();
                latch.countDown();
            }

        }).open(request.build());

        latch.await();


        logger.error("SOCKET STATUS [{}]", socket.status());

        assertEquals(response.get(), "HELLO");
        assertEquals(socket.status(), STATUS.OPEN);

        socket.close();

        assertEquals(socket.status(), STATUS.CLOSE);
    }
}

Should have SocketChain to queue sockets

here the usecase :

for implementing Socket.io client, I could use a SocketChain. I need to create a get to received the available transport list, after that, another get connection to create the session on the server, and a third connection to create the suspended connection.

3 steps to login into the server.

Could be useful to be able to chain the socket.

SocketChain sc= new SocketChain();
sc.chain(new TransportSocketWrapper(client, url..)).chain(new CreateSessionSocketWrapper(client,url).chain(LoginSocketWrapper(client, url));

chain.start();

each SocketWrapper (wrap a Socket and custom function to process the request/response).

The SocketChain should have a "Session" to pass response between SocketWrapper.

Like when the TransportSocketWrapper received the transport list, it put in the session and return CONTINUE to the SocketChain (SC), and the SC call the next SocketWrapper (SW)... The second SW will check in the session for the transportList and use it to connect to the server with the best transport, and when the SessionID is return by the server, it put it in the session and return CONTINUE.... so on.

the SuspendWrapper will open a suspend connection with reconnect enabled (configurable). Just need to be able to add Listener into the SW to be able to be acknoledged when I connection is reconnected.

Client doesn't reconnect after a message is received

Hi!
I'm using the wasync client as follow:

Client client = ClientFactory.getDefault().newClient();
final Options options = new Options.OptionsBuilder().reconnect(true).build();

RequestBuilder request = client.newRequestBuilder().method(Request.METHOD.GET).uri(finalEndpoint).transport(TRANSPORT.WEBSOCKET)
                    .transport(TRANSPORT.LONG_POLLING)
            .header(HeaderConfig.X_ATMOSPHERE_TRANSPORT, HeaderConfig.LONG_POLLING_TRANSPORT);

        Socket socket = client.create(options);

        try {
            socket.on(Function.MESSAGE.message.toString(), new MyFunction()).open(request.build());


        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

I've the following issue: after the first message is received, the java client doesn't perform the re-connection.

Direct disconnect and reconnect with Streaming and Long Polling

I currently use RC5 to try to connect to http://demo.openhab.org:8080 on an Android device. A WebSocket connection doesn't seem to work at all. It is established but nothing is received (could be a server problem).
However if I fall back to Streaming or Long Polling the connection is openend, some data is received (actually a whole lot of XML), and the the connection is immediately closed. When I set reconnect to true in the options the connection is openend again and I receive the XML stream again. The problem is all this happens as fast as the device is.
In my understanding also the fall backs shouldn't close the connection immediatley, but hold open and listen for pushes from the server.
You can find my implementation here https://github.com/dereulenspiegel/HABSweetie
This app tries to connect to an Atmosphere enabled server (openHAB) and listen for push updates.

Streaming Transport Requirements

What do I have to do on server-side to make use of wasync STREAMING transport?

I am using @AtmosphereHandlerService and AtmosphereHandler on JBoss 7.1.1?

Authentication

it seems wasync does not support server authentication

however the underlying AsyncHttpClient implementation fully supports authentication

please include a Realm parameter in Socket.open org.atmosphere.wasync.Socket and pass it to invocations of internal AsyncHttpClient object (prepare...setRealm.execute)

client cannot receive message broadcastered

I'm using wasync to connect to atmosphere handler and tried to catch the message the handler broadcastered and do some operations.

But the socket on callback will never be triggered when I broadcastered message from atmosphere handler.
So did I miss anything?

The java client is following:

Client client = ClientFactory.getDefault().newClient();
request = client.newRequestBuilder().method(Request.METHOD.GET).uri(targetUrl)
            .encoder(new Encoder() {
                // Stream the request body
                @Override
                public Reader encode(String s) {
                    return new StringReader(s);
                }
                }).decoder(new Decoder() {
                @Override
                public Operation decode(Event e, String s) {
                    try {
                        if (e.equals(Event.MESSAGE)) {
                            return mapper.readValue(s, Operation.class);
                        }
                        return null;
                    } catch (IOException ioe) {
                                return null;
                    }
                    }
                }).transport(Request.TRANSPORT.WEBSOCKET) // Try WebSocket
                .transport(Request.TRANSPORT.LONG_POLLING); // Fallback to
                                                                // Long-Polling

    socket = client.create();
            
    socket.on(Event.MESSAGE.name(), new Function() {
        @Override
        public void on(Operation operation) {
            // do according operation
            }
        }).on(new Function() {
        @Override
            public void on(IOException ioe) {
               if (ConnectException.class.isAssignableFrom(ioe.getCause().getClass())) {
                handleConnError();
            }
                }
            }).on(new Function() {
                @Override
                public void on(Integer statusCode) {
                    if (statusCode.intValue() == 404) {
                        handleConnError();
                    }
                }
            }).open(request.build(), MAX_TIMEOUT, TimeUnit.SECONDS);

And the AtmosphereHandler is briefed like:

@AtmosphereHandlerService(path = "/mypath", interceptors = { AtmosphereResourceLifecycleInterceptor.class,
        TrackMessageSizeInterceptor.class })
public class MyAtmosphereHandler extends AbstractReflectorAtmosphereHandler {

    private final static ObjectMapper mapper = new ObjectMapper();
    @Override
    public void onRequest(AtmosphereResource r) throws IOException {
        Broadcaster broadcaster = BroadcasterFactory.getDefault().lookup("JavaClientFixedBroadcaster", true);
        r.setBroadcaster(broadcaster);
        r.suspend();
        broadcaster.broadcast(mapper.writeValueAsString(new Operation("test")));
    }
}

I cannot get sample code to work

I am trying to create a java client to connect via websocket to a web service running on Tomcat implemented with the Atmosphere framework and Spring. I am running on Ubuntu. I downloaded the async-http-client jar from com.ning in maven.

I copied the sample code from the readme:

Client client = ClientFactory.getDefault().newClient();

    RequestBuilder request = client.newRequestBuilder()
        .method(Request.METHOD.GET)
        .uri("http://vcb2.hp.com/websockets/")
        .encoder(new Encoder<String, Reader>() {        // Stream the request body
            @Override
            public Reader encode(String s) {
                return new StringReader(s);
            }
        })
        .decoder(new Decoder<String, Reader>() {
            @Override
            public Reader decode(String s) {
                return new StringReader(s);
            }
        })
        .transport(Request.TRANSPORT.WEBSOCKET)                        // Try WebSocket
        .transport(Request.TRANSPORT.LONG_POLLING)
        .header("ContentType","application/json");                   

    Socket socket = client.create(options);
    socket.on(new Function<Reader>() {
        @Override
        public void on(Reader r) {
            // Read the response
            char[] message = new char[100];
            try {
                r.read(message);
                logger.fine("Message received: " + message);
            }
            catch (IOException e) {
                logger.severe(e.getMessage());
                e.printStackTrace();
            }

        }
    }).on(new Function<IOException>() {

        @Override
        public void on(IOException e) {
            // Some IOException occurred
            logger.severe(e.getMessage());
            e.printStackTrace();
        }

    }).open(request.build())
        .fire("echo")
        .fire("bong");

Fails in the socket.on:

SEVERE: unknown protocol: ws
java.net.MalformedURLException: unknown protocol: ws
at java.net.URL.(URL.java:590)
at java.net.URL.(URL.java:480)
at java.net.URL.(URL.java:429)
at java.net.URI.toURL(URI.java:1096)
at com.ning.http.client.providers.jdk.JDKAsyncHttpProvider.createUrlConnection(JDKAsyncHttpProvider.java:180)
at com.ning.http.client.providers.jdk.JDKAsyncHttpProvider.execute(JDKAsyncHttpProvider.java:145)
at com.ning.http.client.providers.jdk.JDKAsyncHttpProvider.execute(JDKAsyncHttpProvider.java:121)
at com.ning.http.client.AsyncHttpClient.executeRequest(AsyncHttpClient.java:512)
at com.ning.http.client.AsyncHttpClient$BoundRequestBuilder.execute(AsyncHttpClient.java:230)
at org.atmosphere.wasync.impl.DefaultSocket.connect(DefaultSocket.java:110)
at org.atmosphere.wasync.impl.DefaultSocket.open(DefaultSocket.java:94)
at vcbconnector.VCBConnector.run(VCBConnector.java:59)
at vcbconnector.VCBConnector.main(VCBConnector.java:147)

Atmosphere mapper exception

hello,

when annotating an org.atmosphere.handler.OnMessage subclass with
@AtmosphereHandlerService(
path=
"/something/somethingelse/etc"
)
it gets mapped to context-path with name equals the name of the class

here is the related output from console
04:26:58,403 INFO [org.atmosphere.cpr.AtmosphereFramework](ServerService Thread Pool -- 140) Installed AtmosphereHandler {class name} mapped to context-path: {class name}

is this OK?
shouldn't it be mapping to "/something/somethingelse/etc" as defined in related annotation?

I feel this has to do something with the error that is produced on Atmosphere 1.1.0.RC2 server-side under JBoss 7.2.0 when trying to connect to Atmosphere endpoint with wasync-1.0.0.RC3

here is the server-side error

04:27:20,043 ERROR stderr java.lang.StringIndexOutOfBoundsException: String index out of range: -1

04:27:20,043 ERROR stderr at java.lang.String.substring(String.java:1911)

04:27:20,044 ERROR stderr at org.atmosphere.util.DefaultEndpointMapper.map(DefaultEndpointMapper.java:134)

04:27:20,044 ERROR stderr at org.atmosphere.util.DefaultEndpointMapper.map(DefaultEndpointMapper.java:106)

04:27:20,044 ERROR stderr at org.atmosphere.cpr.AsynchronousProcessor.action(AsynchronousProcessor.java:204)

04:27:20,045 ERROR stderr at org.atmosphere.cpr.AsynchronousProcessor.suspended(AsynchronousProcessor.java:164)

04:27:20,045 ERROR stderr at org.atmosphere.container.JBossWebCometSupport.service(JBossWebCometSupport.java:112)

04:27:20,045 ERROR stderr at org.atmosphere.cpr.AtmosphereFramework.doCometSupport(AtmosphereFramework.java:1485)

04:27:20,045 ERROR stderr at org.atmosphere.cpr.AtmosphereServlet.event(AtmosphereServlet.java:422)

04:27:20,046 ERROR stderr at org.apache.catalina.core.ApplicationFilterChain.internalDoFilterEvent(ApplicationFilterChain.java:458)

04:27:20,046 ERROR stderr at org.apache.catalina.core.ApplicationFilterChain.doFilterEvent(ApplicationFilterChain.java:364)

04:27:20,046 ERROR stderr at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:228)

04:27:20,046 ERROR stderr at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:149)

04:27:20,047 ERROR stderr at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:389)

04:27:20,047 ERROR stderr at org.jboss.as.jpa.interceptor.WebNonTxEmCloserValve.invoke(WebNonTxEmCloserValve.java:50)

04:27:20,047 ERROR stderr at org.jboss.as.jpa.interceptor.WebNonTxEmCloserValve.invoke(WebNonTxEmCloserValve.java:50)

04:27:20,047 ERROR stderr at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:169)

04:27:20,048 ERROR stderr at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:145)

04:27:20,048 ERROR stderr at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:97)

04:27:20,048 ERROR stderr at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:102)

04:27:20,048 ERROR stderr at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:336)

04:27:20,048 ERROR stderr at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:880)

04:27:20,049 ERROR stderr at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:607)

04:27:20,049 ERROR stderr at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:2036)

04:27:20,049 ERROR stderr at java.lang.Thread.run(Thread.java:722)

here is the client-side code

    AsyncHttpClient runtime =
        new AsyncHttpClient(
            new AsyncHttpClientConfig.Builder().
                setRealm(
                    realm
                    ).
                build()
            );
    SerializedClient client =
        ClientFactory.getDefault().newClient(
            SerializedClient.class
            );
    SerializedOptionsBuilder socketOptionsBuilder =
        client.newOptionsBuilder();
    socketOptionsBuilder.serializedFireStage(
        new DefaultSerializedFireStage()
        );
    socketOptionsBuilder.runtime(
        runtime
        );
    AtmosphereRequestBuilder requestBuilder =
        client.newRequestBuilder();
    requestBuilder.uri(
        "http://{host}:{port}/something/somethingelse/etc"
        );
    requestBuilder.method(
        Request.METHOD.GET
        );
    //requestBuilder.transport(
    //  Request.TRANSPORT.STREAMING
    //  );
    requestBuilder.transport(
        Request.TRANSPORT.LONG_POLLING
        );
    AtmosphereRequest request =
        requestBuilder.build();
    SerializedOptions socketOptions =
        socketOptionsBuilder.build();
    Socket socket =
        client.create(
            socketOptions
            );
    socket.open(
        request
        );

any ideas?

What will happen to socket client when server is forcibly shut down?

When testing, I tried to shut down the remote server and see if the socket client will detect this so I can take some steps. But I cannot receive CLOSE message when the server is forcibly shut down.
I got log in client side:

FINE: Unexpected I/O exception on channel [id: 0xd7e759c5, /127.0.0.1:52918 => localhost/127.0.0.1:8443]
java.io.IOException: An existing connection was forcibly closed by the remote host
    at sun.nio.ch.SocketDispatcher.read0(Native Method)
    at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:25)
    at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:198)
    at sun.nio.ch.IOUtil.read(IOUtil.java:166)
    at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:245)
    at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:64)
    at org.jboss.netty.channel.socket.nio.AbstractNioWorker.process(AbstractNioWorker.java:107)
    at org.jboss.netty.channel.socket.nio.AbstractNioSelector.run(AbstractNioSelector.java:312)
    at org.jboss.netty.channel.socket.nio.AbstractNioWorker.run(AbstractNioWorker.java:88)
    at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:178)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)

Test case:

 @Test
    public void shutdownServerTest() throws Exception {
        Config config = new Config.Builder()
                .port(port)
                .host("127.0.0.1")
                .resource("/suspend", new AtmosphereHandler() {

                    private final AtomicBoolean b = new AtomicBoolean(false);

                    @Override
                    public void onRequest(AtmosphereResource r) throws IOException {
                        if (!b.getAndSet(true)) {
                            r.suspend(-1);
                        } else {
                            r.getBroadcaster().broadcast(RESUME);
                        }
                    }

                    @Override
                    public void onStateChange(AtmosphereResourceEvent r) throws IOException {
                        if (!r.isResuming() || !r.isCancelled()) {
                            r.getResource().getResponse().getWriter().print(r.getMessage());
                            r.getResource().resume();
                        }
                    }

                    @Override
                    public void destroy() {

                    }
                }).build();

        server = new Nettosphere.Builder().config(config).build();
        assertNotNull(server);
        server.start();

        final CountDownLatch latch = new CountDownLatch(1);
        final AtomicReference<String> response = new AtomicReference<String>();
        Client client = ClientFactory.getDefault().newClient();

        RequestBuilder request = client.newRequestBuilder()
                .method(Request.METHOD.GET)
                .uri(targetUrl + "/suspend")
                .transport(transport());

        Socket socket = client.create(client.newOptionsBuilder().reconnect(false).build());
        socket.on(Event.CLOSE.name(), new Function<String>() {
            @Override
            public void on(String t) {
                <strong>//Can I receive close message when server is stopped?</strong>
                logger.info("Function invoked {}", t);
                response.set(t);
                latch.countDown();
            }
        }).on(new Function<Throwable>() {

            @Override
            public void on(Throwable t) {
                t.printStackTrace();
                latch.countDown();
            }

        }).open(request.build()).fire("PING");

        latch.await(10, TimeUnit.SECONDS);

        server.stop();

        latch.await(10, TimeUnit.SECONDS);
        socket.close();

        assertEquals(socket.status(), Socket.STATUS.CLOSE);<strong>//or ERROR?</strong>
    }

NettyWebSocket#channel closed but transportInUse status is still open

I used atmosphere wasync connected with atmosphere handler. I didn't know when the Channel is closed, just after the system runs some time(several minutes), I used the socket to fire some message to atmosphere handler, when debugging the transportInUse status is open but the underlying channel is already closed and the atmosphere handler didn't receive any request meanwhile.

STREAMING Transport behaves as LONG_POLLING

hello,

using wAsync 1.0.0-RC3 STREAMING-only transport with Atmosphere 1.1.0.RC2 endpoint on JBoss 7.2.0 (APR enabled)

here is the client-side code

    AsyncHttpClient runtime =
        new AsyncHttpClient(
            new NettyAsyncHttpProvider(
                new AsyncHttpClientConfig.Builder().
                    setRealm(
                        this.realm
                        ).
                    build()
                    )
            );
    SerializedClient client =
        ClientFactory.getDefault().newClient(
            SerializedClient.class
            );
    SerializedOptionsBuilder socketOptionsBuilder =
        client.newOptionsBuilder();
    socketOptionsBuilder.serializedFireStage(
        new DefaultSerializedFireStage()
        );
    socketOptionsBuilder.runtime(
        runtime
        );
    AtmosphereRequestBuilder requestBuilder =
        client.newRequestBuilder();
    requestBuilder.uri(
        "http://localhost:8080/financePlatform/async/handler/main"
        );
    requestBuilder.method(
        Request.METHOD.GET
        );
    requestBuilder.transport(
        Request.TRANSPORT.STREAMING
        );
    requestBuilder.trackMessageLength(
        true
        );
    AtmosphereRequest request =
        requestBuilder.build();
    SerializedOptions socketOptions =
        socketOptionsBuilder.build();
    Socket socket =
        client.create(
            socketOptions
            );
    socket.on(
        new Function<String>() {
                @Override
                public void on(
                    String text
                ) {
                    System.out.println(
                        "Received: "+text
                        );
                }
            }
        );
    socket.on(
        new Function<Throwable>() {
                @Override
                public void on(
                    Throwable cause
                ) {
                    System.out.println(
                        "Exception occured"+"\n"+
                        cause.getMessage()
                        );
                }
            }
        );
    socket.open(
        request
        );
    while(
        true
    ) {
        //String message =
        //  "HELLO";
        //socket.fire(
        //  message
        //  );
        //System.out.println(
        //  "Sent: "+message
        //  );
        Thread.sleep(
            5000
            );
    }

here is the related Atmosphere servlet configuration under WEB-INF/web.xml

<servlet>
    <description>AtmosphereServlet</description>
    <servlet-name>AtmosphereServlet</servlet-name>
    <servlet-class>org.atmosphere.cpr.AtmosphereServlet</servlet-class>
    <!-- Jersey base package of your resources -->
    <init-param>
        <param-name>com.sun.jersey.config.property.packages</param-name>
        <param-value></param-value>
    </init-param>
    <!-- Enable Jersey's JSON mapping feature -->
    <init-param>
        <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
        <param-value>false</param-value>
    </init-param>
    <init-param>
        <param-name>org.atmosphere.useNative</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
        <param-name>org.atmosphere.useBlocking</param-name>
        <param-value>false</param-value>
    </init-param>
    <init-param>
        <param-name>org.atmosphere.useWebSocket</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
        <param-name>org.atmosphere.useWebSocketAndServlet3</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
        <param-name>org.atmosphere.useStream</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
        <param-name>org.atmosphere.cpr.broadcasterCacheClass</param-name>
        <param-value>org.atmosphere.cache.UUIDBroadcasterCache</param-value>
    </init-param>
    <init-param>
        <param-name>org.atmosphere.cpr.broadcaster.shareableThreadPool</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
        <param-name>org.atmosphere.cpr.broadcaster.maxProcessingThreads</param-name>
        <param-value>10</param-value>
    </init-param>
    <init-param>
        <param-name>org.atmosphere.cpr.broadcaster.maxAsyncWriteThreads</param-name>
        <param-value>10</param-value>
    </init-param>
    <init-param>
        <param-name>org.atmosphere.cpr.asyncSupport</param-name>
        <param-value>org.atmosphere.container.JBossWebCometSupport</param-value>
    </init-param>
    <init-param>
        <param-name>org.atmosphere.cpr.sessionSupport</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
        <param-name>org.atmosphere.cpr.allowQueryStreamAsPostOrGet</param-name>
        <param-value>true</param-value>
    </init-param>
    <async-supported>true</async-supported>
    <load-on-startup>0</load-on-startup>
</servlet>

there is an AtmosphereHandler mapped to path /async/handler/main
which generates every second a string message to connected client
using
AtmosphereResource.getResponse().write(
message
);

however,
the generated message is only received when the org.atmosphere.wasync.Socket.fire() method is called on client-side (in remarks under client-side code above)
the message is properly sent to the server and the server successfully produces a response
the client successfully receives the response
and with it all the generated messages
this is behavior of LONG_POLLING

here is a copy from client-side console output

03:02:00.385 [main] DEBUG c.n.h.c.p.n.NettyAsyncHttpProvider - Number of application's worker threads is 16
03:02:00.505 [main] DEBUG c.n.h.c.p.n.NettyAsyncHttpProvider -
Non cached request
DefaultHttpRequest(chunked: false)
GET /financePlatform/async/handler/main?X-Atmosphere-Transport=STREAMING&X-Atmosphere-Framework=1.0&X-atmo-protocol=true&X-Atmosphere-tracking-id=0&X-Cache-Date=0 HTTP/1.1
Host: localhost:8080
Authorization: Basic dGVzdDE6dGVzdDE=
Connection: keep-alive
Accept: /
User-Agent: NING/1.0

using Channel
[id: 0x3c97f6dd]

03:02:00.517 [New I/O worker #1] DEBUG c.n.h.c.p.n.NettyAsyncHttpProvider -

Request DefaultHttpRequest(chunked: false)
GET /financePlatform/async/handler/main?X-Atmosphere-Transport=STREAMING&X-Atmosphere-Framework=1.0&X-atmo-protocol=true&X-Atmosphere-tracking-id=0&X-Cache-Date=0 HTTP/1.1
Host: localhost:8080
Authorization: Basic dGVzdDE6dGVzdDE=
Connection: keep-alive
Accept: /
User-Agent: NING/1.0

Response DefaultHttpResponse(chunked: true)
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=5OxLKv+2LuY8vQbh9G9GWg8a; Path=/financePlatform
X-Atmosphere-tracking-id: 101b33a8-b935-45c2-882d-106cf9a5ad0e
Expires: -1
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Content-Type: text/plain
Transfer-Encoding: chunked
Date: Fri, 24 May 2013 00:02:00 GMT

03:02:00.521 [New I/O worker #1] DEBUG o.a.wasync.transport.TransportsUtil - OPEN .on OPEN
Received: OPEN
After socket.open

it seems that there is only one connection to the server and it is a permanent one
this is quite correct for STREAMING transport
however the generated messages from the server-side are not received unless something is requested from the server
this is not STREAMING behavior, it is LONG_POLLING behavior
moreover the server request contains X-Atmosphere-Transport=STREAMING which means it requests STREAMING support from server
it seems everything is in order, still the behavior is not as expected

what am I doing wrong?

please assist

AsyncHttpClient times out on SSE connection

I am using wasync library to create an atmosphere client that connects to an atmosphere server in order to receive Server Sent Events and so I need the connection to stay open. I am using an AsyncHttpClient to provide the credentials. The program connects to the server okay and any events the server sends are picked up by the client.
However, after 60 seconds, the AsyncHttpClient times out with the message 'No response received'

java.util.concurrent.TimeoutException: No response received after 60000
    at com.ning.http.client.providers.netty.NettyAsyncHttpProvider$ReaperFuture.run(NettyAsyncHttpProvider.java:1767)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
    at java.util.concurrent.FutureTask$Sync.innerRunAndReset(FutureTask.java:351)
    at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:178)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:722)

The code I am using is below. Have I missed something out from the configuration of either the AsyncHttpClient client or the AtmosphereClient client that would cause this to happen ?

        Realm.RealmBuilder realmbuilder = new Realm.RealmBuilder();
        realmbuilder.setPrincipal(user);
        realmbuilder.setPassword(password);
        realmbuilder.setUsePreemptiveAuth(true);
        realmbuilder.setScheme(Realm.AuthScheme.BASIC);
        Realm realm = realmbuilder.build();

        AsyncHttpClientConfig.Builder ahccBuilder = new AsyncHttpClientConfig.Builder();
        ahccBuilder.setRealm(realm);

        AsyncHttpClient ahClient = new AsyncHttpClient(ahccBuilder.build());

        AtmosphereClient atmosClient = ClientFactory.getDefault().newClient(AtmosphereClient.class);

        AtmosphereRequest.AtmosphereRequestBuilder requestbuilder = atmosClient.newRequestBuilder();
        requestbuilder.method(Request.METHOD.GET);
        requestbuilder.uri(url);
        requestbuilder.transport(Request.TRANSPORT.SSE);

        Request request = requestbuilder.build();

        DefaultOptionsBuilder optionsBuilder = atmosClient.newOptionsBuilder();
        DefaultOptions options = optionsBuilder.build();
        options.runtime(ahClient);

        Socket socket = atmosClient.create(options);
        socket.on(new Function<TimeoutException>()
        {
            @Override
            public void on(final TimeoutException t)
            {
                t.printStackTrace();
            }

        }).on(Event.CLOSE, new Function<String>()
        {
            @Override
            public void on(final String t)
            {
                System.out.println("Connection closed");
            }
        }).on(Event.HEADERS, new Function<String>()
        {
            @Override
            public void on(final String t)
            {
                System.out.println("Headers: " + t);
            }
        }).on(Event.MESSAGE, new Function<String>()
        {
            @Override
            public void on(final String t)
            {
                System.out.println("Message: " + t);
            }
        }).on(Event.OPEN, new Function<String>()
        {
            @Override
            public void on(final String t)
            {
                System.out.println("Open");
            }
        }).on(Event.TRANSPORT, new Function<String>()
        {
            @Override
            public void on(final String t)
            {
                System.out.println("Transport: " + t);
            }
        });

        socket.open(request);

Headers Event message type is Event.MESSAGE instead of Event.HEADERS

The following code shows filtration needed in order to remove headers that sneak up as messages. The root cause is that StreamTransport#onHeadersReceived calls the wrong TransportsUtil.invokeFunction() method overload (should pass Event.HEADERS as first args)

socket.on(Event.MESSAGE.name(), new Function<Object>() {
            @Override
            public void on(Object message) {
                if (message != null &&
                    listener.getMessageClass().isAssignableFrom(message.getClass())) {
                    listener.onMessage(uri, (T)message);
                }
            }
        })

wasync/chat example not working

Running Chat.java against NettosphereChat.java in the Chat example gives the following exception (maybe related to decoders refactoring?) used to work great against RC3.
(when disabling trackMessageLength it's possible to overcomde this exception, but it causes other issues)

10:40:09.955 [main] DEBUG c.n.h.c.p.n.NettyAsyncHttpProvider - Number of application's worker threads is 8
10:40:10.107 [main] DEBUG c.n.h.c.p.n.NettyAsyncHttpProvider - 
Non cached request 
DefaultHttpRequest(chunked: false)
GET /chat?X-Atmosphere-Transport=websocket&X-Atmosphere-Framework=1.1.0&X-atmo-protocol=true&X-Atmosphere-tracking-id=0&X-Cache-Date=0 HTTP/1.1
Upgrade: WebSocket
Connection: Upgrade
Origin: http://127.0.0.1:8080
Sec-WebSocket-Key: P8/yUxt1mHLt75kB29bVHw==
Sec-WebSocket-Version: 13
Host: 127.0.0.1:8080
Accept: */*
User-Agent: wAsync/1.0

using Channel 
[id: 0x95a1c8ba, /127.0.0.1:61701 => /127.0.0.1:8080]

10:40:10.199 [New I/O worker #1] DEBUG c.n.h.c.p.n.NettyAsyncHttpProvider - Unexpected I/O exception on channel [id: 0x95a1c8ba, /127.0.0.1:61701 => /127.0.0.1:8080]
java.lang.ClassCastException: null
    at java.lang.Class.cast(Class.java:2990) ~[na:1.6.0_34]
    at org.atmosphere.wasync.transport.TransportsUtil.matchDecoder(TransportsUtil.java:134) ~[wasync-1.0.0-SNAPSHOT.jar:na]
    at org.atmosphere.wasync.transport.TransportsUtil.invokeFunction(TransportsUtil.java:57) ~[wasync-1.0.0-SNAPSHOT.jar:na]
    at org.atmosphere.wasync.transport.WebSocketTransport$2.onOpen(WebSocketTransport.java:219) ~[wasync-1.0.0-SNAPSHOT.jar:na]
    at org.atmosphere.wasync.transport.WebSocketTransport.onSuccess(WebSocketTransport.java:251) ~[wasync-1.0.0-SNAPSHOT.jar:na]
    at com.ning.http.client.providers.netty.NettyAsyncHttpProvider$WebSocketProtocol.handle(NettyAsyncHttpProvider.java:2329) ~[async-http-client-1.7.17.jar:na]
    at com.ning.http.client.providers.netty.NettyAsyncHttpProvider.messageReceived(NettyAsyncHttpProvider.java:1158) ~[async-http-client-1.7.17.jar:na]
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:296) ~[netty-3.6.3.Final.jar:na]
    at org.jboss.netty.handler.codec.frame.FrameDecoder.unfoldAndFireMessageReceived(FrameDecoder.java:459) ~[netty-3.6.3.Final.jar:na]
    at org.jboss.netty.handler.codec.replay.ReplayingDecoder.callDecode(ReplayingDecoder.java:536) ~[netty-3.6.3.Final.jar:na]
    at org.jboss.netty.handler.codec.replay.ReplayingDecoder.messageReceived(ReplayingDecoder.java:435) ~[netty-3.6.3.Final.jar:na]
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:268) ~[netty-3.6.3.Final.jar:na]
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:255) ~[netty-3.6.3.Final.jar:na]
    at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:88) ~[netty-3.6.3.Final.jar:na]
    at org.jboss.netty.channel.socket.nio.AbstractNioWorker.process(AbstractNioWorker.java:107) ~[netty-3.6.3.Final.jar:na]
    at org.jboss.netty.channel.socket.nio.AbstractNioSelector.run(AbstractNioSelector.java:312) ~[netty-3.6.3.Final.jar:na]
    at org.jboss.netty.channel.socket.nio.AbstractNioWorker.run(AbstractNioWorker.java:88) ~[netty-3.6.3.Final.jar:na]
    at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:178) ~[netty-3.6.3.Final.jar:na]
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) [na:1.6.0_34]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) [na:1.6.0_34]
    at java.lang.Thread.run(Thread.java:662) [na:1.6.0_34]

Relax policy on Socket.fire

Socket.fire status check should only apply WebSocket as this is the only transport using a single connection.

Possible NPE

Reported by one user

java.lang.NullPointerException
    at org.atmosphere.wasync.impl.DefaultFuture.get(DefaultFuture.java:101)
    at org.atmosphere.wasync.impl.DefaultSocket.connect(DefaultSocket.java:189)
    at org.atmosphere.wasync.impl.DefaultSocket.open(DefaultSocket.java:112)
    at org.atmosphere.wasync.impl.DefaultSocket.open(DefaultSocket.java:95)

Socket should support multiple Encoders

Here my usecase.

I want to create a request (GET) that will be suspended using long-polling. I'll received String on that connection.

BUT, I want to send message using POST, but the messages sent and received will be in JSON format.

I think there isn't a way to do that right now the socket.open(requestBuilder.build());

and socket.fire(JSONMESSAGE);

it could be useful, to have a Encoder/Decoder different for Get and Post is specify.

Atmosphere HTTP Headers passed as Query String arguments

Hello,

using wasync-1.0.0.RC3 I observed that the implementation of AtmosphereRequestBuilder is passing what it seems to be atmosphere HTTP headers as query string arguments

I am using the following test code

    AsyncHttpClient runtime =
        new AsyncHttpClient(
            new AsyncHttpClientConfig.Builder().
                setRealm(
                    realm
                    ).
                build()
            );
    SerializedClient client =
        ClientFactory.getDefault().newClient(
            SerializedClient.class
            );
    SerializedOptionsBuilder socketOptionsBuilder =
        client.newOptionsBuilder();
    socketOptionsBuilder.serializedFireStage(
        new DefaultSerializedFireStage()
        );
    socketOptionsBuilder.runtime(
        runtime
        );
    SerializedOptions socketOptions =
        socketOptionsBuilder.build();
    Socket socket =
        client.create(
            socketOptions
            );
    AtmosphereRequestBuilder requestBuilder =
        client.newRequestBuilder();
    requestBuilder.uri(
        "http://localhost:8080/financePlatform/async/handler/main"
        );
    requestBuilder.method(
        Request.METHOD.GET
        );
    requestBuilder.transport(
        Request.TRANSPORT.STREAMING
        );
    requestBuilder.transport(
        Request.TRANSPORT.LONG_POLLING
        );
    requestBuilder.trackMessageLength(
        true
        );
    AtmosphereRequest request =
        requestBuilder.build();
    socket.open(
        request
        );

it is not in the recommended "compact" form but it helped me better understand

the "compact" writing technique is by the way very interesting

here is a snapshot of the console output
observe the generated URL
it contains what it seems to be atmosphere headers as query string parameters

01:44:33.290 [main] DEBUG com.ning.http.client.AsyncHttpClient - Default provider not found com.ning.http.client.providers.netty.NettyAsyncHttpProvider. Using the com.ning.http.client.providers.jdk.JDKAsyncHttpProvider
01:44:33.343 [AsyncHttpClient-Callback] DEBUG c.n.h.c.p.jdk.JDKAsyncHttpProvider -

Request http://localhost:8080/financePlatform/async/handler/main?X-Atmosphere-Transport=STREAMING&X-Atmosphere-Framework=1.0&X-atmo-protocol=true&X-Atmosphere-tracking-id=0&X-Cache-Date=0 GET headers:

Response 500

01:44:35.374 [AsyncHttpClient-Callback] DEBUG c.n.h.c.p.jdk.JDKAsyncHttpProvider -

Request http://localhost:8080/financePlatform/async/handler/main?X-Atmosphere-Transport=polling&X-Atmosphere-Framework=1.0&X-Atmosphere-tracking-id=0&X-Cache-Date=0 POST headers:

Response 500

any ideas?

wasync fails to connect to ChatAtmosphereHandler

I've used following code to send message to ChatAtmosphereHandler. Request doesn't seem to be reaching at all. Do you have any inputs?

// custom Grizzly Client
System.setProperty("wasync.client", "org.mortbay.ijetty.GrizzlyClient");

// create client
final Client client = ClientFactory.getDefault().newClient();

                final RequestBuilder request = client.newRequestBuilder()
                        .method(Request.METHOD.GET)
                        .uri("ws://localhost:8080/socketio-chat/ChatAtmosphereHandler")
                        .encoder(new Encoder<String, Reader>() {        // Stream the request body
                            //@Override
                            public Reader encode(String s) {
                                return new StringReader(s);
                            }
                        })
                        .decoder(new Decoder<String, Reader>() {
                            //@Override
                            public Reader decode(String s) {
                                return new StringReader(s);
                            }
                        })
                        .transport(Request.TRANSPORT.WEBSOCKET);

final Socket socket = client.create();

socket.open(request.build());
socket.fire("PING");

little issue in the Wiki

I'm reading the wiki and I found that in the Decoder section.

If a Decoder has been defined for a Function's Type:

Request request = client.newRequestBuilder()
        .method(Request.METHOD.GET)
        .uri("http://127.0.0.1:8080")
        .decoder(new Decoder<String, Message>() {
            @Override
            public Message decode(Event e, String s) {
                return new Message(s);
            }
        })

socket.on(Event.MESSAGE, new Function<Message>() {
    @Override
    public void on(String message t) {
        ....
    }
});

Should it be this instead ?

@Override
    public void on(Message message t) {
        ....
    }

unavailable server will log ConnectException but cannot be caught

I'm getting the following stack trace when I tried to connect to unreachable server. I hoped that I can catch the ConnectException and take some steps as sometimes target server may down unexpectly, but seems the underlying Netty just output the exception, I'm not pretty sure about this. Any idea? Or maybe I should post this on Netty? Or is there any step can be taken in wAsync side.

java.net.ConnectException: Connection refused: no further information to wss://localhost:8443/webmail-im/addon
        at com.ning.http.client.providers.netty.NettyConnectListener.operationComplete(NettyConnectListener.java:103)
        at org.jboss.netty.channel.DefaultChannelFuture.notifyListener(DefaultChannelFuture.java:427)
        at org.jboss.netty.channel.DefaultChannelFuture.notifyListeners(DefaultChannelFuture.java:418)
        at org.jboss.netty.channel.DefaultChannelFuture.setFailure(DefaultChannelFuture.java:380)
        at org.jboss.netty.channel.socket.nio.NioClientBoss.processSelectedKeys(NioClientBoss.java:108)
        at org.jboss.netty.channel.socket.nio.NioClientBoss.process(NioClientBoss.java:78)
        at org.jboss.netty.channel.socket.nio.AbstractNioSelector.run(AbstractNioSelector.java:312)
        at org.jboss.netty.channel.socket.nio.NioClientBoss.run(NioClientBoss.java:41)
        at org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:108)
        at org.jboss.netty.util.internal.DeadLockProofWorker$1.run(DeadLockProofWorker.java:42)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
        at java.lang.Thread.run(Thread.java:662)
Caused by: java.net.ConnectException: Connection refused: no further information
        at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
        at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:599)
        at org.jboss.netty.channel.socket.nio.NioClientBoss.connect(NioClientBoss.java:148)
        at org.jboss.netty.channel.socket.nio.NioClientBoss.processSelectedKeys(NioClientBoss.java:104)
        ... 8 more

Socket.fire()

Thanks for the previous reply !

I want to know something about the fire() method .... i think i don't understand the concept ... when i invoke fire() for the first time, i send some data and expect a response, if i use fire() again with the same socket it's not doing the same, i have to open the socket again to use fire() succesfully.

Am i doing right ?
Using open() again opens a new socket ?
how can i use the same socket to communicate with my resource ?

I'm connecting to a Jersey Resource .... and JBoss 7.1.1 (Long Polling for Transport)

Your feedback is pretty appreciated

Wasync + GWT-Atmosphere

Hi,

I am a bit stuck with the tutorial from the readme.
Everytime the wasync client opens a request, I receive the following exception:

"[http-apr-8080-exec-2] ERROR org.atmosphere.cpr.AtmosphereFramework - Atmosphere
Framework exception
java.lang.IllegalStateException: Failed to determine responsewriter
at org.atmosphere.gwt.server.impl.GwtAtmosphereResourceImpl.createRespon
seWriter(GwtAtmosphereResourceImpl.java:248).
..."

I had a look at the code in GwtAtmosphereResourceImpl (https://github.com/Atmosphere/atmosphere-extensions/blob/master/gwt/modules/atmosphere-gwt-server/src/main/java/org/atmosphere/gwt/server/impl/GwtAtmosphereResourceImpl.java ):

private GwtResponseWriterImpl createResponseWriter() throws IOException {

    String transport = atmResource.getRequest().getParameter("tr");
    if (transport == null || transport.isEmpty()) {
        throw new IllegalStateException("Failed to determine transport");
    }
    if ("WebSocket".equals(transport)) {
        logger.debug("atmosphere-gwt Using websocket");
        return new WebsocketResponseWriter(this);
    }  // ...
     else {
        throw new IllegalStateException("Failed to determine responsewriter for transport: " + transport);
    }
}

so basically the responseWriter gets determined by evaluating the ?tr=XYZ Query parameter. In my case, I try to initiate a connection using wasync like this:
public static void main(String[] args){
final String uri = "ws://localhost:8080/someUri";
Client client = ClientFactory.getDefault().newClient();

    RequestBuilder request = client.newRequestBuilder()
            .method(Request.METHOD.GET).uri(uri)
            .transport(Request.TRANSPORT.WEBSOCKET);

    Socket socket = client.create();
    socket.on(new Function<Reader>() {
        @Override
        public void on(Reader r) {
            System.out.println("Got something..");
        }
    }).on(new Function<IOException>() {

        @Override
        public void on(IOException t) {
            System.out.println("Exception: " + t.getMessage());
        }

    }).open(request.build());

}
the Request.Transport defines the WebSocket as "WEBSOCKET" and the WebSocketTransport class returns the name of the transport as:

public Request.TRANSPORT name()
{
return Request.TRANSPORT.WEBSOCKET;
}

So what I guess:

The GwtAtmosphereResourceImpl is expecting a parameter like ?tr=WebSocket, but it receives a parameter like ?tr=WEBSOCKET

I hope that I didn't miss something imoportant to add, but until now I had no luck to achieve my goal: Open a WebSocket connection to a GWT-Atmosphere based application.

In addition to that:
I have no idea how to change the default client to a valid implementation of wasync.Client (System.setProperty("wasync.client", ?);) Maybe this is the cause of my problems?

thanks in advance,

Andi

wAsynch 1.0.0 Java Client Doesn't Authenticate With JBoss 7.1.2 Server

Hi JF,

wAsynch 1.0.0.RC3 doesn't authenticate when trying to connect from a standalone Java client via https to a Windows 7 JBoss 7.1.2 server using atmosphere-runtime 1.1.0-SNAPSHOT. When wAsynch tries to connect it logs a message: "WARN org.atmosphere.wasync.impl.AtmosphereRequest - Unable to decode the protocol", followed by a jboss html error page that states, "HTTP Status 401 ... This request requires HTTP authentication". Authentication and message send/receive work perfectly from a browser client, and message send/receive works perfectly from the Java/wAsync client if the auth-constraint element is removed from web.xml

Java Client:


//package com.myco.test

import com.ning.http.client.AsyncHttpClient;
import com.ning.http.client.AsyncHttpClientConfig;
import com.ning.http.client.Realm;

import org.atmosphere.wasync.*;
import org.atmosphere.wasync.impl.AtmosphereClient;

import java.io.*;
import java.util.concurrent.TimeUnit;

public class AtmosphereRemoteClientTest
{
private static final String protocolSeparator = "://";
private static final String pubSub = "/pubsub/";
private static final char colon = ':';
private static final String NL = System.lineSeparator();

private final AtmosphereClient client;
private final Socket socket;

public AtmosphereRemoteClientTest(String pProtocol, String pServer, int pPort, String                     pUser, String pPassword, String pTopic)
{
    StringBuilder sb = (new StringBuilder(pProtocol)).append(protocolSeparator).append(pServer);
    if (pPort > 0)
    {
        sb = sb.append(colon).append(Integer.toString(pPort));
    }
    sb = sb.append(pubSub);
    if (pTopic != null)
    {
        sb = sb.append(pTopic);
    }

    AsyncHttpClientConfig.Builder builder = new AsyncHttpClientConfig.Builder();
    Realm realm = new Realm.RealmBuilder()
            .setPrincipal(pUser)
            .setPassword(pPassword)
            .setUsePreemptiveAuth(true)
            .setScheme(Realm.AuthScheme.BASIC)
            .build();
    builder.setRealm(realm).build();
    AsyncHttpClient ahcClient = new AsyncHttpClient(builder.build());
    client = ClientFactory.getDefault().newClient(AtmosphereClient.class);
    OptionsBuilder optionsBuilder = client.newOptionsBuilder();
    Options options = optionsBuilder.build();
    options.runtime(ahcClient);

    System.out.println(NL + NL + "Using URL: " + sb.toString() + NL);
    try
    {
        RequestBuilder request = client
                .newRequestBuilder()
                .method(Request.METHOD.GET)
                .uri(sb.toString())
                .trackMessageLength(true)
                .transport(Request.TRANSPORT.LONG_POLLING);

        socket = client.create();
        System.out.println(NL + "Socket created." + NL);
        socket.on("message", new Function<String>() {
            @Override
            public void on(String msg) {
                System.out.println("Message Received:" + msg);
            }
        }).on(new Function<Throwable>() {

            @Override
            public void on(Throwable t) {
                System.out.println("Error receiving message" + t.toString());
            }

        }).open(request.build(), 30, TimeUnit.SECONDS);
    }
    catch (IOException e)
    {
        throw new RuntimeException(e);
    }
}

public void sendMessage(String pMessage)
{
    try
    {
        System.out.println("Calling socket.fire");
        socket.fire(pMessage);
    }
    catch (IOException e)
    {
        throw new RuntimeException(e);
    }
}

public void closeSocket()
{
    socket.close();
}

public static void main(String[] args)
{
    if (args == null || args.length < 4)
    {
        System.out.println(NL + "Usage:  <servername> <username> <password> <channelname>" + NL +
                          "Example: myco.com john johnpassword test1" + NL +
                          "Enter message 'quit' to exit.");
        System.exit(0);
    }
    AtmosphereRemoteClientTest atmosphereRemoteClient = new AtmosphereRemoteClientTest("https", args[0], 0, args[1], args[2], args[3]);

    try
    {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        System.out.println(NL + "Enter Message:" + NL);
        String input = br.readLine();
        while (!(input.equals("quit"))) {
            atmosphereRemoteClient.sendMessage(input);
            Thread.sleep(1000);
            System.out.println(NL + "Enter Message:" + NL);
            input = br.readLine();
        }
        System.out.println(NL + "Closing Socket...");
        atmosphereRemoteClient.closeSocket();
        System.exit(0);
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
}

}


Web.xml attached as JPEG file.
web xml

Regards,

John

Socket.open doesn´t return after specified timeout

I was actually traying to set a timeout, when the socket.open have to return in case of no server response. My code is like this:

socket.open(request.build(),5,TimeUnit.SECONDS) (used form android chat sample)

The function does not return after 5 seconds. It returns after ~60 seconds. Is there an issue in this case?

I am using AtmosphereClient with AtmosphereSocket.

Greets,
tobiasom

bug in future.get(x,tu) and TimeoutException

Hi
scenario to reproduce:

Future future = socket.fire(message);
future.get(10,TimeUnit.SECONDS);

do some breakpoint on server side to get timeoutException in SocketRuntime write method

catch (TimeoutException t) {
       logger.trace("AHC Timeout", t);
       rootFuture.timeoutException(t);
 } 

here you set this.te = te; to rootFuture (DefaultFuture)

make next "fire" as good request,
SocketRuntime write method return rootFuture.done();

but in rootFuture.done(); you don't clear this.te field

@Override
    public Socket get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
        time = timeout;
        tu = unit;
        if (!latch.await(timeout, unit) || te != null) {
            throw te == null ? new TimeoutException() : te;
        }
        return socket;
    }

here you check || te != null and throw an old te from prev fire

thanks.

Provide response HTTP Status code. Like 200 OK, 404...

I need to know the http status code when a connection is established.

final Socket socket = client.create(client.newOptionsBuilder().reconnect(false).build());
socket.on(Event.MESSAGE, new Function<String>() {
     .....
}).open(request.build());

I could try to do a login to the server, and the server doesn't return a 200 OK, but a 5xx with a message. I need the know the return code to make a business decision.

(it's for my socket.io-client implementation)

Bug - No suitable transport supported

DefaultSocket.connect removes the transport from transports list

transportInUse = transports.remove(0);

subsequent invocations find transports list empty

consider using transportInUse = transports.get(0); instead

I am using wasync 1.0.0.beta, but master branch has same implementation

first invocation occurs on initial socket.open call
still, there should be no more subsequent invocations of DefaultSocket.connect
it seems that subsequent invocations occur on call to socket.fire
I suspect somewhere inside InternalSocket, creates new request instead of reusing existing one

I am patching locally, please consider changing accordingly or apply better fix, if my observation is correct

Setting atmosphere headers. Exception when reconnecting.

Wasync does not support setting atmosphere specific headers(X-Cache-Date, X-Atmosphere-tracking-id, ...) before reconnecting.

The async-http-client tries to reestablish the connection when client loses network connectivity with the same request that was used to connect previously. This connection must be dropped and reconnected using updated request because the atmosphere specific headers might have changed.

I think atmosphere client must reconnect even in case of exception. The exception must be passed on to client application. And next, if the client application did not threw a RuntimeException, atmosphere client (wasync) must try to reconnect.

The current wasync has a bug which causes IOException with message "No suitable transport supported" even if the transporter is set and available.

I have implemented this feature to set X-Cache-Date, X-Atmosphere-tracking-id and the other issues mentioned above for transports other than websocket. I don't have an option to attach patch files here. I posted the patch file in atmosphere mailing list https://groups.google.com/forum/#!topic/atmosphere-framework/A4my3qdoacc

Network activity on UI thread on Android

When creating a connection in Android activities in onCreate (like shown here http://jfarcand.wordpress.com/2013/04/04/wasync-websockets-with-fallbacks-transports-for-android-node-js-and-atmosphere/) the exception android.os.NetworkOnMainThreadException is thrown. wasync seems to invoke networking methods not on in a background thread.
While it is possible and trivial to do the connection set up in the background the expectation is that an synchronous librarylike wasync does all networking in a background thread.
This would simplify the usage of this library.

socket close called but app still running

If you open a socket connection and call the socket.close() function, seems the socket is not shutdown. To reproduce, just create one socket and open the request in main, after the open operation, call socket.close(). The main will be still running.

Anything I missed? Or besides socket.close(), what shall I do?

CLOSE Event.Type is Event.MESSAGE instead of Event.CLOSE

The following example is of a json decoder, that recieves a message with the text "CLOSE". It seems like the StreamTransport#close calls the wrong TransportsUtil.invokeFunction method overload. This also happens in Long_Polling transport.

        client.newRequestBuilder()
                        .method(Request.METHOD.GET)
                        .uri(uri.toString())
                        .decoder(new Decoder<String, T>() {
                            @Override
                            public T decode(Event type, String data) {

                                data = data.trim();

                                // Padding
                                if (data.length() == 0) {
                                    return null;
                                }

                                if (type.equals(Event.MESSAGE)) {
                                    try {
                                        final T message = mapper.readValue(data, messageClass);
                                        return message;
                                    } catch (IOException e) {
                                        if (data.equals("CLOSE")) {
                                            //Suppress error. Need to report bug
                                            //Event type should be Event.CLOSE
                                            return null;
                                        }
                                        throw new IllegalStateException("Failed to decode " + data,e);
                                    }
                                } else {
                                    return null;
                                }
                            }
                        })
                        .transport(Request.TRANSPORT.LONG_POLLING);

wasync freezes using specialized clients on connecting to non-available server process

Hi Jeanfrancois

When trying to connect to a server (based on Nettosphere) which is not up, the wasync client freezes when using the specialized clients (AtmosphereClient and SerializedClient) instead of throwing an exception. This is rooted in an unconditional future.get() in DefaultSocket::connect() :


} else {
            r.setUrl(request.uri().replace("ws", "http"));
            transportInUse.future(options.runtime().prepareRequest(r.build()).execute((AsyncHandler<String>) transportInUse));

            try {
                if (options.waitBeforeUnlocking() > 0) {
                    logger.info("Waiting {}, allowing the http connection to get handled by the server. To reduce the delay, make sure some bytes get written when the connection is suspendeded on the server", options.waitBeforeUnlocking());
                }
                if (request.queryString().containsKey("X-atmo-protocol")) {
                    f.get();
                } else {
                    f.get(options.waitBeforeUnlocking(), TimeUnit.MILLISECONDS);
                }
            } catch (Throwable t) {
                // Swallow  LOG ME
                logger.trace("", t);
            } finally {
                f.done();
            }
        }
        return this;

I am using the latest wasync Snapshot wasync-1.0.0-20130828.144509-85

I am not sure if putting the timeout on the blocking get() is the cure, so I did not submit a pull request this time around, regards Christian.

Lost in the default socket connect exception handling

I'm using jetty 7.6 on Win7.
After this request #13 was merged, I used in my app, the socket open function returns after timeout expires, but I cannot see any Timeout log or something. It's just nothing.

Then I felt that I should throw out the TimeoutException. But actually the underlying Future in my case wraps the TimeoutException to an ExecutionException, which was caught in the wasync DefaultSocket and returned a new VoidSocket.

If I do not assign this new VoidSocket to the outside caller. The info in the VoidSocket is meaningless. But in the sample it does not assign after a socket open is called. Though only exception happens it bothered I think.

The caught ExecutionException has details about the Timeout, so how about throw out this or wrap to the VoidSocket? Or VoidSocket is just a prototype currently?

Regards.

TrackMessageSizeDecoder: Unable to handle multiple messages received at once

TrackMessageSizeDecoder throws a NumberFormatException on line 70 when the following message is received from Atmosphere:

37|{"message":"ab","time":1373900488808}37|{"message":"ab","time":1373900488808}37|{"message":"ab","time":1373900488810}37|{"message":"ab","time":1373900488812}37|{"message":"ab","time":1373900488825}37|{"message":"ab","time":1373900488827}37|{"message":"ab","time":1373900488829}37|{"message":"ab","time":1373900488830}37|{"message":"ab","time":1373900488831}

The problem seems to be on line 88. The first message is parsed correctly, but after that the messageStartIndex is given a value that is incorrect (too high). When the while loop expression is evaluated after that message.indexOf() returns the index of the third delimiter, not the second one.

Do not reconnect forever with status code 404

I'm using WebSocket transport and downgrading to LongPolling.
I tried to connect with a reachable host but not exist target. Eg: https://localhost/I/do/not/exist. The server responses with a 404 not found. Then it turns to LongPolling and kept reconnecting with repeating 404 response. I tried to handle the status in StreamTransport#onStatusReceived:

@Override
    public STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception {
        
    }

But I'm afraid it's not good, as someone may want to reconnect when 404 happens, but Options seems does not support like maxReconnectTrialTimes(just example),. I cannot make the reconnect not reconnect forever.

Provide more information with response code

StreamTransport#onStatusReceived propagates only the response status code:

TransportsUtil.invokeFunction(MESSAGE, decoders, functions, Integer.class, new Integer(responseStatus.getStatusCode()), STATUS.name(), resolver);

I would like to translate that status into an exception and this requires also the responseStatus message (text).

QoS Info - Retrieve established transport type (Request.TRANSPORT) while sending messages.

Hi,

A minor request. For QoS it makes sence to determin the transport type (i.e. the Request.TRANSPORT enum), which has been employed to send messages. It's utterly important do detect when and in what environments the transportation switches back to the alternative transport way (e.g. from websockets to long-polling). It supports developers and infrastructure guys (e.g. if a transparent proxy doesn't relay the HTTP-UPGRADE command to the next hop). Great to put that into the log files.

Great if one could retrieve this info within the Socket.on(String functionMessage, Function<? extends Object> function) method. i.e. recommend to extend the Socket interface.

If that is a good idea, I could submit an implementation proposal via GIT.

Unable to handle more than 256 simultaneous connections

I'm having problems when creating many connections simultaneously. The limit seems to be at 256 according to http://massapi.com/source/netty-3.2.4.Final/src/main/java/org/jboss/netty/util/internal/SharedResourceMisuseDetector.java.html. I'm using version 1.0.0.RC1.

Apr 08, 2013 11:13:24 AM org.jboss.netty.util.internal.SharedResourceMisuseDetector
WARNING: You are creating too many HashedWheelTimer instances.  HashedWheelTimer is a shared resource that must be reused across the application, so that only a few instances are created.

Are there resources that could/should be shared between different connections in wAsync? At the moment I use something like this when creating new connections:

Client client = ClientFactory.getDefault().newClient();
RequestBuilder request = client.newRequestBuilder();
request.method(Request.METHOD.GET);
request.transport(Request.TRANSPORT.WEBSOCKET);
request.encoder(new Encoder<String, String>() {
    @Override
    public String encode(String s) {
        return s;
    }
});
request.decoder(new Decoder<String, String>() {
    @Override
    public String decode(Transport.EVENT_TYPE evntp, String s) {
        return s;
    }
});

Socket socket = client.create();
socket.on(new Function<Integer>() {
    @Override
    public void on(Integer statusCode) {
        // do something
    }
});
socket.on(new Function<String>() {
    @Override
    public void on(String s) {
        // do something
    }
});
socket.on(new Function<Throwable>() {
    @Override
    public void on(Throwable t) {
        // do something
    }
});

socket.open(request.build());
socket.fire("OPEN");

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.