2010年9月16日 星期四

在Hibernate中Config Connection Pool

今天試著在Hibernate中Config Connection Pool時發現 Hibernate3.3.1 GA版裡面,已經將C3P0ConnectionProvider這個class搬到 hibernate-c3p0-3.3.1.GA.jar這個Jar中了,可以到這個網址下載http://www.java2s.com/Code/Jar/GHI/Downloadhibernatec3p0331GAjar.htm

把它加到build path後,編輯persistence.xml。Mark紅色的部分,即為新增的Connection Pool設定。

<?xml version="1.0" encoding="UTF-8"?>
<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="Test">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
            <properties>
                <property name="hibernate.connection.driver_class" value="com.ibm.db2.jcc.DB2Driver"/>
                <property name="hibernate.connection.password" value="db2admin"/>
                <property name="hibernate.connection.url" value="jdbc:db2://localhost:50000/puli"/>
                <property name="hibernate.connection.username" value="db2admin"/>
                <property name="hibernate.default_schema" value="db2admin"/>
                <property name="hibernate.dialect" value="org.hibernate.dialect.DB2Dialect"/>
                    <!--使用c3p Connection Pool -->
                <property name="hibernate.connection.provider_class" value="org.hibernate.connection.C3P0ConnectionProvider" />
                <property name="hibernate.c3p0.max_size" value="100" />
                <property name="hibernate.c3p0.min_size" value="3" />
                <property name="hibernate.c3p0.acquire_increment" value="1" />
                <property name="hibernate.c3p0.idle_test_period" value="300" />
                <property name="hibernate.c3p0.max_statements" value="0" />
                <property name="hibernate.c3p0.timeout" value="100" />
            </properties>
    </persistence-unit>
</persistence>

回到使用JPA的程式碼,假設在以下的程式碼中,在把程式由原本的standalone轉成使用connection pool後,不能在程式碼裡面呼叫JPAUtil.shutdown()這個方法,因為這個方法會把connection中斷。

public class PuliTest {
    public static void main(String[] args) {
        EntityManager newEntityManager =
        JPAUtil.getEntityManagerFactory().createEntityManager();
        EntityTransaction newEtx = newEntityManager.getTransaction();
        newEtx.begin();
        PatientBasicInfo patient = (PatientBasicInfo) newEntityManager.find(PatientBasicInfo.class, "12345");
        System.out.println(patient.getPatientfirstname());
        System.out.println(patient.getPatientlastname());
        System.out.println(patient.getPatientaddress());
        newEtx.commit();
        newEntityManager.close();
        //JPAUtil.shutdown(); 在使用connection pool的程式中,需 comment掉此method call
    }
}

2010年9月15日 星期三

使用Hibernate的JPA實作來 由DDL產生Domain Object

JPA是Java的Persistent標準,針對這個標準,不同單位有不同的實作方式,而Hibernate提供了其中一種實作的選擇。Hibernate是透過Hibernate Annotations(包含hibernate-annotations.jar、hibernate-commons- annotations.jar與ejb3-persistence.jar這些jar)和 Hibernate EntityManager(包含hibernate-entitymanager.jar這個jar) 這兩個component來進行實作。

為了免除尋找這些jar的麻煩,可以直接到Jboss Tools下載Jboss的Tool pakcage,裡面就直接包含了所有Jboss的工具,包含Hibernate。下載網址:http://www.jboss.org/tools/download  (請注意不同版本的Jboss Tool需搭配不同的eclipse版本)  如下圖,可選擇Download: 下面的下載連結,把整個 package的zip下載後並解開後,再用Eclipse的add new site功能,把整個package安裝到eclipse中

image

安裝完後,開始下列步驟

  1. 打開eclipse,新增一個JPA project,填上專案名稱後按下一步
    image
  2. 設定產生的程式碼要放在那個目錄下,按下一步
    image
  3. 在JPA Facet對話框的上半部,先設定platform為Hibernate,然後在JPA Implementation中,設定Type為User Library。然後點選紅色框框處,以設定User Library
     image
  4. 新增一個User Library Entry,為其名命後按Add Jar,到下列目錄把所有的jar檔加到這個User Library Entry下
    \eclipse\plugins\org.hibernate.eclipse_3.3.1.v201006011046R-H111-GA\lib\hibernate\*.jar
    \eclipse\plugins\org.hibernate.eclipse_3.3.1.v201006011046R-H111-GA\lib\tools\*.jar
    \eclipse\plugins\org.hibernate.eclipse_3.3.1.v201006011046R-H111-GA\lib\annotations\*.jar
    image
  5. 加完之後,回到JPA Facet對話框,勾選剛才新建的User Library
    image
  6. 在JPA Facet對話框中間,點選 Add Connections
    image
  7. 此時會打開Database設定對話框,設定connection名稱後,按下一步
    image
  8. 在下一個對話框中,點選如下圖的圖示
    image
  9. 在New Driver Definition處,選定資料庫為IBM Data Server Driver for JDBC後,點選 Jar List的tab
    image
  10. 按下clear all後,重新指定db2 driver的位置
    image
  11. 完成後,回到設定資料庫連結對話框。完成後,按下finish
    image
  12. 回到JPA Facet,勾選下圖的設定後,按finish
    image
  13. 完成後,回到File—>New—>Others ,找到 JPA下的Entities From Tables
    image
  14. 一直按下一步,到下列對話框可以選擇要將那些Table Mapping成Entity。勾選完畢後,uncheck 同步class到persistence.xml,按下一步 
    image
  15. 對話框中會列出這些Table之間的association的關係
    image
  16. 填上產生的Code要到那個package下,按完成。即自動建立這些所需的class
    image
  17. 到此完成Domain class的建立。如前所述Hibernate是透過EntityManager這個Component來實作JPA的persistence。建立一個Utility class來取得EntityManager。若仔細看的話,可以發現EntityManager的角色類似Hibernate本身的Session

    package test.puli.util;

    import javax.persistence.EntityManagerFactory;
    import javax.persistence.Persistence;

    public class JPAUtil {
        private static EntityManagerFactory entityManagerFactory;
        static {
            try {
                entityManagerFactory =
                    Persistence.createEntityManagerFactory("Test"); //對應至persistence.xml中的persistent unit
            }
            catch(Throwable ex) {
                throw new ExceptionInInitializerError(ex);
            }
        }
        public static EntityManagerFactory getEntityManagerFactory() {
            return entityManagerFactory;
        }
        public static void shutdown() {
            getEntityManagerFactory().close();
        }
    }

     

  18. 再建立Test的class來進行測試

    import java.util.List;
    import javax.persistence.*;
    import test.puli.model.*;
    import test.puli.util.JPAUtil;

    public class PuliTest {
        public static void main(String[] args) {
            EntityManager newEntityManager =
            JPAUtil.getEntityManagerFactory().createEntityManager();
            EntityTransaction newEtx = newEntityManager.getTransaction();
            newEtx.begin();
            PatientBasicInfo patient = (PatientBasicInfo) newEntityManager.find(PatientBasicInfo.class, "12345");
            System.out.println(patient.getPatientfirstname());
            System.out.println(patient.getPatientlastname());
            System.out.println(patient.getPatientaddress());
            newEtx.commit();
            newEntityManager.close();
            JPAUtil.shutdown();
        }
    }

  19. 修改persistence.xml如下

    <?xml version="1.0" encoding="UTF-8"?>
    <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="Test">
            <provider>org.hibernate.ejb.HibernatePersistence</provider>
                <properties>
                    <property name="hibernate.connection.driver_class" value="com.ibm.db2.jcc.DB2Driver"/>
                    <property name="hibernate.connection.password" value="db2admin"/>
                    <property name="hibernate.connection.url" value="jdbc:db2://localhost:50000/puli"/>
                    <property name="hibernate.connection.username" value="db2admin"/>
                    <property name="hibernate.default_schema" value="db2admin"/>
                    <property name="hibernate.dialect" value="org.hibernate.dialect.DB2Dialect"/>

                </properties>
        </persistence-unit>
    </persistence>

  20. 執行上述的class
     

2010年9月14日 星期二

如何Parse URL的Query String

資料來源:http://www.coderanch.com/t/383310/java/java/parse-url-query-string-parameter

Java的String有 split()這個類似 perl的分割字串的方法,使用它來Parse URL的sample程式碼如下

1、先寫好getQueryMap

  1. public static Map<String, String> getQueryMap(String query) 
  2.     String[] params = query.split("&"); 
  3.     Map<String, String> map = new HashMap<String, String>(); 
  4. for (String param : params) 
  5.     { 
  6.         String name = param.split("=")[0]; 
  7.         String value = param.split("=")[1]; 
  8.         map.put(name, value); 
  9.     } 
  10. return map; 

2、在需要的地方呼叫getQueryMap()這個方法

  1. String query = url.getQuery(); 
  2. Map<String, String> map = getQueryMap(query); 
  3. Set<String> keys = map.keySet(); 
  4. for (String key : keys) 
  5.    System.out.println("Name=" + key); 
  6.    System.out.println("Value=" + map.get(key)); 

如何拿到URL的Query String

參考:由GlobalContext可以拿到的值:http://www.projectzero.org/sMash/1.1.x/docs/zero.devguide.doc/zero.core/GlobalContextReference.html

用sMash開發RestFul Service時,也可以在Request中帶上query string,呼叫的方法如下:

http://localhost:8080/basic_info/?abc

在上述的例子中,? 後面的東西就會被當作  query string。

檢視zero.config的設定(如下),表示所有URL是 /basic_info/xxx的東西,都會被送交Test.class這個handeler來處理。

# HTTP port (default is 8080)

/config/http/port = 8080

# Runtime mode (default is "production")

/config/runtime/mode="development"

/config/handlers +=[{

    "events":"GET",

    "handler":"Test.class",

    "conditions":"/request/path=~/basic_info/(.*)?"

}]

再檢視Test.class這個class

import java.io.PrintWriter;
   import zero.core.context.GlobalContext;

public class Test {
    public void onGET(){
        PrintWriter writer = (PrintWriter) GlobalContext.zget("/request/writer");
        String uri = (String) GlobalContext.zget("/request/queryString");
        writer.println("Hello World!");
        writer.println(uri);
    }
}

其中,GlobalContext.zget("/request/writer")這個方法目的為從GlobalContext拿到 Writer;而GlobalContext.zget("/request/queryString");則是從GlobalContext拿到queryString(即?之後的東西)。

啟動 sMash後,輸入連結http://localhost:8080/basic_info/?abc 可得到

Hello World! abc

2010年9月1日 星期三

Java Static Class的用處

資料來源:http://www.javaworld.com/javaworld/javaqa/1999-08/01-qa-static2.html?page=1

不錯的文章,原來java的class還有分top-level class、anonymous class、member class及nested top-level class這四種。其中只有member class可以被宣告成static。member class被宣告成static之前,只能為包覆他的class產生的物件所使用;而宣告成static之後,就可以和包覆它的外部class一樣,被其它的class產生的物件所使用。declare成 static的member class就變成了nested top-level class了