전체 페이지뷰

2017년 2월 1일 수요일

vertx application

https://github.com/vert-x3/vertx-examples
http://vertx.io/blog/my-first-vert-x-3-application/

My first Vert.x 3 Application



Let’s say, you heard someone saying that Vert.x is awesome. Ok great, but you may want to try it by yourself. Well, the next natural question is “where do I start ?”. This post is a good starting point. It shows how is built a very simple vert.x application (nothing fancy), how it is tested and how it is packaged and executed. So, everything you need to know before building your own groundbreaking application.
The code developed in this post is available on github. This post is part of the Introduction to Vert.x series. The code of this post in in the post-1 branch.

Let’s start !

First, let’s create a project. In this post, we use Apache Maven, but you can use Gradle or the build process tool you prefer. You could use the Maven jar archetype to create the structure, but basically, you just need a directory with:
  1. src/main/java directory
  2. src/test/java directory
  3. pom.xml file
So, you would get something like:
.
├── pom.xml
├── src
│   ├── main
│   │   └── java
│   └── test
│       └── java
Let’s create the pom.xml file with the following content:
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                      http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>io.vertx.blog</groupId>
  <artifactId>my-first-app</artifactId>
  <version>1.0-SNAPSHOT</version>

  <dependencies>
    <dependency>
      <groupId>io.vertx</groupId>
      <artifactId>vertx-core</artifactId>
      <version>3.0.0</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.3</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>
This pom.xml file is pretty straightforward:
  • it declares a dependency on vertx-core
  • it configures the maven-compiler-plugin to use Java 8.
This second point is important, Vert.x applications require Java 8.

Let’s code !

Ok, now we have made the pom.xml file. Let’s do some real coding… Create the src/main/java/io/vertx/blog/first/MyFirstVerticle.java file with the following content:
package io.vertx.blog.first;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.Future;

public class MyFirstVerticle extends AbstractVerticle {

  @Override
  public void start(Future<Void> fut) {
    vertx
        .createHttpServer()
        .requestHandler(r -> {
          r.response().end("<h1>Hello from my first " +
              "Vert.x 3 application</h1>");
        })
        .listen(8080, result -> {
          if (result.succeeded()) {
            fut.complete();
          } else {
            fut.fail(result.cause());
          }
        });
  }
}
This is actually our not fancy application. The class extends AbstractVerticle. In the Vert.x world, a verticle is a component. By extending AbstractVerticle, our class gets access to the vertx field.
The start method is called when the verticle is deployed. We could also implement a stop method, but in this case Vert.x takes care of the garbage for us. The start method receives a Future object that will let us inform Vert.x when our start sequence is completed or report an error. One of the particularity of Vert.x is its asynchronous / non-blocking aspect. When our verticle is going to be deployed it won’t wait until the start method has been completed. So, the Future parameter is important to notify of the completion.
The start method creates a HTTP server and attaches a request handler to it. The request handler is a lambda, passed in the requestHandler method, called every time the server receives a request. Here, we just reply Hello ... (nothing fancy I told you). Finally, the server is bound to the 8080 port. As this may fails (because the port may already be used), we pass another lambda expression checking whether or not the connection has succeeded. As mentioned above it calls either fut.complete in case of success or fut.fail to report an error.
Let’s try to compile the application using:
mvn clean compile
Fortunately, it should succeed.
That’s all for the application.

Let’s test

Well, that’s good to have developed an application, but we can never be too careful, so let’s test it. The test uses JUnit and vertx-unit - a framework delivered with vert.x to make the testing of vert.x application more natural.
Open the pom.xml file to add the two following dependencies:
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.12</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>io.vertx</groupId>
  <artifactId>vertx-unit</artifactId>
  <version>3.0.0</version>
  <scope>test</scope>
</dependency>
Now create the src/test/java/io/vertx/blog/first/MyFirstVerticleTest.java with the following content:
package io.vertx.blog.first;

import io.vertx.core.Vertx;
import io.vertx.ext.unit.Async;
import io.vertx.ext.unit.TestContext;
import io.vertx.ext.unit.junit.VertxUnitRunner;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(VertxUnitRunner.class)
public class MyFirstVerticleTest {

  private Vertx vertx;

  @Before
  public void setUp(TestContext context) {
    vertx = Vertx.vertx();
    vertx.deployVerticle(MyFirstVerticle.class.getName(),
        context.asyncAssertSuccess());
  }

  @After
  public void tearDown(TestContext context) {
    vertx.close(context.asyncAssertSuccess());
  }

  @Test
  public void testMyApplication(TestContext context) {
    final Async async = context.async();

    vertx.createHttpClient().getNow(8080, "localhost", "/",
     response -> {
      response.handler(body -> {
        context.assertTrue(body.toString().contains("Hello"));
        async.complete();
      });
    });
  }
}
This is a JUnit test for our verticle. The test uses vertx-unit, so we use a custom runner. vert.x-unit makes easy to test asynchronous interactions, which are the basis of vert.x applications.
In the setUp method, we creates an instance of Vertx and deploy our verticle. You may have noticed that unlike the traditional JUnit @Before method, it receives a TestContext. This object lets us control the asynchronous aspect of our test. For instance, when we deploy our verticle, it starts asynchronously, as most Vert.x interactions. We cannot check anything until it gets started correctly. So, as second argument of the deployVerticle method, we pass a result handler: context.asyncAssertSuccess(). It fails the test if the verticle does not start correctly. In addition it waits until the verticle has completed its start sequence. Remember, in our verticle, we call fut.complete(). So it waits until this method is called, and in the case of a failures, fails the test.
Well, the tearDown method is straightforward, and just terminates the vertx instance we created.
Let’s now have a look to the test of our application: the testMyApplication method. The test emits a request to our application and checks the result. Emitting the request and receiving the response is asynchronous. So we need a way to control this. As the setUp and tearDownmethods, the test method receives a TestContext. From this object we creates an async handle (async) that lets us notify the test framework when the test has completed (using async.complete()).
So, once the async handle is created, we create a HTTP client and emits a HTTP request handled by our application with the getNow()method (getNow is just a shortcut for get(...).end()). The response is handled by a lambda. In this lambda we retrieves the response body by passing another lambda to the handler method. The body argument is the response body (as a buffer object). We check that the body contains the "Hello" String and declare the test complete.
Let’s take a minute to mention the assertions. Unlike in traditional JUnit tests, it uses context.assert.... Indeed, if the assertion fails, it will interrupt the test immediately. So it’s pretty important to always uses these assertion methods because of the asynchronous aspect of the Vert.x application and so tests.
Our test can be run from an IDE, or using Maven:
mvn clean test

Packaging

So, let’s sum up. We have an application and a test. Well, let’s now package the application. In this post we package the application in a fat jar. A fat jar is a standalone executable Jar file containing all the dependencies required to run the application. This is a very convenient way to package Vert.x applications as it’s only one file. It also make them easy to execute.
To create a fat jar, edit the pom.xml file and add the following snippet just before </plugins>:
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <version>2.3</version>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>shade</goal>
      </goals>
      <configuration>
        <transformers>
          <transformer
            implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
            <manifestEntries>
              <Main-Class>io.vertx.core.Starter</Main-Class>
              <Main-Verticle>io.vertx.blog.first.MyFirstVerticle</Main-Verticle>
            </manifestEntries>
          </transformer>
        </transformers>
        <artifactSet/>
        <outputFile>${project.build.directory}/${project.artifactId}-${project.version}-fat.jar</outputFile>
      </configuration>
    </execution>
  </executions>
</plugin>
It uses the maven-shade-plugin to create the fat jar. In the manifestEntries it indicates the name of our verticle. You may wonder from where comes the Starter class. It’s actually a class from vert.x, that is going to create the vertx instance and deploy our verticle.
So, with this plugin configured, let’s launch:
mvn clean package
This is going to create target/my-first-app-1.0-SNAPSHOT-fat.jar embedding our application along with all the dependencies (including vert.x itself).

Executing our application

Well, it’s nice to have a fat jar, but we want to see our application running! As said above, thanks to the fat jar packaging, running Vert.x application is easy as:
java -jar target/my-first-app-1.0-SNAPSHOT-fat.jar
Then, open a browser to http://localhost:8080.
To stop the application, hit CTRL+C.

Conclusion

This Vert.x 3 crash class has presented how you can develop a simple application using Vert.x 3, how to test it, package it and run it. So, you now know everything you need to build amazing system on top of Vert.x 3. Next time we will see how to configure our application.
Happy coding & Stay tuned !

http://tutorials.jenkov.com/vert.x/


Vert.x TCP Server

Jakob Jenkov
Last update: 2015-04-29
Vert.x comes with a TCP server which makes it easy to create TCP servers in your application. You can create one or more TCP servers, depending on your need. In this tutorial I will look at how to create a TCP server from inside a verticle and how to handle incoming connections and data.

Creating a TCP Server

You create a Vert.x TCP server by calling the createNetServer() method on the Vertx object. Here is how that looks:
NetServer server = vertx.createNetServer();
You will often create a TCP server from inside a verticle. Here is how you create a Vert.x TCP server from inside a verticle:
import io.vertx.core.AbstractVerticle;
import io.vertx.core.net.NetServer;

public class VertxTcpServerVerticle extends AbstractVerticle {

    @Override
    public void start() throws Exception {
        NetServer server = vertx.createNetServer();
    }
}

Starting the TCP Server

Once you have created the TCP server, you can start it using its listen() method. Here is how starting the TCP server looks:
public class VertxTcpServerVerticle extends AbstractVerticle {

    @Override
    public void start() throws Exception {
        NetServer server = vertx.createNetServer();

        server.listen(10000);
    }
}
This example starts the server and instructs it to listen on TCP port 10.000 .
The NetServer class contains more versions of the listen() method which gives you different options for starting the TCP server.

Setting a Connect Handler on the TCP Server

In order to handle incoming TCP connections you need to set a connect handler on the TCP server. This is normally done before starting the TCP server. Here is a Vert.x TCP server connect handler example:
public class VertxTcpServerVerticle extends AbstractVerticle {

    @Override
    public void start() throws Exception {
        NetServer server = vertx.createNetServer();

        server.connectHandler(new Handler<NetSocket>() {

            @Override
            public void handle(NetSocket netSocket) {
                System.out.println("Incoming connection!");
            }
        });
    
        server.listen(10000);
    }
}
The handle() method of the connect handler is called whenever a new TCP connection is created by a client of the TCP server. The NetSocket object passed as parameter to the handle() method gives access to the incoming connection (socket etc.).

Reading Data From The Socket

In order to read data from the incoming connections you need to set a handler on the NetSocket object for the connection. Here is how that is done:
public class VertxTcpServerVerticle extends AbstractVerticle {

    @Override
    public void start() throws Exception {
        NetServer server = vertx.createNetServer();

        server.connectHandler(new Handler<NetSocket>() {

            @Override
            public void handle(NetSocket netSocket) {
                System.out.println("Incoming connection!");

                netSocket.handler(new Handler<Buffer>() {

                    @Override
                    public void handle(Buffer buffer) {
                        System.out.println("incoming data: "+buffer.length());

                        buffer.getString(0,buffer.length());
                    }
                });
            }
        });

        server.listen(10000);
    }
}

Writing Data to The Socket

Once you have processed the incoming data you may want to write a response back to the client. You can do so via the NetSocket instance passed to the connect handler's handle() method. Here is an example of writing data back to the client via the NetSocket:
public class VertxTcpServerVerticle extends AbstractVerticle {

    @Override
    public void start() throws Exception {
        NetServer server = vertx.createNetServer();

        server.connectHandler(new Handler<NetSocket>() {

            @Override
            public void handle(NetSocket netSocket) {
                System.out.println("Incoming connection!");

                netSocket.handler(new Handler<Buffer>() {

                    @Override
                    public void handle(Buffer inBuffer) {
                        System.out.println("incoming data: " + inBuffer.length());

                        String data =
                            inBuffer.getString(0, inBuffer.length());

                        Buffer outBuffer = Buffer.buffer();
                        outBuffer.appendString("response...");

                        netSocket.write(outBuffer);
                    }
                });
            }
        });
        server.listen(10000);
    }
}
The write() method of the NetSocket method is asynchronous. Thus, it returns immediately. The data will be written to the underlying socket at a later time.
The NetSocket class contains more versions of the write() method which enables you to write e.g. a String directly to the socket without using a Buffer. See the Vert.x JavaDoc for more details.

Closing The TCP Server

When you are finished with the TCP server you can close it using its close() method. Here is how closing a Vert.x TCP server looks:
server.close();
Closing the TCP server is an asynchronous actions, so the close() method may exit before the TCP server is actually closed. If you need to be notified of when the TCP server has shut down, you can pass aHandler to the close() method. This handler will then be called when the TCP server is fully closed. Here is how that looks:
server.close(new Handler<AsyncResult<Void>>() {
    @Override
    public void handle(AsyncResult result) {
        if(result.succeeded()){
            //TCP server fully closed
        }
    }
});

댓글 없음:

댓글 쓰기