【Oracle】Oracle Integration Cloudで使用できるjavascriptのコードの記述ルールの調査


Oracle Integration Cloud(OIC)で自作のJavaScriptライブラリが使えるらしいので、前回のXLST関数の調査と似てますが、どこまで使えるのか、どんなことができるのか、試してみました。
※version 19.1.3.0.0 (190129.1200.23460)にて確認


 


 
【もくじ】

0.はじめに
1.無名関数を使用する
2.var以外の変数宣言を使う
3.functionブロック外に宣言した変数を使う
4.ラムダ式(アロー関数)を使う
5.JSONユーティリティを使う
6.XMLHttpRequestを使う
7.jqueryの記法を使う(ajaxを呼び出す)
8.Node.jsを使ってみる
9.おまけ:日本語コメント




           0.はじめに

OICの統合のメインメニューから「ライブラリ」を選択します。



ライブラリの一覧画面が表示されるので、右上の「登録」を押します。



登録用の情報入力ウインドウが出てきますので、作成済のjsファイルを「ファイルを選択」から選択してアップロードします。
管理用の名前等を入力して「作成」ボタンを押します。


これで基本的には登録完了ですが、Javascriptコードの記述内容によっては、登録ができないケースや、登録できても有効な関数と認められないケースがあります。
たとえば登録できないケースでは以下のようなエラーメッセージが出てきます。

 

また、登録できても有効な関数と認められない場合は、この先の画面で対象の関数を選択したときに以下のようなワーニングメッセージが出てきます。



この「登録ができないケース」や「登録できても有効な関数と認められないケース」が、前回のXSLT関数同様、結構クセがあるようでして…
一応、OICのHELPに、jsライブラリの取り扱いに対する簡単なルールや考え方の記載がある他、オラクルの社員の人が書いたブログにも近いことが書かれた記述があります(両方とも英語ですが…)

例えば、このHELPやブログに記載がありますが、

// OIC的にはNG  
function add(param1 , param2) {  
  return param1 + param2;  
}  


認められていません。(なぜだ…)
「値をreturnする場合は、return用の変数をちゃんと定義しろ」というのがOIC側に登録する際のルールになっているようです。
つまりこの場合は

// こっちはOK  
function add(param1 , param2) {  
  var returnValue = param1 + param2;  
  return returnValue;  
}  


と、書かなければなりません。

これについては↑のブログには「OICでメタデータを生成できないから」といった旨の理由が記載されています。
(変数なくても関数名からなんとなくメタデータ作れるんじゃねえの…とか…ブツブツ)

他にもいろいろルールありそうなので探ってみました。
以下に試した種類ごとにコードと結果を載せておきます。
なお、以下に紹介するものは、いずれも単独のJavascript関数としては問題なく動作することを確認済です。
(まあどれも大した関数ではありませんが…)

           1.無名関数を使用する

コード登録可否有効関数判定実行可否

function getTest1() {  
   var getTestFunc1 = function() {  
      var test = "test1";  
      return test;  
   };  

return getTestFunc1();
}

×※ ×※


これはfunction内にもう一つ無名関数を定義して、それを呼び出す関数です。
結果的にはただの文字列返却をしてるだけですが。
これはOIC的にOKでした(有効な関数と認められました)。
しかし実は罠があり、内部に一つ関数を用意すると、OICが最終的に関数定義として採用するメタデータはそっちのほう(内部定義した無名関数のほう)が優先されるらしく、実態と乖離してしまいます。
例えば

function getTest8() {  
  var param1 = 1;  
  var param2 = 3;  
  var func = function (arg1,arg2) {  
    return arg1 + arg2;  
  };  
  var param3 = func(param1,param2);  

return param1;
}


とすると、内部で定義している無名関数funcが引数を2つとることが優先されて、最終的にOICの画面上以下のような入力定義を設定させられる形になります



見ての通り、「getTest8()」は引数を必要としないのにも関わらず、OICで呼び出す際に引数を強要される形になるので、関数の実態と乖離しています。
よって無名関数の使用は、OIC的には登録可能で問題ないとしても実態としてはNGと考えておくべきでしょう。
というかこれ単にOICのバグですね。w

まあOIC上に自作のfunctionを定義する前提で、中にもう一つfuncitonを用意する意図があまり考えつきませんが…
とりあえず無名関数は使えないというのが結論になるようです。




           2.var以外の変数宣言を使う

コード登録可否有効関数判定実行可否

function getTest2() {  
  const testConst = "const";  
  return testConst;  
}  
× × ×


varではなくconstを使って変数(というかもはや定数)を宣言しています。
しかし、結論から言うとこれはNGです。
登録を認めてくれません。

というかOIC的にはvar以外の変数宣言をそもそも認めていません。
従ってletを使った以下のような変数宣言

function getTest2() {  
  let testConst = "let";  
  return testConst;  
}  


も同様にNGです。

個人的にはこれには若干「?」を感じます。
まあconstに関しては、少なくともfuncitonブロック内で使う必要性があまり思いつかないので百歩譲ってよしとしても、letは別に問題ないはずです。
むしろ変数のスコープ的もletを使うべきなのでは?って感じがしますが。
「let」「const」という文字を見た瞬間に拒否反応を起こしてしまうようです。
う~ん。。。
(これ以外にも本項でいくつか関数の種類を紹介しますが、いずれもしつこく「var」を使って変数定義しているのはこれが理由になります)




           3.functionブロック外に宣言した変数を使う

コード登録可否有効関数判定実行可否

var test3FunctionReturn = "test3";  
function getTest3() {  
  return test3FunctionReturn;  
}  
× × ×



functionのreturn値の変数がfunctionブロックの外に定義されているものです。
単独のJavascriptとしては別になんの問題もありませんが、これもOIC的にはNGです。
「OICから呼び出される関数は、その関数ブロック内で全ての処理が賄えていること」を前提としているようですね。
ブロック外に定義した変数は使えませんでした。




           4.ラムダ式(アロー関数)を使う

コード登録可否有効関数判定実行可否

function getTest4() {  
  var arrow = () => {  
    var returnValue = "test4";  
    return returnValue;  
  };  
  return arrow();  
}  
× × ×



処理内容としては「1.無名関数を使う」とほぼ同じです。
記法がラムダ式(アロー関数定義)になっただけです。
しかしこれはOIC的にNGです。
登録を許可してくれません。
他のNG系と同様で、何が悪いんだかわかりませんが、まあ、そういわれれば、逆にあえてラムダ式で記述する必要性も感じませんので、別にいっか、って感じでもありますね。




           5.JSONユーティリティを使う

コード登録可否有効化可否実行可否

function getTest5() {  
  var test5Json = {  
    "test5" : {  
       "name" : "test5",  
       "id" : "12345"  
    }  
  };  

var test5JsonString = JSON.stringify(test5Json);

return test5JsonString;
}



jsonオブジェクトの変数を定義した後、それをJSON.stringifyで文字列に変換して返却する関数です。
これはまあ予想通りといえばそうでしたが、OIC的にOKです。
全部試してるとキリがないのでやりませんが、いわゆる標準ビルトインオブジェクトは問題なく使えるようです。(使えるような気がします)




           6.XMLHttpRequestを使う

コード登録可否有効関数判定実行可否

function getTest6() {  
  var data = " ";  
  var xhr = new XMLHttpRequest();  
  xhr.onreadystatechange = function() {  
    if(xhr.readyState == 4) {  
      if(xhr.status == 200) {  
        data = xhr.responseText;  
      }  
    }  
  };  
  xhr.open("GET","https://www.google.co.jp/",true);  
  xhr.send();  

var test6Return = data;
return test6Return;
}

×


XMLHttpRequestを使って外部のリソース(このケースだとhttps://www.google.co.jp/)にリクエストを送り、レスポンスを受け取ってそれを文字列で返却する関数です。
XMLHttpRequestの性質上非同期通信ですが、使い方としては同期通信の処理のイメージで使用させます。
このケースでは、APIを呼び出すというよりは、ただの静的ページにアクセスして、返ってきたHTML情報を何もせずそのまま返却しているので、「curl https://www.google.co.jp」と内容的にはほぼ同じです。
なお、成功することを前提としているため、エラー時の処理のハンドリングは定義していません(普通ならあり得ませんがw)

この関数はOIC的にOKでした。
少なくとも登録自体は認められすし、有効な関数とも判定されます。
よってそのまま統合定義に組み込むことができます。

しかし、実際に組み込んで動作させると、内部エラー(Internal Server Error;HTTP 500)が発生します。

{  
  "type" : "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.1",  
  "title" : "Internal Server Error",  
  "detail" : "Internal server error. Please contact oracle support for details.",  
  "o:errorCode" : "500",  
  "o:errorDetails" : [ {  
    "type" : "UnMappedFault:NA",  
    "instance" : "NA",  
    "title" : "Encountered error(s) while executing JavaScript:Review JavaScript error(s) and fix them:\nerror: null@45 -> ReferenceError: \"XMLHttpRequest\" is not defined.\n   at: function=getTest6, loc=js/TEST_01.00.0000/test.js, line=45\n",  
    "o:errorPath" : "NA",  
    "o:errorCode" : "NA"  
  } ]  
}  


要するに「XMLHttpRequestなんてオブジェクトは使えねえぜ(XMLHttpRequest\" is not defined.)」ってことのようです。
じゃあ有効な関数って判定するなよ…って感じですが、まあ、登録時にはfunction内のコードの詳細はいちいち見ていないってことですね。
Javascriptはインタプリタ方式だし、文法の致命的な誤り以外はその場では判断できないってことなのかもしれません。

 




           7.jqueryの記法を使う(ajaxを呼び出す)

コード登録可否有効関数判定実行可否

function getTest7() {  
  var data = "";  
  $.ajax({  
    type: "get",  
    url:"https://www.google.co.jp",  
    dataType: "html"  
  }).done(function(response){  
    data = response;  
    console.log("complete,response="+data);  
  });  

var test7Return = data;
return test7Return;
}

× ×


処理内容的には「6.XMLHttpRequestを使う」と同じです。
単に書き方がjqeuryを使ったもの($.ajax~)になっただけです。

知っての通り、「$」による記法をするためにはjqeuryの読み込みが必要です。
なので、「jqueryを読み込み」という隙すら与えられていないこの関数だけでは、もしかしたら無理かもな、と思いましたが、意外にもこれはOIC的に登録OKでした。
動作時点でjqueryを読み込んでるってことなんですかね。
ただし、doneに記述しているコールバック関数が1.の無名関数と同じ扱いになるようで、この「getTest7」という関数自体は引数なしですが、OICに登録すると引数を1つとる定義になってしまっています。
よって結果的には「登録はできるけど使えない」というのが結論となるでしょう。(そういう意味で有効関数判定を×にしました)

そしてさらに言えば、実際に実行すると「6.XMLHttpRequestを使う」と同じでInternal Server Errorが発生します($\ is not definedって言われる)
総合的に見て「使えない」ってことですね。




           8.Node.jsを使ってみる

コード登録可否有効関数判定実行可否

function getTest9() {  
  var os = require("os");  
  var hostname = os.hostname();  

return hostname;
}

×



osモジュールを読み込んでホスト名を取り出し、返却するだけの非常に簡単な処理ですが、Node.jsのrequire関数を使っています。
これは登録自体は可能で、有効な関数判定もOKでした。
しかし実行すると「6.XMLHttpRequestを使う」「7.jqueryの記法を使う(ajaxを呼び出す)」と同じInternal Server Errorが発生します。("require" is not defined.)
「require」が使えないみたいです。
というわけでこれも使えないということになるようです。




           9.おまけ:日本語コメント

コード登録可否有効関数判定実行可否

// テストだよ~~ん  
...(略)...  
×



これはOKです。
文字コードをShift_JISにしてますが、登録時に文句言われることもありませんでした。
サロゲートペアとかの、変な文字使ってるとどうなるかわかりませんが…
ただ、コメントは、OICに登録した時点で消滅するうえ、OICの関数ライブラリ自体にdescriptionをつけられることを考えると、OKというより、「単にOIC上で無視されてるだけで書いている意味がない」というほうが実態に即していますね。
実際、上記にあるNG系の記述、例えばラムダ式のコードなんかを

//function getTest4() {  
//  var arrow = () => {  
//    var returnValue = "test4";  
//    return returnValue;  
//  };  
//  return arrow();  
//}  


とすると、この部分が無視されて問題なく登録できました。
「コメント行は無視している(そこにどんなに破綻したコードがあっても問題ない)」というのがOICのライブラリ登録ルールのようですね。




総括として、あくまで個人的な感想ですが「あんまり自由なことできないな」という感じですね。
コーディングのルールやら云々はまあ目を瞑るとしても、「できること」があまり多くないという実感です。
割かし役に立ちそうなのは5.の標準ビルドイン関数の利用くらいですかね。
といいつつ、5.でJSONを使ったのは、6.のXMLHttpRequestとかと組み合わせていろいろ加工できたら幅が広がるな、と思ってのことだったのですが、6.が使えないなら単独利用する意味があまり見つからないし…
妙にガチガチなコーディングルールを強いてくるところや、デフォルトで用意されてるサンプル用の関数が、ただの文字列結合だけをしている非常に簡素なfunctionであるところを見ても、「そんなにガリガリといろいろなことををやらせるために用意するものではない」というのがなんとなく無言のメッセージとして伝わってくるのを感じます。

なお、自身の経験としては、「ミリ秒から日付オブジェクトをつくって日付形式の文字列に整形」というのがやりたくてこのJavascriptライブラリに手を出しました。
とあるAPIで、日付形式の値として「ミリ秒」をレスポンスしてくるものがあったのですが、標準のXSLT関数だとそれに相当するものがなく、一方でJavascript関数ならそれが比較的手軽にできるので、、という経緯です。
標準のXSLT関数でも、文字列の加工やちょっとした計算くらいなら可能ですが、正直豊富な種類があるとはいえず、実際問題、こうしたユーティリティの側面においては、Javascript等他のプログラムにやはり一日の長があります。
なので個人的な感覚では、「標準のXSLT関数で出来ない部分を補うためのちょっとしたユーティリティ」という程度の認識のほうが良いかもしれません。