#
在application server下,比如常見的weblogic,glassfish,jboss等,由于javaee規(guī)范的要求,一般不容許直接啟動(dòng)線程。因此在常見的異步/并行任務(wù)執(zhí)行上,會(huì)遭遇到比普通javase程序更多的麻煩。
典型例子,在javase中,jdk1.5后就引入了java.util.concurrent包,提供Executor這個(gè)非常好用的框架,完美的滿足一下典型需求:
1. 同步變異步
請求進(jìn)來后,將請求封裝為task,交給Executor執(zhí)行,原線程可以立即返回
2. 并行執(zhí)行
請求進(jìn)來后,將請求拆分為若干個(gè)task,例如下發(fā)短信,有100個(gè)收件人就可以按照每個(gè)收件人一個(gè)task來執(zhí)行,這樣可以通過Executor來并行執(zhí)行這些請求,遠(yuǎn)比循環(huán)執(zhí)行要快的多。
3. 等待任務(wù)結(jié)束
有時(shí)有要求調(diào)用線程必須等待所有任務(wù)完成后再繼續(xù)運(yùn)行的需要,此外還有超時(shí)等細(xì)節(jié)設(shè)置要求。
而在application server,為了避開自己啟動(dòng)線程的弊端,只好通過其他的方式來完成類似的功能。
目前我們的項(xiàng)目開發(fā)中主要有三種實(shí)現(xiàn)方式:
1. jms queue
通過jms來實(shí)現(xiàn)異步和并發(fā),然后自己通過編碼方式完成調(diào)用線程等待所有任務(wù)執(zhí)行成功。
這個(gè)方案比較通用,因?yàn)閖ms是javaee的標(biāo)準(zhǔn),所有的application server上都支持。因此天然具有跨application server的能力。
缺點(diǎn)就比較多了,首先jms是需要實(shí)現(xiàn)串行化的,因此對task是有要求,不能串行化的類是不能傳遞的。另外串行化的性能損失比較大,造成性能和穩(wěn)定性問題,這個(gè)在大壓力下比較突出,基本我們目前在考慮放棄這個(gè)方案,而且逐步將原有的實(shí)現(xiàn)替換掉。
這個(gè)方案還有另外一個(gè)缺點(diǎn),配置麻煩,維護(hù)困難:需要?jiǎng)?chuàng)建jsm queque, connection factory, MDB等,如果系統(tǒng)中使用的多了,配置起來很羅嗦,修改時(shí)容許出錯(cuò)。
2. commonj work manager
這個(gè)是weblogic和WebSphere上支持的一個(gè)很實(shí)用的解決方案,個(gè)人感覺使用上非常舒服,配置簡單,只要在weblogic-ejb-jar.xml中間中簡單配置:
< work-manager >
< name > wm/taskDistributionWorkManager </ name >
< min-threads-constraint >
< name > minthreads </ name >
< count > 1 </ count >
</ min-threads-constraint >
< max-threads-constraint >
< name > maxthreads </ name >
< count > 100 </ count >
</ max-threads-constraint >
</ work-manager > 使用時(shí)用jdni lookup到就可以使用了。功能和使用方式和executor框架很類似,同樣提供future,而且提供一個(gè)非常實(shí)用的waitAll()方法論支持等待任務(wù)完成。
這個(gè)方案的性能非常好,和jms相比提升極大,運(yùn)行也穩(wěn)定。缺點(diǎn)就是不是標(biāo)準(zhǔn),只有weblogic和WebSphere執(zhí)行,在glassfish,jboss上無法使用。
3. JCA work manager
這個(gè)是JCA標(biāo)準(zhǔn)了,glassfish,jboss都支持的,和commonj work manager很像,但是,很遺憾的是沒有future的支持,而且也沒有類似的waitAll()方法,只能自己編碼實(shí)現(xiàn)。
spring為glassfish提供了一個(gè)工具類"org.springframework.jca.work.WorkManagerTaskExecutor",簡化了JCA work manager的使用。
JCA work manager的性能和穩(wěn)定性都還不錯(cuò),對比jms要好的多。
JBOSS下的配置
jboss-web.xml
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
<resource-ref id="ResourceRef_1163654014164">
<description>WorkManager</description>
<res-ref-name>jboss.jca:service=WorkManager</res-ref-name>
<res-type>org.jboss.resource.work.JBossWorkManager</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
<jndi-name>WorkManager</jndi-name>
</resource-ref>
</jboss-web>

applicationContext.xml
<bean id="taskExecutor" class="org.springframework.jca.work.jboss.JBossWorkManagerTaskExecutor">
<property name="workManagerName" value="WorkManager"/>
<property name="resourceRef" value="true"/>
</bean>

從目前我們項(xiàng)目的使用經(jīng)驗(yàn)上看,jms是準(zhǔn)備要被淘汰的了(其實(shí)我是一直對jms不感冒的,尤其是在有性能要求的地方,想不出用jms的理由)。目前項(xiàng)目要求同時(shí)支持weblogic和glassfish,因此commonj work manager和JCA work manager剛好對應(yīng)于weblogic和glassfish平臺(tái)。實(shí)際使用中,是在這兩個(gè)work manager上封裝了一個(gè)通用的接口,然后再有commonj work manager和JCA work manager兩個(gè)實(shí)現(xiàn),在運(yùn)行時(shí)通過判斷平臺(tái)來自動(dòng)選擇注入其中的一個(gè)。
摘要: 用ThreadPoolExecutor的時(shí)候,又想知道被執(zhí)行的任務(wù)的執(zhí)行情況,這時(shí)就可以用FutureTask。ThreadPoolTask
Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->package com.paul.threadP...
閱讀全文
這是一堂關(guān)于UML基礎(chǔ)知識(shí)的補(bǔ)習(xí)課;現(xiàn)在我們做項(xiàng)目時(shí)間都太緊了,基本上都沒有做過真正的class級別的詳細(xì)設(shè)計(jì),更別提使用UML來實(shí)現(xiàn)規(guī)范建模了;本篇主要就以前自己一直感覺很迷糊的幾種class之間的關(guān)系進(jìn)行整理,讓我們在真正用UML進(jìn)行比如類圖設(shè)計(jì)時(shí)能夠更加清晰明了;以下就分別介紹這幾種關(guān)系:
繼承
指的是一個(gè)類(稱為子類、子接口)繼承另外的一個(gè)類(稱為父類、父接口)的功能,并可以增加它自己的新功能的能力,繼承是類與類或者接口與接口之間最常見的關(guān)系;在Java中此類關(guān)系通過關(guān)鍵字extends明確標(biāo)識(shí),在設(shè)計(jì)時(shí)一般沒有爭議性;

實(shí)現(xiàn)
指的是一個(gè)class類實(shí)現(xiàn)interface接口(可以是多個(gè))的功能;實(shí)現(xiàn)是類與接口之間最常見的關(guān)系;在Java中此類關(guān)系通過關(guān)鍵字implements明確標(biāo)識(shí),在設(shè)計(jì)時(shí)一般沒有爭議性;

依賴
可以簡單的理解,就是一個(gè)類A使用到了另一個(gè)類B,而這種使用關(guān)系是具有偶然性的、、臨時(shí)性的、非常弱的,但是B類的變化會(huì)影響到A;比如某人要過河,需要借用一條船,此時(shí)人與船之間的關(guān)系就是依賴;表現(xiàn)在代碼層面,為類B作為參數(shù)被類A在某個(gè)method方法中使用;

關(guān)聯(lián)
他體現(xiàn)的是兩個(gè)類、或者類與接口之間語義級別的一種強(qiáng)依賴關(guān)系,比如我和我的朋友;這種關(guān)系比依賴更強(qiáng)、不存在依賴關(guān)系的偶然性、關(guān)系也不是臨時(shí)性的,一般是長期性的,而且雙方的關(guān)系一般是平等的、關(guān)聯(lián)可以是單向、雙向的;表現(xiàn)在代碼層面,為被關(guān)聯(lián)類B以類屬性的形式出現(xiàn)在關(guān)聯(lián)類A中,也可能是關(guān)聯(lián)類A引用了一個(gè)類型為被關(guān)聯(lián)類B的全局變量;

聚合
聚合是關(guān)聯(lián)關(guān)系的一種特例,他體現(xiàn)的是整體與部分、擁有的關(guān)系,即has-a的關(guān)系,此時(shí)整體與部分之間是可分離的,他們可以具有各自的生命周期,部分可以屬于多個(gè)整體對象,也可以為多個(gè)整體對象共享;比如計(jì)算機(jī)與CPU、公司與員工的關(guān)系等;表現(xiàn)在代碼層面,和關(guān)聯(lián)關(guān)系是一致的,只能從語義級別來區(qū)分;

組合
組合也是關(guān)聯(lián)關(guān)系的一種特例,他體現(xiàn)的是一種contains-a的關(guān)系,這種關(guān)系比聚合更強(qiáng),也稱為強(qiáng)聚合;他同樣體現(xiàn)整體與部分間的關(guān)系,但此時(shí)整體與部分是不可分的,整體的生命周期結(jié)束也就意味著部分的生命周期結(jié)束;比如你和你的大腦;表現(xiàn)在代碼層面,和關(guān)聯(lián)關(guān)系是一致的,只能從語義級別來區(qū)分;

對于繼承、實(shí)現(xiàn)這兩種關(guān)系沒多少疑問,他們體現(xiàn)的是一種類與類、或者類與接口間的縱向關(guān)系;其他的四者關(guān)系則體現(xiàn)的是類與類、或者類與接口間的引用、橫向關(guān)系,是比較難區(qū)分的,有很多事物間的關(guān)系要想準(zhǔn)備定位是很難的,前面也提到,這幾種關(guān)系都是語義級別的,所以從代碼層面并不能完全區(qū)分各種關(guān)系;但總的來說,后幾種關(guān)系所表現(xiàn)的強(qiáng)弱程度依次為:組合>聚合>關(guān)聯(lián)>依賴;
大多數(shù)并發(fā)應(yīng)用程序是以執(zhí)行任務(wù)(task)為基本單位進(jìn)行管理的。通常情況下,我們會(huì)為每個(gè)任務(wù)單獨(dú)創(chuàng)建一個(gè)線程來執(zhí)行。這樣會(huì)帶來兩個(gè)問題:一,大量的線程(>100)會(huì)消耗系統(tǒng)資源,使線程調(diào)度的開銷變大,引起性能下降;二,對于生命周期短暫的任務(wù),頻繁地創(chuàng)建和消亡線程并不是明智的選擇。因?yàn)閯?chuàng)建和消亡線程的開銷可能會(huì)大于使用多線程帶來的性能好處。
一個(gè)比較簡單的線程池至少應(yīng)包含線程池管理器、工作線程、任務(wù)隊(duì)列、任務(wù)接口等部分。其中線程池管理器(ThreadPool Manager)的作用是創(chuàng)建、銷毀并管理線程池,將工作線程放入線程池中;工作線程是一個(gè)可以循環(huán)執(zhí)行任務(wù)的線程,在沒有任務(wù)時(shí)進(jìn)行等待;任務(wù)隊(duì)列的作用是提供一種緩沖機(jī)制,將沒有處理的任務(wù)放在任務(wù)隊(duì)列中;任務(wù)接口是每個(gè)任務(wù)必須實(shí)現(xiàn)的接口,主要用來規(guī)定任務(wù)的入口、任務(wù)執(zhí)行完后的收尾工作、任務(wù)的執(zhí)行狀態(tài)等,工作線程通過該接口調(diào)度任務(wù)的執(zhí)行。下面的代碼實(shí)現(xiàn)了創(chuàng)建一個(gè)線程池,以及從線程池中取出線程的操作。
在多線程大師Doug Lea的貢獻(xiàn)下,在JDK1.5中加入了許多對并發(fā)特性的支持,例如:線程池。
1.核心線程(任務(wù)):我們定義的線程,即實(shí)現(xiàn)了Runnable接口的類,是我們將要放到線程池中執(zhí)行的類,如實(shí)例代碼中的CountService類
2.工作線程:由線程池中創(chuàng)建的線程,是用來獲得核心線程并執(zhí)行核心線程的線程(比較拗口哦,具體看代碼就知道是什么東東了)。
簡單理解就三個(gè)概念:線程、線程池和任務(wù)。任務(wù):就是要執(zhí)行的業(yè)務(wù)邏輯;線程:任務(wù)是要放到線程中去執(zhí)行的;線程池:主要是控制當(dāng)前正在執(zhí)行的線程的數(shù)量和將要被執(zhí)行的線程隊(duì)列。一、簡介
線程池類為 java.util.concurrent.ThreadPoolExecutor,常用構(gòu)造方法為:
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long keepAliveTime, TimeUnit unit,BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler)corePoolSize: 線程池維護(hù)線程的最少數(shù)量
maximumPoolSize:線程池維護(hù)線程的最大數(shù)量
keepAliveTime: 線程池維護(hù)線程所允許的空閑時(shí)間
unit: 線程池維護(hù)線程所允許的空閑時(shí)間的單位
workQueue: 線程池所使用的緩沖隊(duì)列
handler: 線程池對拒絕任務(wù)的處理策略
一個(gè)任務(wù)通過 execute(Runnable)方法被添加到線程池,任務(wù)就是一個(gè) Runnable類型的對象,任務(wù)的執(zhí)行方法就是 Runnable類型對象的run()方法。
當(dāng)一個(gè)任務(wù)通過execute(Runnable)方法欲添加到線程池時(shí):
如果此時(shí)線程池中的數(shù)量小于corePoolSize,即使線程池中的線程都處于空閑狀態(tài),也要?jiǎng)?chuàng)建新的線程來處理被添加的任務(wù)。
如果此時(shí)線程池中的數(shù)量等于 corePoolSize,但是緩沖隊(duì)列 workQueue未滿,那么任務(wù)被放入緩沖隊(duì)列。
如果此時(shí)線程池中的數(shù)量大于corePoolSize,緩沖隊(duì)列workQueue滿,并且線程池中的數(shù)量小于maximumPoolSize,建新的線程來處理被添加的任務(wù)。
如果此時(shí)線程池中的數(shù)量大于corePoolSize,緩沖隊(duì)列workQueue滿,并且線程池中的數(shù)量等于maximumPoolSize,那么通過 handler所指定的策略來處理此任務(wù)。
也就是:處理任務(wù)的優(yōu)先級為:
核心線程corePoolSize、任務(wù)隊(duì)列workQueue、最大線程maximumPoolSize,如果三者都滿了,使用handler處理被拒絕的任務(wù)。
當(dāng)線程池中的線程數(shù)量大于 corePoolSize時(shí),如果某線程空閑時(shí)間超過keepAliveTime,線程將被終止。這樣,線程池可以動(dòng)態(tài)的調(diào)整池中的線程數(shù)。
unit可選的參數(shù)為java.util.concurrent.TimeUnit中的幾個(gè)靜態(tài)屬性:
NANOSECONDS、MICROSECONDS、MILLISECONDS、SECONDS。
workQueue我常用的是:java.util.concurrent.ArrayBlockingQueue
handler有四個(gè)選擇:
ThreadPoolExecutor.AbortPolicy()
拋出java.util.concurrent.RejectedExecutionException異常
ThreadPoolExecutor.CallerRunsPolicy()
重試添加當(dāng)前的任務(wù),他會(huì)自動(dòng)重復(fù)調(diào)用execute()方法
ThreadPoolExecutor.DiscardOldestPolicy()
拋棄舊的任務(wù)
ThreadPoolExecutor.DiscardPolicy()
拋棄當(dāng)前的任務(wù)
二、一般用法舉例
package com.paul.threadPool;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


public class TestThreadPool
{
private static int produceTaskSleepTime = 10;
private static int produceTaskMaxNumber = 10;

public static void main(String[] args)
{
// 構(gòu)造一個(gè)線程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 4, 3,
TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(3),
new ThreadPoolExecutor.CallerRunsPolicy());

for (int i = 1; i <= produceTaskMaxNumber; i++)
{

try
{
String task = "task@ " + i;
System.out.println("創(chuàng)建任務(wù)并提交到線程池中:" + task);
threadPool.execute(new ThreadPoolTask(task));
Thread.sleep(produceTaskSleepTime);

} catch (Exception e)
{
e.printStackTrace();
}
}
}
}
package com.paul.threadPool;

import java.io.Serializable;


public class ThreadPoolTask implements Runnable, Serializable
{

private static final long serialVersionUID = 0;
// 保存任務(wù)所需要的數(shù)據(jù)
private Object threadPoolTaskData;

private static int consumeTaskSleepTime = 2000;


ThreadPoolTask(Object tasks)
{
this.threadPoolTaskData = tasks;
}


public synchronized void run()
{
// 處理一個(gè)任務(wù),這里的處理方式太簡單了,僅僅是一個(gè)打印語句
System.out.println("開始執(zhí)行任務(wù):" + threadPoolTaskData);

try
{
// //便于觀察,等待一段時(shí)間
Thread.sleep(consumeTaskSleepTime);

} catch (Exception e)
{
e.printStackTrace();
}
threadPoolTaskData = null;
}


public Object getTask()
{
return this.threadPoolTaskData;
}

}說明:
1、在這段程序中,一個(gè)任務(wù)就是一個(gè)Runnable類型的對象,也就是一個(gè)ThreadPoolTask類型的對象。
2、一般來說任務(wù)除了處理方式外,還需要處理的數(shù)據(jù),處理的數(shù)據(jù)通過構(gòu)造方法傳給任務(wù)。
3、在這段程序中,main()方法相當(dāng)于一個(gè)殘忍的領(lǐng)導(dǎo),他派發(fā)出許多任務(wù),丟給一個(gè)叫 threadPool的任勞任怨的小組來做。
這個(gè)小組里面隊(duì)員至少有兩個(gè),如果他們兩個(gè)忙不過來,任務(wù)就被放到任務(wù)列表里面。
如果積壓的任務(wù)過多,多到任務(wù)列表都裝不下(超過3個(gè))的時(shí)候,就雇傭新的隊(duì)員來幫忙。但是基于成本的考慮,不能雇傭太多的隊(duì)員,至多只能雇傭 4個(gè)。
如果四個(gè)隊(duì)員都在忙時(shí),再有新的任務(wù),這個(gè)小組就處理不了了,任務(wù)就會(huì)被通過一種策略來處理,我們的處理方式是不停的派發(fā),直到接受這個(gè)任務(wù)為止(更殘忍!呵呵)。
因?yàn)殛?duì)員工作是需要成本的,如果工作很閑,閑到 3SECONDS都沒有新的任務(wù)了,那么有的隊(duì)員就會(huì)被解雇了,但是,為了小組的正常運(yùn)轉(zhuǎn),即使工作再閑,小組的隊(duì)員也不能少于兩個(gè)。
4、通過調(diào)整 produceTaskSleepTime和 consumeTaskSleepTime的大小來實(shí)現(xiàn)對派發(fā)任務(wù)和處理任務(wù)的速度的控制,改變這兩個(gè)值就可以觀察不同速率下程序的工作情況。
5、通過調(diào)整4中所指的數(shù)據(jù),再加上調(diào)整任務(wù)丟棄策略,換上其他三種策略,就可以看出不同策略下的不同處理方式。
6、對于其他的使用方法,參看jdk的幫助,很容易理解和使用。
摘要: 有依賴的包管理,可以部署到TOMCAT 6.X,可以使用JETTY作開發(fā)測試,可以生成站點(diǎn),作CHECK STYLE,PMD代碼檢查,代碼覆蓋率,生成JAVA DOC。
Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><project ...
閱讀全文
使用maven的一個(gè)方便之處是可以使用Jetty Plugin來運(yùn)行web項(xiàng)目。只要maven jetty:run就可以把web項(xiàng)目跑起來了。只是很多時(shí)候我們都需要在IDE中進(jìn)行調(diào)試。那如何在Eclipse中調(diào)試使用jetty Plugin的web項(xiàng)目呢?
下面我們就來配置一下。
- 首先在Run->Externel Tools->Open Externel Tools Dialog.. 打開配置對話框,選中左邊的Program節(jié)點(diǎn),右鍵選擇New然后再右邊的配置里面輸入Name信息,在Main tab下的Location選擇你maven可執(zhí)行文件的全路徑(eg:/home/rory/apps/apache-maven-2.0.8/bin/mvn),Working Directory選擇你的maven項(xiàng)目(eg:${workspace_loc:/guice-example}),Arguments里輸入jetty:run。然后再切換到Environment tab。New 一下變量,name是
MAVEN_OPTS
value是
-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=8080,server=y,suspend=y
ok,這一步設(shè)置完畢,Apply一下,close關(guān)閉
- 接下來添加一個(gè)Debug,打開Run->Open Debug Dialog..打開Debug Dialog窗口,選中左邊的Remote Java Application,右鍵New輸入name,Project里選中要Debug的項(xiàng)目Connection Properties里的Host里設(shè)置成localhost,Port設(shè)置成上面配置的8080(這里要填JETTY默認(rèn)啟動(dòng)的端口)然后Apply一下就ok了。
- 接下來就可以開始調(diào)試了。首先啟動(dòng)第一步配置的Externel Tools配置,然后再運(yùn)行第二步配置的Debug.就可以看到控制臺(tái)有mvn jetty:run的輸出了。接下來就開如Debug你的項(xiàng)目吧。:)
The motivation behind the framework
We had worked on a project where we hand-coded all of our DAOs. This produced four irksome difficulties: (1) Method names and implementations were not altogether consistent. (2) It was a pain to make additional columns sortable or filterable, and as a result, a lot of pages lacked good sorting and filtering. (3) Making additional DAOs was tedious and took a fair amount of time. (4) Writing tests for DAOs is tricky and tedious, so no one really did.
This framework aims to ease our troubles.
Why might you consider looking into this framework?
- Generic DAO: With the sweetness of Java generics, the concept of generic DAOs is not new, and it’s not difficult. However, we’ve put a lot of work into making these easy to use and robust. So if you like the way we’ve done it, then this framework provides ready-made code for you. On the other hand if you’d rather make your own, then simply feel free to look at our source code for ideas and help on a few potentially tricky issues.
- Search: Search is the most original and sophisticated part of this framework, and it can be used with or without the generic DAO portion of the framework. The search capability is designed around the use-case of a list page with sorting, filtering, column selection and paging. However, its use is certainly not limited to that. The value that the search adds is simpler, more robust querying with less coding and less testing. It is similar to Hibernate Criteria, but it is simpler to use and can easily move across layers of an application including view and even remote layers. Plus is works with both Hibernate and JPA*.
- Remote DAO (for R.I.A.s?): If you you’re like us, you don’t want to write and configure an individual DAO style remote service for each entity in a R.I.A. or other client-heavy application. This framework may have the solution. We provide utilities and sample code to adapt our single general DAO to any remoting technology interface. Just configure this single remote access point and the client can do any basic CRUD or search operation on any entity. Again, if you don’t like our way of doing things, maybe you can at least get some ideas from our source code.
- Remote Search (for R.I.A.s?): As mentioned above, the framework can provide a single point for client-server CRUD and search operations. The framework’s search is meant to be able to cross the client-server boundary. So lists and searches in the client application can take advantage of the same easy-to-use features and consistency that the search functionality provides in the server tier or single tier application. This consistency allowed us to create a reusable collection type in Adobe Flex 3 that is associated with a single search object and automatically updates itself from the server according to the search parameters.**
*A fairly simple adapter is required for each JPA provider. Right now we only have an adapter for Hibernate Entity Manager. If anyone would like to contribute an adapter for any other JPA provider (OpenJPA, TopLink, etc.), that would be great.
**If time permits, we would like to eventually post our corresponding Adobe Flex 3 framework and utilities.
More Information
Wiki Documentation: UserGuide
Javadoc: http://hibernate-generic-dao.googlecode.com/svn/trunk/docs/api/index.html
Blog: http://hibernategenericdao.wordpress.com/
Questions and Comments
Please post at http://groups.google.com/group/java-generic-dao.
Code Examples
Creating DAOs for individual model classes:
Simply extend the GenericDAO class with the specific type.

public interface ProjectDAO extends GenericDAO<Project, Long>
{

}


public class ProjectDAOImpl extends GenericDAOImpl<Project, Long> implements ProjectDAO
{

}
The following methods (and several more) are now available on ProjectDAO
Project project = projectDAO.find(projectId);
List<Project> list = projectDAO.findAll();
projectDAO.save(project);
projectDAO.remove(project);
projectDAO.removeById(project.getId());
Search search = new Search();
search.addFilterEqual("name", "hibernate-generic-dao");
List<Project> list = projectDAO.search(search);
int count = projectDAO.count(search);
SearchResult<Project> result = projectDAO.searchAndCount(search);
list = result.getResult();
count = result.getTotalCount();
search.clear();
search.addField("rating", Field.OP_AVG);
int avgProjectRating = (Integer) prjoectDAO.searchUnique(search);
A GeneralDAO is also provided with DAO methods for any entity:

public interface GeneralDAO
{
public <T> T find(Class<T> type, Serializable id);
public <T> T[] find(Class<T> type, Serializable ids);
public <T> T getReference(Class<T> type, Serializable id);
public <T> T[] getReferences(Class<T> type, Serializable ids);
public boolean save(Object entity); public boolean[] save(Object entities);
public boolean remove(Object entity); public void remove(Object entities);
public boolean removeById(Class<?> type, Serializable id);
public void removeByIds(Class<?> type, Serializable ids);
public <T> List<T> findAll(Class<T> type);
public List search(ISearch search); public Object searchUnique(ISearch search);
public int count(ISearch search); public SearchResult searchAndCount(ISearch search);
public boolean isAttached(Object entity);
public void refresh(Object entities); public void flush();
public Filter getFilterFromExample(Object example);
public Filter getFilterFromExample(Object example, ExampleOptions options); }
Search DTO usage examples
Search search = new Search(Project.class);

//filtering
search.addFilterEqual("name", "hibernate-generic-dao");

search.addFilterLessThan("completionDate", new Date());

search.addFilterOr(
Filter.equal("name", "Jack"),
Filter.and(
Filter.equal("name", "Jill"),
Filter.like("location", "%Chicago%"),
Filter.greaterThan("age", 5) )
);

search.addFilterIn("name", "Jack", "Jill", "Bob");

search.addFilterNot(Filter.in("name","Jack", "Jill", "Bob"));

//sorting
search.addSort("name");
search.addSort("age", true); //descending

//projection
search.addField("name");
search.addField("location");

//or with column operators
search.addField("rating", Field.OP_AVG);
search.addField("developerCount", Field.OP_MAX);

//paging
search.setMaxResults(15); //a.k.a. results per page
search.setPage(3);

//controlling eager fetching of relationships
serach.addFetch("owner");
Nested properties are also fully supported...
search.addFilterEqua("status.name", "active");
search.addFilterGreaterThan("workgroup.manager.salary", 75000.00);
search.addSort("status.name");