本文へジャンプ

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


お客様が developerWorks に初めてサインインすると、プロフィールが作成されます。プロフィールで選択した情報は公開されますが、いつでもその情報を編集できます。お客様の姓名(非表示設定にしていない限り)とディスプレイ・ネームは、投稿するコンテンツと一緒に表示されます。

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

  • 閉じる [x]

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

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

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


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

  • 閉じる [x]

Flex 4 アプリケーションと Java Web アプリケーションを作成する

オブジェクト・リモーティングについて学ぶ

Arron Ferguson, College Instructor, British Columbia Institute of Technology
Photo of Arron Ferguson
Arron Ferguson はこの 13 年間、British Columbia Institute of Technology の講師としてソフトウェア工学を教えています。彼の経験した領域や関心領域は、Java、XML、Web 技術、2-D や 3-D のアニメーション、デジタル・メディア・オーサリングなどです。彼はソフトウェアも作成し、またフリーの技術編集者、校閲者、著作者でもあり、彼の著書には『Creating Content Management Systems in Java』(Delmar Cengage Learning 刊) などがあります。

概要: RIA (Rich Internet Application) では、さまざまな技術を同時に使用する場合がよくあります。技術を適切にグループ分けして選択することで開発時間を短縮することができ、またユーザーに対し、完全でリッチなインターネット・エクスペリエンスを提供することができます。サーバー・サイドで Java™ EE プラットフォームのコンポーネントを使用し、クライアント・サイドで Adobe® Flex™ プラットフォームを使用し、永続ストレージとして MySQL® データベース・サーバーを使用する方法を学びましょう。

日付:  2010年 4月 27日
レベル:  中級 この記事の原文:  英語
アクティビティー: 10781 ビュー
お気軽にご意見・ご感想をお寄せください: 


最近の Web 技術には、多くのことが要求されています。Web 技術には、ユーザー・アカウントを管理できること、コンテンツをアップロードできること、そして動画をストリーミングできることが要求されます。こうした要求から、RIA の開発者は、開発ワークフローを合理化すると同時に、共通して求められる機能を提供する技術を探さなければなりません。開発者にとっての課題は、そうしたサービスを提供するために、どのようにして一連の適切な技術を選択すればよいか、という点にあります。

よく使われる頭字語

  • AMF: Action Message Format
  • API: Application Programming Interface
  • CSS: Cascading StyleSheet
  • GUI: Graphical User Interface
  • HTTP: HyperText Transfer Protocol
  • JAR: Java ARchive
  • POJO: Plain Old Java Object
  • RIA: Rich Internet Application
  • RPC: Remote Procedure Call
  • SDK: Software Development Kit
  • SQL: Structured Query Language
  • UI: User Interface
  • WAR: Web ARchive
  • XML: Extensible Markup Language

Adobe Flex はクライアント・サイドの技術です。Adobe Flex のリッチな API 呼び出しを使用すると、GUI の作成、グラフィックスの描画、メディアの再生やストリーミング、Web サービスへの接続を行うことができます。サーバー・サイドでは、Java 技術を利用することで RDBMS (Relational DataBase Management System) への接続やサービス・リクエストのマルチスレッド処理、需要の増大に合わせた最適なスケーリングを行うことができます。この 2 つの技術を組み合わせることで、RIA アプリケーションの需要を満たす強力な技術スタックを実現することができます。

この記事では、クライアントで Flex を、サーバーで Java 技術を、そしてバックエンド・データベースとして MySQL を使用する、単純ながら強力な RIA を作成する方法について説明します。

サンプル・アプリケーション

このサンプル・アプリケーション (下記の「ダウンロード」セクションから入手することができます) が提供するリッチな UI を利用すると、連絡先情報に対する CRUD (Create、Read、Update、Delete) 操作を Adobe Flash® (SWF) アプリケーションを使って行うことができます。この 3 層構造の Web アーキテクチャーを示したものが図 1 です。この図では、クライアントは Web ページに組み込まれた SWF ファイルとして表現されており、サーバー・アプリケーションは Java サーブレット・コンテナー (この場合は Apache Tomcat) の中で実行しており、データベースは MySQL です。この 3 つの階層を組み合わせることにより、処理能力が分散されたアプリケーションを作成することができます。


図 1. Contacts (連絡先) アプリケーション
上記で説明した、処理能力が分散されたアプリケーションを示すブロック図

Flash アプリケーションと Java サーブレット・コンテナーとの通信として、Adobe BlazeDS フレームワークによるオブジェクト・リモーティングを行っています。オブジェクト・リモーティングは一種の RPC であり、Adobe ActionScript™ オブジェクトからの Java オブジェクトの呼び出し、またその逆を行うことができます。Java サーバー・アプリケーションとリレーショナル・データベースとの通信は Hibernate ORM (Object Relational Mapping) フレームワークによって行います。Hibernate を使うことで、Java オブジェクトから SQL コードへの変換、またその逆の変換を行うことができます。


アプリケーション: サーバー層

最初のステップとして、連絡先情報の保存に必要なすべての情報を網羅する Java クラスを作成します。このサンプル・アプリケーションには、基本的な情報を持つ単純なモデルが含まれています。Contact オブジェクトに必要な属性とデータ型は以下のとおりです。

- String emailAddress
- String firstName
- long id
- String lastName
- String phoneNumber
- long serialVersionUID
+ Contact()
+ Contact(String first, String last, String email, String number)
+ String getEmailAddress()
+ String getFirstName()
+ long getId()
+ String getLastName()
+ String getPhoneNumber()
+ void setEmailAddress(String address)
+ void setFirstName(String first)
+ void setId(long newId)
+ void setLastName(String last)
+ void setPhoneNumber(String number)
+ StringtoString()

ビジネス・オブジェクトにアノテーションを付ける

Java の Contact クラスは、ビジネス・オブジェクトとして動作する POJO (Plain Old Java Object) と考えることができます。つまり Contact クラスはビジネス・ドメインの特性と動作を表現します。Contact オブジェクトの中にあるデータは、データベースの中に永続化する必要があります。そのためのソリューションとして、Hibernate などの ORM フレームワークを使用します。Hibernate は、オブジェクトからデータベース・テーブルのレコードへのマッピング、またその逆のマッピングの大部分を行います。JPA (Java Persistence API) のアノテーションを使用すると、ORM を実現するためのコーディングがほとんど必要なくなります。リスト 1 は、アノテーションが付けられた Java の Contact クラスを示しています。


リスト 1. Java Contact クラス

package bcit.contacts;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

@Entity
@Table(name="contact")
@NamedQueries( {
    @NamedQuery(name = "contact.findAll", query = "from Contact"),
    @NamedQuery(name = "contact.getById", query =
        "select c from Contact c where c.id = :id")
} )
public class Contact {

    private static final long serialVersionUID = 123456789L;

    public Contact() {
        firstName = "N/A";
        lastName = "N/A";
        emailAddress = "N/A";
        phoneNumber = "N/A";
    }

    public Contact(String first, String last, String email, String number) {
        firstName = first;
        lastName = last;
        emailAddress = email;
        phoneNumber = number;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id", nullable = false, updatable=false)
    private long id;

    @Column(name = "lastName", nullable = false, unique = false)
    private String lastName;

    @Column(name = "firstName", nullable = false, unique = false)
    private String firstName;

    @Column(name = "emailAddress", nullable = false, unique = false)
    private String emailAddress;

    @Column(name = "phoneNumber", nullable = false, unique = false)
    private String phoneNumber;

    public void setPhoneNumber(String number) { phoneNumber = number; }

    public String getPhoneNumber() { return phoneNumber; }

    public String getEmailAddress() { return emailAddress; }

    public void setEmailAddress(String address) { emailAddress = address; }

    public String getFirstName() { return firstName; }

    public void setFirstName(String first) { firstName = first; }

    public String getLastName() { return lastName; }

    public void setLastName(String last) { lastName = last; }

    public long getId() { return id; }

    public void setId(long newId) { id = newId; }

    @Override
    public String toString() {
        return id + " " + firstName + " " + lastName + " " + emailAddress
            + " " + phoneNumber;
    }
}

このクラスは単純ですが、ここではアノテーションによって多くのことが行われています。

  • @Column: データベースの列としてプロパティーにラベルを付けます。ラベルの選択肢としては、列の名前、列が一意かどうか、列が nullable (ヌル可能) かどうか、などがあります。
  • @Entity: このクラスをエンティティー Bean (つまり永続化される予定の POJO である) と宣言します。
  • @GeneratedValue: 主キーを生成する方法を指定します。選択肢としては、AUTOIDENTITYSEQUENCETABLE があります。
  • @Id: このプロパティーが各 Java オブジェクトの一意の識別子 (つまり主キー) であると宣言します。
  • @NamedQueries: 一群の名前付きクエリーをリストアップします。
  • @NamedQuery: 定義済みのクエリーを、後で参照して実行されるストリング・リテラルとして宣言します。
  • @Table: この Java クラスをデータベースの中のテーブルとして指定します。

メモリー内の Java オブジェクトを永続化する必要が生じるたびに、Hibernate はすべての Java オブジェクトの状態情報を SQL の更新へと変換します。同様に、結果セットを持つ SQL 文を使って Java オブジェクトに情報を追加します。その結果、すべてのオブジェクトはデータベース内にレコードとして保存され、またすべてのレコードをデータベースから取得して Java オブジェクトに逆変換することができます。

アノテーションによって、クラス内の何を永続的と見なす必要があるかを Hibernate に通知します。ただしそれは、アノテーションの役割の一部にすぎません。

ビジネス・サービス: データベース接続

Hibernate を呼び出して ORM を実行するためには、サービス・クラスが必要です。リスト 2 はアプリケーション・サービスとして動作する ContactsService クラスを示しています。


リスト 2. ContactsService クラス

public class ContactsService {

    private static Logger logger = Logger.getLogger(ContactsService.class);

    private static final String PERSISTENCE_UNIT = "contacts";

    private static EntityManagerFactory emf = null;

    static {
        logger.info("LOADING CONTACTSSERVICE CLASS.");
        emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT);
    }

    public ContactsService() {
        super();
    }

    public void addContact(Contact c) {
        if(c == null) {
            return;
        }

        EntityManager em = emf.createEntityManager();
        logger.info("PERSISTENCE ENTITYMANAGER ACQUIRED.");

        logger.info("ABOUT TO ADD CONTACT: fName: " + c.getFirstName()
            + ", lName: " + c.getLastName() + ", email:" + c.getEmailAddress()
            + ", phone: " + c.getPhoneNumber());
        EntityTransaction tx = em.getTransaction();
        try {
            tx.begin();
            em.merge(c);
            tx.commit();
        } catch (Exception e) {
            logger.error("CONTACT APP PERSISTING ERROR: " + e.getMessage());
            tx.rollback();
        } finally {
            logger.info("CONTACT APP CLOSING ENTITY MANAGER.");
            em.close();
        }
    }

    public void editContact(Contact c) {
        logger.info("CONTACT TO UPDATE: " + c);
        addContact(c);
    }

    public void deleteContact(Long id) {
        logger.info("ABOUT TO DELETE CONTACT");

        EntityManager em = emf.createEntityManager();
        logger.info("PERSISTENCE ENTITYMANAGER ACQUIRED.");

        Query contactByIdQuery = em.createNamedQuery("contact.getById");
        contactByIdQuery.setParameter("id", id);
        Contact c = (Contact) contactByIdQuery.getSingleResult();
        EntityTransaction tx = em.getTransaction();
        try {
            tx.begin();
            em.remove(c);
            tx.commit();

        } catch (Exception e) {
            logger.error("CONTACT APP PERSISTING ERROR: " + e.getMessage());
            tx.rollback();
        } finally {
            logger.info("CONTACT APP CLOSING ENTITY MANAGER.");
            em.close();
        }
    }

    public List<Contact> getContacts() {
        logger.info("ABOUT TO RETRIEVE CONTACTS");

        EntityManager em = emf.createEntityManager();
        logger.info("PERSISTENCE ENTITYMANAGER ACQUIRED.");

        Query findAllContactsQuery =
            em.createNamedQuery("contact.findAll");
        List<Contact> contacts = findAllContactsQuery.getResultList();

        if (contacts != null) {
            logger.debug("CONTACT APP RETRIEVED: " + contacts.size()
                + " CONTACT(S)");
        }
        return contacts;
    }
}

各メソッドは、メモリー内のキャッシュを表す EntityManager への参照を取得します。データベースとのデータの送受信には時間がかかるため、キャッシングは効率を高める強力な機能です。必要なことは、作成されたキャッシュが必ずデータベースにコミットされ、必要ない場合には必ずロールバックされるようにすればよいだけです。

JPA ではキャッシュをパーシスタンス・コンテキストと呼び、またキャッシュは EntityManager クラスによって表現されます。各パーシスタンス・コンテキストによって一連のエンティティーを管理します。エンティティーは、@Entity アノテーションによって注釈が付けられた Java オブジェクトです。EntityManagerFactory クラスはパーシスタンス・ユニットを表します。パーシスタンス・ユニットは、データ・ストア (例えばリレーショナル・データベース) への接続を構成し、エンティティー・タイプ (つまりデータ・ストアへのマッピングに必要な、指定コンテキスト内のすべてのクラス) を管理し、最後にパーシスタンス・コンテキスト (つまり EntityManager) のインスタンスを提供します。

DB2 Express 9 データベース・サーバーの無料版をお試しください

DB2 Express-C は、数分で起動されるように設計されており、使いやすくて簡単に組み込むことができます。また、自己管理機能を持ち、Linux®、UNIX®、Windows® 用の DB2 のコア機能 (pureXML™ など) のすべてが実現されています。DB2 Express-C は他の DB2 Express エディションと同じく、データ・サーバーとしての基本的なコア機能を備えており、C/C++、Java、.NET®、PHP、Ruby on Rails、Python などのプログラミング言語を使って作成されたアプリケーションを構築、デプロイするための強固なベースとなります。

パーシスタンス・コンテキストの作成プロセスにはあまり時間がかかりませんが、パーシスタンス・ユニットの作成プロセスには時間がかかります。データ・ストアへの接続を設定し、エンティティーとしてアノテーションが付けられたすべてのクラスを見つけ、これらのクラスをデータ・ストアの中のエンティティーにバインドするパーシスタンス・ロジックを構成する作業は、とても瞬時に終わるものではありません。従って、EntityManagerFactory インスタンスの作成はアプリケーション起動時の 1 度だけにする必要があります。パーシスタンス・コンテキストに関しては、1 つの EntityManager を破棄してから別の EntityManager を作成するように注意します。もう 1 つ重要なルールとして、「1 つのリクエストに対して 1 つの EntityManager」というパターンに従う必要があります。このパターンに従うことによって、データベースへの呼び出しがグループ化され (例えばリクエストや更新など)、すべての呼び出しが 1 度に送信されます。こうすることで、JPA のキャッシング・メカニズムをフルに活用することができます。

次の必要なものはクライアント・サイドです。


アプリケーション: クライアント層

Flex フレームワークを利用すると、Adobe Flash Player をユーザーが操作できるアプリケーションを作成することができます。Flex は以下の要素で構成されています。

  • 宣言型の XML UI 言語 (MXML と呼ばれます)
  • ActionScript プログラミング言語
  • UI 作成、Web 接続、その他多くの機能のためのランタイム・ライブラリー
  • アプリケーションを SWF ファイルにコンパイルするための開発者ツール

この記事で紹介しているクライアント・アプリケーションでは Flex バージョン 4 を使用しています。クライアント・サイドのアプリケーションを説明する前に、Flex アプリケーションがどのように作成され、Flash Player の中でどのように実行可能プログラムとして存在しているかを理解することが重要です。

第 1 に、MXML マークアップ・コードと ActionScript コードを組み合わせてアプリケーションを作成します。一般的なワークフローとしては、GUI (プレゼンテーション) の大部分を MXML フォーマットを使って作成し、次に ActionScript コードを使ってイベント処理とビジネス・ロジックを作成します。MXML も ActionScript もテキスト・ベースであるため、Flash アプリケーションの作成に必要なものは標準的なテキスト・エディターと Flex SDK のみです。

第 2 に、Flex アプリケーションを作成したら、MXML コンパイラーを使ってコードをコンパイルします。MXML コンパイラーによって SWF ファイルが作成され、これらの SWF ファイルが (ブラウザー用の Flash Player プラグインによって) Web ブラウザーの中で実行されます。

最後に、Flash アプリケーションはタイムラインの仕組みを使う AVM2 (ActionScript Virtual Machine 2) の中で実行します。この仕組みでは、Flash アプリケーションは (映画と同じように) フレームに分割されて実行されます。Flash アプリケーションの毎秒のフレーム数はコンパイル時に指定します。また Flash Player は、Flash アプリケーションの実行を以下の順序のタスクに分割します。

  • Flash Player イベント (タイマー・イベントやマウス・イベントなど)
  • ユーザー・コード
  • 描画前ロジック (Flash Player では、データ値が変更された場合に GUI を更新する必要があるかどうかをこのロジックによって判断しようとします)
  • データ値の変更にバインドされたユーザー・コード
  • Flash Player の描画

毎秒の描画フレームが非常に少ない場合には、ユーザー・コードの大部分は実行されます。しかしフレーム・レートが (毎秒 60 フレームなど) 高い場合には、ユーザー・コードを実行すると許容時間以上の時間を要する可能性があるため、Flash Player はユーザー・コードをあまり実行できない可能性があります。Flash Player アプリケーションを作成する場合には、この点に注意することが重要です。

MXML

MXML は宣言型の強力な XML フォーマットです。MXML を使用することで、以下の内容を実現することができます。

  • XML フォーマットは宣言型のため、GUI の作成に必要なコードを最小限にとどめることができます。
  • プレゼンテーション・ロジックと対話動作ロジックとを明確に分離できるため、GUI コードの複雑さを軽減することができます。
  • ソフトウェア開発にデザイン・パターンを使用することができます。

リスト 3 は MXML による Application クラスを示しています。


リスト 3. ContactsApp クラス

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
  xmlns:contact="bcit.contacts.*" creationComplete="initPage();"
  layout="vertical" frameRate="30" pageTitle="Contacts Example"
  horizontalAlign="center" verticalAlign="middle" 
  backgroundColor="#A9C0E7">


  <mx:Style>
    .mainBoxStyle {
      borderStyle: solid;
      paddingTop: 5px;
      paddingBottom: 5px;
      paddingLeft: 5px;
      paddingRight: 5px;
    }

    .textMessages {
      fontWeight: bold;
    }
  </mx:Style>


  <mx:RemoteObject id="remotingService" showBusyCursor="false"
    destination="contacts" fault="handleFault(event);"
    result="handleResult(event);"/>

  <mx:Script>
    <![CDATA[

        import mx.rpc.events.FaultEvent;
        import mx.rpc.events.ResultEvent;
        import mx.collections.ArrayCollection;
        import bcit.contacts.dto.Contact;

        [Bindable]
        private var contacts:ArrayCollection = new ArrayCollection();

        // For more on the Bindable metadata tag, see the devguide_flex3.pdf
        // document, page 1249 (1257 in PDF page numbering)
        [Bindable]
        private var message:String = "Status: Ready";

        private var contact:Contact;

        public function setControlBarValid(valid:Boolean):void {
            if(valid) {
                // if the selected item is -1, then no item is selected but at
                // the same time the fields are valid which means the user chose
                // to add a contact, not update one
                if(contactsDataGrid.selectedIndex == -1) {
                    createButton.enabled = valid;
                } else {
                    editButton.enabled = valid;
                }
              } else {
                  // else nothing is valid
                  createButton.enabled = false;
                  editButton.enabled = false;
            }
        }

        private function initPage():void {
            editContactForm.setApp(this);
            contact = new Contact();
            getAllContacts();
            resetPage();
        }

        private function createContact():void {
            contact = editContactForm.getContact();
            remotingService.addContact(contact);
            message = "Status: Contact Added";
            getAllContacts();
        }

        private function editContact():void {
            var id:Number = contact.id;
            contact = editContactForm.getContact();
            contact.id = id;
            remotingService.editContact(contact);
            message = "Status: Contact Edited";
            getAllContacts();
        }

        private function deleteContact():void {
            if(contactsDataGrid.selectedItem != null) {
                var c:Contact = contactsDataGrid.selectedItem as Contact;
                // no sense in sending the whole contact - just send the id
                // to cut down on bandwidth
                remotingService.deleteContact(c.id);
                message = "Status: Contact Deleted";
            }
            getAllContacts();
        }

        private function getAllContacts():void {
            loadButton.enabled = false;
            remotingService.getContacts();
            loadButton.enabled = true;
            resetPage();
        }

        private function populateFormWithContact():void {
            contact = contactsDataGrid.selectedItem as Contact;
            editContactForm.setContact(contact);
            editButton.enabled = true;
            deleteButton.enabled = true;
        }

        private function resetPage():void {
            editContactForm.clearForm();
            contact = new Contact();
            createButton.enabled = false;
            editButton.enabled = false;
            deleteButton.enabled = false;
            contactsDataGrid.selectedIndex = -1;
        }

        private function handleFault(e:FaultEvent):void {
            message = "Status: Error"
                + "\nFault code: " + e.fault.faultCode
                + "\nFault detail: " + e.fault.faultDetail
                + "\nFault string: " + e.fault.faultString;
        }

        private function handleResult(e:ResultEvent):void {
            // can get the results by accessing e.result property
            //mx.controls.Alert.show(e.toString());
            contacts = e.result as ArrayCollection;
            var number:int = contacts.length;
            //if(number == 1) {
            //    message = "Status: Retrieved 1 contact";
            //} else {
            //    message = "Status: Retrieved " + contacts.length + " contacts";
            //}
        }

    ]]>
  </mx:Script>

  <mx:VBox styleName="mainBoxStyle">

    <mx:Text id="titleText" text="Single click to select a contact"/>

    <contact:ContactsDataGrid id="contactsDataGrid" dataProvider="{contacts}"
      itemClick="populateFormWithContact();"
      doubleClick="populateFormWithContact();"/>

    <contact:EditContactForm id="editContactForm"/>

    <mx:ControlBar horizontalAlign="center">
      <mx:Button label="List" id="loadButton" click="getAllContacts()"
        toolTip="Retrieve contacts from the server"/>
      <mx:Button label="Add" id="createButton" click="createContact()"
        toolTip="Create a new contact"/>
      <mx:Button label="Update" id="editButton" click="editContact()"
        toolTip="Edit a selected contact"/>
      <mx:Button label="Delete" id="deleteButton" click="deleteContact()"
        toolTip="Delete a selected contact"/>
      <mx:Button label="Clear Form" id="clearButton" click="resetPage()"
        toolTip="Clear the form"/>
    </mx:ControlBar>

    <mx:TextArea text="{message}" styleName="textMessages" wordWrap="true"
      verticalScrollPolicy="auto" horizontalScrollPolicy="off" editable="false"
      width="100%"/>

  </mx:VBox>

</mx:Application>

下記はリスト 3 に関する説明です。

  • MXML 文書のルート要素は Application クラスのサブクラスです。
  • mx:Style 要素を利用すると、CSS プロパティーを使って UI コンポーネントのローカル・スタイルを定義することができます。スタイリングは、ローカルのスタイル定義を使って行う方法 (リスト 3 と同じ)、外部スタイルシートを参照する方法、コンポーネント内にスタイルをインライン化する方法、そして ActionScript の setStyle メソッドを使う方法があります。
  • RemoteObject クラスはサーバーにリモーティング操作を行う HTTP サービス・オブジェクトを表します。
  • mx:Script 要素の CDATA セクションには ActionScript コード・ブロックが含まれています。
  • レイアウト (つまり VBox クラス) が 1 つあります。
  • アプリケーションの中で UI コンポーネント (例えば TextArea など) が宣言されるごとに、インスタンス変数が生成され、そのインスタンス変数が後でアプリケーションの中で、そのコンポーネントの id 属性を使って参照されます。
  • データ・バインディングは丸括弧を使って行われます (例えば TextArea 要素の text 属性は ActionScript の message インスタンス変数にバインドされています)。

ActionScript

MXML で GUI を定義しますが、ActionScript では、イベント処理、([Bindable] メタ・タグによる) データのバインディング、リモート・サービスの呼び出しのための動作を指定します。リスト 3 では、createContact メソッド、editContact メソッド、deleteContact メソッド、getAllContacts メソッドはすべて、サーバー・サイドのリモート・メソッドを呼び出します。リモート・メソッドが呼び出されると、ActionScript はコールバック関数を宣言することで、それらの呼び出しの結果や何らかの障害を処理できるようになります。リスト 3 では、handleResult 関数は呼び出し結果を Object として取得し、その ObjectArrayCollection にキャストしています。サーバー・サイドでは BlazeDS によって ListArrayCollection に変換されています。

リスト 4 は ActionScript による Contact クラスを示しています。このクラスを作成することで、Flash 側の連絡先オブジェクトを表現します。


リスト 4. ActionScript による Contact クラス

package bcit.contacts.dto {

[RemoteClass(alias="bcit.contacts.Contact")]
public class Contact {

    public function Contact() { id = -1; }

    public var id:Number;
    public var lastName:String;
    public var firstName:String;
    public var emailAddress:String;
    public var phoneNumber:String;

    public function toString():String {
        return id + ", " + firstName + " " + lastName + " " + emailAddress
            + " " + phoneNumber;
    }
}
}

これらの ActionScript オブジェクトはサーバー・サイドに送信され、そこで BlazeDS による「魔術」によって ActionScript オブジェクトが Java オブジェクトに変換されます。ActionScript による Contact クラスは DTO (Data Transfer Object) と見なされます。


アプリケーションを構成する

このアプリケーションでは、サーバーの設定の詳細を記述した構成ファイルも使用します。このアプリケーションの構成の主な部分としては、Hibernate と BlazeDS の 2 つがあります。

Hibernate を構成する

Hibernate の構成は JPA の標準的な構成ファイル (この場合は persistence.xml) を使って行うことができます。このファイルを示したものがリスト 5 です。


リスト 5. persistence.xml 構成ファイルの抜粋

<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
  http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
  <persistence-unit name="contacts" transaction-type="RESOURCE_LOCAL">
    <properties>
      <property name="hibernate.dialect"
        value="org.hibernate.dialect.MySQLDialect" />
      <property name="hibernate.default_schema" value="contacts" />
      <property name="hibernate.connection.driver_class"
        value="com.mysql.jdbc.Driver" />
      <property name="hibernate.connection.url"
        value="jdbc:mysql://localhost:3306/contacts" />
      <property name="hibernate.archive.autodetection" value="class, hbm"/>
      <property name="hibernate.connection.username" value="root"/>
      <property name="hibernate.connection.password" value="root"/>
    </properties>
  </persistence-unit>
</persistence>

Hibernate が読み取れるように、persistence.xml ファイルを Web アプリケーションの WEB-INF/classes/META-INF フォルダーに入れる必要があります。そのように配置した後、Hibernate には以下の情報が必要です。

  • データベースの方言 (つまり (多くのデータベースには少しずつ異なる SQL 方言があるため)、どのデータベースと通信しているのか)
  • デフォルトのスキーマによるテーブル・スペース
  • データベースへの接続に使用されるデータベース・ドライバー
  • データベースの URL
  • 自動検出によって何を検出するか (例えば、アノテーションの付いたクラス、Hibernate によってマッピングされた XML ファイルなど)
  • ユーザー名とパスワード

他にも Hibernate のパフォーマンスの向上に役立つ情報はありますが、それらの情報は必須ではありません。

BlazeDS を構成する

BlazeDS には以下の 4 つの構成ファイルがあります。

  • messaging-config.xml: パブリッシュ/サブスクライブ型のメッセージ情報を定義します。
  • proxy-config.xml: HTTP サービスと Web サービス用のプロキシー・サービス情報を提供します。
  • remoting-config.xml: リモーティング・サービス (例えばこの記事のアプリケーションなど) のための情報を定義します。
  • services-config.xml: 最上位レベルの構成ファイルであり、他の構成ファイルを参照し、セキュリティーの制約やチャネル、ロギングを実現します。

リスト 6 は services-config.xml ファイルを示しています。この記事のアプリケーションの場合は BlazeDS のリモーティング・サービスを使っているにすぎないため、重要なファイルは remoting-config.xml のみであることに注意してください。


リスト 6. services-config.xml 構成ファイルの抜粋

<?xml version="1.0" encoding="UTF-8"?>
<services-config>
  <services>
    <service-include file-path="remoting-config.xml" />
    <service-include file-path="messaging-config.xml" />
    <service-include file-path="proxy-config.xml" />
    <default-channels>
       <channel ref="contacts-amf"/>
    </default-channels>
  </services>

  <channels>
    <channel-definition id="contacts-amf" class="mx.messaging.channels.AMFChannel">
      <endpoint url="http://localhost:8080/contacts/messagebroker/amf"
        class="flex.messaging.endpoints.AMFEndpoint"/>
      <properties>
        <polling-enabled>false</polling-enabled>
      </properties>
    </channel-definition>
  </channels>

  <logging>
    <target class="flex.messaging.log.ConsoleTarget" level="Error">
      <properties>
        <prefix>[BlazeDS] </prefix>
        <includeDate>false</includeDate>
        <includeTime>false</includeTime>
        <includeLevel>false</includeLevel>
        <includeCategory>false</includeCategory>
      </properties>
      <filters>
        <pattern>Endpoint.*</pattern>
        <pattern>Service.*</pattern>
        <pattern>Configuration</pattern>
      </filters>
    </target>
  </logging>

</services-config>

services-config.xml 構成ファイルは、他の構成ファイルを参照し (他の構成ファイルが存在するはずです)、BlazeDS のロギングを構成し、何らかのチャネルを設定します。チャネルは、クライアントがサーバーとの通信に使用するプロトコルを抽象化したものです。この記事のアプリケーションでは、標準的な AMF プロトコルをポーリングなしで使用しました。ポーリングというのは、クライアントがサーバーと継続的に通信し、接続が確立されていることを確認することです。しかし、このアプリケーションにはポーリングは必要ありません。

My developerWorks の Web development グループに参加してください。

My developerWorks の Web development グループに参加し、Web 開発について他の開発者と多様な話題を議論し、またリソースを共有してください。

まだ My developerWorks のメンバーになっていない方は、今すぐ登録してください!

チャネルのエンドポイントはサーバーの URL を指定します。このエンドポイントはプロジェクトのコンパイルに必要です。クライアントの Flash アプリケーションは、このエンドポイントをハードコーディングされた値として使用することで接続先のサーバーを認識します。実際には、このようにする代わりに、MXML コードまたは ActionScript コードの中でエンドポイントの URL を直接定義することもできます。

最後に、remoting-config.xml 構成ファイル (リスト 7) は、リモーティング操作の処理に必要なアダプター・クラスと、リモーティング呼び出しに実際に応答するクラスを指定します。(この場合には、リモート・リクエストに対する応答機能として bcit.contacts.ContactsService クラスが指定されています。)


リスト 7. remoting-config.xml 構成ファイルの抜粋

<?xml version="1.0" encoding="UTF-8"?>
<service id="remoting-service"
  class="flex.messaging.services.RemotingService">

  <adapters>
    <adapter-definition id="java-object" default="true"
      class="flex.messaging.services.remoting.adapters.JavaAdapter"/>
  </adapters>

  <default-channels>
    <channel ref="contacts-amf"/>
  </default-channels>

  <destination id="contacts">
    <properties>
      <source>bcit.contacts.ContactsService</source>
      <!--<scope>application</scope>-->
    </properties>
  </destination>

</service>


まとめ

この記事では、サーバー・サイドの Java Web アプリケーションを作成し、そのアプリケーションを Tomcat の中で実行し、連絡先情報に対する要求に応答させる方法を説明しました。また、Flex アプリケーションの作成方法として、MXML と ActionScript の両方を使ってクライアント・サイドの Flash アプリケーションを作成する方法も学びました。MySQL はデータ・ストアとしての役割を果たし、Hibernate (ORM フレームワーク) は Java オブジェクトを SQL 文に変換するために使用され、その SQL 文を使用して MySQL データベースに対して照会や更新を行うことができました。最後に、BlazeDS フレームワークを使用して Flash アプリケーションがリモート・プロシージャー・コールを行えるように、またサーバー・サイドの Java Web アプリケーションに対してリモーティングを行えるようにしました。



ダウンロード

ファイル名サイズダウンロード形式
JEE-BlazeDS-Flex-contacts.zip7MBHTTP

ダウンロード形式について

More downloads

  1. This zip file contains all of the source code (Java, ActionScript 3, MXML) for this project, the Ant build file to generate the WAR, configuration files, and third-party libraries (in the form of JAR files) that this article references and uses.
  2. An open source RDBMS required for use with the example project in this article
  3. A Java-based build tool for building the example project
  4. The Java SDK (JDK) version 6, required for compiling Java source code within the example project
  5. The Flex 4 SDK for compiling MXML and ActionScript source code within the example project
  6. The Apache Software Foundation servlet container that provides a Java HTTP Web server environment for running the example project
  7. The Adobe framework for connecting Flex technology to Java Platform, Enterprise Edition (Java EE). This software is only for reference, as it is already included in the project download for this article.
  8. Red Hat ORM framework for Java EE container middleware. This software is only for reference, as it is already included in the project download for this article.

参考文献

学ぶために

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

  • ご自分に最適な方法で IBM 製品を評価してください。評価の方法としては、製品の試用版をダウンロードすることも、オンラインで製品を試してみることも、クラウド環境で製品を使用することもできます。また、SOA Sandbox では、数時間でサービス指向アーキテクチャーの実装方法を効率的に学ぶことができます。

議論するために

  • My developerWorks コミュニティーに加わってください。ここでは他の developerWorks ユーザーとのつながりを持てる他、開発者が主導するブログ、フォーラム、グループ、ウィキを調べることができます。

著者について

Photo of Arron Ferguson

Arron Ferguson はこの 13 年間、British Columbia Institute of Technology の講師としてソフトウェア工学を教えています。彼の経験した領域や関心領域は、Java、XML、Web 技術、2-D や 3-D のアニメーション、デジタル・メディア・オーサリングなどです。彼はソフトウェアも作成し、またフリーの技術編集者、校閲者、著作者でもあり、彼の著書には『Creating Content Management Systems in Java』(Delmar Cengage Learning 刊) などがあります。

不正使用の報告のヘルプ

不正使用の報告

ありがとうございます。 このエントリーは、モデレーターの注目フラグが設定されました。


不正使用の報告のヘルプ

不正使用の報告

不正使用の報告の送信に失敗しました。


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=Web development, Java technology, Open source
ArticleID=493295
ArticleTitle=Flex 4 アプリケーションと Java Web アプリケーションを作成する
publish-date=04272010
author1-email=arron_ferguson@bcit.ca
author1-email-cc=

タグ

Help
このタグで、My developerWorks のすべてのタイプのコンテンツを見つけるために検索フィールドを使用します。

スライダーバーを使用することで、より多く(少なく)タグを表示します。

人気のタグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するトップのタグを表示します。

マイ・タグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するお客様ご自身のタグを表示します。

このタグで、My developerWorks のすべてのタイプのコンテンツを見つけるために検索フィールドを使用します。人気のタグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するトップのタグを表示します。マイ・タグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するお客様ご自身のタグを表示します。