Firefly v4.6.0 is released

19 Nov 2017, Alvin Qiu

Firefly v4.6.0 adds OpenSSL engine support for network tools, named parameter SQL APIs, connection leak detector for HTTP client and fixes some bugs. We have completed the HTTP server/client document (Kotlin version), Database access document (Kotlin version) and SSL/TLS configuration document.

Use the OpenSSL engine

Firefly provides JDK SSL engine and OpenSSL engine. The JDK SSL engine is the default. The Java8 SSL engine does not support ALPN (Application Layer Protocol Negotiation).

The HTTP/2 need ALPN within a TLS handshake. If you use the Java8 SSL engine, you need to add a VM option to set up Jetty ALPN boot jar.

If you can not modify the VM options in some situations, you can use the OpenSSL engine that supports ALPN, and it need not add any VM options.

public class OpensslHTTPsServer {
    public static void main(String[] args) {
        $.httpsServer(new DefaultOpenSSLSecureSessionFactory())
         .router().get("/").handler(ctx -> ctx.end("hello world!"))
         .listen("localhost", 8081);

Run it and visit the https://localhost:8081. The browser will render

hello world!

You can also use yourself openssl certificate file. For example:

public class OpensslFileCertHTTPsServer {
    public static void main(String[] args) throws IOException {
        ClassPathResource certificate = new ClassPathResource("/myCA.cer");
        ClassPathResource privateKey = new ClassPathResource("/myCAPriv8.key");
        SecureSessionFactory factory = new FileCertificateOpenSSLSecureSessionFactory(

         .router().get("/").handler(ctx -> ctx.end("hello world!"))
         .listen("localhost", 8081);

Notes: the OpenSSL private key must be PKCS8 format. You can use the tool openssl pkcs8 to convert the format. Such as:

openssl genrsa -out myCA.key 2048
openssl req -new -x509 -key myCA.key -out myCA.cer -days 36500
openssl pkcs8 -topk8 -inform PEM -outform PEM -in myCA.key -out myCAPriv8.key -nocrypt

More details, please refer to the SSL/TLS configuration

Named parameter SQL

The named SQL improves readability. When we use the named SQL, we can use javabean or map to replace the placeholders. The javabean uses the property name to match the parameter. The map uses the key to match the parameter. For example:

public void testInsert() {
    String sql = "insert into `test`.`user`(pt_name, pt_password) values(?,?)";
    Mono<Long> newUserId = exec(c -> c.insert(sql, "hello user", "hello user pwd"));
    StepVerifier.create(newUserId).expectNext(size + 1L).verifyComplete();

    String namedSql = "insert into `test`.`user`(pt_name, pt_password) values(:name, :password)";
    Map<String, Object> paramMap = new HashMap<>();
    paramMap.put("name", "hello user1");
    paramMap.put("password", "hello user pwd1");
    newUserId = exec(c -> c.namedInsert(namedSql, paramMap));
    StepVerifier.create(newUserId).expectNext(size + 2L).verifyComplete();

    User user = new User();
    user.setName("hello user2");
    user.setPassword("hello user pwd2");
    newUserId = exec(c -> c.namedInsert(namedSql, user));
    StepVerifier.create(newUserId).expectNext(size + 3L).verifyComplete();

The Kotlin version example:

fun testInsert() = runBlocking {
    val newUserId = exec {
        it.asyncInsert<Long>("insert into `test`.`user`(pt_name, pt_password) values(?,?)",
                "hello user", "hello user pwd")
    assertEquals(size + 1L, newUserId)

    val namedSQL = "insert into `test`.`user`(pt_name, pt_password) values(:name, :password)"
    val newUserId2 = exec {
        it.asyncNamedInsert<Long>(namedSQL, mapOf("name" to "hello user", "password" to "hello user pwd"))
    assertEquals(size + 2L, newUserId2)

    val newUserId3 = exec {
        it.asyncNamedInsert<Long>(namedSQL, User(null, "hello user", "hello user pwd", null))
    assertEquals(size + 3L, newUserId3)

Update log:

  1. Add OpenSSL engine support for network tools.
  2. Add named parameter SQL APIs.
  3. Complete Kotlin API documents.
  4. Add SSL/TLS configuration documents.
  5. Fix the priority mistake when the router is matched by the accept MIME type.
  6. Add default bad message listener for the HTTP server.
  7. Add connection leak detector for the HTTP client.