2016年1月29日 星期五

QRCode with Logo Java Sample

注意事項:
    1. 此範例使用 Maven 建置相關內容請另行查閱
    2. 文章內容僅供參考

目錄

檔案配置

JavaSample
|____main
| |____java
| | |____sample
| |   |____qrcode
| |     |____QRCodeUtils.java
| |     |____SampleMain.java
| |____resources
|   |____qrcode-logo.png
|____output.png
|____pom.xml

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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>tw.cookie.project</groupId>
    <artifactId>JavaSample</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <zxing.version>3.1.0</zxing.version>
    </properties>

    <dependencies>
        <!-- Official ZXing ("Zebra Crossing") -->
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>${zxing.version}</version>
        </dependency>
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>javase</artifactId>
            <version>${zxing.version}</version>
        </dependency>
    </dependencies>
</project>

QRCodeUtils

package sample.qrcode;

import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;

import static com.google.zxing.BarcodeFormat.QR_CODE;

/**
 * Created by Cookie on 16/1/30.
 */
public class QRCodeUtils {
    private static final String IMAGE_FORMAT = "png";

    private static final int BLACK = 0xFF000000;
    private static final int WHITE = 0xFFFFFFFF;

    private static final int WIDTH = 256;
    private static final int HEIGHT = 256;

    private static final String FRONT_IMAGE_NAME = "qrcode-logo.png";
    private static final BufferedImage FRONT_IMG;
    private static final int FRONT_IMG_START_X;
    private static final int FRONT_IMG_START_Y;

    private static final QRCodeWriter WRITER = new QRCodeWriter();

    static {
        InputStream inputStream = null;
        BufferedInputStream headBIS = null;
        BufferedImage image = null;
        int start_x = 0;
        int start_y = 0;
        try {
            inputStream = ClassLoader.getSystemResourceAsStream(FRONT_IMAGE_NAME);
            headBIS = new BufferedInputStream(inputStream);
            image = ImageIO.read(headBIS);

            start_x = (WIDTH - image.getWidth()) /2;
            start_y = (HEIGHT - image.getHeight()) /2;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (headBIS != null) {
                try {
                    headBIS.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        FRONT_IMG = image;
        FRONT_IMG_START_X = start_x;
        FRONT_IMG_START_Y = start_y;
    }

    public static ByteArrayOutputStream encode(String content) {
        ByteArrayOutputStream result = null;
        try {
            BitMatrix matrix = WRITER.encode(content, QR_CODE, WIDTH, HEIGHT);
            result = new ByteArrayOutputStream();
            MatrixToImageWriter.writeToStream(matrix, IMAGE_FORMAT, result);
        } catch (Exception e) {
            e.printStackTrace();
            close(result);
        }
        return result;
    }

    public static ByteArrayOutputStream encodeWithLogo(String content) {
        if (FRONT_IMG == null) {
            return encode(content);
        }
        ByteArrayOutputStream result = null;
        try {
            BitMatrix matrix = WRITER.encode(content, QR_CODE, WIDTH, HEIGHT);
            BufferedImage backImage = QRCodeUtils.toBufferedImage(matrix);

            Graphics2D g = backImage.createGraphics();
            g.drawImage(FRONT_IMG, FRONT_IMG_START_X, FRONT_IMG_START_Y, null);

            result = new ByteArrayOutputStream();
            if(!ImageIO.write(backImage, IMAGE_FORMAT, result)) {
                throw new IOException("Could not write an image of format png.");
            }
        } catch (Exception e) {
            e.printStackTrace();
            close(result);
        }
        return result;
    }

    private static BufferedImage toBufferedImage(BitMatrix matrix) {
        int w = matrix.getWidth();
        int h = matrix.getHeight();
        BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < w; x++) {
            for (int y = 0; y < h; y++) {
                image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE);
            }
        }
        return image;
    }

    private static void close(Closeable obj) {
        if (obj == null) return;
        try {
            obj.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Sample Main

package sample.qrcode;

import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;

/**
 * Created by Cookie on 16/1/30.
 */
public class SampleMain {
    public static void main(String[] args) throws Exception {
        ByteArrayOutputStream stream = QRCodeUtils.encodeWithLogo(
            "http://tsai-cookie.blogspot.com/2016/01/qrcode-with-logo-java-sample.html");
        if (stream == null) throw new RuntimeException("Create QRCode Failed.");
        FileOutputStream out = new FileOutputStream("output.png");
        out.write(stream.toByteArray());
        stream.close();
        out.close();
    }
}

成果

2016年1月18日 星期一

淺談 CookieTsai 的程式設計

注意事項:
    1. 內容僅是自身經驗之分享,如有雷同純屬巧合。
    2. 僅供參考與學習使用,如有其他用途請告知。

目錄

文章簡介

小編是一名 Java 程式設計師,有一日結識了一名想透過小編學習寫程式的外國人。由於小編的英文程度相當令人堪憂,在語言不易溝通的情況下,大多只能分享自身對程式設計的理念與方針,所幸幾次下來也整理出了一些知識,最後整理成這篇文章。

程式設計

  • 目的
    寫一個簡單程式的難度,小編認為可以把它當成寫一句英文(如:Hello World!!)來看待,不會很難也不需要很久的時間。程式語言既然稱之為語言就會有語法及特性,而其主要目的小編認為是用在人與電腦之間當溝通的媒介。
  • 特性
    程式語言由於要給人與電腦閱讀具有幾種特性,其中與一般語言最大的不同,大概會是語法必須是完全正確,正確的意思為可以通過編譯器(Compiler)而不出現錯誤。
  • 設計
    • Simple(為電腦而設計)
      一言以蔽之為精簡的程式碼,邏輯上要達到簡明扼要,除此外還要讓程式碼的長、寬、巢狀及遞迴...等結構減少,以效能達到最高為主要目的。
    • Stupid(為人而設計)
      軟體工程中消耗最多的就是維護的成本,可高達整個專案的 7成以上,撰寫人人都可以輕鬆閱讀的程式碼是 Stupid 最高的目標。
  • 學習
    基於以上種種原因及目的,如果期許自己能學好一門程式語言。除了最初的程式入門外,小編認為通過專案的實作與練習,以有特定目標來學習程式語言是最佳的方法。
  • 閱讀 vs 編寫
    在聽說讀寫中程式語言著重於讀與寫,而讀與寫中又極其偏重讀。在一般請況下,一個大型專案中自己所撰寫過的程式佔不到半數。許多程式是由其他夥伴甚至是第三方團體所提供,為了使專案能正常的運作,我們需要盡可能的不讓無法理解的內容加入到專案之中,因此閱讀他人所編寫的程式碼就變得極其重要。
  • 結語
    如何真的學好一門程式語言,實際上就跟學習其他語言相同,有一些基本語法需要記憶。但更重要的是通過團隊實作來證實所學,在實作過程中電腦可以讓你知道,所學的語法是正確的,而團隊夥伴可以讓你知道撰寫的程式是否簡明扼要。

2015年12月16日 星期三

Grizzly 2.0: HttpServer API. Asynchronous HTTP Server - Part I

注意事項:
    1. 本文轉載於 Mytec Blog for oleksiys
    2. 建議先瞭解一下 Grizzly IOStrategies 的第一種 Worker-thread 模式
    3. 僅供參考查閱使用
In my previous blog entry I described basic Grizzly HttpServer API abstractions and offered a couple of samples to show how one can implement light-weight Servlet-like web application.
Here I'll try to show how we can process HTTP requests asynchronously within HttpHandler, in other words implement asynchronous HTTP application.
What do we mean by "asynchronous"?
Normally HttpServer has a service thread-pool, whose threads are used for HTTP requests processing, which includes following steps:
  1. parse HTTP request;
  2. execute processing logic by calling HttpHandler.handle(Request, Response);
  3. flush HTTP response;
  4. return service thread to a thread-pool.
Normally the steps above are executed sequentially in a service thread. Using "asynchronous" feature it's possible to delegate execution of steps 2 and 3 to a custom thread, which will let us release the service thread faster.
Why would we want to do that?
As it was said above, the service thread-pool instance is shared between all the HttpHandlers registered on HttpServer. Assume we have application (HttpHandler) "A", which executes a long lasting task (say a SQL query on pretty busy DB server), and application "B", which serves static resources. It's easy to imagine the situation, when couple of application "A" clients block all the service threads by waiting for response from DB server. The main problem is that clients of application "B", which is pretty light-weight, can not be served at the same time because there are no available service threads. So it might be a good idea to isolate these applications by executing application "A" logic in the dedicated thread pool, so service threads won't be blocked.
Ok, let's do some coding and make sure the issue we've just described is real.
HttpServer httpServer = new HttpServer();

NetworkListener networkListener = new NetworkListener("sample-listener", "127.0.0.1", 18888);

// Configure NetworkListener thread pool to have just one thread,
// so it would be easier to reproduce the problem
ThreadPoolConfig threadPoolConfig = ThreadPoolConfig
        .defaultConfig()
        .setCorePoolSize(1)
        .setMaxPoolSize(1);

networkListener.getTransport().setWorkerThreadPoolConfig(threadPoolConfig);

httpServer.addListener(networkListener);

httpServer.getServerConfiguration().addHttpHandler(new HttpHandler() {
    @Override
    public void service(Request request, Response response) throws Exception {
        response.setContentType("text/plain");
        response.getWriter().write("Simple task is done!");
    }
}, "/simple");

httpServer.getServerConfiguration().addHttpHandler(new HttpHandler() {
    @Override
    public void service(Request request, Response response) throws Exception {
        response.setContentType("text/plain");
        // Simulate long lasting task
        Thread.sleep(10000);
        response.getWriter().write("Complex task is done!");
    }
}, "/complex");

try {
    server.start();
    System.out.println("Press any key to stop the server...");
    System.in.read();
} catch (Exception e) {
    System.err.println(e);
}
In the sample above we create, initialize and run HTTP server, which has 2 applications (HttpHandlers) registered: "simple" and "complex". To simulate long-lasting task in the "complex" application we're just causing the current thread to sleep for 10 seconds.
Now if you try to call "simple" application from you Web browser using URL: http://localhost:18888/simple - you see the response immediately. However, if you try to call "complex" application http://localhost:18888/complex - you'll see response in 10 seconds. That's fine. But try to call "complex" application first and then quickly, in different tab, call the "simple" application, do you see the response immediately? Probably not. You'll see the response right after "complex" application execution completed. The sad thing here is that service thread, which is executing "complex" operation is idle (the same situation is when you wait for SQL query result), so CPU is doing nothing, but still we're not able to process another HTTP request.
How we can rework the "complex" application to execute its task in custom thread pool? Normally application (HttpHandler) logic is encapsulated within HttpHandler.service(Request, Response) method, once we exit this method, Grizzly finishes and flushes HTTP response. So coming back to the service thread processing steps:
  1. parse HTTP request;
  2. execute processing logic by calling HttpHandler.handle(Request, Response);
  3. flush HTTP response;
  4. return service thread to a thread-pool.
we see that it wouldn't be enough just to delegate HTTP request processing to a custom thread on step 2, because on step 3 Grizzly will automatically flush HTTP response back to client at the state it currently is. We need a way to instruct Grizzly to not do 3 automatically on the service thread, instead we want to be able to perform this step ourselves once asynchronous processing is complete.
Using Grizzly HttpServer API it could be achieved following way:
  • HttpResponse.suspend(...) to instruct Grizzly to not flush HTTP response in the service thread;
  • HttpResponse.resume() to finish HTTP request processing and flush response back to client.
So asynchronous version of the "complex" application (HttpHandler) will look like:
httpServer.getServerConfiguration().addHttpHandler(new HttpHandler() {
    final ExecutorService complexAppExecutorService =
        GrizzlyExecutorService.createInstance(
            ThreadPoolConfig.defaultConfig()
            .copy()
            .setCorePoolSize(5)
            .setMaxPoolSize(5));
            
    @Override
    public void service(final Request request, final Response response) throws Exception {
                
        response.suspend(); // Instruct Grizzly to not flush response, once we exit the service(...) method 
                
        complexAppExecutorService.execute(new Runnable() {   // Execute long-lasting task in the custom thread
            public void run() {
                try {
                    response.setContentType("text/plain");
                    // Simulate long lasting task
                    Thread.sleep(10000);
                    response.getWriter().write("Complex task is done!");
                } catch (Exception e) {
                    response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR_500);
                } finally {
                    response.resume();  // Finishing HTTP request processing and flushing the response to the client
                }
            }
        });
    }
}, "/complex");
  • As you might have noticed, "complex" application uses Grizzly ExecutorService implementation. This is the preferred approach, however you can still use own ExecutorService.
The three most important steps in the code above are marked red:
  1. Suspend HTTP response processing: response.suspend()
  2. Delegating task to the custom thread pool: complexAppExecutorService.execute(...)
  3. Resuming HTTP response processing: response.resume()
Now, using your browser, you can make sure "simple" and "complex" applications are not affecting each other, and the "simple" application works just fine when the "complex" application is busy.

筆記

實作中筆者刻意將 thread pool 設定為僅有一個 Worker 的情況下運行。
在此案例中,如果我們先行呼叫 complex 而後在呼叫 simple 會發現,simple 需要等 complex 做完才可以運行。
在這樣的狀況下會發生一個問題,也就是當一些複雜的 API 被呼叫時可能造成一些簡單的 Request 在排隊等待。
緊接著筆者透過另起一群 Thread pool 專門處理 complex 這樣即使只有一個 Worker 也不至會造成排隊的問題。
個人對此文章的理解為:建議耗時長的API應與耗時短的API,分別處理這樣可以使伺服器運作得更為順利

Best Practices

注意事項:
    1. 本文來源為 Grizzly 官方網站文件
    2. 請以官方文件為主,此文僅供參考使用
When developing a network application, we usually wonder how we can optimize it. How should the worker thread pool be sized? Which I/O strategy to employ?
There is no general answer for that question, but we’ll try to provide some tips.
  • IOStrategy
    In the IOStrategy section, we introduced different Grizzly IOStrategies.
    By default, Grizzly Transports use the worker-thread IOStrategy, which is reliable for any possible usecase. However, if the application processing logic doesn’t involve any blocking I/O operations, the same-thread IOStrategy can be used. For these cases, the same-thread strategy will yield better performance as there are no thread context switches.
    For example, if we implement general HTTP Servlet container, we can’t be sure about nature of specific Servlets developers may have. In this case it’s safer to use the worker-thread IOStrategy. However, if application uses the Grizzly’s HttpServer and HttpHandler, which leverages NIO streams, then the same-thread strategy could be used to optimize processing time and resource consumption;
  • Selector runners count
    The Grizzly runtime will automatically set the SelectorRunner count value equal to Runtime.getRuntime().availableProcessors(). Depending on the usecase, developers may change this value to better suit their needs.
    Scott Oaks, from the Glassfish performance team, suggests that there should be one SelectorRunner for every 1-4 cores on your machine; no more than that;
  • Worker thread pool
    In the Configuration threadpool-config section, the different thread pool implementations, and their pros and cons, were discussed.
    All IOStrategies, except the same-thread IOStrategy, use worker threads to process IOEvents which occur on Connections. A common question is how many worker threads will be needed by an application?
    In his blog, Scott suggests How many is “just enough”? It depends, of course – in a case where HTTP requests don’t use any external resource and are hence CPU bound, you want only as many HTTP request processing threads as you have CPUs on the machine. But if the HTTP request makes a database call (even indirectly, like by using a JPA entity), the request will block while waiting for the database, and you could profitably run another thread. So this takes some trial and error, but start with the same number of threads as you have CPU and increase them until you no longer see an improvement in throughput.
    Translating this to the general, non HTTP usecase: If IOEvent processing includes blocking I/O operation(s), which will make thread block doing nothing for some time (i.e, waiting for a result from a peer), it’s best to have more worker threads to not starve other request processing. For simpler application processes, the fewer threads, the better.

筆記

  • Grizzly 建議的調整方向可區分成三個 IOStrategy, Selector 和 Worker thread pool。
    • IOStrategy 調整伺服器運作模式,包含 Worker-thread(預設), Same-thread, Dynamic 和 Leader-follower。
    • Selector 建議配合電腦核心數去設定,每 1 ~ 4個核心對應 1 個 Selector(此預設值為 Runtime.getRuntime().availableProcessors() 的數值)
    • 官方提供建議 thread pool 設定為夠用就好並非越大就越快,此外 Worker thread pool 必須配合 IOStrategy 決定是否有效。如:Same-thread 模式中似乎並沒有運用到 Worker。

2015年10月29日 星期四

Java 之神奇的 1+1+1+1+1 = 1

注意事項:
    1. 文章內容為閱讀相關資訊後所做的測試結果及心得
    2. 可供參考、分享及測試
下面是某程式的一部分,表達的只是 5 個 1 相加,結果卻會是 1。
Integer a = 1;
Integer b = new Integer(1);
Integer c = Integer.valueOf(1);
Integer d = Integer.parseInt("1");
Integer e = Long.valueOf(1).intValue();

System.out.println("a : " + a);
System.out.println("b : " + b);
System.out.println("c : " + c);
System.out.println("d : " + d);
System.out.println("e : " + e);

System.out.println("a+b+c+d+e : " + (a+b+c+d+e)); // output 'a+b+c+d+e : 1'
在看解答前不仿先嘗試猜猜看原因為何。
.
.
.
.
.
.
.
完整程式碼 如下:
package sample.puzzler;

import java.lang.reflect.Field;

/**
 * Created by Cookie on 15/10/29.
 */
public class JavaPuzzler {

    public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException {

        Integer one = 1;

        Field field = Integer.class.getDeclaredField("value");
        field.setAccessible(true);
        field.setInt(one, 0);

        Integer a = 1;
        Integer b = new Integer(1);
        Integer c = Integer.valueOf(1);
        Integer d = Integer.parseInt("1");
        Integer e = Long.valueOf(1).intValue();

        System.out.println("a : " + a);
        System.out.println("b : " + b);
        System.out.println("c : " + c);
        System.out.println("d : " + d);
        System.out.println("e : " + e);

        System.out.println("a+b+c+d+e : " + (a+b+c+d+e));

    }
}
Console Output
a : 0
b : 1
c : 0
d : 0
e : 0
a+b+c+d+e : 1
在程式後半段宣告 a ~ e 並執行 a+b+c+d+e 應該為 5,可執行結果卻為 1,究竟是什麼原因會造成這樣的結果呢?

程式解讀

Field field = Integer.class.getDeclaredField("value");
這是利用 Java 反射機制來取得 Integer 中名叫 value 的欄位。
field.setAccessible(true);
field.setInt(one, 0);
再來的兩行,分別是將存取權限改成 true,之後將整數 0 放入 one 這個物件的 value 欄位之中。
// 宣告 a ~ e
Integer a = 1;
Integer b = new Integer(1);
Integer c = Integer.valueOf(1);
Integer d = Integer.parseInt("1");
Integer e = Long.valueOf(1).intValue();

// 輸出每一個變數的數值
System.out.println("a : " + a);
System.out.println("b : " + b);
System.out.println("c : " + c);
System.out.println("d : " + d);
System.out.println("e : " + e);

// 計算 a+b+c+d+e 然後輸出到畫面
System.out.println("a+b+c+d+e : " + (a+b+c+d+e));
後面幾行如一開始所說的是宣告 a ~ e 的變數,之後做輸出及加總後輸出。

認識 IntegerCache

IntegerCache 是 Integer 物件中的一個 Inner Class。如其名是用來存放 Integer 的 Cache 以達到加速的效果,IntegerCache 程式碼 內容如下:
private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];

    static {
        // high value may be configured by property
        int h = 127;
        String integerCacheHighPropValue =
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            int i = parseInt(integerCacheHighPropValue);
            i = Math.max(i, 127);
            // Maximum array size is Integer.MAX_VALUE
            h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
        }
        high = h;

        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);
    }

    private IntegerCache() {}
}

觀察 Integer.valueOf()

public static Integer valueOf(int i) {
    assert IntegerCache.high >= 127;
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

結論

在實作 Integer 的工程師,為了提高 Integer 物件的效能,定義了一段 Cache 的規則,大致上內容為如果所宣告的數值 -128 ~ 127 之間,將直接從 integerCache 中直接取得相對應的物件。
Example:
Integer one = 1;
Integer a = 1;
Integer c = Integer.valueOf(1);
上列三個參考皆會指向到相同的 Integer 物件並不會不同,除非是自行宣告為 new Integer(1),否則是不會產生新物件的。所以當使用field.setInt(one, 0);將 one 所指向的物件進行修改。由於 a 和 c 也指在相同物件上自然也就會被修改到。

2015年10月28日 星期三

Java Sample Trigger and Masker

注意事項:
    1. 文章內容為使用二進制實現開關效果
    2. 利用一個整數來存取大量開關
    3. 文章及程式碼皆為 CookieTsai 撰寫,可供參考及分享

目錄

前言

有些時候,在 Coding 時會面臨需要使用大量開關來處理的問題。
在這時候程式碼會使用大量 if else 造成不易閱讀及不易維護。除此之外,在儲存這些設定時可能會需要用到許多欄位。過多的判斷式及欄位將造成維護上的困擾。
因此,這幾天嘗試實作了一個叫 Trigger 還有 Masker 的兩種物件。Trigger and Masker 是利用一個整數來便於管理及儲存這大量的開關的設計。
文章的 Start Demo 是實作 SampleMasker 及 SampleMain 來管理五個開關。

Defined Trigger and Masker

Trigger Java Class

package sample.trigger;

/**
 * Created by Cookie on 15/10/29.
 */
public class Trigger {
    public static final int ALL_ON  = -1;
    public static final int ALL_OFF = 0;

    private int value;

    public Trigger(Masker... maskers) {
        for (Masker masker: maskers) {
            on(masker);
        }
    }

    public void on(Masker... maskers){
        for (Masker masker: maskers) {
            value = (value | masker.getMask());
        }
    }

    public void off(Masker... maskers){
        for (Masker masker: maskers) {
            if (!isOn(masker)) {
                continue;
            }
            value -= masker.getMask();
        }
    }

    public boolean isOn(Masker masker){
        return (value & masker.getMask()) > 0;
    }

    public int getValue() {
        return value;
    }

    @Override
    public String toString() {
        return String.valueOf(getValue());
    }
}

Masker Interface

package sample.trigger;

/**
 * Created by Cookie on 15/10/29.
 */
public interface Masker {
    boolean isOn(int value);
    int getIndex();
    int getMask();
}

Start Demo

Sample Masker Java Class

package sample.trigger;

/**
 * Created by Cookie on 15/10/29.
 */
public enum  SampleMasker implements Masker {

    OPTION_01(1),
    OPTION_02(2),
    OPTION_03(3),
    OPTION_04(4),
    OPTION_05(5);

    private final int index;
    private final int mask;

    SampleMasker(int index) {
        this.index = index;
        this.mask = (1 << (index -1));
    }

    public int getIndex() {
        return index;
    }

    public int getMask() {
        return mask;
    }

    public boolean isOn(int value){
        return (value & getMask()) > 0;
    }

    public static Trigger newTrigger() {
        return new Trigger();
    }

    public static Trigger newTrigger(Integer value) {
        if (value == null) {
            return new Trigger(values());
        }
        Trigger result = new Trigger();
        for (Masker masker: values()) {
            if (masker.isOn(value)) {
                result.on(masker);
            }
        }
        return result;
    }

    @Override
    public String toString() {
        return this.name();
    }
}

Sample Main Java Class

package sample.trigger;

/**
 * Created by Cookie on 15/10/29.
 */
public class SampleMain {

    public static void main(String[] args) {

        Trigger trigger;

        System.out.println("========== Sample 1 output ==========");

        // Create a new Trigger
        trigger = SampleMasker.newTrigger();

        // Open the option 02 and 05
        trigger.on(SampleMasker.OPTION_02, SampleMasker.OPTION_05);

        // show all option
        for (Masker masker: SampleMasker.values()) {
            System.out.println(masker.toString() + " => " + trigger.isOn(masker) );
        }

        // show the trigger value
        System.out.println("Get Trigger Value => " + trigger.getValue());
        System.out.println();

        System.out.println("========== Sample 2 output ==========");

        // Create a new Trigger,and all option be on
        trigger = SampleMasker.newTrigger(Trigger.ALL_ON);

        // Close the option 04
        trigger.off(SampleMasker.OPTION_04);

        for (Masker masker: SampleMasker.values()) {
            System.out.println(masker.toString() + " => " + trigger.isOn(masker) );
        }

        // show the trigger value
        System.out.println("Get Trigger Value => " + trigger.getValue());
        System.out.println();

        int value = trigger.getValue();

        System.out.println("========== Sample 3 output ==========");

        // Using a trigger value to create a new Trigger
        trigger = SampleMasker.newTrigger(value);

        // show all option
        for (Masker masker: SampleMasker.values()) {
            System.out.println(masker.toString() + " => " + trigger.isOn(masker) );
        }

        // show the trigger value
        System.out.println("turn to Int Value => " + trigger.getValue());
        System.out.println();

    }
}

Console Output

========== Sample 1 output ==========
OPTION_01 => false
OPTION_02 => true
OPTION_03 => false
OPTION_04 => false
OPTION_05 => true
Get Trigger Value => 18

========== Sample 2 output ==========
OPTION_01 => true
OPTION_02 => true
OPTION_03 => true
OPTION_04 => false
OPTION_05 => true
Get Trigger Value => 23

========== Sample 3 output ==========
OPTION_01 => true
OPTION_02 => true
OPTION_03 => true
OPTION_04 => false
OPTION_05 => true
turn to Int Value => 23