Appache Commons CLIを使ってコマンドラインツールを開発します。


Appache Commons CLIによる命令行の設計
通常コマンドライン処理には3つのステップがあります。定義、解析、問い合わせの段階です。この3つのステップを順次説明し、それらをどのようにしてApache Commons CLIで実現するかを例に合わせて議論します。本論文の著者は、ストレージ関連の仕事をしていますので、Serverにデータソースを追加/削除するCLIを設計します。
以下は具体的なアプリケーションシーンであり、ユーザーはCIM(Common Information Model)Serverで管理されている格納データソースを追加/削除することができる。
  • CIM Serverで管理されているメモリを追加します。例えばIBM DS Seriesを追加します。コマンドラインの設計は以下の通りです。
     mkdatasource [-h | -? | --help] 
     mkdatasource [-t string] [-i string] [-p string] [-u string] [-w string] [-n string]
     -h 
     Lists short help 
     -t 
     Sets the HTTP communication protocol for CIM connection 
     -i 
    	 Sets the IPv4 address of the device 
     -p 
     Sets the HTTP communication port for CIM connection 
     -u 
    	 Specifies the user ID for the data source connection 
     -w 
    	 Specifies the password for the data source connection 
     -n 
    	 Identifies the namespace of the CIM connection 
    
     Examples: 
     Add CIM Storage Subsystem 
     mkdatasource –t http –i 9.3.194.11 –p 5988 –u admin –w admin –n root/lsiarray13
     
  • CIM Serverで管理されている記憶を削除します。例えばIBM DS Seriesを削除します。コマンドラインの設計は以下の通りです。
     rmdatasource [-h | -? | --help] 
     rmdatasource [-t string] [-i string] [-p string] 
    
     -h 
     Lists short help 
     -t 
     Sets the HTTP communication protocol for CIM connection 
     -i 
     Sets the IPv4 address of the device 
     -p 
     Sets the HTTP communication port for CIM connection 
    
     Examples: 
     Remove CIM Storage Subsystem 
     rmdatasource –t http –i 9.3.194.11 –p 5988 
    
  • CLI定義フェーズ
    各コマンド行は、アプリケーションのインターフェースを定義するために使用されるパラメータのセットを定義しなければなりません。Apache Commons CLIは、Optionsというクラスを使用してパラメータを定義し、設定します。これはすべてのOptionのインスタンスのコンテナです。CLIでは現在、Optionsを作成する2つの方法があります。1つは構造関数を通して、これは最も一般的で、最もよく知られている方法です。もう一つの方法はOptionsで定義された工場方式によって実現される。
    CLI定義段階の目標結果はOptionsのインスタンスを作成することである。
    上記の具体的なコマンドラインの設計によれば、データソースを追加するためのコードセグメントでOptionsを定義できます。
    明細書1.Optionsコードセグメントを定義する
    				
     //    Options   
     Options options = new Options(); 
    
     //    -h   
     options.addOption("h", false, "Lists short help"); 
    
     //    -t   
     options.addOption("t", true, "Sets the HTTP communication protocol for CIM connection"); 
    
    addOption()メソッドには3つのパラメータがあり、最初のパラメータはこのoptionの単一文字名を設定し、2番目のパラメータはこのoptionに数値を入力する必要があるかどうかを指定します。3番目のパラメータはこのoptionの簡単な説明です。このコードセグメントでは、最初のパラメータはヘルプファイルのリストだけであり、ユーザーがいかなる値を入力する必要はありません。第二のパラメータはユーザがHTTPを入力する通信プロトコルが必要です。この二つのoptionの第二のパラメータはそれぞれfalseとtrueです。完全なコードと注釈は第二章のコマンドライン開発部分を参照してください。
    CLI解析段階
    解析段階では、コマンドラインからアプリケーションのテキストが入ってきます。処理プロセスは、解像度の実装中に定義された規則に従って行われる。CommundLine Parseクラスで定義されているパース方法は、CLI定義段階で生成されたOptionsの例と文字列のセットを入力とし、解析後に生成されたCommundLineに戻る。
    CLI解析段階の目標結果はCommandLineのインスタンスを作成することである。
    上記の具体的なコマンドラインの設計によれば、データソースを追加するためのコードセグメントを使用して、Optionsを解析できます。
    明細書2.Optionsコードのセグメントを解析する
    				
     CommandLineParser parser = new PosixParser(); 
     CommandLine cmd = parser.parse(options, args); 
    
     if(cmd.hasOption("h")) { 
        //            
     } 
    
    コマンドラインにhパラメータがあるかどうかを判断する必要があります。あれば、アプリケーションは短いヘルプ情報を一覧表示する必要があります。完全なコードとコメントは第二章のコマンドライン開発部分を参照してください。
    CLI問い合わせ段階
    問合せ段階では、アプリケーションはCommandLineを照会し、その中のブールパラメータとアプリケーションに提供されるパラメータ値によって、どのプログラム分岐を実行するべきかを決定する。この段階はユーザーのコードにおいて実現され、CommundLineにおけるアクセス方法はユーザーコードにCLIの問合せ能力を提供する。
    CLI問合せ段階の目標結果は、コマンドラインおよび処理パラメータによって得られたテキスト情報をすべてユーザのコードに渡すことである。
    上記の具体的なコマンドラインの設計によれば、下記のコードセグメントを使ってデータソースの追加操作に関する問い合わせができます。
    明細書3.Optionsコードのセグメントを問い合わせる
    				
     //    -t    
     String protocol = cmd.getOptionValue("t"); 
    
     if(protocol == null) { 
        //       HTTP     
     } else { 
     //          HTTP      
     } 
    
    ユーザーがtパラメータを設定すると、get OptionValue()メソッドはユーザーが設定した値を取得します。このパラメータが指定されていない場合、get OptionValue()メソッドはnullに戻ります。アプリケーションは戻り値によってコードの運行を決定します。完全なコードとコメントは第二章のコマンドライン開発部分を参照してください。
    ページの端に戻る
    Appache Commons CLIによるコマンドライン開発
    Apple Commons CLI概要
    Appche Commons CLIは、Appacheの下にある解析コマンド行から入力されるツールバッグであり、このツールパッケージは自動的に出力ヘルプドキュメントを生成する機能を提供しています。
    Appche Commons CLIは複数の入力パラメータフォーマットをサポートしています。主にサポートされているフォーマットは以下の通りです。
  • POSIX(Portable Operating System Interface of Unix)におけるパラメータ形式、例えば、tar-zxvf foo.tar.gz
  • GNUにおける長いパラメータ形式、例えばdu--huoman-readable--max-depth=1
  • Javaコマンドにおけるパラメータ形式、例えば、java-Djava.net.useSystem Proxies=true Foo
  • 短棒パラメータのパラメータ値を持つパラメータ形式、例えば、gcc-O 2 foo.c
  • 長棒パラメータはパラメータ値を持たない形式で、例えばant-projecthelp
  • CLI命令コードの実現
    コマンドラインのプロセスは比較的簡単で、メインフローは設定コマンドラインのパラメータ->解析入力パラメータ->入力データを使って論理処理を行います。下図は、rmdatasourceを例にした運行フローチャートで、実際に実現する過程の一部の論理を図に入れています。
    図1.コマンドライン運転フローチャート
     
    リスト5は、rmdatasourceの実現コードセグメントであり、主なロジックはsimpleTest関数の中にあります。まずResource Bundeleをロードし、実行中の出力情報を設定ファイル(xmlやpropertyファイルなど)に定義しておいて、Resource Bundeleで読み込みます。このように動作環境のlocaleによって、出力情報言語を決定してもいいし、ユーザーに出力情報の言語を指定してもいいです。
    その後、プログラムはOptionsでコマンドラインのパラメータを定義します。パラメータ形式が簡単なので、OptionsのaddOptionを使ってパラメータ設定を作成します。複雑なパラメータ形式があれば、OptionBuiderを使ってOptionを生成できます。例は以下の通りです。
    明細書4.Option Buiderを使ってOptionsコードセグメントを生成する
    				
     Option help = new Option("h", "the command help"); 
     Option user = OptionBuilder.withArgName("type").hasArg().withDescription( 
       "target the search type").create("t"); 
           
        //           java      -D<name>=<value> 
     Option property = OptionBuilder.withArgName("property=value") 
    			 .hasArgs(2).withValueSeparator().withDescription( 
    "search the objects which have the target property and value").create("D"); 
     Options opts = new Options(); 
     opts.addOption(help); 
     opts.addOption(user); 
     opts.addOption(property); 
    
    パラメータ設定後、プログラムはBaicPaser類を使用してユーザが入力したパラメータを解析し、パラメータに–h時のプログラム印刷コマンド行のヘルプ情報(Apache Commons CLIのHelpFormaterで自動生成)を含んでいない場合、プログラムは必要なip、portなどのパラメータを読み取り、チェックします。チェックが通ったら、内部インターフェースを呼び出して、rmdatasourceの操作を行います。
    リスト5.rmdatasourceコードセグメント
    				
     public class RMDataSource { 
    
    	 /** 
     * @param args     
    	 */ 
    public static void main(String[] args) { 
    		 simpleTest(args); 
    	 } 
    
    public static void simpleTest(String[] args) { 
             ResourceBundle resourceBundle = ResourceBundle.getBundle("message", 
    				 Locale.getDefault()); 
    		 Options opts = new Options(); 
             opts.addOption("h", false, resourceBundle.getString("HELP_DESCRIPTION"));
    		 opts.addOption("i", true, resourceBundle.getString("HELP_IPADDRESS")); 
    		 opts.addOption("p", true, resourceBundle.getString("HELP_PORT")); 
    		 opts.addOption("t", true, resourceBundle.getString("HELP_PROTOCOL")); 
    		 BasicParser parser = new BasicParser(); 
    		 CommandLine cl; 
    		 try { 
    			 cl = parser.parse(opts, args); 
    			 if (cl.getOptions().length > 0) { 
    				 if (cl.hasOption('h')) { 
    					 HelpFormatter hf = new HelpFormatter(); 
    					 hf.printHelp("Options", opts); 
    				 } else { 
    					 String ip = cl.getOptionValue("i"); 
    					 String port = cl.getOptionValue("p"); 
    					 String protocol = cl.getOptionValue("t"); 
                         if(!CIMServiceFactory.getinstance().isIPValid(ip))
    					 { 
                             System.err.println(resourceBundle.getString("INVALID_IP"));
                             System.exit(1); 
    					 } 
    					 try { 
                             int rc = CIMServiceFactory.getinstance().rmdatasource( 
    								 ip, port, protocol); 
    						 if (rc == 0) { 
                                 System.out.println(resourceBundle 
                                   .getString("RMDATASOURCE_SUCCEEDED")); 
    						 } else { 
                                 System.err.println(resourceBundle 
                                   .getString("RMDATASOURCE_FAILED")); 
    						 } 
    					 } catch (Exception e) { 
    						 System.err.println(resourceBundle 
                                   .getString("RMDATASOURCE_FAILED")); 
    						 e.printStackTrace(); 
    					 } 
    				 } 
    			 } else { 
                    System.err.println(resourceBundle.getString("ERROR_NOARGS")); 
    			 } 
    		 } catch (ParseException e) { 
    			 e.printStackTrace(); 
    		 } 
    	 } 
     } 
    
    ページの端に戻る
    Appache Commons CLIによる命令行テスト
    CLIのテストは二つの状況に分けられます。内部論理のテストはJUnitで実現できます。便利で、簡潔で、迅速です。CLIの実行は、シナリオ(Windowsではbatスクリプト、Linuxではshellスクリプト)でCLIの実行結果を検証することができます。
    JUnitの運行とテスト
    コードリスト5では、CLIが受信したパラメータは、その1つのStering入力配列から由来することが見られますので、JUnitのTestCaseにString配列を作成して入力をシミュレートします。以下のリスト6は、rmdatsourceのhelpにパラメータがない場合のユニットテストのコードです。方法の戻り値だけをテストしました。
    明細書6.JUnitテストコードのセグメント
    				
     //      –h        
     public void testHelp() { 
    	 String args[]={"-h"}; 
    	 assertEquals(0, RMDataSource.simpleTest(args)); 
     } 
    
     //       –h        
     public void testNoArgs() { 
    	 String args[] = new String[0]; 
    	 assertEquals(1, RMDataSource.simpleTest(args)); 
     } 
    
     //                
     public void testRMDataSource() { 
       /** 
        *                     java rmdatasource -i 192.168.0.2 -p 5988 -t http 
    	 */ 
    	 String args[] = new String[]{"-i","192.168.0.2","-p","5988","-t","http"}; 
    	 assertEquals(0, RMDataSource.simpleTest(args)); 
     } 
    
    CLIの運行とテスト
    開発が完了したら、プロジェクトをjarパッケージにコンパイルしてCLIを実行できます。仮に私達のjarパッケージの名前がrmdatasource.jarであると仮定して、jarカバンのあるディレクトリでjava-jar rmdatasource.jar–hを実行すれば、CLIのヘルプ情報が得られます。同様に、開発されたコマンドラインツールをスクリプトで実行し、コマンドの戻り値と出力をチェックしても良いです。下図のリスト7であるように、コマンドの戻り値と出力情報のコードを取得します。
    明細書7.CLIテストコードのセグメント
    				
     /opt/ibm/java-i386-60/bin/java -jar /tmp/test/rmdatasource.jar -h > /tmp/test/result 
    
     echo "cli return code is $?"
    
     if [ $? -eq 0 ] 
     then 
      while read line 
      do 
        echo $line 
    
      done < /tmp/test/result 
     fi 
    
    ページの端に戻る
    締め括りをつける
    科学的な計算可視化とマルチメディア技術の急速な発展に伴い、ヒューマンマシンのインタラクティブ技術は絶えず更新されていますが、最も伝統的なコマンドラインモードは依然として多くの分野に応用されています。コマンドを暗記する前提の下で、コマンドラインのインターフェースを使うのは、グラフィカルユーザーインターフェースを使うよりも速いです。同時に、コマンドラインモードもお客様の二次開発に有利で、アプリケーションの統合に便利です。Apache Commons CLIは多くの実用的なツールとクラスの実現を提供しています。さらに便利になりました。コマンドラインツールの開発について、本稿では完全な実例を紹介しました。関係読者の今後の仕事に役に立つことを期待しています。
    cliバッグのダウンロード先はクリックしてリンクを開きます。
    apacheのcli項目の住所
    http://commons.apache.org/cli/index.html