14 Oracle Database Cloud - Database Schema Service内のスケジューラを使用したデータのポーリング

Oracle Database Cloud - Database Schema Serviceは、アプリケーション・ランドスケープ内のSOAPおよびRESTサービスを起動できます。

スケジューラと連携してSOAPおよびRESTサービスを起動することにより、Oracle Database Cloud - Database Schema Serviceを使用してアプリケーション内のデータを定期的にポーリングできます。これにより、Oracle Java Cloud Service - SaaS Extension上に構築されたユーザー・インタフェースを使用してこのデータを表示できるようになります。

アウトバウンドSOAP起動を使用したデータのポーリング

Oracle Database Cloud - Database Schema Serviceでは、APEX_WEB_SERVICEパッケージ内にPL/SQL APIが用意されています。

これらのAPIを使用して、SOAPおよびRESTサービスを起動できます。次の例のAPIには、レスポンスの解析、Cookieの管理、およびHTTPヘッダーの管理が可能なプロシージャおよびファンクションが含まれています。

SOAPサービスの起動

MAKE_REQUESTプロシージャまたはMAKE_REQUESTファンクションを使用して、SOAPサービスを起動できます。レスポンスは、Oracle Application ExpressコレクションまたはXMLTYPEとしてそれぞれ返されます。

MAKE_REQUESTプロシージャのシグネチャは、次のとおりです。

APEX_WEB_SERVICE.MAKE_REQUEST ( p_url IN VARCHAR2, p_action IN VARCHAR2 default null, p_version IN VARCHAR2 default '1.1', p_collection_name IN VARCHAR2 default null, p_envelope IN CLOB, p_username IN VARCHAR2 default null, p_password IN VARCHAR2 default null, p_proxy_override IN VARCHAR2 default null, p_transfer_timeout IN NUMBER default 180, p_wallet_path IN VARCHAR2 default null, p_wallet_pwd IN VARCHAR2 default null );

この例では、p_urlはエンドポイント、p_actionはSOAPアクション、およびp_versionはSOAPバージョンです。

プロシージャによってレスポンスはOracle Application Expressコレクション内に格納されます。Oracle Application Expressコレクションを使用すると、1つ以上の非スカラー値を取得できます。コレクションを使用して現在セッション状態にある行および列を格納することにより、特定のセッション中にこれらをアクセス、操作または処理できます。

コレクションは、情報の行を一時的に格納して名前を付けるバケツのようなものと考えてください。コレクションには、APEX_COLLECTIONSビューを介してアクセスでき、データはデータベース内に物理的に格納されています。MAKE_REQUESTプロシージャは、p_collection_nameを介して指定される入力としてコレクションを受け入れ、コレクションを自動的に作成および移入します。コレクション内の戻り値は、ラージ・オブジェクト(LOB)として格納されます。

p_envelopeを使用して、完全なSOAPエンベロープをキャラクタ・ラージ・オブジェクト(CLOB)として送信します。このSOAPペイロードは、MAKE_REQUESTプロシージャを起動する前にPL/SQL本体内で直接構成できます。HTTP基本認可を構成している場合、p_usernameおよびp_passwordを使用できます。WS-Securityヘッダーを使用している場合、認可ヘッダーはSOAPエンベロープのバイナリ・ラージ・オブジェクト(BLOB)の一部として構築されます。

また、次の作業も可能です。

  • p_proxy_overrideを使用して、プロキシを指定します。

  • p_transfer_timeoutを使用して、プロシージャがSOAPサービスからのレスポンスを待機するときにタイムアウトするまでの時間を定義します。

  • p_wallet_pathを使用して、HTTPS関連のウォレット設定のオーバーライド・パスを定義します。Oracle Database Cloud - Database Schema Serviceを操作する場合、このオプションは使用しないでください。

MAKE_REQUESTプロシージャに加えて、Oracle Application Expressには、レスポンスをXMLTYPEとして返すMAKE_REQUESTファンクションが用意されています。MAKE_REQUESTファンクションのシグネチャは、次のとおりです。

APEX_WEB_SERVICE.MAKE_REQUEST ( p_url IN VARCHAR2, p_action IN VARCHAR2 default null, p_version IN VARCHAR2 default '1.1', p_envelope IN CLOB, p_username IN VARCHAR2 default null, p_password IN VARCHAR2 default null, p_proxy_override IN VARCHAR2 default null, p_transfer_timeout IN NUMBER default 180, p_wallet_path IN VARCHAR2 default null, p_wallet_pwd IN VARCHAR2 default null ) RETURN XMLTYPE;

このプロシージャとファンクションの唯一の違いは、ファンクションがレスポンスをXMLTYPEとして返す点です。

SOAPレスポンスの解析

SOAPサービスからのレスポンスは、Oracle Application Expressのコレクション・タイプまたはXMLTYPEタイプとして使用可能になります。

APEX_WEB_SERVICEパッケージには、次のように、MAKE_REQUESTプロシージャまたはファンクションを介して取得されたレスポンスを簡単に解析できるPARSE_RESPONSEファンクションが用意されています。

APEX_WEB_SERVICE.PARSE_RESPONSE ( p_collection_name IN VARCHAR2, p_xpath IN VARCHAR2, p_ns IN VARCHAR2 default null ) RETURN VARCHAR2;

p_xpathおよびp_ns (ネームスペース)を使用して必要なデータを抽出できます。PARSE_RESPONSEファンクションは、コレクションを入力として使用し、VARCHAR2を返します。PARSE_RESPONSE_CLOBファンクションは、同じパラメータをPARSE_RESPONSEとして使用しますが、CLOBを返します。

同様に、PARSE_XMLファンクションは、(MAKE_REQUESTファンクションから返されるとおりに)XMLTYPEを入力として使用し、VARCHAR2を返します。PARSE_XML_CLOBファンクションは、同じパラメータをPARSE_XMLとして使用しますが、CLOBを返します。

解析したデータの表への挿入

標準PL/SQLコーディングを使用して、解析したレスポンス・データをデータベース表に挿入できます。

挿入対象の列の数が少ない場合、PARSE_RESPONSEまたはPARSE_XMLファンクションを使用して個々のVARCHAR2列値を取得し、SQL挿入を即時実行する方が簡単である場合があります。

多くの列がある場合、XML処理APIを使用する方が効率的です。たとえば、MAKE_REQUESTファンクションを使用する場合、レスポンスはXMLTYPEとして取得されます。XMLTYPEXQueryおよびXMLTableと連携して使用することにより、迅速に解析し、データの複数の列を同じ文に挿入できます。同様に、MAKE_REQUESTプロシージャを使用する場合、データはLOBとして返されます。データを解析および挿入する前に、このLOBをXMLTYPEに変換できます。

アウトバウンドSOAPサービスを使用したデータのポーリング(作業例)

前のステップを説明するために、特定の都市の天気データを返す単純なWebサービスについて検討してみます。

このWebサービスには次のWSDLおよびエンドポイントがあると想定します。

  • WSDL: http://example.com/WeatherWS/Weather.asmx?WSDL

  • エンドポイント: http://example.com/WeatherWS/Weather.asmx

起動対象操作がGetCityWeatherByZIPであると想定します。次のコードは、このWebサービスのサンプルのリクエストおよびレスポンスを示しています。

リクエストのサンプル

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:weat="http://ws.cdyne.com/WeatherWS/"> <soapenv:Header/> <soapenv:Body> <weat:GetCityWeatherByZIP> <weat:ZIP>02120</weat:ZIP> </weat:GetCityWeatherByZIP> </soapenv:Body> </soapenv:Envelope>

レスポンスのサンプル

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <GetCityWeatherByZIPResponse xmlns="http://ws.cdyne.com/WeatherWS/"> <GetCityWeatherByZIPResult> <Success>true</Success> <ResponseText>City Found</ResponseText> <State>MA</State> <City>Boston</City> <WeatherStationCity>Boston</WeatherStationCity> <WeatherID>32</WeatherID> <Description>Light Rain</Description> <Temperature>56</Temperature> <RelativeHumidity>97</RelativeHumidity> <Wind>N8</Wind> <Pressure>30.04F</Pressure> <Visibility/> <WindChill/> <Remarks/> </GetCityWeatherByZIPResult> </GetCityWeatherByZIPResponse> </soap:Body> </soap:Envelope>

これらの結果を、4つの列を持つWEATHER_HISTORYと呼ばれる表に挿入するとします。

  • ZIP INTEGER

  • CITY VARCHAR2(32)

  • TEMPERATURE_F INTEGER

  • DATEANDTIME DATE

APEX_WEB_SERVICE APIを使用して、Webサービスを起動し、特定の時刻の温度をWEATHER_HISTORY表に挿入します。

このために、次のスクリプトに示すように、PL/SQLプロシージャを作成します。Oracle Database Cloud - Database Schema ServiceインスタンスのSQLワークショップを使用してPL/SQLパッケージを作成および実行します。

開始する手順:

  1. Oracle Cloud (https://cloud.oracle.com)にサインインします。

  2. マイ・サービスに移動し、Oracle Database Cloud - Database Schema Serviceインスタンスを選択します。

  3. 「サービス・コンソールを開く」をクリックします。

  4. コンソールで、「SQLワークショップ」をクリックします。

  5. 「SQLコマンド」をクリックします。

  6. 次のスクリプトを入力し、「実行」をクリックします。

    create or replace procedure insert_current_temperature (p_zip varchar2) is l_envelope CLOB; l_city_name varchar2(100); l_city_temp varchar2(100); BEGIN -- compose request l_envelope := '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:weat="http://xyz.com/WeatherWS/"> <soapenv:Header/> <soapenv:Body> <weat:GetCityWeatherByZIP> <weat:ZIP>' || p_zip || '</weat:ZIP> </weat:GetCityWeatherByZIP> </soapenv:Body> </soapenv:Envelope>'; -- invoke web service apex_web_service.make_request( p_url => 'http://xyz.com/WeatherWS/Weather.asmx', p_action => 'http://xyz.com/WeatherWS/GetCityWeatherByZIP', p_collection_name => 'WEATHER_CITY', p_envelope => l_envelope ); -- parse response l_city_name := apex_web_service.parse_response( p_collection_name=>'WEATHER_CITY', p_xpath => '//wtr:GetCityWeatherByZIPResponse/wtr:GetCityWeatherByZIPResult/wtr:City/text()', p_ns=>'xmlns:wtr="http://xyz.com/WeatherWS/"'); l_city_temp := apex_web_service.parse_response( p_collection_name=>'WEATHER_CITY', p_xpath => '//wtr:GetCityWeatherByZIPResponse/wtr:GetCityWeatherByZIPResult/wtr:Temperature/text()', p_ns=>'xmlns:wtr="http://xyz.com/WeatherWS/"'); dbms_output.put_line('The current temperature at ' || l_city_name || ' is '|| l_city_temp || 'F' ); -- insert into table insert into WEATHER_HISTORY values (p_zip, l_city_name, l_city_temp, SYSDATE); commit; END;

    コードの説明についてスクリプト内のコメントを参照します。コレクションを返すSOAPサービスを使用する場合、PL/SQLループと一緒にXPath述語を使用して、同様の結果を実現します。

前の例では、XMLTYPEを返すMAKE_REQUESTファンクションを使用することもできます。このXMLTYPEデータは、XMLTableと一緒に使用できます。

XMLTable ('/GetCityWeatherByZIPResponse/GetCityWeatherByZIPResult' passing p_xml_response columns x_city varchar2(32) PATH 'City' …

アウトバウンドREST起動を使用したデータのポーリング

Oracle Database Cloud - Database Schema Serviceを使用してSOAPサービスを起動する場合と同じように、Oracle Database Cloud - Database Schema Serviceを使用してRESTサービスを起動できます。

MAKE_REST_REQUESTプロシージャを使用して、RESTサービスを起動します。

APEX_WEB_SERVICE.MAKE_REST_REQUEST( p_url IN VARCHAR2, p_http_method IN VARCHAR2, p_username IN VARCHAR2 default null, p_password IN VARCHAR2 default null, p_proxy_override IN VARCHAR2 default null, p_transfer_timeout IN NUMBER default 180, p_body IN CLOB default empty_clob(), p_body_blob IN BLOB default empty_blob(), p_parm_name IN WWV_FLOW_GLOBAL.VC_ARR2 default empty_vc_arr, p_parm_value IN WWV_FLOW_GLOBAL.VC_ARR2 default empty_vc_arr, p_wallet_path IN VARCHAR2 default null, p_wallet_pwd IN VARCHAR2 default null ) RETURN CLOB;

ペイロードを送信する方法は複数あります。

  • p_bodyを使用して、ペイロードをXMLまたはJSONとして送信します。

  • p_body_blobを使用して、HTTPペイロードをバイナリBLOBとして送信します(ファイルのポストなど)。

  • p_parm_name/p_parm_valueを使用して、HTTPペイロードをURLでエンコードされた名前として送信するときに名前/値ペアで使用するパラメータの名前を指定します。

APEX_WEB_SERVICEパッケージには、HTTPヘッダーにアクセスするためのAPIが用意されています。これらを使用して、MAKE_REST_REQUESTを起動する前にコンテンツ・タイプを設定します。次に例を示します。

apex_web_service.g_request_headers(1).name := 'Content-Type'; apex_web_service.g_request_headers(1).value := 'application/xml';

APEX_WEB_SERVICEパッケージおよびRESTサービスの詳細は、Oracle Application Expressのドキュメントを参照してください。

スケジューラを使用したポーリング・スケジュールの定義

標準のDBMS_SCHEDULER APIを使用して、APEX_WEB_SERVICEベースのプロシージャをスケジュールできます。

DBMS_SCHEDULERには、次のプロシージャが用意されています。

  • create_program

  • create_schedule

  • create_job

これは、DBMS_SCHEDULERを実装する方法の例です。
dbms_scheduler.create_program (program_name=> 'COLLECT_WEATHER_DATA', program_type=> 'STORED_PROCEDURE', program_action=> 'pkg_1.insert_current_temperature', number_of_arguments => 1, enabled=>true, comments=>'Procedure to collect session information' ); dbms_scheduler.define_program_argument (program_name => 'COLLECT_WEATHER_DATA', argument_name => 'p_zip', argument_position => 1, argument_type => 'INTEGER', default_value => 0); -- daily at 23:00 dbms_scheduler.create_schedule (schedule_name => 'NIGHTLY_WEATHER_DATA', start_date=> trunc(sysdate), repeat_interval=> 'FREQ=DAILY; BYDAY=MON,TUE,WED,THU,FRI,SAT,SUN; BYHOUR=22;', comments=>'Runs every night at 11pm'); -- run every hour, every day dbms_scheduler.create_schedule( schedule_name => 'HOURLY_WEATHER_DATA', start_date => trunc(sysdate), repeat_interval => 'freq=HOURLY;interval=1', comments => 'Runs every hour'); dbms_scheduler.create_job (job_name => 'COLLECT_WEATHER_DATA_FOR_CITIES', program_name=> 'COLLECT_WEATHER_DATA', schedule_name=>'HOURLY_WEATHER_DATA', enabled=>true, auto_drop=>false, comments=>'Job to collect temperature of cities every hour'); dbms_scheduler.set_job_argument_value (job_name => 'COLLECT_WEATHER_DATA_FOR_CITIES', argument_position => 1, argument_value => 'value');

次の文を使用してジョブ・ステータスを参照できます。

select * from user_scheduler_jobs; select * from user_scheduler_job_run_details

温度の詳細のロードに関する前の例で、every hourは説明のみを目的として使用されました。JCS - SaaS ExtensionおよびOracle Database Cloud - Database Schema Serviceが含まれるエンタープライズ・クラス・ユースケースのより一般的なシナリオでは、オフピーク時の複数のデータ・レコードのロードを扱います。

このようなシナリオでは、レコードごとに個別にMAKE_REQUESTを起動するのではなくデータのコレクションを返すWebサービスを使用します。Webサービスからデータがコレクションとして 返される場合、PL/SQLを使用してコレクション・レスポンス・データを処理できます。大規模なデータ・セットの場合、データをチャンクとして処理します。

DBMS_SCHEDULERの詳細は、Oracle Application Expressのドキュメントを参照してください。