ZKtodo-0.9.2 の MySQL,JavaEE6-EJB3.1 バージョンを作成する。

ZK の入門としてZKtodo はデータベース利用の最適な参考例となります。
ここでは、URL: http://books.zkoss.org/wiki/ZK_Getting_Started/Creating_a_Database-driven_Application)で取り上げられた、zktodo-0.9.2 をベースにして、データベースをHSQLDB からMySQL に変更し、CRUD アクセス手法を”JavaEE6 - EJB3.1”のglobal JNDI利用に置き換え、プライマリキーをストリングからロングへ変更します。
これは、”ZK with EJB3.1 running on Glassfish (URL: http://javadude.wordpress.com/2011/01/11/zk-with-ejb3-1-running-on-glassfish/)を参考にしています。

作成に当たって NetBeans7.0.1 、 GlassFish3.1.1 と ZK5.09CE を使用しました。

ソースコードはここからダウンロードできます。
ソースコード中の/web/data/todoejb.sql で MySQL のデータベースを作成できます。

1. プロジェクト作成

  ZK509CE のプラグインをインストールしたNetBeans 7.0.1 を使用し、アプリケーションサーバーはGlassFish3.1.1です。
プロジェクト名は ZKtodoEvent で、ZK: JavaEE6 Application のテンプレートを利用して作成します。Java ソースコードは JDK6 を選択します。

2. データベース作成

まず、データベース( tudoejb )をMySQL に作成します。
次のようにデータベースを定義します。

/*DDL Information*/
CREATE TABLE `todoevent` (
  `id` bigint(20) NOT NULL,
  `name` varchar(50) DEFAULT NULL,
  `priority` int(11) DEFAULT NULL,
  `date` date DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

3. entity 作成

  IDE で、「カテゴリー」持続性で新規 -->> 新規 「エンティティクラス」作成 wizard に入り、
クラス名 : TodoEvent
パッケージ : org.zkoss.todo
持続性ユニットを作成のチェックボックスにチェックを入れて、次へをクリックします。

entity

 

PU 名に自動的に ZKtodoEventPU が入りデータソースの選択を求められます。

pu

 

「新しいデータソース」をクリックするとデータソースを作成がポップアップします。

pu2


When clicked “new Database Connection” ,then “New Connection Wizard” is pop uped.
これから作成する JNDI ネームを jdbc/todoejb とするので、入力します。
「新しいデータソース」をクリックすると「新規接続」ウィザードがポップアップします。

jndi

When clicked “new Database Connection” ,then “New Connection Wizard” pop up appears.
Here we select MySQL (Connector/J driver) . Then click "Next" button.
「新しいデータソース」をクリックすると「新規接続」ウィザードが現れますので、
ここで MySQL (Connector/J driver) を選択し、「次へ」 ボタンを押します。

driver


Here we customize connection.
We enter todoejb in Database field.
Enter password and click "Test Connection" to confirm connection.
Then click "Next" button.

ここでは、接続をカスタマイズします。
ここで データベース フィールドに todoejb を入力します。
パスワードを入力して、「接続をテスト」押して確認します。
そして、「次へ」ボタンをクリックします。

pu3

データベースにtodoejb を入力して、接続を確認し、「完了」押します。

pu4

「データソースを作成」となりますので、「完了」ボタンを押します。

provider

この画面のままで、「完了」ボタンでウィザードを完了します。
するとプロジェクトは次のようになっています

プロジェクトの src フォルダの下に conf フォルダが作成され、中に persistence.xml があります。

persistence.xml



  
    jdbc/todoejb
    false
    
		
	
  

「表作成の方針」を「作成」にチェックを入れて作成したので、不要のコードが入っています。
<property name="eclipselink.ddl-generation" value="create-tables"/>
これを削除します。
「表作成の方針」を「なし」にすべきでした。

プロジェクトルートに setup フォルダが作成され、中に sun-resources.xml が
あります。

sun-resources.xml




    
        
        
        
        
        
        
        
    
    
	

出来上がった entity ( TodoEvent.java )はプライマリキーの id だけがフィールドとして定義されています。
必要なフィールド name, priority, date を追加します。
date フィールドには次のアノテーションが必要でした。
   @Temporal(TemporalType.TIMESTAMP) is needed at date field.
コンパイルは可能ですが「一時属性は@temporal注釈でマークする必要があります」というエラーメッセージが出ます。

追加フィールドのセッター、ゲッターメソッドも追加します。

 

4. セッションfacade の作成

   At IDE, we enter into wizard of “creation of entity class Session Bean” by new -->>Session Beans For new Entity classes creation at the category "Enterprise JavaBeans".
IDE の「エンタープライズ JavaBeans」のカテゴリで、新規 >> 新規 「エンティティクラスのセッション Bean」 を選択して、
「エンティティクラスのセッション Bean」 wizard に入ります。

SB0
As available Entity classes,there is “org.zkoss.toto.TodoEvent”,we move this class to selected Entity classes window.
Then click “Next” button.
利用可能な Entity クラスとして org.zkoss.todo.TodoEventがあるので「選択されている
エンティティクラス」のウィンドウへ移動して、「次へ」をクリックする。

SB

次の画面で「完了」をクリックします。

SB2

この時点で、AbstractFacade.java, TodoEventFacade.java の二つのクラスが追加されます。

5. 元の ZKtodo-0.9.2プロジェクト から zul ファイル( index.zul )のコピー


    3行目の apply="org.zkforge.todo.event.EventController" を
次のように修正します。
         apply= "org.zkoss.todo.EventController"

6. 元の ZKtodo-0.9.2プロジェクト から DAOクラス( EventDAO.java )、コントローラークラス( EventController.java )のリファクターリングコピー

7. NetBeans で global JNDI を使用して EventDAO.java 内で TodoEventFacade を call するコードの 自動生成

 
①空きスペースで右クリック
②コードを挿入を選択
③エンタープライズBeanを呼び出し
④プロジェクトのリストが現れ、プロジェクトを選択するとその中のEJB が現れるので、欲しいものを選択する。

次に自動生成されたコードを示す。

//    TodoEventFacade todoEventFacade = lookupTodoEventFacadeBean();
    TodoEventFacade tEF = lookupTodoEventFacadeBean();
    private TodoEventFacade lookupTodoEventFacadeBean() {
        try {
            Context c = new InitialContext();
            return (TodoEventFacade) c.lookup("java:global/ZKtodoEvent/TodoEventFacade!org.zkoss.todo.TodoEventFacade");
        } catch (NamingException ne) {
            Logger.getLogger(getClass().getName()).log(Level.SEVERE, "exception caught", ne);
            throw new RuntimeException(ne);
        }
    }

At the end of web.xml,here placed unneeded code.why?
web.xml の最後に次の不要なコードが挿入されるときがあります( 何故か) ので、
プロジェクトの実行の妨げになりますので取り除きます。


	TodoEventFacade
	Session
	#TodoEventFacade

8. 完成された EventDAO.java and EventController.java
  なんとシンプルなコードでしょうか!!

  EventDAO.java

package org.zkoss.todo;

/**
 * Event DAO.
 * 
 * @author robbiecheng
 */
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class EventDAO {
//    TodoEventFacade todoEventFacade = lookupTodoEventFacadeBean();
    TodoEventFacade tEF = lookupTodoEventFacadeBean();
    private TodoEventFacade lookupTodoEventFacadeBean() {
        try {
            Context c = new InitialContext();
            return (TodoEventFacade) c.lookup("java:global/ZKtodoEvent/TodoEventFacade!org.zkoss.todo.TodoEventFacade");
        } catch (NamingException ne) {
            Logger.getLogger(getClass().getName()).log(Level.SEVERE, "exception caught", ne);
            throw new RuntimeException(ne);
        }
    }
	
    
	public List<TodoEvent> findAll() {
            List allEvents = tEF.findAll();
            return allEvents;
	}
	
	public void delete(TodoEvent evt) {
            tEF.remove(evt);
	}
	
	public void insert(TodoEvent evt) {
            tEF.create(evt);
	}
	
	public void update(TodoEvent evt) {
            tEF.edit(evt);
    }

}

  EventController.java

package org.zkoss.todo;

/**
 * Event Controller.
 * 
 * @author robbiecheng
 */

import java.util.List;
import java.util.UUID;

import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.ForwardEvent;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.Datebox;
import org.zkoss.zul.Intbox;
import org.zkoss.zul.Listbox;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Textbox;

public class EventController extends GenericForwardComposer {
    private static final long serialVersionUID = -9145887024839938515L;
    private TodoEvent current = new TodoEvent();
    private EventDAO eventDao = new EventDAO();
    private Textbox name;
    private Intbox priority;
    private Datebox date;
    
    public void onSelect$box(Event e) {
        ForwardEvent forwardEvt = (ForwardEvent) e;
        Listbox box = (Listbox) forwardEvt.getOrigin().getTarget();
        
        if (box.getSelectedItem() != null) {
            current = (TodoEvent) box.getSelectedItem().getValue();
            refresh();
        }
    }

    private void refresh() {
        name.setValue(current.getName());
        priority.setValue(current.getPriority());
        date.setValue(current.getDate());
    }

    public TodoEvent getCurrent() {
        return current;
    }

    public void setCurrent(TodoEvent current) {
        this.current = current;
    }

    public List<TodoEvent> getAllEvents() {
        return eventDao.findAll();
    }
    
    private boolean validate(TodoEvent current2) {
        if(current.getName() == null || 
           current.getName().length() <= 0 ||
           current.getDate() == null) {
            try {
                Messagebox.show("All fields cannot be empty, please check fields.");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            return false;
        }
        
        return true;
    }

    public void onClick$add() {
            if (validate(current)) {
                // insert into database
                eventDao.insert(current);
            }
    }

    public void onClick$update() {
        if (current != null && validate(current)) {
            // update database
            eventDao.update(current);
        }
    }

    public void onClick$delete() {
        if (current != null && validate(current)) {
            eventDao.delete(current);
        }
    }
}