japan.internet.com
japan.internet.com メンバーID
Twitter
Facebook
RSS
ピックアップ
2006年9月5日 11:00

Eclipse RCPとSpringによる実用的なシッククライアントの構築

著者Stephen Lumオリジナル版を読む海外海外発

はじめに

 世間ではWeb 2.0やRIA(Rich Internet Application)が大流行していますが、投資家向けに機能豊富なWebフロントエンドを構築したとしても、本当に必要なものがシッククライアント(thick-client)の機能である場合には役に立ちません。私の以前の投稿『シッククライアントを配備するためのJavaアプリケーションサーバー基盤の構築』では、従来のJava Webサーバーアーキテクチャを活用してシッククライアントを簡単に配備する方法を紹介しました。

 しかし、RIAの流行を避けて実用的なシッククライアントソリューションを構築するためには、実際にどうしたらよいでしょうか。その答えとなるのがRCP(Rich Client Platform)です。RCPは、Javaデスクトップアプリケーションの世界にフレームワークの概念を持ち込むものです。J2EE/Java EEの世界には以前から数多くのフレームワークが存在し、そこでベストプラクティスの標準化が行われてきました(Spring、Struts、WebWorkなどが良い例です)。今ようやく、Javaデスクトップの世界でもその経験が生かされようとしています。

 RCPは、アプリケーションのスケルトン/シェルと、このシェルに基づいて独自のアプリケーションを構築する際に利用できるモジュールベースのAPIを提供します。メニュー、ツールバー、各種ビューの作成など、基本的な部分はすべてRCPが処理してくれるので、一から作成する必要はありません。自動的に処理してくれる環境があるならば、わざわざ自分でフレームワークを動かす理由はないでしょう。

 本稿では、前回の記事で構築したサーバーに接続するシッククライアントインターフェイスを構築する方法を解説します。Eclipse RCPベースのシッククライアントを構築し、その後でEclipse RCPとSpringを統合します。

必要な環境

  • Eclipse 3.1.2
  • MyEclipse 4.1.1
  • Java SE 5(およびその実用的な知識)
  • サーブレットコンテナまたはJ2EEサーバー(このチュートリアルではTomcat 5.5+を使用)
  • Spring 1.2+(およびその実用的な知識)
  • サンプルコード
補足説明1 Springを入手する
 Spring Frameworkをまだ入手していない場合は、ダウンロードしてインストールしてください。私はSpring1.2.8を選びました。本稿の執筆時点ではこれが最新の安定したリリースでした。必要になるサードパーティライブラリが入っているので、Spring Framework with dependenciesをダウンロードすることをお勧めします。また、リソースとしてソースとjavadocもダウンロードしてください。ダウンロードし終えたら、ファイルを解凍してください。

Eclipse RCPを選ぶ理由

 さて、Javaに初めて触れる方や長いこと遠ざかっていた方のためにお伝えしますが、Eclipseの人気は史上最高です。人気だけでは成功が保証されないというものの、数百万人のユーザー、非常に活発なコミュニティ、高い評判、そしてIBMの支持は悪いものではありません。また、今も数多くのアプリケーションがEclipse RCPベースで開発されているので、手製のフレームワークよりもはるかにしっかりとしたテストが行われると考えてよいでしょう。

 では、始めましょう。

新しいEclipseプラグインプロジェクトを作成する

 次の手順に従って、リッチクライアントアプリケーション用の新しいEclipseプラグインプロジェクトを作成します。

  1. Eclipseで新しいプラグインプロジェクト「EclipseTradeClient」を作成します。このプラグインのフォーマットをEclipseバージョン3.1とし、[Create an OSGi bundle manifest]チェックボックスがオンであることを確認します(図1を参照)。[Next]をクリックします。
  2. 図1 新しいプラグインプロジェクト
    図1 新しいプラグインプロジェクト
  3. [Plug-in Content]画面はデフォルトのままとします。ただし、[Would you like to create a rich client application?]で[Yes]が選択されていることを確認します(図2を参照)。[Next]をクリックします。
  4. 図2 リッチクライアントアプリケーションの作成を選択する
    図2 リッチクライアントアプリケーションの作成を選択する
  5. テンプレートで、[RCP application with a view]を選択し、[Next]をクリックします。
  6. RCPアプリケーションのプロパティを入力し(図3を参照)、[Finish]をクリックします。プラグイン開発のパースペクティブに移動することを確認するプロンプトが表示されます。[Yes]をクリックします。
  7. 図3 RCPプラグインプロジェクトウィザードの最後の画面
    図3 RCPプラグインプロジェクトウィザードの最後の画面
  8. これでプロジェクトの作成は終了です。「plugin.xml」をまだ開いていない場合は開きます。図4に示す画面が表示されます。
  9. 図4 Plugin.XMLの概要
    図4 Plugin.XMLの概要
    Eclipseプラグインに初めて触れる場合は、「plugin.xml」の一番下のタブをよく使うことを覚えておきましょう。[Overview]タブから分かるように、Eclipseリッチクライアントアプリケーションを実行/デバッグすることができます。
  10. EclipseTradeClient/src/eclipseTradeClientパッケージを展開し、EclipseのRCPウィザードによって自動的に作成されたクラスを確認します。Eclipseエディタで、[All Extensions]タブをクリックし、図5のように最上位の各ノードを展開します。
  11. 図5 Eclipseで生成されたクラスとすべての拡張エントリ
    図5 Eclipseで生成されたクラスとすべての拡張エントリ

 Applicationクラス、Perspectiveクラス、およびViewクラスの拡張エントリに注意してください。EclipseのRCPの中心は「plugin.xml」ファイルなので、[Extensions]タブを選択し[Add...]ボタンをクリックするだけで新しいコンポーネントを追加できます(Eclipseによって自動的に提供されるクラスの一覧については、「補足説明2 Eclipseによって生成されるクラス」を参照)。

補足説明2 Eclipseによって生成されるクラス
 Eclipseが自動的に生成するクラスは次のとおりです。
  • Application
  • このクラスは事実上のJavaメインクラスです。アプリケーションを起動すると、最終的にrun(Object args)メソッドが呼び出されます。
  • ApplicationActionBarAdvisor
  • このクラスを使って、ToolbarとMenuBarに追加するためのコードをリンクします。
  • ApplicationWorkbenchAdvisor
  • このクラスで実行する一番重要なことは、デフォルトにするパースペクティブを定義することです。この定義にはメソッドgetInitialWindowPerspectiveId()を使います。
  • ApplicationWorkbenchWindowAdvisor
  • メソッドcreateActionBarAdvisor()ApplicationActionBarAdvisorのインスタンスを作成します(ApplicationXXXAdvisorsという名前のクラスがたくさんありますね)。
  • EclipseTradeClientPlugin
  • これはメインのEclipseプラグインクラスです。ここで作成しているのは、最終的にはEclipseのプラグインです。
  • Perspective
  • これまでにEclipseの使用経験があり、Perspectiveが何かをご存知だとうれしいのですが、そうでなくても、PerspectiveがIPerspectiveFactoryを実装することはお分かりでしょう。javadocには、「パースペクティブファクトリは初期ページレイアウトとページの可視アクションを生成する」と書かれています。Eclipse IDEでPerspectiveを実際に確認するには、[Debug]、[Java]、[Plug-in Development]、[Java]など、右下隅にあるさまざまなPerspectiveをクリックするだけで十分です。また、Eclipseのメニューで[Window]-[Open Perspective]を使う方法もあります。基本的に、パースペクティブは同じ機能を持つビューをグループにまとめるためのレイアウトです。
  • View
  • ビューは基本的にコンポーネントを追加するパネル/パレットです。ビューを作成して1つの機能をカプセル化します。Eclipseでは、メニュー[Window]-[Show View]をクリックすると、IDEが提供しなければならないさまざまなビューが表示されます。例えば、Eclipseには、Package Explorer、Outline、JUnit、Antなどのビューがあります。
 要するに、階層的に表現すれば、ワークベンチはn個のパースペクティブを持つことができ、パースペクティブはn個のビューを持つことができる、ということです。

デフォルトのViewクラスをリファクタリングする

 このように、EclipseのウィザードはViewというクラスを自動的に作成しました。このままでは不便なので、次の手順に従って、このデフォルトのViewクラスをリファクタリングします。

  1. ビューの名前を変更するには、パッケージエクスプローラで「View.java」を右クリックし、[Refactor]-[Rename]と選択します。新しい名前として「ExplorerView」と入力し、[Preview]をクリックします。表示される画面で、PerspectiveクラスがView.IDではなくExplorerView.IDを使うようにリファクタリングされていることを確認します(図6を参照)。[OK]をクリックします。
  2. 図6 Viewクラスの名前をExplorerViewにリファクタリングする
    図6 Viewクラスの名前をExplorerViewにリファクタリングする
  3. 残念なことに、Eclipseのリファクタリング機能は、特にIntelliJの機能と比べると少し貧弱です。IntelliJでこのようなリファクタリングを行うと、指定されたクラスだけでなく、.xmlファイルに対してもリファクタリングが適用されます。余談ですが、これは、特にSpring、Hibernate、XMLなどの構成が重い環境で非常に役立ちます。
  4. 「plugin.xml」でリファクタリングを更新する場合は手動で行わなければなりません。「plugin.xml」を開き、[plugin.xml]タブをクリックします。Viewという拡張を探して、次のように更新します。
    name="ExplorerView"
    class="eclipseTradeClient.ExplorerView"
    id="EclipseTradeClient.explorerView">
    
    更新を終えたら、保存します(図7を参照)。
    図7 リファクタリングの追加作業 - Plugin.XMLを手動で更新する
    図7 リファクタリングの追加作業 - Plugin.XMLを手動で更新する
  5. リファクタリングに必要な作業は以上です――と言いたいところですが、まだ終わりではありません。初期化する静的変数IDをEclipseTradeClient.explorerViewに変更します。これは「plugin.xml」で先ほど設定したIDに対応します。
  6. これで、ようやくリファクタリングは終了です。では、すべて正しく変更されたかどうかテストしてみましょう。エディタで再び「plugin.xml」を開き、[Overview]タブをクリックします。[Launch an Eclipse application]をクリックすると、図8のような画面が表示されるはずです。
  7. 図8 [Eclipse Trade Client]画面
    図8 [Eclipse Trade Client]画面
  8. 次に、ノードの名前を変更します。クラスExplorerViewを開きます。内部クラスViewContentProviderを探し、メソッドObject getElements(Object parent)を変更して、"Watch List", "Order History"の文字列配列を返すようにします。

アプリケーションにSpring Remotingを追加する

 前回の記事で構築したStockTradeServerプロジェクトに要求を送るために、EclipseリッチクライアントにSpringを追加します。

 まず、Eclipseプラグイン/RCPアプリケーションを開発しているときにサードパーティライブラリを追加する場合は、別のプラグインを使う方法をお勧めします。こうすれば、プロジェクトを作成するたびにサードパーティのjarを追加する必要がなく、プラグイン/RCPプロジェクトとサードパーティライブラリのプロジェクトとの依存関係を作成するだけで済みます。最も、これは言うほど簡単なことではありません。Eclipseのクラスローダーに慣れていない場合は、こちらを参照してください。要するに、プラグインの依存関係の中でクラスが互いを検出できるようにするために、2つの追加手順を実行する必要があります。

  1. Eclipseで新しいプラグインプロジェクトを作成します。この新しいプロジェクトの名前を「SpringClient」として、次の値を設定します。
  2. ID = SpringClient
    Class = springClient.SpringClientPlugin
    
    プラグインプロパティを入力し終えたら、[Finish]をクリックします。SpringClientプラグインプロジェクトの主な目的はSpringのライブラリとSpring関連のサービスクラスを保持することなので、テンプレートは不要です。
  3. spring-framework-1.2.8ディストリビューションを解凍すると、次のjarが入っています。これらのjarをすべて「SpringClient」ディレクトリのルートにコピーします。
    • spring-aop.jar ―― 「dist」フォルダ
    • spring-beans.jar ―― 「dist」フォルダ
    • spring-context.jar ―― 「dist」フォルダ
    • spring-core.jar ―― 「dist」フォルダ
    • spring-remoting.jar ―― 「dist」フォルダ
    • commons-logging.jar ―― 「libjakarta-commons」フォルダ
    • log4j-1.2.13.jar ―― 「liblog4j」フォルダ
  4. Eclipseのパッケージエクスプローラで、SpringClientを右クリックしてプロジェクトプロパティを開きます。[Java Build Path]を選択し、[Libraries]タブをクリックし、[Add JARs]ボタンで先ほど追加したjarをすべて追加します。これらのライブラリをエクスポートすることも確認します。[Order and Export]タブをクリックし、すべてのライブラリのチェックボックスをオンにします(図9を参照)。こうしておけば、SpringClientとのプロジェクト依存関係を作成したときに、Springのjarとログのjarも確実に利用できるようになります。最後に[OK]をクリックします。
  5. 図9 サードパーティライブラリをエクスポートする
    図9 サードパーティライブラリをエクスポートする
  6. 次に、SpringClientのマニフェストに変更を加える必要があります。パッケージエクスプローラで、[SpringClient]-[META-INF]をクリックし、「MANIFEST.MF」を開きます。[Runtime]タブをクリックし、[Classpath]エリアで[Add]をクリックします。Springのjarとログのjarをすべて選択し、[OK]をクリックします。次に、[Exported Packages]セクションで[Add]をクリックします。エクスポート対象のパッケージをすべて選択し、[OK]をクリックします(図10を参照)。
  7. 図10 プラグインクラスパスにサードパーティライブラリを追加してパッケージをエクスポートする
    図10 プラグインクラスパスにサードパーティライブラリを追加してパッケージをエクスポートする
    前にも述べたとおり、Eclipseのクラスローダーはたびたび問題を起こすことがあります。これを修正するため、[MANIFEST.MF]タブをクリックして次の行を追加します。
    Eclipse-BuddyPolicy: registered
    
  8. 次に、Springの構成ファイルを追加します。パッケージエクスプローラで、「src」ディレクトリに移動し、「applicationContext.xml」という新しいファイルを作成して、次の行を追加します。
  9. 「src」ディレクトリの下にも「beanRefFactory.xml」という新しいファイルを作成し、次の行を追加します。
    おや、と思った場合は正解です。これらのファイルはstocktradeserverプロジェクトのユニットテストで使用したものと同じSpringの構成ファイルで、名前を「applicationContext.xml」に変更しただけです。
  10. 簡潔にするため、stocktradeserverプロジェクトからSpringClientの「src」ディレクトリにクラスをコピーします。SpringClientの「src」ディレクトリの下にパッケージstephenlum.services.stockとstephenlum.services.stock.dtoを作成します。
  11. この記事のダウンロードサンプルまたは前回の記事を参照し、stephenlum.services.stockの下にクラスStockService.javaをコピーします。次に、stephenlum.services.stock.dtoの下にクラスStockDTO.javaをコピーします(図11を参照)。
    図11 実行後のパッケージエクスプローラ画面
    図11 実行後のパッケージエクスプローラ画面
  12. クラスSpringClientPluginに、Springのアプリケーションコンテキストを読み込むコードを追加します。このコードはコンストラクタに追加します。新しいSpringClientPluginクラスは次のようになります。
  13. package springClient;
    
    import org.eclipse.jface.resource.ImageDescriptor;
    import org.eclipse.ui.plugin.AbstractUIPlugin;
    import org.osgi.framework.BundleContext;
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.beans.factory.access.BeanFactoryLocator;
    import org.springframework.beans.factory.access.BeanFactoryReference;
    import org.springframework.beans.factory.access.SingletonBeanFactoryLocator;
    
    /**
     * The main plugin class to be used in the desktop.
     */
    public class SpringClientPlugin extends AbstractUIPlugin {
        private BeanFactory beanFactory;
    
        //The shared instance.
        private static SpringClientPlugin plugin;
    
        /**
         * The constructor.
         */
        public SpringClientPlugin() {
            plugin = this;
            BeanFactoryLocator beanFactoryLocator =
    SingletonBeanFactoryLocator.getInstance();
            BeanFactoryReference beanFactoryReference =
     beanFactoryLocator.useBeanFactory("ctx");
            beanFactory = beanFactoryReference.getFactory();
        }
    
        /**
         * This method is called upon plug-in activation
         */
        public void start(BundleContext context) throws Exception {
            super.start(context);
        }
    
        /**
         * This method is called when the plug-in is stopped
         */
        public void stop(BundleContext context) throws Exception {
            super.stop(context);
            plugin = null;
        }
    
        /**
         * Returns the shared instance.
         */
        public static SpringClientPlugin getDefault() {
            return plugin;
        }
    
        /**
         * Returns an image descriptor for the image file at the given
         * plug-in relative path.
         *
         * @param path the path
         * @return the image descriptor
         */
        public static ImageDescriptor getImageDescriptor(String path) {
            return AbstractUIPlugin.
                imageDescriptorFromPlugin("SpringClient", path);
        }
    
        public BeanFactory getBeanFactory() {
            return beanFactory;
        }
    }
    
  14. 最後に、プロジェクトEclipseTradeClientが新しいプラグインプロジェクトSpringClientに依存するように依存関係を追加します。プロジェクトEclipseTradeClientで、「plugin.xml」を開き、[Dependencies]タブをクリックします。[Required Plug-ins]セクションで、[Add]をクリックし、SpringClient (1.0.0)を選択して、[OK]をクリックします(図12を参照)。
  15. 図12 必須プラグインとしてSpringClientを追加する
    図12 必須プラグインとしてSpringClientを追加する
    次に、Eclipseのバディポリシーに関してEclipseTradeClientマニフェストファイルにコードを追加する必要があります。ファイル「plugin.xml」で、[MANIFEST.MF]タブをクリックし、次のエントリを追加します。
    Eclipse-RegisterBuddy: SpringClient
    

新しいWatchListViewを作成する

 これで、独自のViewクラスの作成を始めることができます。まず、WatchListViewを作成します。これは、アプリケーションサーバーのStockDataServiceに要求を行うクラスです。

  1. 「plugin.xml」で、[Extentions]タブに移動します。
  2. [All Extensions]ツリーでorg.eclipse.ui.viewsを選択し、[Add]をクリックします。
  3. 新しいダイアログウィンドウが作成されます。[Extension Points]ツリーを下にスクロールしてorg.eclipse.ui.viewsを選択します。[Available templates for org.eclipse.ui.views]の下でSampleViewを選択し、[Next]をクリックします(図13を参照)。
  4. 図13 新しい拡張ダイアログ
    図13 新しい拡張ダイアログ
  5. [Main View Settings]ウィンドウに次の情報を入力します。
  6. Java Package Name = eclipseTradeClient.views.watchlist
    View Class Name = WatchListView
    View Name = Watch List View
    View Category ID = EclipseTradeClient
    View Category Name = WatchList Category
    
    [Table Viewer]ボタンを選択したまま、[Add the view to the resource perspective]チェックボックスをオンにします(図14を参照)。[Next]をクリックします。
    図14 Watch List Viewの[Main View Settings]画面
    図14 Watch List Viewの[Main View Settings]画面
  7. [View Features]をデフォルトのままにして、[Finish]をクリックします。
  8. 「plugin.xml」の[All Extensions]タブに新しいViewとCategoryが表示されます。
  9. これで、Watch List Viewのコードを作成することができます。ウォッチリストはテーブルなので、まずそのテーブルに対するITableLabelProviderを実装します。パッケージeclipseTradeClient.views.watchlistの下にWatchListTableLabelProviderという新しいクラスを作成します。ITableLabelProviderはSwingのTableCellRendererに相当すると考えてください。WatchListTableLabelProviderのコードは次のようになります。
  10. package eclipseTradeClient.views.watchlist;
    
    import java.text.NumberFormat;
    
    import org.eclipse.jface.viewers.ITableLabelProvider;
    import org.eclipse.jface.viewers.LabelProvider;
    import org.eclipse.swt.graphics.Image;
    
    import stephenlum.services.stock.dto.StockDTO;
    
    public class WatchListTableLabelProvider extends LabelProvider
        implements ITableLabelProvider {
    
        private static NumberFormat numberFormat =
                NumberFormat.getInstance();
    
        public Image getColumnImage(Object element, int columnIndex) {
            return null;
        }
    
        public String getColumnText(Object element, int columnIndex) {
            if (element != null) {
                switch (columnIndex) {
                    case 0:
                        return ((StockDTO) element).getTickerSymbol();
                    case 1:
                        return ((StockDTO) element).getLastTrade().toString();
                    case 2:
                        return numberFormat.
                            format(((StockDTO) element).getVolume());
                    case 3:
                        return ((StockDTO) element).getDaysRange();
                    case 4:
                        return numberFormat.
                            format(((StockDTO) element).getAvgVol());
                    case 5:
                        return ((StockDTO) element).getDaysRange();
                    case 6:
                        return ((StockDTO) element).getFiftyTwoWeekRange();
                    case 7:
                        return ((StockDTO) element).getMarketCap();
                }
            }
    
            return "";
        }
    
    }
    
  11. 最後に、PerspectiveクラスにWatchListViewを追加します。パッケージエクスプローラでクラスPerspectiveを開き、WatchListViewがページの一番下に表示されるように次の変更を加えます。
  12. package eclipseTradeClient;
    
    import org.eclipse.ui.IPageLayout;
    import org.eclipse.ui.IPerspectiveFactory;
    import org.eclipse.ui.IFolderLayout;
    import eclipseTradeClient.views.WatchListView;
    
    public class Perspective implements IPerspectiveFactory {
    
        public void createInitialLayout(IPageLayout layout) {
            String editorArea = layout.getEditorArea();
            layout.setEditorAreaVisible(false);
            layout.setFixed(false);
    
            layout.addStandaloneView(ExplorerView.ID,
                    false,
                    IPageLayout.LEFT,
                    0.25f,
                    editorArea);
            IFolderLayout topLeft = layout.createFolder("TOP",
                    IPageLayout.TOP,
                    0.50f,
                    editorArea);
            layout.addView(WatchListView.ID,
                    IPageLayout.BOTTOM,
                    0.25f,
                    editorArea);
        }
    }
    
  13. 次に、クラスWatchListViewにコードを追加します。独自のコードを自由に追加できるように、テンプレートウィザードで生成されたコードの大半は手を付けずそのままにしておきました。基本的には、クラスStockDTOのインスタンスに含まれているすべての情報を表示するテーブルを追加します。当然、列はStockDTOのメンバに基づきます。action1はstocktradeserverから株式の一覧をフェッチしてテーブルに表示し、action2はテーブルからすべての要素を削除するので、生成された2つのアクションの名前を変更しました(リスト1を参照)。
リスト1 eclipseTradeClient.views.watchlist
package eclipseTradeClient.views.watchlist;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.dialogs.ViewContentProvider;
import org.eclipse.ui.part.ViewPart;

import springClient.SpringClientPlugin;
import stephenlum.services.stock.StockService;
import stephenlum.services.stock.dto.StockDTO;

public class WatchListView extends ViewPart {

    public static final String ID =
        "eclipseTradeClient.views.watchlist.WatchListView";

    private TableViewer viewer;
    private Action getStocksAction;
    private Action clearTableAction;
    private Action doubleClickAction;

    class NameSorter extends ViewerSorter {
    }

    /**
     * The constructor.
     */
    public WatchListView() {
    }

    /**
     * This is a callback that will allow us
     * to create the viewer and initialize it.
     */
    public void createPartControl(Composite parent) {
        GridLayout gridLayout = new GridLayout();
        gridLayout.numColumns = 8;
        gridLayout.marginHeight = 5;
        gridLayout.marginWidth = 5;
        parent.setLayout(gridLayout);

        GridData gridData = new GridData();
        gridData.verticalAlignment = GridData.FILL;
        gridData.horizontalSpan = 3;
        gridData.grabExcessHorizontalSpace = true;
        gridData.grabExcessVerticalSpace = true;
        gridData.horizontalAlignment = GridData.FILL;

        viewer = new TableViewer(
            parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
        viewer.setContentProvider(new ViewContentProvider());
        viewer.setLabelProvider(new WatchListTableLabelProvider());
        viewer.setSorter(new NameSorter());
        viewer.setInput(StockDTO.class);
        viewer.getControl().setLayoutData(gridData);

        Table table = viewer.getTable();
        table.setHeaderVisible(true);
        table.setLinesVisible(true);

        TableColumn tickerSymbolColumn =
            new TableColumn(table, SWT.NONE);
        tickerSymbolColumn.setText("Ticker Symbol");
        tickerSymbolColumn.setWidth(100);

        TableColumn lastTradeColumn = new TableColumn(table, SWT.NONE);
        lastTradeColumn.setText("Last Trade");
        lastTradeColumn.setWidth(100);

        TableColumn volumeColumn = new TableColumn(table, SWT.NONE);
        volumeColumn.setText("Volume");
        volumeColumn.setWidth(100);

        TableColumn daysrangeColumn = new TableColumn(table, SWT.NONE);
        daysrangeColumn.setText("Days Range");
        daysrangeColumn.setWidth(100);

        TableColumn avgvolColumn = new TableColumn(table, SWT.NONE);
        avgvolColumn.setText("Avg Vol");
        avgvolColumn.setWidth(100);

        TableColumn daysRangeColumn = new TableColumn(table, SWT.NONE);
        daysRangeColumn.setText("Days Range");
        daysRangeColumn.setWidth(100);

        TableColumn fiftyTwoWeekColumn = new TableColumn(table, SWT.NONE);
        fiftyTwoWeekColumn.setText("52 Week Range");
        fiftyTwoWeekColumn.setWidth(100);

        TableColumn marketCapColumn = new TableColumn(table, SWT.NONE);
        marketCapColumn.setText("Market Cap");
        marketCapColumn.setWidth(100);

        makeActions();
        hookContextMenu();
        hookDoubleClickAction();
        contributeToActionBars();
    }

    private void hookContextMenu() {
        MenuManager menuMgr = new MenuManager("#PopupMenu");
        menuMgr.setRemoveAllWhenShown(true);
        menuMgr.addMenuListener(new IMenuListener() {
            public void menuAboutToShow(IMenuManager manager) {
                WatchListView.this.fillContextMenu(manager);
            }
        });
        Menu menu = menuMgr.createContextMenu(viewer.getControl());
        viewer.getControl().setMenu(menu);
        getSite().registerContextMenu(menuMgr, viewer);
    }

    private void contributeToActionBars() {
        IActionBars bars = getViewSite().getActionBars();
        fillLocalPullDown(bars.getMenuManager());
        fillLocalToolBar(bars.getToolBarManager());
    }

    private void fillLocalPullDown(IMenuManager manager) {
        manager.add(getStocksAction);
        manager.add(new Separator());
        manager.add(clearTableAction);
    }

    private void fillContextMenu(IMenuManager manager) {
        manager.add(getStocksAction);
        manager.add(clearTableAction);
        // Other plug-ins can contribute there actions here
        manager.add(new Separator(
            IWorkbenchActionConstants.MB_ADDITIONS));
    }

    private void fillLocalToolBar(IToolBarManager manager) {
        manager.add(getStocksAction);
        manager.add(clearTableAction);
    }

    private void makeActions() {
        getStocksAction = new Action() {
            public void run() {
                showMessage("Getting Watch List...");

                StockService stockServiceHttp =
                    (StockService)SpringClientPlugin.getDefault().
                    getBeanFactory().getBean("stockServiceHttpInvoker");

                List<String> tickerList = new ArrayList<String>();
                tickerList.add("msft");
                tickerList.add("sunw");
                tickerList.add("orcl");
                tickerList.add("ibm");
                List stockList = stockServiceHttp.getStocks(tickerList);

                viewer.add(stockList.toArray());
            }
        };
        getStocksAction.setText("Get Watch List");
        getStocksAction.setToolTipText("Get Watch List");
        getStocksAction.setImageDescriptor(PlatformUI.getWorkbench().
            getSharedImages().getImageDescriptor(
            ISharedImages.IMG_OBJS_INFO_TSK));

        clearTableAction = new Action() {
            public void run() {
                showMessage("Clear Watch List");
                viewer.getTable().removeAll();
            }
        };
        clearTableAction.setText("Clear Watch List");
        clearTableAction.setToolTipText("Clear Watch List");
        clearTableAction.setImageDescriptor(PlatformUI.getWorkbench().
            getSharedImages().getImageDescriptor(
            ISharedImages.IMG_OBJS_INFO_TSK));
        doubleClickAction = new Action() {
            public void run() {
                ISelection selection = viewer.getSelection();
                Object obj = ((IStructuredSelection)selection).
                    getFirstElement();
                showMessage("Double-click detected on "+obj.toString());
            }
        };
    }

    private void hookDoubleClickAction() {
        viewer.addDoubleClickListener(new IDoubleClickListener() {
            public void doubleClick(DoubleClickEvent event) {
                doubleClickAction.run();
            }
        });
    }
    private void showMessage(String message) {
        MessageDialog.openInformation(
            viewer.getControl().getShell(),
            "Watch List View",
            message);
    }

    /**
     * Passing the focus request to the viewer’s control.
     */
    public void setFocus() {
        viewer.getControl().setFocus();
    }
}

アプリケーションを実行する

 これで、アプリケーションを実行する準備ができました。まだEclipseにstocktradeserverプロジェクトをインポートしていない場合は、次のようにしてインポートします。

  1. Eclipseで、ツールバーボタン[Deploy MyEclipse J2EE project to Server]をクリックします(図15を参照)。
  2. 図15 [Deploy MyEclipse J2EE Server]ボタン
    図15 [Deploy MyEclipse J2EE Server]ボタン
    ドロップダウンリストにあるプロジェクトがstocktradeserverであることを確認します。[Add]をクリックし、サーバーとしてTomcat 5を選択して、[Finish]をクリックします。Successfully deployedというメッセージが表示されたら、[OK]をクリックします(図16を参照)。
    図16 正しく配備されたStockTradeServer
    図16 正しく配備されたStockTradeServer
    次に、Tomcatサーバーを始動します(図17を参照)。Tomcatは正常に始動されるはずです。
    図17 MyEclipseプラグインからTomcatを始動する
    図17 MyEclipseプラグインからTomcatを始動する
  3. ERCを始動します。EclipseTradeClientの「plugin.xml」ファイルを開き、[Overview]タブをクリックして、[Launch an Eclipse application]をクリックします。アプリケーションが起動したら、図18に示す赤い円で囲まれたボタンをクリックして、株式の一覧を取得します。このアクションは、Spring HttpInvokerを使ってアプリケーションサーバーから株式の一覧をフェッチします。円で囲まれたボタンの右側のボタンをクリックすると、株式の一覧はクリアされます(図18を参照)。
  4. 図18 正常に実行されているEclipseTradeClient
    図18 正常に実行されているEclipseTradeClient

 お疲れさまでした。小さいEclipseリッチクライアントを構築し、Spring Remotingを使ってアプリケーションサーバーに接続することができました。

Eclipse RCPの豊富な機能を調べる

 今後はRCPベースの開発をぜひ検討してみてください。RCPにはそれだけの価値があります。次にEclipse RCPベースのシッククライアントを構築するときには、シッククライアントのGUIフレームワークを構築するために必要な基本部分のコードがかなり少なくなるでしょう。さらに、Spring Remotingをクライアント/サーバー通信のメカニズムとして利用すれば、プロトコルの切り替えが非常に簡単になるだけでなく、サーバーサイドでSpringのその他のメリットを利用することもできます。

著者紹介

Stephen Lum(Stephen Lum)
ロンドンの投資銀行の上級開発者。Javaのプログラミング経験は7年に及ぶ。SunのJavaプログラマ認定資格とOracleの開発者認定資格のほか、CPAの資格を持つ。

関連テーマ
プリンター用
記事を転送
この記事をクリップ!
厳選した九州のお野菜とお米をお届け
厳選した九州のお野菜とお米をお届け 野菜の木では、老舗料亭 沙羅の木が厳選した九州のお野菜とお米をお届けします。 毎週、隔週での定期のご購入も可能です。 入会費、年会費、送料、荷造手数料は無料です。
注目のトピックス
Copyright 2012 internet.com K.K. (Japan) All Rights Reserved.