レベル: 中級 Michael Abernethy, Software Engineer II, FIT Team, IBM China Development Lab Kulvir Bhogal (kbhogal@us.ibm.com), Software Engineer, FIT Team, IBM China Development Lab
2002年 7月 01日 この記事では、UPCシンボルとUPCバーコードに関して、Javaを使用してUPCバーコードから情報を読み取る方法について説明します。さらに、IBM DB2データベースを中心に展開する企業の業務を、促進し系統立てる方法について説明します。この記事で説明されているサンプル・アプリケーションには、ダウンロード可能なコードが含まれています。
はじめに
辺りを見回すと何が見えますか。もしあなたが他のプログラマーに囲まれているソフトウェア・プログラマーだとすれば、あまり良い眺めではないはずです。といっても、パーティションを隔てて働く同僚の方々のことではありません。目前に散らばるバーコードのことです。バーコードは、ペースの速い経済においてその機能が急速に採用され、いたる所で見られるようになりました。宅配便の追跡から図書館の本の貸出に至るまで、あらゆる用途で利用されています。
この記事では、シマウマのようなこの黒と白のしま模様について詳しく考察し、IBM DB2データベースを中心に展開する企業の業務を促進し系統立てるために、どのようにJavaを活用すべきかを説明します。
この記事の理解を深めるために、jmart.jar コード・ファイルと必要なcommポート・ファイルであるbarcode.zip をダウンロードすることをお奨めします。
行間ならぬ線間を眺める
バーコードにはさまざまなタイプのものがありますが、この記事ではUPCバーコードのみに焦点を当てます。UPCとはUniversal Product Code (汎用製品コード) の略語です。このコードは、もともと食料品店のレジ・カウンターにおける精算業務の迅速化と在庫の正確な把握を目的に作成されたものですが、その成功に刺激されて、そのアイデアは他の小売商品にもあっという間に普及しました。
商品用UPCは、実際にはUniform Code Council (UCC) という会社が発行しています。つまり、UCCは2つの異なる商品に同じUPCコードが割り当てられないようにする機関と考えることができます。このシステムへ参加する許可を得ようとするメーカーは、UCCに登録申請し、年会費を支払う必要があります。UCCは、それを受けてメーカー識別番号を発行します。
UPCシンボルは通常、次の2つの部分からなります。
- 機械可読バーコード
- 人間が読み取れる12桁のUPC番号
UPC番号の最初の6桁はメーカー識別番号で、次の5桁はアイテム番号です。メーカーは、複数の商品に同じアイテム番号を割り当てないようにする責任があります。つまり、メーカーが販売するすべての商品に異なったアイテム番号を付ける必要があります。さらに、商品にさまざまなサイズの詰合せまたは再詰合せがある場合も、それぞれ固有のアイテム番号が必要です。
ここまで、12桁のUPC番号のうちの11桁についてのみ説明しました。最後の桁はチェック・ディジットです。バーコードの知識にあまり深入りするのはやめて、最後の桁はスキャンしたUPCシンボルが正確にスキャンされているかどうかを確認するためのものであるという程度にとどめておきましょう。しかし、ここで立ち止まって、利用できるすべてのUPCコードについて詳しく調べたい方もいらっしゃることでしょう。そうした方のために付け加えておきますが、UPCコードには12桁でないものもあり、そうした短縮タイプのものはゼロ抑制バーコードと呼ばれます。この記事に付属するサンプル・コードは、そのままでは短縮タイプのバーコードには対応しませんが、短縮UPCコードに対して動作するように適合させることは簡単にできるはずです。
プロジェクトの概要
それでは我々のプロジェクトの話に移りましょう。UPCコードに格納されている情報は、メーカー番号とアイテム番号だけです。価格や在庫数量などに関する情報はUPCシンボルに格納されていませんが、これは理にかなっています。そのようにしてしまうことは、そうした設定が価格の変更や在庫の変動に対応できないため、賢明な方法ではありません。では、どのような仕組みで対応しているのでしょうか。レジ・カウンターのスキャナーでUPCコードをスキャンすると、スキャンされたUPCコード情報は、キャッシュ・レジスターによってPOS (販売時点管理) コンピューターに送信されます。POSコンピューターは、スキャンされた商品に関するあらかじめプログラムされた情報を返します。その情報に価格、在庫数量、その他の要求された情報を入れておくことができるわけです。
このBarCodeScannerプロジェクトの目標は、前パラグラフで説明した仕組みをエミュレートすることです。我々のコードでは、シリアル・ポートに接続可能なスキャナーからのデータを処理します。このデータを使用すれば、近くの食料品店で商品補充係が行っている作業を皆さんが行えるようになります。近所にあるなじみの食料品店をJ*Martと呼ぶことにします。IBM DB2データベースはバックエンドとして働き、各商品に関する情報を格納します。前置きはこれくらいにして、実際に各部を見ていきましょう。
バックエンド
バックエンドにはDB2データベースを使用し、これをPOS データベースと呼ぶことにします。DB2コマンド行で以下のステートメントを実行することによって、データベースを作成します。
CREATE DB POSDB
次に、データを格納するための表が必要です。以下の表は、データベースで必要と思われる項目をまとめたものです。
| プロパティー名 | 値の例 | データベース列名 | 列の型 |
|---|
| アイテム番号 | 12345 | ITEMNUMBER | Integer | | メーカー識別番号 | 12345 | MANUFACTURERNUMBER | Integer | | 製品名 | Doritos | NAME | Varchar(40) | | メーカー名 | Frito-Lay | MANUFACTURERNAME | Varchar(40) | | 数量 | 23 | QUANTITY | Integer | | 価格 | 1.67 | PRICE | Decimal(5,2) |
以下のステートメントを実行して表を作成します。
Create Table posTable (Itemnumber Integer NOT NULL, ManufacturerNumber Integer NOT NULL, name varchar(40) NOT NULL,manufacturerName varchar(40) NOT NULL, quantity Integer NOT NULL, Price decimal(5,2) NOT NULL)
上記のデータベース列はすべて、新規レコードがNULL値を含んでいないことが要件となっている点に注意してください。
フロントエンドは、次のようなさまざまな方法でデータベースとやり取りすることができます。
- 新しい商品をデータベースに入力する
- 既存商品の数量を更新する
- POSデータベースから商品を完全に削除する
- データベース内の既存商品に関する情報を取得する
上記の作業を実現するために、このJavaプログラムではJDBC (Java Database Connectivity) を使用してIBM DB2データベースとやり取りします。ここで、com.jmart.dbaccess 内のコードをもう一度見直すと参考になるでしょう (ダウンロードをまだ行っていない方は、JARファイルをダウンロードしてください)。特に、Database クラスは、DB2データベースとの接続を容易にするhelperクラスです。DatabaseAccess クラスは、関数delInventory、qryInventory、およびupdInventory を含むクラスです。コードは文書化されているので、それほど頭を悩ませなくても動作を理解できるはずです。
これらのメソッドは、InventoryData という受信パラメーター・タイプを持っています。com.jmart.data パッケージの一部であるInventoryData クラスは、データの受け渡しをするための一時的格納場所として、プロジェクト全体にわたって使用されます。Javaプログラマー用語で言えば、InventoryData クラスは一種のJavaBeanコンポーネントと考えることができます。このクラスは、通信経路として働きます。Javaにおけるオブジェクトが参照によって受け渡されるという点を、このコード全体にわたってフルに活用しています。
スキャンの概要
 |
必要なcommポート・ファイル
BarCodeScannerを実行するには、barcode.zip ファイルをダウンロードし、そのZIPファイルを正しくインストールする必要があります。
comm.jar - シリアル・ポートまたはパラレル・ポートを使用するBarCodeScannerやその他のアプリケーションを実行するのに必要なクラスを含んでいます。アプリケーションを実行する際には、クラスパスがこのJARファイルを指していることを確認してください。
javax.comm properties - このファイルは、JREのlibディレクトリー内に置きます。
win32comm.dll - このファイルは、Windowsディレクトリー (例えばc:\Windows) 内に置きます。
その他のOS上でこのプログラムを実行する場合は、必要なdllファイルを探してください。
|
|
信じられないかもしれませんが、バーコード・スキャンはかなり標準化されています。今日では、PCのCOMポートに接続できるハンドヘルド・スキャナーを購入することも可能です。スキャナーがCOMポートに送信する信号は、受信ストリームをlistenするように組まれたプログラムによって受信することができます。listen機能は、Javaの世界ではかなりプリミティブです。とはいえ、そのプリミティブ性こそが問題を簡単にしてくれるのです。受信スキャンはバイト配列としてシリアル・ポートに送られますが、これを有用な情報に変えるのはプログラマーの仕事です。
BarCodeScannerの実装そのものは、それほど難しくありません。というのは、我々が取得しようとしているのは情報であり、そしてその情報を入手するための構文解析に便利なストリングに変えることは我々の仕事であることがわかっているからです。この情報をシリアル・ポートまたはパラレル・ポートから収集するのに必要なフレームワークは、javax.comm パッケージによって提供されます (javax.comm パッケージの詳細については参考文献を参照)。
javax.comm パッケージは、ポートの処理やそこから情報を検索する方法に関して、ごく基本的な機能しか備えていません。しかし、今や21世紀であり、オブジェクト指向 (OO) は1998年の昔から大いに進歩しています。そこで我々は、バーコード・スキャナーを他の確立したJava設計モデルのように動作させるために、バーコードがスキャンされるごとにBarCodeEvent を起動する、バーコード用のイベント / リスナー・モデルを作成しました。その意味では、ボタンを押したりマウスをクリックしたりするのと同様に、バーコード・スキャナーを扱い、プログラムすることができます。では、コードの細部を見ていきましょう。
BarCodeScanner
BarCodeScanner クラスのコンストラクターは、ポートを作成し、バーコード・スキャナーの動作を制御するすべてのパラメーターを設定します。これらの設定の大部分は、使用するバーコード・スキャナーに合わせて変更することができます。使用するバーコード・スキャナーの設定を確認した上で、それに応じてコードを調整するか、あるいは (なるべくなら) コードから該当部分を除去し、その部分をプロパティー・ファイル内に置いてください。
BarcodeScannerコンストラクター
CommPortIdentifier commPort = CommPortIdentifier.getPortIdentifier("COM1");
serialPort = (SerialPort)commPort.open("Barcode Scanner",3000);
inputStream = new BufferedReader (new InputStreamReader
(new BufferedInputStream(serialPort.getInputStream())));
serialPort.setInputBufferSize(200);
serialPort.addEventListener(this);
serialPort.notifyOnDataAvailable(true);
serialPort.setSerialPortParams(BAUD_RATE, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
|
シリアル・ポートをオープンし、listen中にしたら、読み取られたバーコードをいつでも受信し、解釈できる状態にする必要があります。javax.comm は、ポートに対する独自のイベント / リスナー・インターフェースとして、serialEvent() メソッドを備えています。このメソッドは、バッファーにデータが追加されたことをクラスに通知します。次に、このコードについて説明します。
入力ストリームを使用してバイト配列をStringに変換するのですが、バーコード・スキャナーやバーコードの種類によっては、以下の問題が生じることがわかりました。
- 約100文字を超える大きなバーコードを扱う場合、バッファーが一部しか満たされていないときとバッファーが完全に満たされたときの2回、serialEventsが起動されます。この問題を回避するには、バッファー内のデータが完全でないときにはイベントを無視し、データが完全になるのを待ってリスナーに渡すのが最も簡単です。
if (inputStream.available() < length)return; |
- 一部のバーコード・スキャナーは、各String読み取りの終わりにキャリッジ・リターン、または各改行文字(あるいはその両方)、を挿入します。これを解決して、コードをどんなバーコードでも使用可能なものとするためには、バーコードの長さよりも大きなバッファーを作成し、Stringを作成する際に必要な文字のみを使用するようにします。つまり、一部のバーコードが末尾に持つ余分な文字を無視するということです。
barCodeString = new String(buffer, 0, length); |
最後に、バーコードが読み取られ変換されたところで、新しいStringのすべてのリスナーに通知する必要があります。しかし、リスナーのすべてのbarCodeScanned() メソッドを繰り返し実行するのは時間がかかります。特に (この場合のように) データベースの照会があるときでは、なおさらです。Java AWT (Abstract Window Toolkit) モデルでは、actionPerformed() が最初のイベントに対して完了していない場合、ボタンを2回クリックしてもActionEventsが2回起動することはありません。バーコード・スキャナーの場合、高速に読み取ったときにバーコードが欠落すると困るため、これは問題となります。したがって、バーコードの読み取りごとに新しいスレッドを作成し、AWTスレッド上でこのスレッドを呼び出し、待機させることにより、「高速連写」が行われた場合にバーコードが欠落しないようにする必要があります。
バーコードの読み取りごとに新しいスレッドを作成することにはマイナス面もあります。それは、ロック、モニター、競合状態など、スレッド化に関するあらゆる一般的な問題が生じることです。こうした問題については、読者の皆さんも、大学のOSクラスでプログラムの提出期限前日の真夜中に無視しようとした経験があるかと思います。本論から外れてしまいましたが、デモ・アプリケーションではこれらの問題には、レジ・カウンターのような用途ではユーザーがバーコードを「高速連写」することはないという理由で、対処していませんが、スレッド・セーフのキューとsynchronizedブロックにより解決できます。
GUI
このシンプルなGUIは、アプリケーションの主目的ではありませんが、これを見ればアプリケーションにおけるバーコード・スキャナーの利用方法がわかります。これは、MVC(モデル - ビュー - コントローラー)デザインを用いて構成したものです。また、J*Martアプリケーションを起動するメイン・メソッドもInventoryView クラス内にあります。
モデル
InventoryData は、このアプリケーションにおいてモデルとなるもので、ビューからデータベースに渡す必要があるすべてのデータを格納するシンプルなJavaBeanです。
ビュー
InventoryView は、このアプリケーションを実行するのに必要なすべての情報を表示するもので、いくつかのシナリオに対処しています。
上記のシナリオでは、ユーザーは空の表から始めてデータベース内の在庫を完全に管理することができます。
コントローラー
InventoryController は、DatabaseAccess クラスへのゲートウェイとして働き、BarCodeScannerを処理し、表示する情報をInventoryView に渡します。
まとめ
この小さなアプリケーションの目的は、バーコードを処理し、そのバーコードに含まれる内容を検索キーとして使用してデータベースから情報を検索するのに役立つフレームワークを開発する方法を示すことです。このアプリケーションはUPCシンボル用に調整されていますが、BarCodeScannerのコードは、プロパティー設定にいくつかの変更を加えるだけで、あらゆるバーコード体系に対して、また市販されているすべてのバーコード・スキャナーに対して完全に再利用可能です。
ダウンロード | ファイル名 | サイズ | ダウンロード形式 |
|---|
| i-barcode.zip | | HTTP | | i-jmart.jar | | HTTP |
参考文献
著者について  | 
|  | Michael Abernethyは現在、WebSphere System Management Functional テスト・チームのリーダーとして働いています。以前は4年間WebSphere Servicesチームで働いており、WebSphere上の企業アプリケーションの作成や展開を行っていました。暇な時にはSwingやUI開発で遊んでいます。 |
 | 
|  | Kulvir Singh Bhogalは、IBMコンサルタントとして、米国中のお客様サイトでJava中心のソリューションの考案および実装を行っています。 |
記事の評価
|