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

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

タグ:cobol

このブログエントリの続きのような、関係ないような内容です:
IBM COBOL for Linux 1.1 を使ってみた

もともとは「過去の COBOL 資産をウェブやクラウド環境で活用するにはどうすればいい?」かを考えていて、最初は CGI 化してウェブからうまく呼び出して使えないか、、、と検討していたのですが、「活用」と呼ぶにはそのための準備がなかなかに面倒そうで頓挫していました。要は COBOL エンジニアが少なくなってメンテナンスも難しくなっている昨今、COBOL 資産をどうやって今の環境で活用するか、というテーマは実際に検討してもキレイな答を見つけるのが難しいことを再認識する結果となっています。

といいつつ、「難しいですね~」で終わらせるのもシャクなので自分なりの答を用意しました。それがブログタイトルでもある Node.js の child_process を使う方法です。


Node.js + Express で普通にウェブアプリを作りつつ、COBOL 資産をサブルーチンのように(子プロセスとして)呼び出して動かし、その実行結果をウェブのレスポンスとする、という方法です。その子プロセスとしてコマンドを動かす際に child_process を利用します。ぶっちゃけ COBOL 資産でなくても応用の効く泥臭い方法ですが、コマンドラインパラメータを受け取って動き、結果を stdout へ出力する一般的なタイプのバイナリであれば再コンパイル無しで使えるという大きなメリットのあるウェブ化手法といえます。

言葉で説明するよりも実際のコードを見ていただくのが早いと思っています。まず COBOL 資産(資産といえる代物じゃないけど)として先日紹介した COBOL 版 Hello World を使います。特にこのファイルは x86_64 Linux 向けの実行可能バイナリになっているので、ダウンロードして `$ chmod +x hello` するだけで動きます(`$ ./hello` で "Hello World!" と出力するだけですが)。とりあえず、これを COBOL 資産とみなすことにします。


そしてこのコマンドを呼び出してレスポンスを返すウェブアプリケーションを Node.js + Express で作ります:
https://github.com/dotnsf/hello-cobol-web


アプリケーションの実体となる app.js の中は以下のようになっています:
//. app.js
var express = require( 'express' ),
    { exec } = require( 'child_process' ),
    app = express();
var command = '/home/dotnsf/src/hello/hello';

app.use( express.Router() );

app.get( '/', function( req, res ){
  res.contentType( 'text/plain; charset=utf-8' );
  
  exec( command, function( err, result, stderr ){
    if( err ){
      res.status( 400 );
      res.write( err.message );
      res.end();
    }else if( stderr ){
      res.status( 400 );
      res.write( stderr );
      res.end();
    }else{
      res.write( result );
      res.end();
    }
  });
});

var port = process.env.PORT || 8080;
app.listen( port );
console.log( "server starging on " + port + " ..." );

まず赤字部分で child_process ライブラリを呼び出し、シェルコマンドを実行する準備をしています。次に緑字部分で実際に呼び出すコマンド(この場合は上記 hello コマンド)をフルパスで指定します(コマンドラインパラメータが必要な場合はこのコマンド文字列に含めておきます)。

そして実際にコマンドを呼び出しているのが青字部分です。GET / の HTTP リクエストを受けたら hello コマンドを(JavaScript らしく)非同期に実行し、その実行時や実行結果にエラーがあった場合は HTTP ステータスコード 400 で、なかった場合は(デフォルトの)HTTP ステータスコード 200 でそれぞれの結果を text/plain で返すコードになっています。

上述のコードを Node.js で実行し、GET / を実行すると(hello コマンドのフルパスやパーミッションを間違えていなければ)COBOL 資産の実行結果が HTTP の結果として "Hello World!" と表示されるはずです:
2021042601


専用コマンドのインストール部分が、特に有償ツールなどの場合だとコンテナ化までは難しいかもしれません。ただ COBOL 資産に限らず、形態素解析エンジンのような専用インストールが必要なコマンド・アプリケーションをウェブ化するようなケースでも応用できる便利な方法の紹介でした。

IBM COBOL for Linux 1.1 がリリースされたので、入手できる立場を利用して(笑)使ってみました。


このソフトウェアを使える権利をお持ちの方は IBM のダウンロードページで "IBM COBOL for Linux" を検索すると見つかります。ちなみに x86_64 の RHEL 7 or 8 または Ubuntu 16 or 18 or 20 の LTS リリースがサポートプラットフォームとされています。インストーラーを含む実行バイナリは CC7XYML で検索して見つかるものです:
2021042000


実行バイナリ(COBOL_LINUX86_6.1.tar.gz)を展開すると以下のようなファイルが入手できます。この中の install というファイルがインストーラーです:
2021042001


この install を実行すると実行環境に合わせた標準インストールが実行されます。インストール先フォルダの指定などはできないのですが、インストール時の前提ライブラリなども合わせて導入されるため非常に簡単にインストールできます:
2021042002


RHEL で実行した場合は足りない前提ライブラリが yum でインストールされます:
2021042003


インストールが成功すると "Installation and configuration successful" というメッセージが表示されます。標準インストールの場合、/opt/ibm/cobol/1.1.0/ 以下にモジュールが格納されます:
2021042004


実際に COBOL のプログラムを作ってコンパイルしてみます。とりあえずは Hello World をみようみまねで・・・
2021042005


そしてコンパイラ(/opt/ibm/cobol/1.1.0/usr/bin/cob2)でコンパイル・・・・
2021042006


・・・エラー!?
2021042007


(知らなかったのですが)COBOL は行のどの位置に記述するかによってコードの意味が変わるらしいです。この例では DISPLAY 命令を書く位置を(「タブ=スペース2」派の僕が勝手にインデント数を減らして)変えてしまったので、その意味合いが変わってしまったことが原因のようでした。というわけで、正しい位置に変更:
2021042008


そして再コンパイル、今度は成功しました:
2021042009


そして実行。ちと躓きましたが(苦笑)、無事に Hello World を表示できました:
2021042010


では今度はこいつを CGI 化してウェブブラウザから・・・と考えていたのですが、調べていて不毛な気がしてきて(苦笑)、もう少し別の形でウェブ対応する方向を考えます。できたらここで紹介する予定です。

(2021/04/26 追記)
上述の COBOL 版 Hello World を公開しました:
https://github.com/dotnsf/hello-cobol



このページのトップヘ