まだプログラマーですが何か?

プログラマーネタとアスリートネタ中心。たまに作成したウェブサービス関連の話も http://twitter.com/dotnsf

タグ:decode

BlueMix でアプリケーションを作ると、データベースなどのサービス環境に接続するための情報を VCAP_SERVICES という変数から取得する必要があります。アプリケーションを Java で開発する場合に、これを具体的にどうやって実現するか、というサンプルを紹介します。


まず、これは Java で開発する場合だけでなく、全ての言語で言えることですが、BlueMix のアプリケーションサーバーにバインドされたサービスの情報は VCAP_SERVICES という環境変数から取得することになります。例えば MySQL サービスとバインドしていると、VCAP_SERVICES 変数には以下のような内容の JSON 文字列が追加されます:
"mysql-5.5": [
      {
         "name": "mysql-scsrh",
         "label": "mysql-5.5",
         "plan": "100",
         "credentials": {
            "name": "(データベース名)",
            "hostname": "XX.XXX.XX.XXX",
            "host": "XX.XXX.XX.XXX",
            "port": 3307,
            "user": "(接続ユーザー名)",
            "username": "(接続ユーザー名)",
            "password": "(接続パスワード)",
            "uri": "mysql://(接続ユーザ名):(接続パスワード)@XX.XXX.XX.XXX:3307/(データベース名)"
         }
      }
   ]
ここから接続に必要な値を取り出して接続することになります。Java 言語で JDBC を使うのであれば、赤字に相当する部分を取り出して、以下の様な処理を実行することでコネクションを取得することができます(別途 MySQL 用の JDBC ドライバを用意しておく必要があります):
try{
  Class.forName( "com.mysql.jdbc.Driver" );
  Connection conn = DriverManager.getConnection( "jdbc:" + "mysql://XX.XXX.XX.XXX:3307/(データベース名)", "(接続ユーザ名)", "(接続パスワード)" );
    :
}catch( Exception e ){
  e.printStackTrace();
}
MySQL に限らず DB2 や MongoDB、Twilio などでも同様です。接続情報が必要かどうかはともかくとして、バインドされたサービスに関する設定情報は VCAP_SERVICES 環境変数の中に JSON 形式で格納されるので、そこから必要な情報を取り出して利用する、という流れになります。


問題は Java で JSON を扱うのが意外と面倒、ということです。JSON は JavaScript 用のオブジェクト形式ですが、Java と JavaScript の親和性がいいとは思えないくらいに扱いが難しいのでした。

とりあえず、サンプルとしてシンプルな JSON ライブラリである JSON simple を使って実装してみます:
jsonsimple

json-simple - A simple java toolkit for JSON
 
これをダウンロードして jar をプロジェクトにインポートした上で、こんな感じのコードを実装することになります:
import org.json.simple.*;
import org.json.simple.parse.*;
import java.sql.*;


:
:
Connection conn = null;
String vcap = System.getenv( "VCAP_SERVICES" );
if( vcap != null ){
//. 環境変数 VCAP_SERVICES をデコード JSONParser parser = new JSONParser(); Object obj = parser.parse( vcap ); JSONObject json = ( JSONObject )obj;
//. mysql5-5 の credentials 以下のみを取り出す
JSONObject credentials = ( JSONObject )( ( JSONObject )( ( JSONArray )json.get( "mysql-5.5" ) ).get( 0 ) ).get( "credentials" );
//. 上記赤字部分の情報を取り出す
String name = ( String )credentials.get( "name" );
String hostname = ( String )credentials.get( "hostname" );
Integer port = ( Integer )credentials.get( "port" );
String username = ( String )credentials.get( "username" );
String password = ( String )credentials.get( "password" );

//. コネクション取得
try{
Class.forName( "com.mysql.jdbc.Driver" );
conn = DriverManager.getConnection( "jdbc:mysql://" + hostname + ":" + port + "/" + name, username, password );
}catch( Exception e ){
e.printStackTrace();
}
}
:

でもまだちと面倒だよなあ・・・ もう少し可読性よく書きたいんだけど、Java だと JSON は本当に厄介です。


 

「Java で使えるバーコード読み取りライブラリ」を探していました。

開発の関係で「Java から使える」ことが条件でした。また「QRコード」のライブラリは見かけるけど、いわゆる「バーコード」 のは意外と少ない。そしてバーコードを「生成する」のではなく、バーコード画像を「読み取り」たかった、という条件もあります。 加えてライセンスフリーだといいな、と。

これだけの条件で探すとほとんど選択肢はなく、唯一見つけたのが「ZXing(ゼブラクロッシング)」というライブラリでした。 ZXing は単に JavaSE で使えるというだけでなく、Android SDK からも使えます。また QR コードにも対応していたり、読み書き両方に使えたりと汎用性も高そうです。ZXing はソースファイルで提供されているので、そのビルド方法も含めた利用手順を紹介します。なお最新版(3.0)の ZXing をビルドするには JDK 1.7 以上、および Apache Maven が必要です。 

RedHat Enterprise Linux や CentOS であれば以下のコマンドで JDK1.7 をインストールできます:
# yum install java-1.7.0-openjdk-devel

Apache Maven はこんな感じ:
# cd /etc/yum.repos.d
# wget http://repos.fedorapeople.org/repos/dchen/apache-maven/epel-apache-maven.repo # yum install apache-maven

JDK 1.7 と Maven が用意できたら ZXing をビルドすることができます。まず ZXing のダウンロードページから最新のソースファイルをダウンロードして、zip ファイルを展開しておきます。

と、言いたかったのですが、4月25日現在の最新版(3.0.2-SNAPSHOT)はビルドの途中でエラーになってしまい、なんかよく分からなかったので、僕はこちらの 2.3.0 というバージョンを使いました。

展開後、いくつかのフォルダが出来上がりますが、通常の Java(SE) 環境で利用するには core と javase のライブラリが必要です。そのためこの2つのフォルダで JAR ライブラリを Maven でビルドします:
# cd core
# mvn -DskipTests -Dgpg.skip=true install
→ ./target/ に JAR ファイルができている # cd ../javase # mvn -DskipTests -Dgpg.skip=true install
 → ./target/ に JAR ファイルができている

ビルドでできあがった core-X.X.X.jar と javase-X.X.X.jar(X.X.X 部分は ZXing のバージョン)が必要なライブラリになります。これらを Java のプロジェクト内で利用できるように(例えば WEB-INF/lib/ 以下に)コピーして、これで準備完了。

実際にバーコードをデコードするサンプルも記載しておきます。これはローカルシステムの c:/tmp/sample.jpg にバーコード画像がある場合の例ですが、こんな感じ: 
  String filename = "c:/tmp/sample.jpg";
    :
  try{
    //. 画像読み込み
    BufferedImage image = ImageIO.read( new File( filename ) );
    LuminanceSource source = new BufferedImageLuminanceSource( image );
    BinaryBitmap bitmap = new BinaryBitmap( new HybridBinarizer( source ) );

    //. デコード
    Reader reader = new MultiFormatReader();
    Result result = reader.decode( bitmap );

    //. バーコードフォーマット
    BarcodeFormat format = result.getBarcodeFormat();

    //. バーコードコンテンツ(読み取り結果)
    String text = result.getText();
      :
  }catch( Exception e ){
    e.printStackTrace();
  }
    :





さて問題の認識精度ですが、 、、まあ仕方ないのかな、って感じです。画像にバーコードだけが写っている状態であればまだしも、周囲に関係ない部分が含まれていたりすると認識してくれないケースが多いです。

とはいえフリーで使えるデコードライブラリは他に選択肢がないので、贅沢は言えませんよね。
 

このページのトップヘ