Hello Account (JavaScript Remoting)

JavaScript Remoting で Hello Account。

<apex:page controller="HelloAccountRemoter">
    
<script type="text/javascript">
  function doGetAccounts() {
      HelloAccountRemoter.getAccounts(
        function(result, event) {
            for (var i = 0; i < result.length; i++) {
                console.log(result[i].Id, result[i].Name);
            }
        },
        {escape: true}
      );
  } 
</script>
    
<apex:form id="formId">
	<apex:commandButton onclick="doGetAccounts()" value="hello" rerender="formId" />
</apex:form>
    
</apex:page>

Hello Account (Ajax Toolkit)

Ajax Toolkit で Hello Account。

<apex:page >

<script src="/soap/ajax/31.0/connection.js" type="text/javascript"></script>
<script src="/soap/ajax/31.0/apex.js" type="text/javascript"></script>  

<script type="text/javascript">
  function getAccounts() {
    sforce.connection.sessionId = "{!$Api.Session_ID}";
    var accounts = sforce.connection.query("SELECT Id, Name FROM Account").getArray("records");
    for (var i = 0; i < accounts.length; i++) {
      console.log(accounts[i].Id, accounts[i].Name);
    }
  }
</script>

<apex:form >
    <apex:commandButton value="hello" onclick="getAccounts();"/>
</apex:form>

</apex:page>

Hello Account (Apex and Visualforce)

Apex と Visualforce で Hello Account。

public with sharing class HelloAccountController {

  public List<Account> acctList {get; set;}

  public PageReference getAccounts() {
    acctList = [SELECT Id, Name FROM Account];
    return null;
  }
}
<apex:page controller="HelloAccountController">
    
    <apex:form >
        <apex:commandButton value="hello" action="{!getAccounts}" rerender="dtb" />
    </apex:form>
    
    <apex:dataTable var="acct" value="{!acctList}" id="dtb">
        <apex:column value="{!acct.Id}" />
		<apex:column value="{!acct.Name}" />
    </apex:dataTable>
    
</apex:page>

GT3(Globus Toolkit 3) – Tutorial chapter 3.1

グリッドサービスではまず、サービスのインタフェースから作成する。Webサービスでいう"WSDL"を作成するというものである。

概要

グリッドサービスではこのサービスインタフェースのことを”portType"という。GWSDLは、Javaのインタフェースのようなものであり、またWSDLを拡張したものである。GWSDLでは、新たに<gwsdl:portType>というタグが導入され<operation>タグにJavaのインタフェースの様な抽象メソッドを書く。具体的には入出力を書く。
Webサービス(WSDL)とグリッドサービス(GWSDL)のメモ↓

  • WSDL1.1系列とWSDL1.2/2.0系列がある。
  • GWSDLは1.1系列にない性質がある。
    • グリッドサービスでは<portType>の属性extendsで継承することができる。
    • ”サービスデータ”という概念がある。
  • グリッドサービスは"stateful" Webサービスは"stateless"
  • GGF(:Global Grid Forum)ではOGSIに1.2/2.0を採用していない。
  • そこでGGFでは一時的にGWSDLを用いている。(いずれは1.2/2.0を採用?)
  • WSRF(WS-Resource Framework)はGWSDLと1.2/2.0は採用せず、純粋は1.1を採用?

Namespace mappings

グリッドサービスのインタフェースとJava実装をマッピングさせるファイルがnamespacemappingファイル。具体的にはサービスインタフェース(portType)とJavaパッケージをマッピングさせる。

Step2:Implementing the service in Java

Step1で作成したサービスインタフェースの記述したGWSDLファイルを基にサービスをJavaで実装していく。ソースは以下のような感じ↓

package org.globus.progtutorial.services.core.first.impl;

import org.globus.ogsa.impl.ogsi.GridServiceImpl;
import org.globus.progtutorial.stubs.MathService.MathPortType;
import java.rmi.RemoteException;

public class MathImpl extends GridServiceImpl implements MathPortType
{
       private int value = 0;

       public MathImpl()
       {
               super(&quot;Simple MathService&quot;);
       }

       public void add(int a) throws RemoteException
       {
               value = value + a;
       }

       public void subtract(int a) throws RemoteException
       {
               value = value - a;
       }

       public int getValue() throws RemoteException
       {
               return value;
       }
}

大事なポインとしては以下の点↓

  • すべてのグリッドサービスはGridServiceImpl?を継承している。
  • サービスインタフェースのportType(ここではMathportType?)を実装している。
  • RPC(:Remote Proceduer Call)メソッドなのでRemoteException?が投げられる。

Step3:Configuring the deployment in WSDD

グリッドサービスを実装してもそれを公開する(サーバに登録する)必要がある(デプロイ)。サービスインタフェースが一体どこにあるのか?どんなサービスなのか?を外部に公開する必要がある。そこで先ほどのWSDLのようなxmlベースのWSDDというファイルを記述する。

Step4:Create a Gar file with Ant

今まで作成したファイルは、

  • サービスインタフェース(GWSDLファイル)
  • サービス実装(Javaファイル)
  • デプロイファイル(WSDD)

である。これら3つのファイルを用いて、サービスを稼働させる。具体的な手順としては以下の通り↓

  • 1. GWSDLからWSDLを作成
  • 2. WSDLからスタブを作成(クライアント実装のため)
  • 3. スタブをコンパイル
  • 4. サービス実装をコンパイル
  • 5. すべてのファイルをサーバ側の特定のディレクトリへ移動

である。これら一つ一つを順々にやっていくのは大変なので、通常はAntというJava用ビルドツールを用いる。そして必要なファイルをGarファイルという(jarファイルをまたアーカイブにまとめたようなもの)ファイルを作成する。
また,Antでビルドする際に,build.xmlを用いる.

Step5:Deploy the service into a grid services container

Step3で作成したWSDDファイルを用いて、Step4で作成したGarファイル(すべてのファイルと情報が入ったファイル)をサーバ側にデプロイする。ここでも先ほどのAntツールを用いると非常に便利。

Step6:Create a client propram

グリッドサービスを実際に利用するクライアントプログラムを作成する。Step4で作成したスタブファイルを用いてサーバ側のメソッドをRPCで呼び出すプログラムである↓

package org.globus.progtutorial.clients.MathService;

import org.globus.progtutorial.stubs.MathService.service.MathServiceGridLocator;
import org.globus.progtutorial.stubs.MathService.MathPortType;

import java.net.URL;

public class Client
{
       public static void main(String[] args)
       {
               try
               {
                       // Get command-line arguments
                       URL GSH = new java.net.URL(args[0]);
                       int a = Integer.parseInt(args[1]);

                       // Get a reference to the MathService instance
                       MathServiceGridLocator mathServiceLocator = new MathServiceGridLocator();
                       MathPortType math = mathServiceLocator.getMathServicePort(GSH);

                       // Call remote method 'add'
                       math.add(a);
                       System.out.println("Added " + a);

                       // Get current value through remote method 'getValue'
                       int value = math.getValue();
                       System.out.println("Current value: " + value);
               }catch(Exception e)
               {
                       System.out.println("ERROR!");
                       e.printStackTrace();
               }
       }
}

作成したクライアントプログラムをコンパイルしておく。

Step7:Run the Grid Service

上記で作成したグリッドサービスを実際に稼働させる。

1. サーバを起動する

$ globus-start-container

2. クライアントプログラム実行

$ java -classpath ./build/classes/:$CLASSPATH org.globus.progtutorial.clients.MathService.Client http://localhost:8080/ogsa/services/progtutorial/core/first/MathService 10

例えば上記ではその後、

Added 10
Current value: 10

という返信がある。

GT3(Globus Toolkit 3) – Service Data

Gridサービスの特徴として,「サービスデータ」という概念がある.これは読んで字のごとく,「Gridサービスが保持するデータ」であり,Webサービスとの違いである「内部的に状態を保持することができる」のを実現している機構を「サービスデータ」と呼ぶ.

概要

サービスデータは,実は,よーく見てみると,ただの「Javaの変数」と同じであったりする.例えば,int型のspeedとfloat型のcostというサービスデータ(サービスデータエレメント:SDE)をxml形式でxsdというファイルで定義すると以下の様になる.

SDE-xsd.gif

XSD(サービスデータ)

サービスデータを定義する.SDEとしては,int型のvalue,String型のlastOpとすると以下の様な感じ.

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions name="MathData"
       targetNamespace="http://www.globus.org/namespaces/2004/02/progtutorial/MathService_sd/
MathSDE"
       xmlns:tns="http://www.globus.org/namespaces/2004/02/progtutorial/MathService_sd/MathSDE"
       xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">

<wsdl:types>
<schema targetNamespace="http://www.globus.org/namespaces/2004/02/progtutorial/
MathService_sd/MathSDE"
       attributeFormDefault="qualified"
       elementFormDefault="qualified"
       xmlns="http://www.w3.org/2001/XMLSchema">

       <complexType name="MathDataType">
               <sequence>
                       <element name="value" type="int"/>
                       <element name="lastOp" type="string"/>
               </sequence>
       </complexType>

</schema>
</wsdl:types>

</wsdl:definitions>

※elementタグのmaxOccures="unbounded"にすると配列になる.

GWSDL(サービスインタフェース)

サービスデータを定義したらgwsdlファイルもちょこっと修正する.
まず,サービスデータを使うための名前空間として以下を追加

xmlns:sd="http://www.gridforum.org/namespaces/2003/03/serviceData"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"

定義した自分のサービスデータをimportする

<import location="MathSDE.xsd"
       namespace="http://www.globus.org/namespaces/2004/02/progtutorial/MathService_sd/
MathSDE"/>

で,<portType>に以下を追加.

  <gwsdl:portType name="MathPortType" extends="ogsi:GridService">

 …

  <sd:serviceData name="MathData"
                 type="data:MathDataType"
                 minOccurs="1"
                 maxOccurs="1"
                 mutability="mutable"
                 modifiable="false"
                 nillable="false">
 </sd:serviceData>
…
</gwsdl:portType>
  • type:サービスデータの名前.
  • minOccurs:サービスデータエレメントの(数の)最小個数.
  • maxOccurs:サービスデータエレメントの(数の)最大個数."unbounded”にすると無制限の配列になる.
  • modifiable:クライアントによって修正可能かどうか.
  • nillable:"null"で良いのか悪いのか.
  • mutability:
    • static:サービスデータエレメントの値がgwsdlで定義されている.
    • constant:Gridサービスが起動した時に,セットされその後はそのまま.
    • extendable:新たにサービスデータを追加できるが,消去することはできない.
    • mutable:新たにサービスデータを追加でき,消去もできる.

マッピング

名前空間とJavaのパッケージをマッピングするnamespace2package.mappingsに以下を追加する.

http?://www.globus.org/namespaces/2004/02/progtutorial/
MathService_sd=org.globus.progtutorial.stubs.MathService_sd
http?://www.globus.org/namespaces/2004/02/progtutorial/MathService_sd/
bindings=org.globus.progtutorial.stubs.MathService_sd.bindings
http?://www.globus.org/namespaces/2004/02/progtutorial/MathService_sd/
service=org.globus.progtutorial.stubs.MathService_sd.service
http?://www.globus.org/namespaces/2004/02/progtutorial/MathService_sd/
MathSDE=org.globus.progtutorial.stubs.MathService_sd.servicedata

上記の

http?://www.globus.org/namespaces/2004/02/progtutorial/MathService_sd/
MathSDE=org.globus.progtutorial.stubs.MathService_sd.servicedata

で,実際にはMathDataType?.javaというJava Bean的なのができる.

サービスプログラム

定義したサービスデータを使うためにまず,以下をimportする

import org.globus.ogsa.ServiceData;
import org.globus.progtutorial.stubs.MathService_sd.servicedata.MathDataType;

MathDataType?が定義したサービスデータのJava Bean的なもの

次に,変数で以下を用意する.

private ServiceData mathDataSDE;
private MathDataType mathDataValue;

そして,postCreateという「サービスが起動したときに実行されるメソッド」を記述する.

public void postCreate(GridContext context) throws GridServiceException {
               // Call base class's postCreate
               super.postCreate(context);

               // Create Service Data Element
               mathDataSDE = this.getServiceDataSet().create("MathData");

               // Create a MathDataType instance and set intial values
               mathDataValue = new MathDataType();
               mathDataValue.setLastOp("NONE");
               mathDataValue.setNumOps(0);
               mathDataValue.setValue(0);
               mathDataValue.setNow(0);
                                
               // Set the value of the SDE to the MathDataType instance
               mathDataSDE.setValue(mathDataValue);

               // Add SDE to Service Data Set
               this.getServiceDataSet().add(mathDataSDE);
}

「Create Service Data Element」で"getServiceDataSet?()"メソッドは"GridServiceBase?”インタフェースで定義されており,"GridServiceBase?"インタフェースを実装している"GridServiceImpl?"を継承している"MathImpl?"(上記のサービスプログラム)のインスタンスに対して行っている.

また,mathDataValue?(サービスデータエレメントの各変数)に対してset***して,mathDataSDE(サービスデータエレメント)にaddして,最後にthis(サービスデータ)にaddする.

同様に,サービスデータの値をgetするには,

mathDataValue.getValue();

の様にする.

クライアントプログラム

クライアント側のプログラムは以下のように,importする.

import org.globus.progtutorial.stubs.MathService_sd.service.MathServiceGridLocator;
import org.globus.progtutorial.stubs.MathService_sd.MathPortType;
import org.globus.progtutorial.stubs.MathService_sd.servicedata.MathDataType;

MathDataType?がサービスデータである.また,サービスデータを利用するために以下もimportする.

import org.gridforum.ogsi.ExtensibilityType;
import org.gridforum.ogsi.ServiceDataValuesType;
import org.globus.ogsa.utils.AnyHelper;
import org.globus.ogsa.utils.QueryHelper;

サービスデータにアクセスするために,以下のようにする.

// Get Service Data Element "MathData"
ExtensibilityType extensibility =  math.findServiceData(QueryHelper.getNamesQuery("MathData"));
ServiceDataValuesType serviceData = AnyHelper.getAsServiceDataValues(extensibility);
MathDataType mathData = (MathDataType) 
AnyHelper.getAsSingleObject(serviceData,MathDataType.class);

"findServiceData?()"はgwsdlで継承した"GridService?"で定義されているメソッドであり,AnyHelper?クラスはよく分からないが,まー,よくよく使うラッパー的な手法らしい….

で,実際にサービスデータの値にアクセスするには,

mathData.getLastOp();
mathData.getNumOps();

のようにする.