ASync

ASync is an asynchronous library to handle asynchronous communication over sockets, console and web. It provides an easy to use interface, simplifying the work that needs to be done. All connection types (socket/console/web) use a similar approach, making it easy to switch between them.

The purpose of ASync is to simplify a tedious task, and to make it swifter to develop debugging interfaces.

The ASync library uses the Factory design pattern, among others.

1. Short examples

2. Dispatcher

 2.1. Exist hooks

3. Exceptions

4. Threads

Short examples

Some short examples to illustrate how to use the different interfaces of the ASync library.

Console
 
                new ASync().console().start(new IOCallback() {//Create new console
                        public void call(InputStream in, OutputStream out) throws IOException {
                                byte[] bs = new byte[1024];
                                int a;
                                //Get data from console input and send it to console output.
                                while ((a = in.read(bs)) != -1) {
                                        out.write(bs, 0, a);                            
                                        out.flush();// Force a flush if stream is buffered. 
                                }
                        }
                });
 
 
Connect to socket
 
                new ASync().socket().connectTo("127.0.0.1", 12345, new IOCallback() {// Connect to host 127.0.0.1 on port 12345
                        public void call(InputStream in, OutputStream out) throws IOException {
                                // This is just nonsense example code
                                out.write("ASync\n".getBytes());//Sends a "ASync" to server
                                out.flush();// Force a flush if stream is buffered.
                                inBytes = new byte[1024];
                                // read just one chunk.
                                inLen = in.read(inBytes);
                                System.out.println(new String(inBytes,0,inLen,"UTF-8"));
                        }// socket will be closed "automatically" (since out of scope)
                });
 
 
Listen on a socket
 
                // This creates a RemoteControl. To stop use remote.stop();
                RemoteControl remote = new ASync().socket().listenOn(12345,//Start listening on socket. RemoteControl makes it possible from outside of ASync API to monitoring and close down service
                                new BufferedCharacterCallback("UTF-8") {
                        public void call(BufferedReader reader, BufferedWriter writer) throws IOException {
                                String line;
                                while ((line = reader.readLine()) != null) {//Read a line
                                        writer.write(new StringBuffer(line).reverse().toString());//Send the read line back to client
                                        writer.flush();// Force a flush if stream is buffered.
                                }
                        }// socket will be closed "automatically" (since out of scope)
                });
                remotes.add(remote);
 
 

When starting a listener or a webserver it return a remote control. It's used to check status of listener/webserver or close it.

In this example BufferedCharacterCallback is used. Thats a type of IOCallback that has a buffered writer/reader.

Web server
 
                new ASync().http().listen(12347, new HttpCallback() {// Start a web server that listening on port 12347
                        public void call(HttpRequest request, HttpResponse response) throws IOException {
                                // This is just nonsense example code
                                PrintWriter writer = response.getWriter();// Get a writer to response client.
                                writer.write(request.getPath());// Get requested path and send it to client.
                                writer.write(" ");
                                writer.write(request.getQueryString());// Gets query string and send it to client.
                                writer.flush();
                        }
                });
 
 
Web server with pages
 
                new ASync().http().listen(12348,new PageAwareHttpCallback().// Start a web server that listening on port 12348
                add("/", new HttpCallback() {//Add httpCallback for page '/'
                        public void call(HttpRequest request, HttpResponse response) throws IOException {
                                PrintWriter writer = response.getWriter();
                                writer.write("StartPage");
                                writer.flush();                         
                        }
                }).
                add("/page2", new HttpCallback() {//Add httpCallback for page 'page2'
                        public void call(HttpRequest request, HttpResponse response) throws IOException {
                                PrintWriter writer = response.getWriter();
                                writer.write("Page2");
                                writer.flush();                         
                        }
                }).addDefault(new HttpCallback() {//Add httpCallback for all other page
                        public void call(HttpRequest request, HttpResponse response) throws IOException {
                                response.setReturnCode(404);
                                PrintWriter writer = response.getWriter();
                                writer.write(String.format("File '%s' not found.", request.getPath()));
                                writer.flush();                         
                        }
                }));
 
 
Web server with method[POST/GET]
 
                new ASync().http().listen(12349,new MethodAwareHttpCallback()
                .add(HTTPType.POST, new HttpCallback() {
                        public void call(HttpRequest request, final HttpResponse response) throws IOException {
                                request.setOutputStream(new PostParameterCollecter("UTF-8") {
                                        public void requestFinish(Map parameters) {// Called when request is done.
                                                        response.getWriter().print(parameters);
                                        }
                                });
                        }
                }).addDefault(new HttpCallback() {
                        public void call(HttpRequest request, HttpResponse response) throws IOException {
                                response.getWriter().print("
<input type=\ "input\" name=\"name\"><input type=\"submit\">
"); } }));

All post data is fetch by a OutputStream and it's closed when request is done. To fetch post parameter use PostParameterFetcher thats a OutputStream thats for each post parameter calls addParameter and at the end of request requestFinish is called. In this example PostParameterCollecter is used. Thats a fetcher of post parameter. It's a type of PostParameterFetcher that only returns all post data as a map when request is done.

2. Dispatcher

The Dispatcher is used to dispatch requests. A dispatcher is a controller that listen on inputStreams from all added callbacks and propagaters it to all other outputStreams.

Connect console to a socket

Next example is a simple client to a chat server.

 
                ASync aSync = new ASync();
                Dispatcher dispatcher = aSync.createDispatcher();
                aSync.console().start(dispatcher.createCallback());
                aSync.socket().connectTo("127.0.0.1", 12346, dispatcher.createCallback());
 
 
Connect one connection to all other connections(Simple chat server)

Next example is a simple chat server.

 
                ASync aSync = new ASync();
                Dispatcher dispatcher = aSync.createDispatcher();
                remotes.add(aSync.socket().listenOn(12346, dispatcher.createFactory()));
 
 

In this example createFactory method is used which will create a new IOCallback for every request. When connecting to a socket or console IOCallback.call is only called once. When listening on a socket IOCallback.call is called for each request. Because of this, a factory is needed that creates new IOCallback for each new call.

2.1. Exist hooks on Dispatcher

Exit hook is called when a dispatchers IOCallback has exit. Thats can be used for writing a message or exit a program when a recource has closed down. To create a exit hook on on a dispatcher callback you just add a ExitCallback.

 
                ASync aSync = new ASync();
                Dispatcher dispatcher = aSync.createDispatcher();
                aSync.console().start(dispatcher.createCallback());
                aSync.socket().connectTo("127.0.0.1", 12346, dispatcher.createCallback(new ExitCallback() {
                        public void onExit() {//called when socket has close
                                System.exit(0);
                        }
                }));
 
 

3. Exceptions

In ASync library there are two types of exceptions:

The first one when starting a resource is a checked exception and will be added on the starting method. The reason for that is when starting a resource you don't wont to check a implemented callback interface to make sure your resource is started, we believe you want a quick and accurate response.

The second on error when service is working. There is a ExceptionCallback that can be added as a parameter to start method.

 
                new ASync().exception(new ExceptionCallback() {
                        public void exception(IOException exception) {
                                // ..deal with the Exception.
                        }
                }).socket().listenOn(12348, myIoCallback);
 
 
	

4. Threads

By default Executors.newCachedThreadPool() is used, however you can customize witch ExecutorService ASync uses by adding ExecutorService.

 
                ASync aSync = new ASync();
                aSync.setExecutor(myExecutorService);// Add custom ExecutorService
                aSync.console().start(myIoCallback);
 
 

Example above uses same service for all type of recourses, to specify different service for different recourses use ThreadHandler.

 
                ASync aSync = new ASync();
                aSync.setHandler(new ThreadHandler() {
                        public ExecutorService getExecutorService(ASyncType socketListen) {
                                switch (socketListen) {
                                case CONSOL_LISTEN:// ASyncType.CONSOL_LISTEN
                                        return Executors.newFixedThreadPool(1);
                                default:
                                        return Executors.newCachedThreadPool();
                                }
                        }
                });
                aSync.console().start(myIoCallback);