Skip to main content

This is documentation for Caché & Ensemble. See the InterSystems IRIS version of this content.Opens in a new tab

For information on migrating to InterSystems IRISOpens in a new tab, see Why Migrate to InterSystems IRIS?

CSP におけるタグを使用した開発

CSP を使用すると、標準の HTML ファイルを使用して CSP アプリケーションを開発できます。この機能は CSP コンパイラといい、HTML ドキュメントおよび XML ドキュメントを、HTTP 要求への応答が可能な %CSP.PageOpens in a new tab クラスに変換します。

CSP コンパイラで生成されたクラスは、プログラマ自身が作成したクラスとまったく同じなので、相互運用にも問題はありません。CSP ページの開発方法として、HTML ページを使用する方法、または %CSP.PageOpens in a new tab を拡張したクラス (これはアプリケーションで使用できます) を作成する方法を選択できます。生成した CSP クラスを検証しておくと、デバッグ時に役立ちます。

CSP コンパイラで処理した HTML ドキュメントには、例えば、クラスの生成を管理するタグ、コントロール・フローを提供するタグ、データ・アクセスを管理するタグ、およびサーバ側の動作を制御するタグを記述できます。これらのタグは、CSP マークアップ言語または CSP タグです。これらのタグは、開発時に CSP サーバで解釈されます。HTTP クライアントに送信される HTML は、完全に標準に準拠したもので、CSP タグを持っていません。

CSP ファイルでは、通常の HTML タグ以外に、以下も使用できます。

  • #( )# を使用した Caché データ式は、ページが生成されるときに値を置換します。

  • Caché CSP タグ <csp:xxx> は、組み込み機能およびユーザ定義機能を提供します。

  • Caché スクリプト <script language=cache runat=server/compiler> は、ページの生成時あるいはコンパイル時に Caché コードを実行します。

  • Caché の各メソッドは、ページから起動できる再使用可能なクラス・メソッドです。

  • サーバ側のサブルーチン呼び出しである #server()# および call()# は、クライアント側のコード (ハイパーイベント) からサーバ側のサブルーチンを実行します。

  • カスタム・タグの開発” の章で説明されているカスタム・タグ。

CSP コンパイラ

CSP コンパイラは、Caché サーバ上で動作する Caché クラスとプログラムのセットで、以下の動作を実現します。

  1. CSP マークアップ言語を使用して HTML ドキュメントを読み取り、解析します。

  2. CSP ルールに基づいてパターン・マッチング論理を適用します。

  3. Caché クラスを生成します。

  4. このクラスを実行可能コードにコンパイルします。

例えば、以下の簡単な CSP ドキュメント hello.csp をコンパイルするとします。

<html>
<body>
Hello!
</body>
</html>

CSP コンパイラは、これを以下のようなクラスに変換します。

Class csp.hello extends %CSP.Page
{

ClassMethod OnPage() As %Status
{
    Write "<html>"
    Write "<body>"
    Write "Hello!"
    Write "</body>"
    Write "</html>"
    Quit $$$OK
}
}

ユーザがブラウザから hello.csp を要求すると、CSP サーバは生成した OnPage メソッドを呼び出し、CSP ドキュメントの元のテキストをブラウザに送信して表示できるようにします。

自動および手動によるページ・コンパイル

CSP サーバで CSP ソース・ドキュメントをクラスにコンパイルする処理は、自動的に実行できるほか、手動で実行することもできます。

自動コンパイル・モード (既定) では、必要に応じて CSP ソース・ドキュメントをクラスにコンパイルする指示が、CSP サーバから自動的に CSP コンパイラに出されます。CSP サーバは、ソース・ファイルとクラスのタイムスタンプを比較し、クラスのタイムスタンプより新しいソースを持つページをすべて再コンパイルします。一般的に、タイムスタンプを確認するためのオーバーヘッドを回避するために、展開済みのアプリケーションでは、このモードはオフになっています。

自動コンパイルをオフにするには、以下の手順に従います。

  1. 管理ポータルで、システム, セキュリティ, ウェブアプリケーション の順にクリックします。

  2. アプリケーションをテーブルから選択して [編集] をクリックします。

  3. [CSPアプリケーション編集] ページで、[自動コンパイル] を無効にします。

CSP ソース・ファイルをクラスに明示的にコンパイルできます。これはエラーの検出に便利です。

  1. スタジオで CSP ソース・ファイルを開きます。

  2. [ビルド]→[コンパイル] を選択します。

以下の例に示すように、$System.CSP API を使用して Caché コマンド行 (ターミナル) から CSP ソース・ファイルをコンパイルすることもできます。このメソッドは、物理的パスではない URL パス /csp/user/mypage.csp を持つ CSP ファイルをロードし、コンパイルします。c (ンパイル) フラグは、生成されたクラスをコンパイルすることを示します。k フラグ (持) は、生成された中間コードを表示できるように保持することを示します。

 Do $System.CSP.LoadPage("/csp/user/mypage.csp","ck")

CSP マークアップ言語

CSP マークアップ言語とは、CSP コンパイラで生成したクラスを制御するために使用する指示文やタグのセットです。

CSP ドキュメントをコンパイルすると、ObjectScript コードまたは Basic コードを実行する Caché クラスが得られます。これを知っていると、正しいアプリケーション・ロジックの開発や、トラブルシューティングに役立ちます。CSP と CSP マークアップ言語を詳しく知るには、CSP コンパイラで生成したコードの検証が役立ちます。

また、HTTP 要求に応答するために、CSP サーバ上で実行されるコードや、HTTP クライアント上で実行されるコード (HTML や JavaScript) を追跡することも重要です。

CSP ページ言語

既定では、CSP コンパイラは実行時式を評価し、ObjectScript を使用してコードを生成します。指定された CSP ドキュメントで、ドキュメントの先頭に PAGE 指示文を記述すると、この既定を Basic に変更できます。

<%@ page language="Basic" %>

例えば、CSP サンプル (ソースを表示するには [ソース] をクリックします) にある basic.cspOpens in a new tab アプリケーションを参照してください。

CSP ドキュメントでは、実行時式やサーバ側の <script> タグのコンテンツに、そのページの既定の言語を使用する必要があります (別の言語を使用するとコンパイル時にエラーが発生します)。または、別の言語でメソッドを定義し、既定の言語からそのメソッドを呼び出します。

テキスト

CSP ドキュメント (HTML または XML) のテキストで、CSP 指示文や CSP 独自のタグでないものは、ページを要求している HTTP クライアントにそのまま送信されます。

例えば、以下のような CSP ドキュメントがあります。

<b>Hello!</b>

これは、生成されたクラスに以下のコードを生成します。

 Write "<b>Hello!</b>",!

その後、以下を HTTP クライアントに送信します。

<b>Hello!</b>

コンパイル時の式とコード

式の評価を、CSP ページの実行時ではなく、コンパイル時に実行するように指定できます。これらの式は通常は、CSP 規則の定義内で使用されますが、他の定義で使用されることもあります。

コンパイル時の式は、##(expr)## 指示文で区切ります。expr は、ObjectScript の式です。

例えば、以下のような CSP ドキュメントがあります。

This page was compiled on: <b>##($ZDATETIME($H,3))##</b>

これは、生成されたクラスに以下のコードを生成します。

 Write "This page was compiled on <b>2000-08-10 10:22:22</b>",!

<script> タグの runat 属性を使用して、ページのコンパイル時にコード行を実行するように定義できます。

<script language="Cache" runat="compiler">
Note:

すべてのコンパイル時式およびコードの記述には、ObjectScript を使用する必要があります。

実行時式

CSP ドキュメントには、ページが処理されるとき (実行時) に CSP サーバ上で実行される式を記述できます。その場合、複数の式は #(expr)# 指示文で区切ります。ここで、expr には、ページの既定の言語に応じて、有効な ObjectScript 式または Basic 式を指定します。実行時式の言語は、CSP ドキュメントの既定の言語と一致している必要があります。

Note:

#(expr)# 指示文では、名前間接演算はサポートされていますが、引数間接演算はサポートされていないことに注意してください。

例えば、以下のような CSP ドキュメントがあります。

Two plus two equals <b>#(2 + 2)#</b>

これは、生成されたクラスに以下のコードを生成します。

Write "Two plus two equals <b>", (2 + 2), "</b>",!

その後、以下を HTTP クライアントに送信します。

Two plus two equals <b>4</b>

実行時式のサンプルは、以下のとおりです。

  • ページに以前に設定した変数の値

    The answer is <b>#(answer)#</b>.
  • オブジェクトのプロパティあるいはメソッド

    Your current balance is: <b>#(account.Balance)#</b>.
    
  • %ResultSetOpens in a new tab オブジェクト内のフィールド

    <table>
    <csp:while condition="result.Next()">
    <tr><td>#(result.Get("BookTitle"))#</td></tr>
    </csp:while>
    </table>
    
  • %request オブジェクトを使用した URL パラメータ

    <table bgcolor='#(%request.Data("tablecolor",1))#'></table>
    

実行時式は、#(expr)# を正当な HTML として使用できる CSP ドキュメントの中であれば、どこにでも記述できます。つまり、HTML 要素の属性値として HTML テキストに記述したり、クライアント側の JavaScript コードの定義に記述したりすることができます。

実行時式の値に特殊文字 (<>、山括弧など) がある場合は、それらをエスケープし、正しいエスケープ・シーケンスが HTTP クライアントに送信されるようにする必要があります。%CSP.PageOpens in a new tab クラスが提供するエスケープ・メソッドの 1 つを使用してエスケープします。詳細は、“HTTP 出力のエスケープと引用” を参照してください。以下の例は、EscapeHTML クラスメソッドを示しています。メソッドを実行すると、object.Description に存在する、エスケープ処理が必要な文字はすべて、該当する HTML エスケープ・シーケンスに置き換えられます。

Description: <b>#(..EscapeHTML(object.Description))#</b>.

HTML 属性値に実行時式を使用している場合、実行可能なコードに変換する前に、実行時式に検出された HTML エンティティはそれが表す文字に変換されます。以下はその例です。

<font size=#(1 &gt; 0)#>

これは、生成されたクラスに以下のコードを生成します。

 Write "<font size=",(1 > 0),">",!

実行時コード

CSP サーバで実行する複雑な式をページに記述する必要がある場合、<script runat=server> タグを使用して、CSP サーバ上で実行するコード行を配置できます。実行時式と同様に、実行時コードもさまざまな用途に使用できます。<script> タグの LANGUAGE 属性で指定する、実行時コードで使用する言語は、CSP ドキュメントの既定の言語と一致している必要があります。

例えば、以下のような CSP ドキュメントがあります。

<ul>
<script language="cache" runat=server>
    For i = 1:1:4 {
        Write "<li>Item ",i,!
    }
</script>
</ul>

これは、生成されたクラスに以下のコードを生成します。

 Write "<ul>",!
 For i = 1:1:4 {
    Write "<li>Item ",i,!
 }
 Write "</ul>",!

その後、以下を HTTP クライアントに送信します。

<ul>
<li>Item 1
<li>Item 2
<li>Item 3
<li>Item 4
</ul>

実行時コード ObjectScript 単一行

以下の構文を使用して、ObjectScript の単一行を実行できます。これは、単一行に対してのみ機能します。行を折り返すことはできません。

#[ set x = a + b write x ]#

サーバ側メソッド

CSP ドキュメントでは、CSP 用に生成されたクラスに属するメソッドを定義できます。これには、<script> タグを持つ引数を使用します。

メソッド名、引数リスト、返り値のタイプや、メソッドの実装に使用する言語を指定することができます。この言語は、CSP ドキュメントの既定の言語と一致している必要はありません

例えば、以下は MakeList というメソッドを定義します。このメソッドは、count アイテムを含む番号付きリストを作成します。

<script language="Cache" method="MakeList"
arguments="count:%Integer" returntype="%String">
   New i
   Write "<ol>",!

   For i = 1:1:count {
      Write "<li> Item",i,!
   }
   Write "</ol>",!
   Quit ""

</script>

これにより、CSP ドキュメントのどこからでもこのメソッドを実行できます。

<hr>
#(..MakeList(100))#

<csp:class> タグによる継承機能を使用して、以前に定義したメソッドをページ・クラスに継承したり、他のクラスのクラス・メソッドを呼び出したりすることもできます。

<hr>
#(##class(MyApp.Utilities).MakeList(100))#

SQL <script> タグ

以下の <script> タグを使用することで、SQL を使用して CSP ページ内で Caché %ResultSetOpens in a new tab オブジェクトを定義できます。

この例では、query という名前のダイナミック SQL %ResultSetOpens in a new tab オブジェクトのインスタンスを生成し、指定された SQL クエリを作成、実行します。ここでは、このクエリを繰り返し実行できるようにしています。

<script language="SQL" name="query">
SELECT Name FROM MyApp.Employee ORDER BY Name
</script>

通常、クエリ結果を表示するためには、SQL script タグで生成した %ResultSetOpens in a new tab オブジェクトを、<csp:while> タグ ("csp:WHILE Tag" 参照) と共に使用します。

SQL <script> タグは、ページの実行が終了すると、%ResultSetOpens in a new tab オブジェクトのインスタンスを閉じます。

SQL テキスト内で ? 文字を使用して、SQL クエリのパラメータを指定できます。また、SQL <script> タグで P1P2、...Pn (n はパラメータ番号) の各属性を使用して、パラメータ値を指定できます。

以下の例では、SQL <script> タグを使用して現在のユーザの購入内容を表示します。現在のユーザのユーザ ID は、元々 %session オブジェクトに格納されていると仮定します。

<script language=SQL name=query P1='%session.Data("UserID")'>
SELECT DateOfPurchase,ItemName,Price
FROM MyApp.Purchases
WHERE UserID = ?
ORDER BY DateOfPurchase
</script>
<hr>
Items purchased by: <b>#(%session.Data("UserID"))#</b>
<br>
<table>
<tr><th>Date</th><th>Item</th><th>Price</th></tr>
<csp:while condition="query.Next()">
<tr>
<td>#(..EscapeHTML(query.GetData(1)))#</td>
<td>#(..EscapeHTML(query.GetData(2)))#</td>
<td>#(..EscapeHTML(query.GetData(3)))#</td>
</tr>
</csp:while>
</table>

csp:<csp:query> タグを使用すると、Caché クラスの一部として定義したクエリを使用して %ResultSetOpens in a new tab オブジェクトを生成できます。

<csp:query NAME="query" CLASSNAME="Sample.Person" QUERYNAME="ByName">

SQL <script> タグで使用するときと同様に、%ResultSetOpens in a new tab オブジェクトの結果を使用できます。

生成されたクラスの管理

<csp:class> タグを使用して、CSP コンパイラで生成したクラスを管理できます。例えば、クラスのスーパークラスの選択や、%CSP.PageOpens in a new tab クラス・パラメータの多くに対する値の定義などができます。

例えば、通常の %CSP.PageOpens in a new tab クラスから継承するクラスのほかに、別のクラスからも継承するクラスを生成するとします。SUPER 属性は、コンマ区切りで列挙したクラスのリストを持ち、生成されたクラスのスーパークラスとしてこれらのクラスを使用します。

<csp:class SUPER="%CSP.Page,MyApp.Utilities">

以下は、クラス・パラメータの値を再定義する例です。クラス・パラメータ PRIVATE の値を 1 に再定義して、ページをプライベート・ページとするには、以下のように指定します。

<csp:class PRIVATE=1>

コントロール・フロー

CSP マークアップ言語には、ページの実行管理を容易にするタグがいくつかあります。サーバ側のタグほど汎用的ではありませんが、これらのタグの使用により特定のタスクの実行が容易になります。

<csp:if> タグ

<csp:if> タグ、<csp:else>タグおよび <csp:elseif> タグと組み合わせて csp:if タグを使用することで、CSP ページに条件付き出力を定義できます。

<csp:if> タグには condition という唯一の属性があります。その属性値には、ページに指定した既定の言語に応じて、ObjectScript 式または Basic の式を指定します。この式は実行時に CSP サーバによって評価されます。値が True の場合、タグの内容が実行されます。

以下はその例です。

<csp:if condition='user="Jack"'>
Welcome Jack!
<csp:elseif condition='user="Jill"'>
Welcome Jill!
<csp:else>
Welcome!
</csp:if>

<csp:while> タグ

<csp:while> タグは、指定されたサーバ側の条件が True の場合、CSP ドキュメントのセクションを繰り返し処理します。

<csp:while> タグの condition 属性には、ページに指定した既定の言語に応じて、ObjectScript または Basic の式を指定します。この値は、ページが提供される際に CSP サーバで評価されます。この条件が True (1) である限り、csp:while タグの内容が 評価されます。

一般に <csp:while> タグは、Caché の %ResultSetOpens in a new tab オブジェクトと併用して、SQL クエリの結果を HTML に表示するために使用します。以下の例では、クエリの Name 列の値を出力する <csp:while> タグの内容が、%ResultSetOpens in a new tab オブジェクトの Next メソッドが結果セットの終了を示す False (0) を返すまで繰り返し実行されます。

<script language=SQL name=query>
SELECT Name
FROM MyApp.Employee
ORDER BY Name
</script>

<csp:while condition="query.Next()">
#(..EscapeHTML(query.Get("Name")))#<BR>
</csp:while>

<csp:while> タグの counter 属性を使用して、カウンタ変数の初期値をゼロ (0) とし、反復が開始するたびに自動的に 1 ずつインクリメントするように定義できます。

例えば、以下の <csp:while> タグは、HTML で 5 列のテーブルを作成します。

<table>
<csp:while counter="row" condition="row<5">
<tr><td>This is row #(row)#.</td></tr>
</csp:while>
</table>

以下は、条件で否定演算子 (一重引用符) を使用した例です。条件には、スペースを含めることはできず、また、開始引用符も終了引用符も含まれないことに注意してください。(mystr'=”QUIT”) のように括弧を使用して条件を記述することもできます。

<csp:while condition=mystr'="QUIT">
//add code
</csp:while>

<csp:loop> タグ : 番号を割り当てたリストの例

CSP ドキュメントでコンテンツを繰り返し実行するには、<csp:loop> タグを使用する方法もあります。

<csp:loop> タグを使用すると、counter 属性を使用してカウンタ変数を定義できるほか、開始値、終了値、増分値を定義できます。既定の増分値は 1 です。

例えば、以下のように <csp:loop> タグを使用して、5 つの項目を含むリストを作成できます。

<ul>
<csp:loop counter="x" FROM="1" TO="5">
<li>Item #(x)#
</csp:loop>
</ul>

HTTP 出力のエスケープと引用

HTML で使用された特殊文字のリテラル表示を作成するには、エスケープ・シーケンスを使用する必要があります。例えば、HTML で特殊な意味を持つ > (右山括弧) 文字を HTML で表示するには、一連の文字 &gt; を使用してエスケープする必要があります。CSP ドキュメントの異なる部分では、異なるエスケープ規則が適用される場合もあります (HTML や JavaScript など)。

%CSP.PageOpens in a new tab クラスは、多数のエスケープ・メソッドと引用メソッドを提供しています。

  • エスケープ・メソッド は、入力された文字列を受け取り、特殊文字が含まれている文字列を適切なエスケープ・シーケンスに置換して返します。

  • 引用メソッドは、入力された文字列を受け取り、引用符で囲まれた文字列にして返します。引用符で囲まれた文字列の特殊文字はすべて、エスケープ・シーケンスに置換されます。

  • また、各エスケープ・メソッドに対し、エスケープ・シーケンスを普通のテキストに置換するアンエスケープ・メソッドもあります。

EscapeHTML による HTML のエスケープ

%CSP.PageOpens in a new tab クラスは、文字を対応する HTML のエスケープ・シーケンスに置換できます。

例えば、CSP ファイルからサーバ側の変数 x の値をブラウザで表示する必要がある場合、x に使用されている任意の文字を以下の式でエスケープできます。

#(..EscapeHTML(x))#

x の値が <mytag> の場合、HTTP クライアントに送信されるテキストは以下のようになります。

&lt;mytag&gt;

同様に、エスケープ処理は HTML 属性の値を送信する場合に必要です。

<input type="BUTTON" value="#(..EscapeHTML(value))#">

value の値が <ABC> の場合、HTTP クライアントに送信されるテキストは以下のようになります。2 つの左右の山括弧は、それぞれ対応する文字シーケンス &lt; および &gt; に置き換えられます。

<input type="BUTTON" value="&lt;ABC&gt;">

#()# 指示文を "" (二重引用符) で囲むと、HTML 属性値の結果が引用符で囲まれます。

データベースから HTTP クライアントに出力を送信する場合は、必ず出力をエスケープすることをお勧めします。例えば、以下は Web ページにユーザ名を書き込む式です (userName プロパティを持つオブジェクトへの参照であるとします)。

User name: #(user.Name)#

ユーザがデータベースに自分の名前を入力できるアプリケーションで、以下のように、HTML コマンドを含む名前が誤って入力されたとします。HTML エスケープ・シーケンスを使用せずに、この名前が HTTP クライアントに書き込まれると、このページは予期しない動作をします。

Set user.Name = "<input type=button onclick=alert('Ha!');>"

EscapeURL による URL パラメータのエスケープ

URL 文字列のパラメータ値もエスケープできます。URL で使用するエスケープ・シーケンスのセットは、HTML で使用するものとは異なっています。%CSP.PageOpens in a new tab クラスの EscapeURL メソッドでは、文字を処理するすべての特殊な URL パラメータ値を、対応するエスケープ・シーケンスに置換します。

例えば、CSP ファイルからサーバ側の変数 x の値を URL パラメータ値として使用する場合、x に使用されている任意の文字を以下の式でエスケープできます。

<a href="page2?ZOOM=#(..EscapeURL(x))#">Link</A>

x の値が 100% の場合、HTTP クライアントに送信されるテキストは以下のようになります。% 文字は %25 とエスケープされます。

<a href="page2?ZOOM=100%25">Link</A>

QuoteJS による JavaScript のエスケープ

%CSP.PageOpens in a new tab クラスの文字列は、すべての特殊な文字列を、対応する JavaScript のエスケープ・シーケンスに置換します。

例えば、警告ボックスにメッセージを表示するクライアント側の JavaScript 関数を CSP ファイルで定義するとします。メッセージはサーバ側の変数 x で指定します。x の値は、以下を使用して JavaScript の引用符で囲まれた文字列に変換されます。

<script language="JavaScript">
function showMessage()
{
   alert(#(..QuoteJS(x))#);
}

</script>

x の値が “Don't press this button!” の場合、HTTP クライアントに送信されるテキストは以下のようになります。

<script language="JavaScript">
function showMessage()
{
   alert('Don\'t press this button!');
}
</script>

サーバ側のメソッド

CSP は、HTML クライアントからサーバ側のメソッドを呼び出す 2 つのテクニックを提供します。

  • HTTP 送信機能の使用

  • #server (同期) または #call (非同期) のいずれかのハイパーイベントの使用

HTTP 送信を使用する利点は、クライアント側のプログラミングが簡単であり、クライアント側のコンポーネントが必要ないことです。HTTP 送信の使用の短所は、メソッド呼び出しの後にページがクライアントによって再描画され、サーバ側のプログラミングがより難しくなることです。

ハイパーイベントを使用する場合、XMLHttpRequest を使用して #server および #call を実装します。#call は非同期です。(ユーザとして) Web ページに値を入力しても、ページは直ちには更新されません。ページが更新されるときまでに、ユーザは別のページに移動している場合があります。 #server は同期です。ページは、呼び出しから値が返されたときにすぐに更新されます。

同期 XMLHttpRequest は多くのブラウザで非推奨となっており、一般的に移動は非同期 XMLHttpRequest をサポートするためのみであることに注意してください。

HTTP 送信およびハイパーイベントについては、以下のセクションで詳述します。

Caché と AJAX

AJAX という略語は、一般的に、クライアント側のページに表示されるサーバのデータが、ブラウザに新しいページが表示されるよう要求しなくても更新されるようにするための、一連のテクノロジを意味します。Caché ハイパーリンクを使用すると AJAX による対話が可能となるので、プログラマにとっては、サーバとの面倒な通信処理がまったく不要になるという利点があります。Caché で AJAX トランザクションを処理できるようにするには、以下の 2 つの方法があります。

  1. CSP の場合は、#server() コマンドと #call() コマンドを使用して、クライアントからサーバ側のメソッドを直接呼び出せるようにします。

  2. Zen の場合は、プログラマが ZenMethod を定義することにより、クライアントとサーバとの対話を処理できます。 この WebMethod は、メソッド・シグニチャによって同期または非同期にすることができます。

同期 AJAX 要求のシグニチャ

Method XYZ(arg) as %Status [ZenMethod]    

非同期 AJAX 要求のシグニチャ

Method XYZ() [ZenMethod]              

Ajax での並行処理

CSP への Ajax 要求は、^%cspSession グローバルのノードに対するロックのため、サーバで順番に処理されます。 Ajax 要求の並列処理を可能にするには、作業中のアプリケーションにおいてセッション・グローバル/オブジェクトに何も設定していない場合に (つまり、読み取り専用)、%CSP.Session.Unlock() メソッドを使用して、当セッションの CSP グローバルおよび処理の最後にある %session.Lock をアンロックすることができます。

詳細は、クラス・リファレンスの "%CSP.SessionOpens in a new tab" を参照してください。

HTTP 送信を経由したサーバ側メソッドの呼び出し

HTTP 送信を使用してサーバ・コードを実行する場合、ブラウザで必要とする機能はほとんどありません。これは、膨大な数のユーザを対象としてさまざまなブラウザをサポートする必要のあるアプリケーションには最適な手法です。HTTP 送信を使用する場合、ユーザが SUBMIT ボタンをクリックするたびに要求されたページが再表示されます。

以下のようにして、HTTP 送信を実行できます。

  1. 以下のように SUBMIT ボタンのある HTML フォームを作成します。

    <form name="MyForm" action="MyPage.csp" method="GET">
    User Name: <input type="TEXT" name="USERNAME"><br>
    <input type="SUBMIT" name="BUTTON1" value="OK">
    </form>

    これは、テキスト・フィールド [USERNAME]SUBMIT ボタンの [BUTTON1] がある単純なフォームです。フォームの ACTION 属性には、フォームの送信先の URL を指定します。METHOD 属性は、POST または GET のどちらの HTTP プロトコルを使用してフォームを送信するかを指定します。

  2. ユーザが SUBMIT ボタンである [BUTTON1] を押すと、ブラウザはフォームにあるすべてのコントロールから値を集め、フォームの ACTION 属性で指定されている URL に値を送信します(ただし、ACTION 属性でページの名前を指定するか、ACTION 属性を空白のままにすることによって、ページはそれ自体に送信し返すことができます)。フォームが、POST または GET のどちらで送信されたのかにかかわらず、CSP は送信された値を URL パラメータとして処理します。この場合、フォームの送信は、以下の URL の要求に相当します。

    MyPage.csp?USERNAME=Elvis&BUTTON1=OK
    

    これには、SUBMIT ボタンの名前と値が記述されています。フォームに複数の SUBMIT ボタンがある場合、実際に押されたデータ・ボタンのみが要求に記述されます。これにより、いつ SUBMIT が実行されたかを検出できます。

  3. サーバ・コードは (この場合は MyPage.csp)、送信されたことを検出します。これは、以下のように %request オブジェクトの BUTTON1 名をテストすることで実現します。

    <script language="Cache" runat="SERVER">
       // test for a submit button
       If ($Data(%request.Data("BUTTON1",1))) {
          // this is a submit; call our method
          Do ..MyMethod($Get(%request.Data("USERNAME",1)))
       }
    </script>
  4. 必要なサーバ側のロジックの実行後、サーバ・コードは継続し、ブラウザで表示する HTML を返します。これにより、現在のフォームが再表示されるか、異なるページが表示されます。

ハイパーイベント #server および #call を使用したサーバ側メソッドの呼び出し

ハイパーイベントは、インタラクティブな Web アクションを作成するための Web ブラウザ・イベントおよび Web 開発技術の当社の CSP 拡張です。ハイパーイベントを使用すると、クライアントの Web ブラウザでのイベントに応答して、クライアントで HTML ページを再ロードせずに、Caché サーバでクラスのメソッドを実行できます。この機能は一般的に AJAX と呼ばれています。Caché ハイパーイベントはさまざまな状況で使用できますが、特に、Web ページ全体の再ロードや再フォーマットをせずに、データベースを検証または検索することが必要なデータベース・アプリケーションに最適です。通常、ハイパーイベントは、XMLHttpRequest を使用して実装されます。

クラスを使用して CSP ページを作成している場合、ハイパーイベントに必要な JavaScript をロードするために <head> セクションの出力中に ..HyperEventHead メソッドを呼び出す必要があります。

#server を使用したサーバ側メソッドの呼び出し

CSP ファイル内で、#server 指示文を使用して、サーバ側のメソッドを呼び出すことができます。この指示文は JavaScript が使用できれば、どこででも使用できます。

#server 指示文の構文は以下のとおりです。

#server(classname.methodname(args,...))#

classname はサーバ側の Caché のクラスの名前、methodname はそのクラスのメソッドの名前です。また、args はサーバ側メソッドに渡されるクライアント側の JavaScript の引数のリストです。開始および終了の # 記号の間にあるすべてのコードは 1 行に記述されている必要があることに注意してください。

例えば、Caché クラスの MyPackage で、サーバ側のメソッド Test を呼び出すには、以下のように指定します。

<script language="JavaScript">
function test(value)
{
   // invoke server-side method Test
   #server(MyPackage.Test(value))#;
}
</script>

CSP コンパイラは、#server 指示文が現れるたびに、それをサーバ側のメソッドを呼び出す JavaScript コードに置換します。

指定された CSP ページから ..MethodName 構文を使用して、生成されたクラスに属するメソッドを呼び出すことができます。以下に例を示します。

#server(..MyMethod(arg))#

#call を使用したサーバ側メソッドの呼び出し

同時性は、呼び出されるメソッドが #server#call のいずれであるかによって決まります。#server は同期で、#call は非同期です。

同期呼び出しでは、UI 応答における一時停止 (待機) が顕著に発生する場合があります。一方、非同期呼び出しには、特有の利点だけでなく問題点もあります。例えば、ユーザが Web ページに値を入力すると、ページは直ちには更新されません。ページが更新されるときまでに、ユーザは別のページに移動している場合があります。

#server は同期的に動作します。サーバ側のメソッドを呼び出すと、(クライアントが待機しているので) #server は値をクライアントに返し、さらにクライアントが実行する JavaScript を返します。

#call は非同期です。サーバ側のメソッドを呼び出しても、#call は返り値を待ちません。代わりに、ユーザのアプリケーションはサーバから返送される JavaScript に依存し、必要な処理をクライアントで実行します。

非同期の #call を使用する場合、複数の連続した呼び出しを行うときは注意が必要です。前のメソッドの完了前に #call を介して別のメソッドを呼び出すと、Web サーバが前のメソッド呼び出しのキャンセルを決定する場合があります。また、JavaScript の実行前にユーザが別のページに移動している場合、JavaScript は誤ったページで実行されて、エラーとなります。よって、ほとんどの場合、実行に時間のかかる可能性があるものを起動する際には、#call を使用して、長時間実行のジョブの状態を示す別ページへのリンクを提供するようにします。

#server と同様に、#call 指示文は、JavaScript が使用できれば、どこででも使用できます。

#call 指示文の構文は以下のとおりです。

#call(classname.methodname(args,...))#

classname はサーバ側の Caché のクラスの名前、methodname はそのクラスのメソッドの名前です。また、args はサーバ側メソッドに渡されるクライアント側の JavaScript の引数のリストです。開始および終了の # 記号の間にあるすべてのコードは 1 行に記述されている必要があることに注意してください。

例えば、Caché クラスの MyPackage で、サーバ側のメソッド Test を呼び出すには、以下のように指定します。

<script language="JavaScript">
function test(value)
{
  // invoke server-side method Test
  #call(MyPackage.Test(value))#;
}
</script>

CSP コンパイラは、#call 指示文が現れるたびに、それをサーバ側のメソッドを呼び出す JavaScript コードに置換します。

指定された CSP ページから ..MethodName 構文を使用して、生成されたクラスに属するメソッドを呼び出すことができます。以下はその例です。

#call(..MyMethod(arg))#

ハイパーイベントの例

このセクションでは、ハイパーイベントの例をいくつか示します。ここでは、#server 指示文と #call 指示文を使用して、クライアント・イベントに応答するサーバの動作を実行します。例えば、新規顧客をデータベースに追加するフォームがあるとします。顧客の名前が入力されると、アプリケーションは同じ顧客名がデータベースに存在するかどうかを調べます。以下のフォーム定義は、入力内容が変更されたときに、サーバ側の Find メソッドを呼び出します。

<form name="Customer" method="POST">
Customer Name:
<input type="Text" name="CName"
onChange=#server(..Find(document.Customer.CName.value))# >
</form>

この場合、Find メソッドは、同じ CSP ファイルで次のように定義されます。

<script language="Cache" method="Find" arguments="name:%String">
 // test if customer with name exists
 // use embedded SQL query

 New id,SQLCODE
 &sql(SELECT ID INTO :id FROM MyApp.Customer WHERE Name = :name)

 If (SQLCODE = 0) {
   // customer was found
   // send JavaScript back to client
   &js<alert('Customer with name: #(name)# already exists.');>
 }
</script>

このメソッドは、クライアントと通信し、実行するための JavaScript を返信します。

サーバ側メソッドが呼び出されるたびに、主デバイスへ書き込まれるすべての出力はクライアントに返送されます。そこで JavaScript 関数に変換され、クライアント・ページにより、クライアント・ページのコンテキストで実行されます。

例えば、サーバ側のメソッドが以下のコード行を実行したとします。

 Write "CSPPage.document.title = 'New Title';"

以下の JavaScript がクライアントに送信、実行されます。

CSPPage.document.title = 'New Title';

この場合、ブラウザの表示タイトルは New Title に変更されます。この方法で、任意の有効な JavaScript をクライアントに送信できます。JavaScript の各行の末尾には、キャリッジ・リターン (! 文字を使用) を記述します。これがないと、ブラウザは JavaScript を実行できません。

サーバ・メソッドから容易に JavaScript が得られるように、ObjectScript は、&js<> 指示文を使用して埋め込み JavaScript をサポートします。これは、ObjectScript メソッドで JavaScript の行を指定するための特殊な言語構造です。埋め込み JavaScript を含むメソッドをコンパイルすると、&js<> 指示文のコンテンツは、適切な Write コマンド文に変換されます。埋め込み JavaScript は、#()# 指示文を使用して ObjectScript 式を参照できます。

例えば、以下のような Caché メソッドがあります。

 Set count = 10
 &js<
   for (var i = 0; i &lt; #(count)#; i++) {
      alert('This is pleasing!');
      }
 >

これは、以下と同等です。

 Set count = 10
 Write "for (var i = 0; i < ", count, "; i++) {",!
 Write "    alert('This is pleasing!');",!
 Write "}",!

クライアントからこのメソッドを呼び出すと、心地良い警告メッセージが 10 回表示されます。

CSP クラスでの #server の使用法

CSP クラス内でハイパーイベントおよび Javascript を使用するには、明示的にハイパーイベント・ブローカ・ファイルを呼び出す必要があります。以下の例のように、<head> 終了タグのすぐ上に #(..HyperEventHead())# を配置します。

Class esl.csptest Extends %CSP.Page [ ProcedureBlock ]
{

ClassMethod OnPage() As %Status
{

   &html<<html>
   <head>
   <script language=javascript>
   function onServer()
   {
      alert(#server(..ServerMethod())#);
   }
   </script>
   #(..HyperEventHead())#
   </head>
   <body>
   <input type=button value="click here" onclick='onServer()' />
   </body>
   </html>>
   Quit $$$OK
}

ClassMethod ServerMethod()
{
   quit "from server"
}

}

サーバ側メソッドを使用するヒント

Web ページからサーバ側のメソッドを呼び出せることは大変便利です。ただし、アプリケーションでサーバ側のメソッドを使用する場合、注意する点がいくつかあります。

Note:

このセクションでは、特に明記されていない限り、#server について説明した内容は、#call にも適用されます。

#server 指示文と #call 指示文のいずれかを使用すると、JavaScript から Caché サーバ上のメソッドを Web ブラウザに呼び出すことができます。これにより CSP は、フォームの送信時点まで待たず、フィールドからフォーカスが移動したときにそのフィールドを検証することで、ユーザに迅速なフィードバックを提供します。#server 構文の使用には、注意すべきいくつかの要素があります。これを無視すると、アプリケーションの速度が低下したり、まったく動作しなくなる可能性があります。

#server を使用する際には、2 つの基本的な規則があります。

  1. Web ページの onload イベントでは、#server を使用しないでください。使用するとエラーを起こす可能性があります。Web ページを生成する場合は、Caché でデータを生成する方が、より高速で簡単です。

  2. Web ページの onunload イベントでは、#server を使用しないでください。ブラウザとサーバ間の通信を含め、#server 呼び出しはコストが高いため、できるかぎり呼び出し数を少なくし、1 回の呼び出しごとの動作量を多くします。

onload イベント内で実行する必要があるコードはすべて、Caché からページを生成した方が、高速で簡単に実行できるため、これはお勧めしません。例えば、JavaScript 変数の初期値を設定し、後でそのページからその変数を #server 呼び出しで使用できるようにするには、以下のように記述します。以下のように記述します。

<html>
<head>
<script language="JavaScript">
function LoadEvent()
{
   var value=#server(..GetValue())#;
}
</script>
</head>
<body onload=LoadEvent();>
</body>
</html>
<script language="Cache" method="GetValue" returntype="%String">
   Quit %session.Data("value")
</script>

しかし、ここで #server を呼び出す必要はありません。JavaScript 変数値は、ページが生成されたときは既に %session.Data("value") で認識されているからです。したがって、以下のように記述します。

<html>
<head>
<script language="JavaScript">
function LoadEvent()
{
   var value='#(%session.Data("value"))#';
}
</script>
</head>
<body onload=LoadEvent();>
</body>
</html>

同様に、ドキュメントをロードするときにフォーム要素値を更新する場合、ページの生成時に値を入力します。例えば、以下のように記述します。

<input type="text" name="TextBox" value='#(%request.Get("Value"))#'>

ページの onload イベントで、#server を使用する必要はありません。

ページはロードされていないため、Caché から返された JavaScript が実行されるかどうかを確認することは困難です。実際の動作はブラウザに依存します。また、ユーザがコンピュータの電源をオフにすると、onunload イベントを取得できません。したがって、%session オブジェクトのタイムアウトを使用するなどして、どのような場合でもアプリケーションが対処できるようにする必要があります。onunload #server ロジック・コードを、例えば、ユーザがクリックする次の CSP ページの最初に移動できます。

#server および #call の呼び出し回数を最小限に抑える方法

#server および #call は、ブラウザがページに HTTP を要求することによって動作します。このページには、暗号化された特殊なトークンがあり、実行する Caché メソッド名を伝えます。Caché はこのメソッドを実行し、返送された出力すべてを JavaScript としてブラウザで実行します。また、#server 呼び出しも値を返します。これらの呼び出しは HTTP 要求を使用するため、サーバのネットワーク・パケットや CPU など通常の CSP ページ要求よりもコストがかかります。#server 要求を多用すると、#server 呼び出しを実行するたびに Caché サーバから新規の CSP ページが要求されるため、アプリケーションの拡張性が大幅に低下します。つまり、従来の Web ページでは、URL に移動するとそのページを 1 回生成するだけですが、10 回の #server 呼び出しがある CSP ページでは、10 回 CSP ページを生成する場合と同じコストがかかります。したがって、これらの #server 呼び出し数を削減すると、アプリケーションがサポートできるユーザ数が 10 倍増加します。

#server 呼び出し数を削減するには、それぞれの #server 呼び出しがアプリケーションで本当に必要かどうか、そして必要な場合には、#server によって一度にできるだけ多くの動作がサーバで行われているかどうかを検証する必要があります。例えば、以下は、サーバから得た新規の値でフォームを更新する JavaScript のブロックです。

このコード・ブロックは、CSP キーワード CSPPage を使用して、Javascript キーワード self ではなくページ自体を参照することに注意してください。この例では、この 2 つのキーワードが同様に機能します。self は、さまざまなコンテキストで予期しない動作をする場合があるので、CSPPage を使用することをお勧めします。

<script language="JavaScript">
function UpdateForm()
{
   CSPPage.document.form.Name.value = #server(..workGet("Name",objid))#;
   CSPPage.document.form.Address.value = #server(..workGet("Address",objid))#;
   CSPPage.document.form.DOB.value = #server(..workGet("DOB",objid))#;
}
</script>

サーバ・コードは以下のとおりです。普通はオブジェクトまたは SQL を使用しますが、ここではコードを小さくするため、グローバルを使用しています。

<script language="Cache" method="workGet"
 arguments="type:%String,id:%String" returntype="%String">
   Quit $get(^work(id,type))
</script>

この 1 回のアップデートは、新規 Web ページ用に Caché サーバから 3 回呼び出しを実行しています。このコードを、すべての値を一度で更新する 1 回の #server 呼び出しに変換できます。 JavaScript は以下のとおりです。

<script language="JavaScript">
function UpdateForm()
{
   #server(..workGet(objid))#;
}
</script>

メソッド定義は以下のようになります。

<script language="Cache" method="workGet"
 arguments="id:%String" returntype="%String">
   &js<CSPPage.document.form.Name.value = #($get(^work("Name",objid)))#;
      CSPPage.document.form.Address.value = #($get(^work("Address",objid)))#;
      CSPPage.document.form.DOB.value = #($get(^work("DOB",objid)))#;>
</script>

これにより、複数回呼び出す代わりに、データを 1 回だけ渡し、Caché ですべての動作を実行できます。以下は、さらに複雑な JavaScript の例です。

<script language="JavaScript">
function UpdateForm()
{
   CSPPage.document.form.Name.value = #server(..workGet("Name",objid))#;
   if (condition) {
      CSPPage.document.form.DOB.value = #server(..workGet("DOB",objid))#;
   }
   else {
       CSPPage.document.form.DOB.value = '';
   }
}
</script>

この場合でも、#server 呼び出しは 1 回にとどめる必要があります。この if 条件文全体を、#server 呼び出しで返される JavaScript に埋め込みます。最終的に workGet メソッドは以下のようになります。

<script language="Cache" method="workGet"
 arguments="id:%String" returntype="%String">
   &js<CSPPage.document.form.Name.value = #(^work("Name",objid))#;
      if (condition) {
         CSPPage.document.form.DOB.value = #(^work("DOB",objid))#;
      }
      else {
         CSPPage.document.form.DOB.value = '';
      }
   >
</script>

#server および #call に対するカスタム・エラー警告の作成

ハイパーイベント (#server または #call) で何かを呼び出し、実行中に何らかの理由でサーバとの通信に失敗した場合は、エラーが生成され、CSP の既定の動作によって、警告ボックスにエラーが表示されます。エラーをログに記録したり、ユーザに別のメッセージを表示するなど、エラーを個別に処理する場合は、cspRunServerMethodError javascript 関数を記述します。以下の例では、エラーは既定の動作のように警告ボックスに表示されます。

function cspRunServerMethodError(err) {
// Just display the error and carry on
alert(err);
return null;
}

FeedbackOpens in a new tab