Shoeisha Technology Media

CodeZine(コードジン)

特集ページ一覧

Oracleの「Developer」で作成された画面をCurlで実装!

  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加

 この記事では、SCSKが提供する「VBマイグレーション」サービスを紹介します。今回は、Oracle社の「Developer」で作成された画面を、Curlで焼き直しする具体的な実装方法を解説します。

はじめに

 Curlの開発・提供を行っているSCSKでは、VBマイグレーションというサービスを提供しています。これはVisual Basicで作成されたソースをCurlにコンバージョンするサービスですが、Visual Basicに限らず他の言語からでもCurlへ焼き直しすることはできるのか考えました。

 そこで今回は、ERPシステム等で使われることが多いOracle社の「Developer」で作成された画面をCurlで作成し、その過程を紹介します。

 Oracle社のDeveloperとは、Webに対応したOracle独自の4GLアプリケーション開発・実行環境です。利用するデータベースはOracle DBのみですが、Oracle DBとの高い親和性・レスポンスが売りのツールで、PL/SQL(Oracle Database用にデータベース言語SQLを独自拡張したプログラミング言語)で業務ロジックを作成していくものです。

 Curlは次世代Webプラットフォームとして標榜し、その生い立ちは、米国マサチューセッツ工科大学(MIT)の研究室からになります。利用するサーバサービスには制約がありません。詳しくはCurl公式サイトを参照ください。

左:Developer画面 右:Curl画面
左:Developer画面 右:Curl画面

必要な環境

 CurlとDB(AP)サーバとの通信手段には「Curl ORB for java」(以下、ORB)を用います。ORBとは、CurlとJavaをシームレスに結合し、高速なデータ通信を実現するためのツールです。詳しくは下記のサイトをご覧ください。

画面の仕様

 実装するにあたり、画面の仕様を決めておきます。今回は以下の仕様とします。

 「検索ボタン押下時、テーブル[HINMK_TBL]より全件取得し、取得結果を明細行に設定する。」

 とても簡単な一覧検索画面です。

Developerの内部仕様

 前ページの画面仕様をDeveloperにて実現する場合、次のような作業が必要となります。

  • ウィンドウ、キャンバスを定義
  • データブロックを定義(ヘッダ部、明細部)
  • 明細部のデータブロックに対して、テーブル[HINMK_TBL]を結びつける
  • 明細部に項目(HINMK_CD、HINMK_NM)を定義
  • ヘッダ部のデータブロックに項目(検索ボタン)を定義
  • 検索ボタン押下時に、明細部へ遷移するように定義(WHEN-BUTTON-PRESSEDトリガーに go_block('明細部')と書く)
  • 明細部に遷移時、execute_queryを実行するように定義(WHEN-NEW-BLOCK-INSTANCEトリガーに execute_queryと書く)

 ロジックと呼べるものはほとんどなく、プロパティの設定で実装可能なのが特徴です。

Curl+ORBで実装する場合

 Curl+ORBで実装する場合は、サーバ側とクライアント側の各々での定義が必要です。データアクセスをサーバ側(Java)で、画面コントロールをクライアント側(Curl)で実装します。Developerはデータアクセスロジックと画面コントロールロジックが融合して実装されていることが多いため、移行する場合はまず「データアクセスロジック」と「画面コントロールロジック」に分割する必要があります。

サーバ側

 サーバ側はJavaで実装します。検索ボタン押下時の処理として、サービスクラスに以下のロジックを定義します。

  • JDBCを用いて、Oracle DBに対してSQLを実行
  • 実行した結果をデータクラスに設定

クライアント側

 クライアント側はCurlで実装します。

  • RecordGrid(名細部)とボタン(検索部)を定義
  • 検索ボタンに対して、ボタン押下時にサーバ側のサービスクラスを実行するように定義
  • サーバ側から返却された結果をRecordGridに定義

 Curl Developer Centerに掲載されている「Curl ORB for Java」の関連記事も併せて参照ください。

サーバ側の実装

 まず、サーバ側の実装を見て行きましょう。実際に定義するプログラムは「HinmkLst.java」「Hinmk.java」の2つです。

HinmkLst.java

 サービスクラスです。品目一覧画面をコントロールするための[HinmkLst]クラスを定義し、検索ボタン押下時の処理として、[kensaku]メソッドを定義します。JDBCを用いて、Oracle DBに対してSQLを実行し、結果をデータクラス(Hinmk)に設定します。クライアントにCurlを使っていることを意識させない、一般的なJavaでのDBアクセスロジックと同様です。

HinmkLst.java
package sample;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;

import com.curlap.orb.security.RemoteService;

/**
 * HttpSession sample
 */
@RemoteService
public class HinmkLst  {

    public ArrayList<Hinmk> kensaku(String pi_cd) throws Exception{

        //クライアントには、配列(ArrayList)型で返却する。
        ArrayList<Hinmk> hinmklist = new ArrayList<Hinmk>();
        
        try
        {
            /* 初期処理 */
            // Oracle JDBC Driverのロード
            Class.forName("oracle.jdbc.driver.OracleDriver");
            // Oracle に接続
            Connection conn = DriverManager.getConnection
            ("jdbc:oracle:thin:@dbhosts:1521:instancename", "user", "user");
            // ステートメントを作成
            Statement stmt = conn.createStatement();

            /* 主処理 */
            /////SQLを実行する
            ResultSet rs  = stmt.executeQuery("SELECT hinmk_cd,hinmk_nm FROM hinmk_tbl");
            //取得結果をセット
            rs.next();
            while(rs.next())
            {
                Hinmk hinmk = new Hinmk();                      //データクラスの生成
                hinmk.setHinmk_cd(rs.getString("hinmk_cd"));    //HINMK_CDの値を設定
                hinmk.setHinmk_nm(rs.getString("hinmk_nm"));    //HINMK_NMの値を設定
                
                hinmklist.add(hinmk); //1行分のデータとして配列へ設定する。
            }

            /* 終了処理 */
            rs.close();
            stmt.close();

            /////////////////////////////////////////////////////////////////////////////////////////////
            conn.close();

        }catch(Exception wl_excp)
        {
            throw new Exception(wl_excp) ;
        }
        return hinmklist;
    }

    public Object echo(Object v) {
        return v;
    }
}

Hinmk.java

 テーブル[HINMK_TBL]を格納するためのデータクラスです。

Hinmk.java
package sample;

/**
 * データクラス(HINMK_TBLの結果を格納する)
 */
public class Hinmk implements java.io.Serializable {
 
 private static final long serialVersionUID = -5592465168071966675L;

 /* フィールド */
 private String hinmk_cd;   //HINMK_CD
 private String hinmk_nm;  //HINMK_NM

 /* ゲッター・セッター */
 public String getHinmk_cd() {
  return hinmk_cd;
 }
 public void setHinmk_cd(String hinmk_cd) {
  this.hinmk_cd = hinmk_cd;
 }
 public String getHinmk_nm() {
  return hinmk_nm;
 }
 public void setHinmk_nm(String hinmk_nm) {
  this.hinmk_nm = hinmk_nm;
 }
 
}

 サーバサイドで作成するロジックは以上です。

クライアント側の実装

 続いて、クライアント側の実装を説明します。実際に定義するプログラムは「sample1.curl」「Hinmk.curl」の2つです。

sample1.curl

 画面プログラムです。最も魂をこめて作成する部分ですが、ご覧のようにとてもシンプルです。一般的なWebシステムの場合、サーバサイドから返却されたデータを取得する部分が煩雑になりがちですが、Curl+ORBで実現するととてもシンプルな構成となります。

sample1.curl
{curl 6.0, 7.0, 8.0 applet}
{curl-file-attributes character-encoding = "utf8"}
{applet manifest = "manifest.mcurl", {compiler-directives careful? = true}}
{import * from SAMPLE}

||-- 
{let staff:RecordSet = {RecordSet
                           {RecordFields
                               {RecordField "HINMK_CD", domain = String},
                               {RecordField "HINMK_NM", domain = String}
                           }
                       }
}
{let rv:RecordView = {RecordView staff}}

||--明細部(RecordGrid)
{let rg:RecordGrid = {RecordGrid
                         record-source = rv,
                         height = 10cm,
                         width = 7.5cm,
                         display-navigation-panel? = false
                     }
}

||--検索部(検索ボタン)
{def cb1 = {CommandButton
               label = "検索",
               width = 7.2cm,

               ||--ボタン押下時のイベント
               {on Action do
                  
                   ||--サーバにアクセスする
                   def search-service = {HinmkLst server-url = {url "http://curl-svr:8080/curl-orb-server/"}}
                   ||--Javaで作成したサービスクラスを呼び出す。(result-listに結果が返却される)
                   def result-list:#{Array-of any} = {search-service.kensaku ""}

               ||--サービスクラスからの結果をRecordGridに設定します。
                   {if-non-null result-list then
                       {rg.records.delete-all}
                   ||--サーバから返却されたresult-listの件数分Recordに設定します。
                       {for item in result-list do
                           {type-switch item
                            case item:Hinmk do
                               def r = {rv.new-record}
                               set r["HINMK_CD"] = item.hinmk_cd
                               set r["HINMK_NM"] = item.hinmk_nm
                               {rg.records.append r}
                           }
                       }
                       {rg.records.commit}
                   }
                   {search-service.destroy-instance}                   
               }
           }
}
{value {spaced-vbox cb1, rg}}

Hinmk.curl

 サーバ側で定義したデータクラス(Hinmk)と同じ定義を行います。以下のソースコードは、ORBのツールにて自動生成できるのでコーディングは不要です。

Hinmk.curl
package sample;

/**
 * データクラス
 */
public class Hinmk implements java.io.Serializable {
 
 private static final long serialVersionUID = -5592465168071966675L;

 private String hinmk_cd;
 
 private String hinmk_nm;
 public String getHinmk_cd() {
  return hinmk_cd;
 }
 public void setHinmk_cd(String hinmk_cd) {
  this.hinmk_cd = hinmk_cd;
 }
 public String getHinmk_nm() {
  return hinmk_nm;
 }
 public void setHinmk_nm(String hinmk_nm) {
  this.hinmk_nm = hinmk_nm;
 }
 
}

HinmkLst.curl

 サーバ側で定義したサービスクラス(HinmkLst)と同じ定義を行います。こちらのソースコードもHinmk.curlと同様、ORBのツールにて自動生成できるのでコーディングは不要です。

HinmkLst.curl
|||
||| Curl ORB for java (version 0.8)
|||  This code was generated by the Curl code generator automatically.

|||  package name   : SAMPLE
|||  generated date : 2011-10-31 10:31:36.836000
|||

{import * from COM.CURLAP.ORB} 

{define-class public HinmkLst {inherits HttpSessionClient}
 

  {constructor public {default server-url:#Url = null} 
    {construct-super.HttpSessionClient "sample.HinmkLst", server-url = server-url} 
  } 

  {method public {echo v0:any}:any 
    {return {self.invoke "echo", arguments = {FastArray v0}}} 
  } 

  {method public {kensaku v0:String}:#Array 
    {return {self.invoke "kensaku", arguments = {FastArray v0}} asa #Array} 
  } 
 
}

 サーバ(Java側)で作成されたデータクラスをクライアント(Curl側)で受け取って表示しています。サーバ側とクライアント側のデータクラスを同じ定義とすることで、JavaとCurlで異なる言語にも関わらず、それを意識する必要がありません。

Curl ORB for Javaのソースコード自動生成機能について

 Hinmk.curl、HinmkLst.curlの自動生成の詳細は、Curl Developer Centerのコード生成ツール・マニュアルを参照ください。

Developer/Curl+ORBでの実装時の違い

 それでは、Developerでの実装時と、Curl+ORBでの実装時の差異を確認していきましょう。

Developerでの特徴

  • サーバサイド、クライアントサイドを意識することが少ない
  • 単一言語(PL/SQL)にて実装ができる
  • DBアクセスレスポンスが良い
  • 今回のサンプル程度であれば、項目定義、プロパティの設定のみで実装が可能である

Curl+ORBでの特徴

  • サーバサイド、クライアントサイドを分割して実装できる。データクラスを定義していれば並行開発が可能
  • サーバサイドは、一般的なJava+DBアクセスロジックにて実現でき、クライアントにCurl/ORBを使っていることを意識する必要がない
  • Curl側のデータクラスはツールにて自動生成できるため、負荷が少ない
  • 煩雑なサーバ/クライアント間のデータ通信部分のロジックを省略でき、Curl側へのデータ描画、Java側のデータ抽出作成 部分に注力できる
  • ORBはオープンソースで公開されているため、自由なカスタマイズが可能

DBアクセスレスポンスについて

 両者のアーキテクチャーが大きく違うため単純な比較はできませんが、DBアクセスレスポンスを比較しました。テーブル[HINMK_TBL]に1000件のデータを格納し、それを画面に表示するという速度検証を行いました。

 結果は、Curl/Developer共に1秒以下で表示されます。体感はDeveloperが早いですが、1000件程度の表示であれば両者の速度に大差は感じられませんでした。

作業性について

 今回の画面作成の作業性を比較してみます。Developerは、1人で作業し、1時間で作成できました。クライアント/サーバを意識する必要がない反面、分担して作業することができません。Curl+ORBは、サーバサイド/クライアントサイドで担当を分け、2人で作業しました。サーバサイド:30分、クライアントサイド:30分で作成できました。DeveloperもCurl+ORBも トータルでかかる作業時間は大差ありませんでした。Curl+ORBでは自動生成で作成する部分もあるので、”コーディング”する部分は局所的です。

 APサーバの設定については、経験がないと苦戦するという点では、Developer/Curlも同じです。両者共に丁寧な解説サイトがありますので、それに従えば構築できます。Curlは、利用するサーバサービスに依存していないため、特段Curlに関する知識がなくても、一般的なWeb/APサーバを構築するための知識さえあればスムーズにサーバを構築できます。

開発ツールについて

 Developerの開発は、Forms Builderという開発ツールを用います。項目を作成し、プロパティを設定していき、必要に応じてPL/SQLでロジックをコーディングしていきます。画面のエディタも配備しております。

 Curlの開発は、CDE(Curl Development Tools for Eclipse)という開発ツールを用います。Curlのソースコードは、テキストベースですので、前述のコーディングレベルであれば、テキストエディタでも作成可能ですが、開発ツールを用いるとコード補完などコーディングする際に有用な機能が多数あり生産性が向上します。

 また、Ver.8.0.0では便利な機能も多数盛り込まれています。詳細は、こちらをご覧ください。

バージョンアップについて

 開発ツール/実行環境の宿命上、バージョンが存在します。旧バージョンの開発ツールで作成したプログラムを新バージョンにコンバージョンさせるシーンに良く出会うと思います。

 Developerでは、古いバージョンのソースを新しいバージョンのソースにコンバージョンできます。やり方はいくつかありますが、基本的には古いバージョンで作成したソースを新しいバージョンのツールで開き、コンパイルして保存する、というやり方です。(もちろん、バージョン間で変更されたAPIに対する対応は必要です)

 Curlの場合は、ヘラルドと呼ばれる部分に新しいバージョン番号を書きます。今回の例では、ヘラルドに{curl 6.0, 7.0, 8.0 applet}と記載しています。これは、Ver.6、7、8のCurl RTEで稼動することを意味しています。

 例えば、このプログラムをVer.9に対応させたい(記載日時点でVer.9は存在しません)場合は、ヘラルドに

{curl 6.0, 7.0, 8.0, 9.0 applet}

 と書きます。変更後のテストは必要ですが、基本的にはこれでVer.9のCurl RTEでも稼動します(Developerと同様に、バージョン間で変更されたAPIに対する対応は必要です)。

 Developerと大きく違うのは、Curlの場合、{curl 6.0, 7.0, 8.0, 9.0 applet}と記載していれば、単一のソースプログラムでCurl RTE Ver.6.0/7.0/8.0/9.0で稼動させることができることです。個々のバージョンで稼動することを確認する必要がありますが、バージョンアップしたからといって、新バージョンでしか稼動しないということはなく、旧バージョンのCurl RTEで稼動させることも可能です。

本格的にCurlに移行したい場合

 では、前ページまでで説明した、画面の作り替えだけでなく、本格的にDeveloperからCurlへと移行したい場合は、どのようにすればよいのでしょうか。

 残念ながら、Developerで作成されたプログラムをCurlに移行するための専用のツールはありません。しかし、ちょっとした工夫で比較的簡単に移行できます。

Developer側のロジック

 Developerのソースコードは、PL/SQLで作られているため、それらの業務ロジックをOracleのストアドプロシージャに移行させ、Javaにて移行したストアドプロシージャを呼び出すサービスクラスを作成し、Curlより作成したサービスクラスを呼び出す構成にします。こうすれば、スムーズに移行でき、既存資産も活かせます。

  1. テキスト項目にコード入力確定時にコードに紐づく名称を表示(テキスト項目のWHEN-VALIDATE-ITEMにて商品マスタから名称を取得するSQL文を実行し、結果を名称項目に設定)
    テキスト項目のWHEN-VALIDATE-ITEM(Developer側で定義)
    BEGIN
       //商品マスタから名称を取得する。
       SELECT 商品名 INTO :検索条件.商品名 
       FROM 商品マスタ 
      WHERE 商品コード = :検索条件.商品コード
    END;
    
  2. 検索ボタン押下時に在庫情報を取得し、表示(検索ボタンのWHEN-BUTTON-PRESSEDにてDBから各種情報を取得するためのSQL文(カーソル)を実行し取得結果を明細に設定)
    検索ボタンのWHEN-BUTTON-PRESSED(Developer側で定義)
    DECLARE
      CURSOR C_SQL IS
          SELECT 倉庫コード,…..
          FROM 倉庫マスタ,……
          WHERE 品目コード = …...
    BEGIN
      first_record;
      FOR r_SQL  in C_SQL 受注 LOOP
         //明細行に設定
        create_record;
        :明細.倉庫コード := r_SQL.倉庫コード;
        ……………………….
      END LOOP;
    END;
    
Developerでの実装イメージ(在庫照会機能)
Developerでの実装イメージ(在庫照会機能)

Curl+ORB側のロジック

  • Curl

     APサーバ上のサービスクラスを呼び出し、その結果を該当の画面項目に設定

  • Java(APサーバ)

     DBにてテキスト項目のWHEN-VALIDATE-ITEM、検索ボタンのWHEN-BUTTON-PRESSEDを実装したストアドプロシジャを作成し、Java(APサーバ)より実行、その戻り値をJavaのデータクラスに設定するようなサービスクラスを作成

  • DBサーバ

     テキスト項目、ボタンに定義しているトリガーのロジックをストアドプロシジャ(※注1)に移行

    DECLARE
      CURSOR C_SQL IS
          SELECT 倉庫コード,…..
          FROM 倉庫マスタ,……
          WHERE 品目コード = …...
    BEGIN
      first_record;
      FOR r_SQL  in C_SQL 受注 LOOP
         //明細行に設定
        create_record;
        :明細.倉庫コード := r_SQL.倉庫コード;
        ……………………….
      END LOOP;
    END;
    
    BEGIN
       //商品マスタから名称を取得する。
       SELECT 商品名 INTO :検索条件.商品名 
       FROM 商品マスタ
      WHERE 商品コード = :検索条件.商品コード
    END;
    
    ※注1 ストアドプロシジャの定義

     ・テキスト項目のWHEN-VALIDATE-ITEM

     IN:商品コード

     OUT:商品名

     ・検索ボタンのWHEN-BUTTON-PRESSED

     IN:商品コード

     OUT:明細行配列

     を、NESTED TABLEにて定義します。

 業務ロジック・データアクセス部分は全てDB層にて定義しており、APサーバ(Java)層は、ロジックを呼び出すだけのラップサービスです。3層構造ですが、APサーバの役割が小さくてすみます。

Curl+ORBでの実装イメージ
Curl+ORBでの実装イメージ

そのほかの注意点

 Developerは元々C/S環境を源流とする開発ツールで、Curlは、当初より「エンタープライズRIA」に取り組んでいる言語です。C/Sシステムから本格的なWebシステムへ移行するにあたり、いくつか考慮すべきことがあります。

排他制御について

 C/S環境のシステムでは、悲観的排他制御を行うケースが見受けられますが、一般的なWebシステムでは、楽観的排他制御を用いるのが常道です。

セッション管理について

 C/S環境のシステムにおけるDBとのセッションは、1システム利用者=DBセッションとなることがほとんどかと思いますが、Webシステムにおけるセッションは、以下の2つが存在し、1Webクライアント≠DBセッションです。

  • クライアント・Webサーバ間のセッション
  • Web(AP)サーバとDBサーバとのセッション

 C/S環境のシステムにて一時領域にデータを書き込む際にクライアントのキーとしてDBセッションを用いている場合などは、WebのセッションIDを書き込むように変更するなどの考慮が必要です。

参考情報

マニュアル(ヘルプ)

 Curlヘルプドキュメントは、Curl言語の記述方法やAPIの解説方法のほか、各種ツールも紹介しています。このヘルプドキュメント自体も、CurlのAPIで構築されています。

Curl ヘルプドキュメント
Curl ヘルプドキュメント

 特筆すべきは、Curlのソースコードをその場で書いて確認できる機能です。ヘルプに記載されているサンプルコードのほとんどは、その場で実行することができます。また、ヘルプドキュメント自体がCurlのエディタとなっており、その場でコードのカスタマイズを行うことも可能です。

サンプルコードのほとんどはその場で実行可能
サンプルコードのほとんどはその場で実行可能
  • Curlの開発者ガイドHTML版(上記の機能はありません)

     Curl開発環境に付属しているCurlの開発者ガイドなどをhtmlに変換したページ

 マニュアルは、体験版の開発ツールに同梱されています。ダウンロード先はこちらです。

困った際のトラブルシューティング

 両者の言語ともに、サポートサービスは提供しているものの、Web上には一般的な知識として、Javaほどの情報量は出回っていません。Curlには、コミュニティサイトがあり、困った際はこちらに投稿することもできます。Curlを開発しているエンジニアが回答してくれることもあるため、非常に心強いです。

そのほかの公開サイト

  • Curl Apps Gallery

     Curlで作られたサンプルデモプログラムをWeb上にて公開。Curlの技術を使用したアプリケーションの投稿や、投稿されたアプリケーションの検索/実行/ダウンロードが可能

  • Developer Center

     Curl言語技術者向けサイト。Curlの逆引きリファレンス、Curlに関するよくある質問(FAQ)などの有用な情報を多数掲載

セミナー・トレーニング

  • Curl WBT(Web Based Training)

     E-learningツールを使用してオンラインでトレーニングを公開。時間や場所に制限されず、利用者の都合に合わせてトレーニングを進めることが可能

  • 各種セミナー・トレーニング情報

     Curl導入検討から開発、運用に到る様々なフェーズをサポートする「Curl プロフェッショナルサービス」の情報はこちら

  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

All contents copyright © 2005-2020 Shoeisha Co., Ltd. All rights reserved. ver.1.5