Ajax アプリケーションは非常に人々に好まれており、デスクトップ・アプリケーションの代わりに Ajax アプリケーションを使おうとする人が増えています。Ajax アプリケーションの唯一の問題は、ネットワークにアクセスできない場合には使うことができないことで、そうした場合にはオフライン機能が必要になります。Apache Derby は、Ajax 機能を備えたアプリケーションにオフラインでアクセスするための素晴らしい選択肢です。Apache Derby をローカルのデータ・ストアとして使う方法を学び、Ajax アプリケーションをオフラインで使えるようにしましょう。

Michael Galpin, Software architect, eBay

Galpin Michael photoMichael Galpin は、1998年以来、プロとして Java ソフトウェアを開発してきています。彼は現在 eBay に勤務しています。彼は California Institute of Technology で数学の学位を取得しています。



2008年 9月 23日

前提条件とシステム要件

この記事では Apache Derby をクライアント・サイドのデータベースとして使います。Derby は単体でダウンロードすることもできますが、Java™ 6 にもバンドルされており、Java DB と呼ばれています。この記事では Derby V10.4.1.3 を Java 5 と 6 と組み合わせて使います。そして Java アプレットを活用してブラウザー上で Derby を動作させ、JavaScript を使ってアプレットにアクセスします。従って Java アプレットと JavaScript についてよく理解している必要があります。Derby では通常の JDBC と SQL を使うことができるため、これらについてもよく理解しているという前提で説明を進めます (「参考文献」を参照)。


アプレットで Derby を使用する

Apache Derby は任意の Java アプリケーションで使うことができる組み込みデータベースです。Apache Derby は非常に便利なツールであるため、Java SE (Java Platform, Standard Edition) V6 にバンドルされています。組み込みデータベースの使い方は無数にありますが、Derby を使うことによって実現できるクライアント・サイドの機能の中には、あまり多くの人に知られていないものもあります。この記事ではその機能の使い方を学ぶために簡単なアドレス帳アプリケーションを作成します。まず Apache Derby を利用する Java アプレットから始め、最終的に Derby をキャッシュとして使う Ajax ベースのアプリケーションへと移行します。

データ・アクセス

この記事はデータベース技術に関する記事なので、データベースのコードから始めるのが適切でしょう。まず、連絡先 (contact) を保存するための単純なテーブル・スキーマを定義します。これを以下に示します。

図 1. Contact テーブル
The Contact table

連絡先用のスキーマとしては、もっとずっと複雑なものを考えることもできます (例えば複数の電話番号や住所等々を持つ、など)。しかしこの記事のアプリケーションでは上記で十分です。もちろん、この連絡先用のテーブルに対応する Java クラスがあります。ここでは Active Record のパターンに従い、すべてのデータベース操作を行えるクラスでデータベースの行をラップします。そのコードを以下に示します。

リスト 1. Contact クラス
public class Contact {
    
    private Integer id;
    private String firstName;
    private String lastName;
    private String email;
    
    public static List<Contact> getContacts(String clause){
        if (clause == null)
            clause = "";
        String sql = SELECT_SQL + clause;
        Connection conn = DbManager.getConnection();
        List<Contact> contacts = new ArrayList<Contact>();
        try {
            ResultSet cursor = conn.createStatement().executeQuery(sql);
            while (cursor.next()){
                Contact c = new Contact();
                c.setId(cursor.getInt(1));
                c.setFirstName(cursor.getString(2));
                c.setLastName(cursor.getString(3));
                c.setEmail(cursor.getString(4));
                contacts.add(c);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return contacts;
    }
    
    public static List<Contact> getAllContacts(){
        return Contact.getContacts(null);
    }
    
    public static Contact getContact(String clause){
        List<Contact> results = Contact.getContacts(clause);
        if (results == null || results.size() != 1){
            return null;
        }
        else return results.get(0);    
    }
    
    public void save(){
        if (id == null)
            insert();
        else
            update();
    }
    
    public void delete(){
        Connection conn = DbManager.getConnection();
        String sql = "delete from Contact where id=?";
        try{
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setInt(1, id);
            ps.executeUpdate();
            System.out.println("Deleted contact id="+id);
        } catch (SQLException e){
            e.printStackTrace();
        }
    }
    
    private void insert() {
        Connection conn = DbManager.getConnection();
        try {
            PreparedStatement ps = conn.prepareStatement(INSERT_SQL, 
                    PreparedStatement.RETURN_GENERATED_KEYS);
            ps.setString(1, firstName);
            ps.setString(2, lastName);
            ps.setString(3, email);
            ps.executeUpdate();
            ResultSet autoRs = ps.getGeneratedKeys();
            if (autoRs.next()){
                id = autoRs.getInt(1);
            }
            System.out.println("Contact saved new id = " + id);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    
    private void update(){
        Connection conn = DbManager.getConnection();
        try{
            PreparedStatement ps = conn.prepareStatement(UPDATE_SQL);
            ps.setString(1, firstName);
            ps.setString(2, lastName);
            ps.setString(3, email);
            ps.setInt(4, id);
            ps.executeUpdate();
            System.out.println("Contact updated with id="+id);
        } catch (SQLException e){
            e.printStackTrace();
        }
    }

このクラスは多くのことを行いますが、どれも非常に単純です。データベースの列に対応するフィールドと、各フィールドに対する通常のアクセサー (ゲッターとセッター) があります。またすべての CRUD (CReate Update Delete) 操作を行うためのメソッドと、それらのメソッドを使った SQL クエリーもあります。連絡先の照会を行うためのメソッドは静的メソッドなので、例えば Contact.getAllContacts() のようなことを行うことができます。保存と削除の操作はインスタンス・メソッドなので、個々の連絡先に対してこれらの操作を呼び出すことができます。クエリーは標準的な SQL なので、ここには示してありません。このクラスには通常のゲッターとセッターもありますが、ここでは簡単のため省略してあります (完全なコード・リストは「ダウンロード」を参照してください)。このクラスは Derby を使ったクライアント・サイドのストレージの基本となります。最初はこのクラスをアプレット UI の一部として使いますが、後でこのアプレットは、JavaScript が (このアプレットを) 利用するためのみに使われることになります。それぞれのメソッドでは、接続を行うために DbManager というユーティリティー・クラスを呼び出していることに注目してください。

リスト 2. DbManager クラス
package org.developerworks.addressbook;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DbManager {
    static{
        try {
            Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } 
    }
    
    public static Connection getConnection(){
        try {
            Connection conn = DriverManager.getConnection("jdbc:derby:contacts;
create=true");
            return conn;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
}

Derby 専用のコードはすべてこの中にあります。いや実は、このコードは必ずしも Derby 専用というわけではありません。ここでは組み込みのデータベースを使っていますが、このデータベースを、JDBC でアクセスされる単なる別のデータベースとして扱う必要があります。このクラスの静的イニシャライザーの中で、ドライバー・クラスとして EmbeddedDriver を使います。また getConnection メソッドに対して create=true というパラメーターを追加し、まだデータベースが存在していなければデータベースを作成するように Derby に指示します。JDBC に通常見られるユーザー名やパスワードが必要ないことに注意してください (これは組み込みのデータベースを使うことによる 1 つのメリットです)。以上見てきたものが、データにアクセスするコードのすべてです。これらのコードはどのアプリケーションにも見られるデータベース・コードと非常に似ており、ここでは単にデータベースが組み込みの Derby データベースであるにすぎません。しかし別のアプリケーション・モデルを作成することも考えられます。つまりアプリケーション専用のデータをクライアント・サイドに保存できるようにするのです。では、リスト 2 に示すデータ・アクセス・コードを活用する単純なアプリケーションを調べてみましょう。

アプレット UI

まず、上のデータ・アクセス・コードを利用する非常に単純なアプレットを使うことから始めます。

リスト 3. アプレット UI のコード
public class AddressBookApplet extends JApplet {
    private static final long serialVersionUID = 1L;    
    private static final String[] columns = { "First Name", "Last Name", "Email", "Id"};
    
    public AddressBookApplet() {
        this.setLayout(new GridLayout(1,0));
        JPanel panel = buildUi();
        this.add(panel);
    }

    public Contact addContact(String firstName, String lastName, String email) {
        Contact c = new Contact();
        c.setFirstName(firstName);
        c.setLastName(lastName);
        c.setEmail(email);
        c.save();
        return c;
    }
    
    public void deleteContact(Integer id){
        Contact c= new Contact();
        c.setId(id);
        c.delete();
    }

    public Object[][] loadContacts() {
        List<Contact> book = Contact.getAllContacts();
        Object[][] contacts = new Object[book.size()][4];
        int cnt = 0;
        for (Contact contact : book){
            contacts[cnt++] = contact.toArray();
        }
        return contacts;
    }

    private JPanel buildUi() {
        JPanel panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        
        final DefaultTableModel dataModel = createDataModel();
        final JTable table = createTable(dataModel);
        
        //Lots of Swing/UI Code omitted for brevity    
      }
    
    private JTable createTable(final DefaultTableModel dataModel) {
        final JTable table = new JTable(dataModel);
        table.setPreferredScrollableViewportSize(new Dimension(500, 70));
        table.setFillsViewportHeight(true);
        return table;
    }

    private DefaultTableModel createDataModel() {
        Object[][] contacts = loadContacts();
        final DefaultTableModel dataModel = new DefaultTableModel(contacts, columns);
        return dataModel;
    }
}

このコードの大部分は UI を作成するための典型的な Swing コードです。すべての UI コードは、このクラスの一番下にある private メソッドの中で実行されます。buildUi メソッドは Swing コンポーネントを作成するための調整を行いますが、その大部分は簡単のため省略してあります。それよりも興味深い部分は、(コンストラクターを除く) addContactdeleteContactloadContacts という 3 つの public メソッドです。これらの各メソッドは基本的に先ほど作成したデータ・アクセス・コードのラッパーです。最終的なアプリケーションの UI ではあまりアプレットを使いたくありませんが、アプレットを使うことでコードのテストを容易に行うことができます。Eclipse を使っている場合には、単純に Applet クラスを右クリックし、Run As > Java Applet の順に選択します。

図 2. Eclipse の中で Java アプレットとして実行する
Eclipse の中で Java アプレットとして実行する

ここでは Eclipse が何か魔法を使っているわけではなく、単に JDK の Applet Viewer を使っているにすぎません。Eclipse を使っていない場合には、コマンドラインで Applet Viewer を呼び出すことができます。どちらの方法を使った場合にも、図 3 のようなものが表示されるはずです。

図 3. Applet Viewer を使ってアプレットを実行する
Applet Viewer を使ってアプレットを実行する

アプリケーションをテストするために、連絡先の追加と削除を行ってみます。ここで説明した方法によって、後で JavaScript を使ってアクセスできるクライアント・サイドのデータベース・コードを容易に作成し、テストすることができます。このアプレット UI は変わった形のユニット・テストのようなものです。この UI はほとんど Web ページに追加できる形になっていますが、まだ完全ではありません。Web ページに追加するにはまず、セキュリティーに関するいくつかの懸念事項に対応する必要があります。

セキュリティー

このアプレットの中で使われる JAR には署名が必要です。ここまでの説明に従っていると、1 つ好都合と思われることがあります。それは、Derby によって、クライアントに組み込まれた永続的なデータベースが得られることです (すべてのものがクライアントに保存されます)。このデータベースは HTTP クッキーのようなものですが、クッキーは悪評のとおりドメイン当たり 4 KB に制限されています。では、クライアント上の Derby データベースの制限はどの程度なのでしょう。その答えは、大量 (例えば実際には無制限)、または少量 (例えばゼロ) のいずれかです。

デフォルトで、アプレットはローカルのファイルシステムにアクセスすることができません。そのため Derby はクライアントにデータを保存することができません。では Derby を使うことは夢物語なのでしょうか。幸いなことに、そんなことはありません。そのための鍵は、アプレットにデジタル署名することです。署名されたアプレットはローカルのファイルシステムにアクセスできるため、署名されたアプレットからのデータであれば、Derby はそのデータを永続化することができます。つまり必要なことは、アプレットに署名することだけです。

リスト 4. アプレットに署名する
$ keytool -genkey -alias sigs -keystore sigstore -keypass password -storepass password
What is your first and last name?
  [Unknown]:  Michael
What is the name of your organizational unit?
  [Unknown]:  developerWorks
What is the name of your organization?
  [Unknown]:  IBM
What is the name of your City or Locality?
  [Unknown]:  San Jose
What is the name of your State or Province?
  [Unknown]:  CA
What is the two-letter country code for this unit?
  [Unknown]:  US
Is CN=Michael, OU=developerWorks, O=IBM, L=San Jose, ST=CA, C=US correct?
  [no]:  yes

$ jarsigner -keystore sigstore -storepass password -keypass password -signedjar 
addrbook.jar derby.jar sigs

Warning: The signer certificate will expire within six months.

これを見るとわかるように、ここでは 2 つの JDK ツールを使ってアプレット (技術的にはアプレットを含む JAR) に署名しています。まず、生成された暗号化キーを保持するためのキー・ストアを keytool を使って作成します。このツールは SSL 証明書の作成などに使われるツールと同じです。キーが作成できたら、そのキーと jarsigner ツールを組み合わせることで JAR に署名します。ただしカスタム・コードを含む addrbook JAR と共に Derby の JAR が含まれていることに注意してください。最後に、この自己署名のアプレットの一例は、開発用には適切ですが、ユーザーに公開されるコードには通常適切ではありません。ユーザーに公開されるコードの場合には、信頼できる提供者 (VeriSign など) の発行したキーと証明書が必要です。以上の要点をまとめると、クライアントにデータを保存する必要があるため、こうした余分なステップを踏むことによって Java 言語でのクライアント・サイドのセキュリティー・モデルに準拠する必要があるということです。こうしたセキュリティーの考慮事項を頭に入れる一方で、動作するアプレットが用意できると、このアプレットを JavaScript から使う準備が整ったことになります。


アプレットで JavaScript を使用する

アプレットは Web アプリケーションのすべてのものに使うことができますが、Web アプリケーションの UI には標準的な HTML と JavaScript を使う方が一般的です。しかし標準的な HTML と JavaScript を使いながら、組み込みの Derby データベースにアクセスする手段としてアプレットを使うことは相変わらず可能です。そのためには、JavaScript とアプレットとを少しばかり統合する必要があります。

アプレットとの統合

JavaScript と Java アプレットの間の通信用のコードを作成すると聞くと、面倒そうであったり、何らかの新しい技術を使ったりするかのように思えます。しかしそんなことはありません。こうした種類の統合は Netscape Navigator の頃から行われており、そこで使われている手法は相変わらず有効なのです。まず、単にページの中にアプレットを組み込むための HTML コードを調べてみましょう。

リスト 5. アプレットを組み込むコード
<applet alt="Address Book Applet" name="addrBookApplet" 
    code="org.developerworks.addressbook.AddressBookApplet"
    width="400" height="200" archive="addrbook.jar, derby.jar">
</applet>

これはアプレットを組み込むためのコードとして非常に標準的なものです。このコードでは、非推奨となっている <applet> タグを使っています。<applet> タグはさまざまなブラウザーで相変わらず広くサポートされており、アプレットを組み込むために Microsoft® と Mozilla のブラウザーで共通で使うことができる唯一のタグです。このタグを使いたくない場合には、JavaScript を使ってブラウザーを検出し (ユーザーがどのブラウザーを使っているのかを判断し)、Internet Explorer が使われている場合には <object> を使い、それ以外の場合には、ネストされた <param> タグを持つ <embed> タグを、高さや幅、アーカイブの属性などに使う必要があります。また、<object> タグを使う場合には、アプレットの Java メソッドを JavaScript が呼び出せるようにするための、スクリプト化可能なパラメーターも必要です。<applet> タグを使う場合には、そうしたものは必要ありません。

もう 1 つ注意しなければならないのは、MAYSCRIPT 属性です。この属性は、ページ上で JavaScript を実行することをアプレットに許可するために使われるもので、非常に便利ですが、ここでは必要ありません。ここでは JavaScript を使ってアプレットにアクセスします (JavaScript がアプレットの Java メソッドを呼び出します)。しかしアプレットが JavaScript を呼び出すことはないので、MAYSCRIPT 属性は必要ないのです。では、これらの Java メソッドを JavaScript から呼び出すにはどのようにするのでしょう。

リスト 6. JavaScript から Java を呼び出す
function saveContact(firstName, lastName, email){
    var applet = document.addrBookApplet;
    var newContact = applet.addContact(firstName, lastName, email);
    addContactToUi(newContact);
}

saveContact 関数の中では最初に、アプレットのハンドルを取得します。そのためにはアプレットの名前 (リスト 5 の name 属性) を使います。ハンドルを取得した後、addContact メソッドを直接呼び出すと、このメソッドはリスト 6 のコードの新しい Contact オブジェクトを返します。そこで、このオブジェクトを別の JavaScript 関数に渡し、新しい連絡先を使って UI を更新します。これ以上のことは必要なく、こんなにも簡単なのです。パーシスタンス (永続化) のためにのみアプレットを使い、それ以外のすべてには JavaScript を使うのです。

ヘッドレス・アプレットを使用する

今度はアプレットをヘッドレス (UI を持たずコード・ライブラリーのみ) にします。そのためには、単にリスト 3 からすべての UI を削除し、先頭の方にある public メソッドのみを残します。ここで UI を組み込むコードを少し変更する必要があります。

リスト 7. ヘッドレス UI の HTML
<applet alt="Headless Applet" name="headlessApplet"
    code="org.developerworks.addressbook.HeadlesApplet"
    width="1" height="1" archive="addrbook.jar, derby.jar">
</applet>

ここで唯一注目すべき点は、幅と高さを両方とも 1 にした、という点です。こうすることによって、ページ上でこのアプレットが実質的に見えなくなります。その結果エンド・ユーザーには、ページ上にアプレットがあることがまったくわかりません。これは目に見えないヘルパーです。もちろん、アプレットの名前を変更する場合には JavaScript も少し変更する必要がありますが、それ以外には何も変更する必要はありません。これで、クライアント・サイドのパーシスタンス・ツールを使って Web アプリケーションをさらに強化する準備が整いました。


Ajax キャッシュを作成する

Ajax で可能なことの多くはアプレットを使っても行うことができます。しかもここまでに説明したとおり、さらに多くのことをアプレットによって行うことができます。ここでは、その「もっと多くの」部分のみに注目します。アプレットはサーバーと通信することができますが、ここではサーバーとの通信には通常どおり Ajax を使います。Derby はクライアント・サイドの組み込みデータベースとして使えるため、Ajax 単体では不可能なことを行うことができます。さらに重要なことに、サーバーからのデータに対するクライアント・サイドの強力なキャッシュとして Derby を使うことができるのです。

Derby をキャッシュとして使用する

この考え方は次のとおりです。つまり連絡先はサーバーに置き、(追加や削除など) すべての操作を Ajax 呼び出しによって行いますが、同じ情報をクライアントの Derby に保持し、キャッシュとして Derby を使うのです。こうすることで、すべての連絡先を Derby からロードできるようになります。

リスト 8. Derby を使ったキャッシュから連絡先をロードする
function init(){
    var book = document.headlessApplet.loadContacts();
    var i = 0;
    var contact = {};
    for (i=0;i<book.length;i++){
        contact = {firstName:book[i][0], lastName:book[i][1], 
                    email:book[i][2], id:book[i][3]};
        addContactToUi(contact);
    }
}

この関数はアプレットから連絡先をロードし、そのデータに繰り返し処理を行うことで各連絡先を UI に追加します。ページが初めてロードされると、このコードが呼び出されます。通常はサーバーから連絡先を取得するため、サーバーからのレスポンスを待つための時間が少し発生します。Derby によるキャッシュを使った場合には待ち時間が発生しません。しかし、サーバーと Derby によるキャッシュの間で必ず連絡先を同期させる必要があります。

同期を保つ

キャッシュは正確でなければ使い道がないため、キャッシュとサーバーとを必ず同期させる必要があります。そのために最も簡単な方法は、非同期の更新をサーバーに送信し、その処理が行われている間にキャッシュとアプリケーションの UI を更新する方法です。

リスト 9. 連絡先を追加する
function addContact(){
    var contact = {};
    var firstName = document.getElementById("firstName").value;
    var lastName = document.getElementById("lastName").value;
    var email = document.getElementById("email").value;
    var req = getXhr(); // get the browser specific XMLHttpRequest object
    var params = "firstName="+username + ",lastName="+lastName+",email="+email;
    req.open("POST", "/contact/create", true);
    req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    req.setRequestHeader("Content-length", params.length);
    req.setRequestHeader("Connection", "close");
    req.onreadystatechange = handleResponse;    
    req.send(params);    
    // update cache
    saveContact(firstName, lastName, email);
}

このコードの大部分は XMLHttpRequest オブジェクトを使った典型的な Ajax コードです。ここでは通常どおり単純に XMLHttpRequest を送信しています。この送信は非同期なので、req.send() 呼び出しからは即座にリターンされます。次にリスト 6 の saveContact() 関数を呼び出します。これらの関数を呼び出す前に (req.onreadystatechange プロパティーを設定することで) ハンドラーを登録していることに注目してください。この方法では、サーバーの呼び出しに失敗した場合の処理を、このハンドラーのコードが行う必要があります。サーバーの呼び出しに失敗するのは、サーバーが一時的にダウンしている場合や、ユーザーにネットワークの問題がある場合などですが、そうした場合には、非常に高度な方法として、後でサーバーまたネットワークが復旧したときに再試行できるように更新情報をキューに入れておく方法があります。あるいは、saveContact 呼び出しをハンドラーに移すこともできます。そうすると UI の応答性が少し悪くなりますが、この方法の場合はサーバーへの更新に成功した場合にのみUI とキャッシュを更新すればよくなります。


まとめ

この記事では、組み込みのデータベースとして Derby を使うことがいかに容易であるかを紹介しました。そしてこのデータベースを Java アプレットの中に組み込み、クライアントのデータを永続化する方法を説明しました。この場合、いくつかのセキュリティー要因を考慮する必要があります。つまりクライアントのファイルシステムにデータを書き込めるのは署名されたアプレットのみです。しかしアプレットに署名するためのプロセスとツールをよく調べた上で考えると、JavaScript から容易にアプレットにアクセスすることができ、また Derby を Ajax 対応の Web アプリケーション用のキャッシュとして使うことができます。こうすることにより、たとえサーバーが一時的に利用できない場合であってもデータにアクセスできるようになります。つまり Derby はあらゆる種類の「オフライン」戦略の重要部分となり得るものであり、たとえサーバーが利用できない場合にも Derby によってデータを利用できるようになります。


ダウンロード

内容ファイル名サイズ
Sample codeos-ad-offline-ajax-AddressBook.zip8KB

参考文献

学ぶために

製品や技術を入手するために

  • バージョン 6 (またはそれ以降) の Java SE (Java Platform, Standard Edition) を入手してください。この中には Java DB と、Sun Microsystem バージョンの Apache Derby が含まれています。
  • Apache Derby をダウンロードしてください。この記事では Derby V10.4.1.3 を使用しています。
  • 皆さんの次期オープンソース開発プロジェクトを IBM ソフトウェアの試用版で革新してください。ダウンロードまたは DVD で入手することができます。
  • IBM 製品の試用版をダウンロードし、DB2® や Lotus®、Rational®、Tivoli®、WebSphere® などが提供するアプリケーション開発ツールやミドルウェア製品をお試しください。

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Open source
ArticleID=347428
ArticleTitle=Apache Derby によるオフラインの Ajax
publish-date=09232008