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.
Some short examples to illustrate how to use the different interfaces of the ASync library.
Consolenew 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 servernew 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(Mapparameters) {// Called when request is done. response.getWriter().print(parameters); } }); } }).addDefault(new HttpCallback() { public void call(HttpRequest request, HttpResponse response) throws IOException { response.getWriter().print(""); } }));
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.
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 socketNext 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.
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); } }));
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);
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);