2008年12月30日 星期二

Servlet3.0 Briefing

Servlet3.0規範新鮮出爐,J2EE陣營實力大增

[IT168專稿]在2005年9月26日,Sun推出了Servlet的最新版API:Servlet2.5。這套Servlet API和以前的Servlet有著很大的不同。最大的區別就是Servlet2.5是完全基於J2SE5.0的。因此,它也理所當然地擁有了 J2SE5.0的所有特性。 Servlet2.5利用J2SE5.0的註釋特性使它的配置更容易。然而,由於在2005年J2SE5.0剛推出不久,支持J2SE5.0的Web服務 器也不多,因此,當時Servlet2.5在使用上並沒有馬上普及。時隔兩年後,Sun又推出了基於J2SE5.0的Servlet的第二個版本 3.0(就是JSR-315)。在這一版本中增加了很多有趣的特性。如可編程的登入登出,通過annotations進行配置,異步通訊等。

下面就讓我們 來看看Servet3.0的主要特性。

一、更靈活的Web框架

現在幾乎所有的基於Java的Web框架都是建立在Servlet之上的。大多數Web構架都是通過Servlets或web.xml來 配置和發布的。而J2SE新加入的註釋功能為我們提供了更好的選擇。我們可以利用註釋來設置Servlets、Listeners、filters等。但 註釋是直接寫在程序中的,無法動態改變配置,因此,JSR同時提供了這兩種方式來操作Servlet。這樣將使Web應用程序具有更大的彈性。

二、EOD的支持

Servlet3.0將使用多種技術來增強API的能力。如使用註釋來聲明編程類型。這將成為EOD的目標之一:使Web程序零配置。也就是說我們將使用 發布描述來覆蓋傳統的配置文章。還有就是泛型的應用,將大大加強程序的Servlet的表現力。在未來的J2SE版本中將加入支持其他語言的能力,這也有 助於增強Servlet API本身的實力。

三、異步通訊的支持

Servlet3.0支持以下異步通訊特性:

1.非阻塞(Non-blocking)輸入:使用這種輸入方式,可以在數據因某種原因暫時未到達時程序不會因此而被阻塞。
2.非阻塞輸出:和非阻塞輸入類似,當由於網絡問題寫入數據緩慢時程序不會受到阻塞。
3.延遲請求處理:在AJAX Web程序中客戶端程序可以向服務端發出異步請求,直到超時或事件返回來處理這個請求。延遲請求在其他的地方也是非常有用的,如我們在處理數據之前必須要 得到一些資源,但這些資源正處在遠程網絡中,而且速度並不快。這就需要異步來處理這種情況。
4.阻塞-非阻塞通知:這個功能是將通知信息放到阻塞或非阻塞事件中。然後由客戶端負責提取。
5.支持通道:通道是JDK1.4及以上版本提供的一種新的通訊API。使用Channel可以更好的進行網絡之間的通訊。也可以增強創建、訂閱、取消等操作的安全性。
6.安全:支持登錄和註銷功能。
7.其他功能
(1)支持歡迎界面。
(2) ServletContentListener排序。
(3)在初始化時可以定制容器的大小。
(4)可以監視文件上傳的進程。

上面只是Servlet3.0的一部分特性。從這些特性可以看出,Servlet3.0 API確實得到了很大的飛越,除了Servlet,EJB3.0也利用J2SE5.0的新特性重獲新生。也許在不久的將來Servlet3.0和 EJB3.0將會成為新的組合,在J2EE應用中起著舉足輕重的作用,就讓我們拭目以待吧!

Source: http://tech.it168.com

2008年12月20日 星期六

為什麼Linux比Windows更不會中毒?

(轉載)本篇文章來源於 IB資訊網

可能不少人持這樣一種觀點,認 為 Linux 病毒少是因為Linux不像Windows那麼普及,其實這種觀點很早已經被人批駁過了,一個最有力的論據是:如果寫病毒的人寫 Windows 病毒是因為 Windows 用戶多而因此破壞性大,那麼 Internet 上大多數服務器都是基於 Unix/Linux 的,攻擊這些服務器,破壞性豈不是更大麼?

對一個二進制的 Linux 病毒,要感染可執行文件,這些可執行文件對啟動這個病毒的用戶一定要是可寫的。而實際情況通常並不是這樣的。實際情況通常是,程序被 root 擁有,用戶通過無特權的帳號運行。而且,越是沒有經驗的用戶,他擁有可執行文件的可能性就越小。因此,越是不瞭解這種危險的用戶的主目錄越不適合病毒繁殖。

即使這個病毒成功地感染了這個用戶擁有的一個程序,由於這個用戶權限受限,它進一步傳播的任務也會非常困難(當然,對於運行單用戶系統的 Linux 新手,這個論證可能不適用。這樣的用戶可能會對 root 帳戶比較粗心)。

Linux 網絡程序構建地很保守,沒有使現在 Windows 病毒如此快速傳播變的可能的高級宏工具。這並不是 Linux 的固有特徵;它僅僅是兩種用戶基礎的不同和這種不同導致的在這兩種市場中的成功產品的不同的反映。通過觀察這些問題學到的經驗也會被用到將來的 Linux 產品中。

Linux的應用軟件和系統軟件幾乎都是開源的。這對病毒有兩方面的影響。首先,病毒很難藏身於開源的代碼中間。其次,對僅有二進制的病毒,一次新的編譯安裝就截斷了病毒一個主要的傳播途徑。雖然 Linux 發行商也提供大量的二進制軟件包,但是用戶大都是從發行商提供的可靠的軟件倉庫中下載這些軟件包,大都具有 md5 驗證機制,安全性極高。

這些障礙每一個都是病毒成功傳播的一個重要阻礙。然而當把他們放在一起考慮的時候,基本的問題才浮現出來。

一個計算機病毒,像生物病毒一樣,要想傳播開來,其繁殖速度必須超過其死亡(被消 滅)的速度。上面提到的障礙有效地降低了 Linux 病毒的繁殖速度。如果它的繁殖速度降到取代原來種群所需要的閾值之下,那麼這個病毒的厄運從一開始就注定了--甚至在潛在受害人意識到它們之前。

我們沒有看到一個真正的 Linux 病毒瘋狂傳播,原因就在於存在的 Linux 病毒中沒有一個能夠在 Linux 提供的敵對的環境中茁壯成長。現在存在的 Linux 病毒僅僅是技術上的好奇;現實是沒有能養得活的 Linux 病毒。

當然,這並不意味著永遠沒有 Linux 病毒能夠流行。然而它確實意味著一個成功的 Linux 病毒要在不適合生存的 Linux 生態系統中存活下來必須是精心製作並具創新的

2008年12月18日 星期四

Jakarta Commons

兩位前輩的總結,寫得很好。
http://www.blogjava.net/sean/articles/Jakarta_Commons_Notes.html
http://www.blogjava.net/sean/archive/2005/08/02/9015.html


據Common BeanUtils的用戶指南學習了很多有用的工具類.

參考:http://commons.apache.org/beanutils/apidocs/org/apache/commons/beanutils/package-summary.html#package_description


1.屬性的存取

簡單式:

PropertyUtils.getSimpleProperty(Object bean, String name)
PropertyUtils.setSimpleProperty(Object bean, String name, Object value)


索引式:
PropertyUtils.getIndexedProperty(Object bean, String name)
PropertyUtils.getIndexedProperty(Object bean, String name, int index)
PropertyUtils.setIndexedProperty(Object bean, String name, Object value)
PropertyUtils.setIndexedProperty(Object bean, String name, int index, Object value)

Map式:

PropertyUtils.getMappedProperty(Object bean, String name)
PropertyUtils.getMappedProperty(Object bean, String name, String key)
PropertyUtils.setMappedProperty(Object bean, String name, Object value)
PropertyUtils.setMappedProperty(Object bean, String name, String key, Object value)


嵌套式:
PropertyUtils.getNestedProperty(Object bean, String name)
PropertyUtils.setNestedProperty(Object bean, String name, Object value)


通用式:
PropertyUtils.getProperty(Object bean, String name)
PropertyUtils.setProperty(Object bean, String name, Object value)


發現通用式最方便,可以替代上面所有的方式(搞不懂為啥還要弄那麼多)。

舉例:
//簡單式
System.out.println(PropertyUtils.getProperty(employee1, "lastName"));

//索引式
System.out.println(PropertyUtils.getProperty(employee1,"addr[0].city"));

//Map式
PropertyUtils.setProperty(employee1, "telphone(tel)", "test1");
System.out.println(PropertyUtils.getProperty(employee1, "telphone(tel)"));

//嵌套式
String address = (String) PropertyUtils.getProperty(employee1, "address.addr");
System.out.println(address);



2.動態Beans

基本式:(需要先定義屬性然後才能使用,不推薦)

BasicDynaBean and BasicDynaClass


包裝ResultSet式:(必須打開數據庫連接可以使用,不推薦)

ResultSetDynaClass


包裝RowSet式:(可以不用打開連接使用,推薦)

RowSetDynaClass

舉例:

try {
Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
Connection conn = DriverManager.getConnection(
"jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=java",
"sa", "sa");
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select code,name from role");
RowSetDynaClass rsdc = new RowSetDynaClass(rs);
rs.close();
stmt.close();

List rows = rsdc.getRows();
for (Object object : rows) {
DynaBean row = (DynaBean) object;
System.out.println("Role code is " +
row.get("code") +
" and name is " + row.get("name"));
}

} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

懶加載式:(方便實用,重點推薦)

LazyDynaBean

舉例:

LazyDynaBean ldb = new LazyDynaBean();
ldb.set("test1", "tt");
ldb.set("test2", null);
ldb.set("test3", new Employee());
System.out.println(ldb.get("test1"));
System.out.println(ldb.get("test2"));//null
System.out.println(ldb.get("test3"));//顯示Employee.toString()信息

並且也具有LazyDynaMap的功能。


3.數據類型的轉換

重點推薦BeanUtils.populate方法。

舉例:

Address bean = new Address();
HashMap map = new HashMap();
map.put("zipCode1", "zipCode");
map.put("addr", new Long(1234));
map.put("city", "");
map.put("country", "country");
System.out.println(bean);
try {
BeanUtils.populate(bean, map);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(bean);

常利用在action填充vo時。

Database外鍵,用還是不用?


對於主/外鍵/索引來說,在一些開發團隊中被認為是處理數據庫關係的利器,也被某些開發團隊認為是處理某些具體業務的魔鬼,您的觀點呢?在實際應用中您會採取哪種方式?

大家共同觀點:
主鍵和索引是不可少的,不僅可以優化數據檢索速度,開發人員還省不其它的工作,

矛盾焦點:數據庫設計是否需要外鍵。這裡有兩個問題:一個是如何保證數據庫數據的完整性和一致性;二是第一條對性能的影響。

正方觀點:
1,由數據庫自身保證數據一致性,完整性,更可靠,因為程序很難100%保證數據的完整性,而用外鍵即使在數據庫服務器當機或者出現其他問題的時候,也能夠最大限度的保證數據的一致性和完整性。
eg:數據庫和應用是一對多的關係,A應用會維護他那部分數據的完整性,系統一變大時,增加了B應用,A和B兩個應用也許是不同的開發團隊來做的。他們如何協調保證數據的完整性,而且一年以後如果又增加了C應用呢?
2,有主外鍵的數據庫設計可以增加ER圖的可讀性,這點在數據庫設計時非常重要。
3,外鍵在一定程度上說明的業務邏輯,會使設計周到具體全面。

反方觀點:
1,可以用觸發器或應用程序保證數據的完整性
2,過分強調或者說使用主鍵/外鍵會平添開發難度,導致表過多等問題
3,不用外鍵時數據管理簡單,操作方便,性能高(導入導出等操作,在insert, update, delete數據的時候更快)
eg:在海量的數據庫中想都不要去想外鍵,試想,一個程序每天要insert數百萬條記錄,當存在外鍵約束的時候,每次要去掃描此記錄是否合格,一般還不 止一個字段有外鍵,這樣掃描的數量是成級數的增長!我的一個程序入庫在3個小時做完,如果加上外鍵,需要28個小時!

結論:
1,在大型系統中(性能要求不高,安全要求高),使用外鍵;在大型系統中(性能要求高,安全自己控制),不用外鍵;小系統隨便,最好用外鍵。
2,用外鍵要適當,不能過分追求
3,不用外鍵而用程序控制數據一致性和完整性時,應該寫一層來保證,然後個個應用通過這個層來訪問數據庫。

2008年12月17日 星期三

軟件發布版本說明

(轉)小草

大型軟件在正式發布前,通常需要執行Alpha和Beta測試,目的是從實際終端用戶的使用角度,對軟件的功能和性能進行測試,以發現可能只有最終用戶才能發現的錯誤。


Alpha測試(α測試)是由一個用戶在開發環境下進行的測試,也可以是公司內部的用戶在模擬實際操作環境下進行的受控測試,Alpha測試不能由程序員或測試員完成。 Alpha測試發現的錯誤,可以在測試現場立刻反饋給開發人員,由開發人員及時分析和處理。目的是評價軟件產品的功能、可使用性、可靠性、性能和支持。尤其註重產品的界面和特色。 Alpha測試可以從軟件產品編碼結束之後開始,或在模塊(子系統)測試完成後開始,也可以在確認測試過程中產品達到一定的穩定和可靠程度之後再開始。有關的手冊(草稿)等應該在Alpha測試前準備好。



Beta測試(β測試)是軟件的多個用戶在一個或多個用戶的實際使用環境下進行的測試。開發者通常不在測試現場,Beta測試不能由程序員或測試員完成。因而,Beta測試是在開發者無法控制的環境下進行的軟件現場應用。在Beta測試中,由用戶記下遇到的所有問題,包括真實的以及主管認定的,定期向開發者報告,開發者在綜合用戶的報告後,做出修改,最後將軟件產品交付給全體用戶使用。 Beta測試著重於產品的支持性,包括文檔、客戶培訓和支持產品的生產能力。只有當Alpha測試達到一定的可靠程度後,才能開始Beta測試。由於 Beta測試的主要目標是測試可支持性,所以Beta測試應該盡可能由主持產品發行的人員來管理。



由於Alpha和Beta測試的組織難度大,測試費用高,測試的隨機性強、測試週期跨度較長,測試質量和測試效率難於保證,所以,很多專業軟件可能不再進行Beta測試。隨著測試技術的提高,以及專業測試服務機構的大量湧現,很多軟件的Beta測試外包給這些專業測試機構進行測試。



α測試和β測試

在軟件交付使用之後,用戶將如何實際使用程序,對於開發者來說是無法預測的.

α測試是由一個用戶在開發環境下進行的測試,也可以是公司內部的用戶在模擬實際操作環境下進行的

測試.

α測試的目的是評價軟件產品的FLURPS(即功能,局域化,可使用性,可靠性,性能和支持).尤其註重產品的

界面和特色.

α測試可以從軟件產品編碼結束之時開始,或在模塊(子系統)測試完成之後開始,也可以在確認測試過程

中產品達到一定的穩定和可靠程度之後再開始.

β測試是由軟件的多個用戶在實際使用環境下進行的測試.這些用戶返回有關錯誤信息給開發者.

測試時,開發者通常不在測試現場.因而,β測試是在開發者無法控制的環境下進行的軟件現場應用.

在β測試中,由用戶記下遇到的所有問題,包括真實的以及主觀認定的,定期向開發者報告.

β測試主要衡量產品的FLURPS.著重於產品的支持性,包括文檔,客戶培訓和支持產品生產能力.

只有當α測試達到一定的可靠程度時,才能開始β測試.它處在整個測試的最後階段.同時,產品的所有手冊

文本也應該在此階段完全定稿.



α、β、λ常用來表示軟件測試過程中的三個階段,α是第一階段,一般只供內部測試使用;β是第二個階段,已經消除了軟件中大部分的不完善之處,但仍有可能還存在缺陷和漏洞,一般只提供給特定的用戶群來測試使用;λ是第三個階段,此時產品已經相當成熟,只需在個別地方再做進一步的優化處理即可上市發行。



其它相關的版本說明:



Trial:試用版,通常都有時間限制,有些試用版軟件還在功能上做了一定的限制。可註冊或購買成為正式版

Unregistered:未註冊版,通常沒有時間限制,在功能上相對於正式版做了一定的限制。可註冊或購買成為正式版。

Demo:演示版,僅僅集成了正式版中的幾個功能,不能升級成正式版。

Lite:精簡版。

Fullversion:完整版,屬於正式版。



開發階段劃分:

α(Alpha)版:內測版,內部交流或者專業測試人員測試用。 Bug較多,普通用戶最好不要安裝。

β(Beta)版:公測版,專業愛好者大規模測試用,存在一些缺陷,該版本也不適合一般用戶安裝。

γ(Gamma)版:相當成熟的測試版,與即將發行的正式版相差無幾。

RC版:ReleaseCandidate。

RC版。是ReleaseCandidate的縮寫,意思是發布倒計時,候選版本,處於Gamma階段,該版本已經完成全部功能並清除大部分的BUG。到了這個階段只會除BUG,不會對軟件做任何大的更改。從Alpha到Beta再到Gamma是改進的先後關係,但RC1、RC2往往是取捨關係。

Final:正式版。



比較少用的:

Enhance:增強版或者加強版屬於正式版1

Free:自由版

Release:發行版有時間限制

Upgrade:升級版

Retail:零售版

Cardware:屬共享軟件的一種,只要給作者回復一封電郵或明信片即可。 (有的作者並由此提供註冊碼等),目前這種形式已不多見。 /S

Plus:屬增強版,不過這種大部分是在程序界面及多媒體功能上增強。

Preview:預覽版

Corporation&Enterprise:企業版

Standard:標準版

Mini:迷你版也叫精簡版只有最基本的功能

Premium:貴價版

Professional:專業版

Express:特別版(但都好mini, e.g. Oracle Database 10g Express Edition)

Deluxe:豪華版

Regged:已註冊版

2008年11月24日 星期一

JDK 6.0自帶web service

JAVA 6.0之後,其中JDK自帶有個輕量級的web service服務器。如果你比較細心一定發現在你安裝java的路徑下,有java webservice的示例代碼。

我 以前也用java開發過web service ,但是當初用了一個apache下axis開源項目。如果axis夜進化了,反正我不認識了。不過java自帶有何必捨近求遠呢。今天我就把自己創建的最 簡單java webservice範例過程記錄下來,與大家分享。

我用的是netbeans 6,首先建立一個java應用程序工程,名為WebServices。建立一個服務端程序。
package WebServices;

import javax.jws. * ;
import javax.xml.ws.Endpoint;

/**
* @author hecm
*/
@WebService(targetNamespace = " http://www.blogjava.net/JAVA-HE " , serviceName = " HelloService " )
public class WSProvider
{

// @WebResult(name = "Greetings") //自定義該方法返回值在WSDL中相關的描述
@WebMethod(action = " sayHi " , operationName = " sayHi " )
public String sayHi(@WebParam(name = " MyName " ) String name)
{
return " Hi, " name; // @WebParam是自定義參數name在WSDL中相關的描述

}

@Oneway //表明該服務方法是單向的,既沒有返回值,也不應該聲明檢查異常

@WebMethod(action = " printSystemTime " , operationName = " printSystemTime " ) //自定義該方法在WSDL中相關的描述
public void printTime()
{
System.out.println(System.currentTimeMillis());
}

public static void main(String[] args)
{
Thread wsPublisher = new Thread( new WSPublisher());
wsPublisher.start();
}

private static class WSPublisher implements Runnable
{

public void run()
{
//發布WSProvider到http: // localhost:8888/hechangmin/WSProvider這個地址,之前必須調用wsgen命令
//生成服務類WSProvider的支持類,命令如下:
// wsgen -cp . WebServices.WSProvider
Endpoint.publish("http://localhost:8888/JAVA-HE/WSProvider", new WSProvider());
}
}
}

當然建立對應的包,就不用說了。
然後編譯文件。
進入命令提示符下,進入classes目錄,運行:wsgen -cp . WebServices.WSProvider

可以看到將剛才的class生成了幾個java文件和class文件。

現在要做的是發布ws到http://localhost:8888/chinajash/WSProvider
而實際上的動作就是:Endpoint.publish("http://localhost:8888/chinajash/WSProvider",new WSProvider());
當然直接運行WSProvider 。

然後輸入http://localhost:8888/JAVA-HE/WSProvider?wsdl

就已經查看到生成的wsdl (webservice描述語言)。

也就是服務端就OK了。

保持運行。編寫一個測試客戶端:

首先選擇項目,右鍵新建web服務客戶端。其中ws url填入剛才生成的wsdl地址:
http://localhost:8888/JAVA-HE/WSProvider?wsdl

(實際上:和wsimport http://localhost:8888/JAVA-HE/WSProvider?wsdl一樣的效果)


產生一個效果:在classes下按照之前指定的名字空間產生的包下(目錄結構)生成了7個幫助class。

然後我們建立一個包client建立測試文件:



/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

package client;

import net.blogjava.java_he. * ;
/**
*
*
@author hecm
*/
public class Test {
public static void main(String args[])
{
HelloService hs
= new HelloService();
WSProvider ws
= hs.getWSProviderPort();
System.out.println(ws.sayHi(
" hechangmin " ));
ws.printSystemTime();
}

}







運行這個測試類:
Hi,hechangmin

輸出了。順利完成!

一點個人經驗,你發布的地址最好寫成可配置。還有就是wsdl中會嚴格按照你指定的url來訪問,比如你指定的127.0.0.1那麼你用本機IP的時候也許並不能順利訪問。

Source: http://www.blogjava.net/JAVA-HE

2008年11月16日 星期日

How To Develop iPhone Applications in Java

Phone is a great phone to develop applications for. Unfortunately Apple decided to restrict developing iPhone applications in a less known language called Objective C, which is used pretty much within Apple (and by Apple developers) and almost noweher else. Only Steve Jobs knows the reason behind this strange decision. Java ( J2ME) is the most popular language & platform for mobile development. So Java developers need a way to develop applications for iPhone too by leveraging their core competency.


Previously I have provided two ways how Java developers can install, compile and run iPhone applications on Java. Today I will present a third method.

Apple's SDK for the iPhone, as you know, is based on Objective-C as the development language as well as Cocoa for the GUI.
Unfortunately Apple's super-restrictive license agreement for the iPhone SDK prohibits the porting of the Java virtual machine to the iPhone. Today we will talk about how we can use Open Source Java to run applications which will run on Apple's iPhone. The open source project by
Arno Puder, Associate Professor at the San Francisco State University, uses a cross-compiler to convert Open Source Java code to Objective-C and provide a Java-based implementation of the Cocoa library. With the help of these tools, iPhone applications can be written in pure Java.

Using the Java version of Cocoa, it is possible to run a Java-based iPhone application as a Java desktop/applet application that can be cross-compiled to run natively on the iPhone.

You can find more details about the software from http://www.xmlvm.org/

XmlVM's SourceForge.net Subversion repository can only be checked out through SVN with the following instruction set:

svn co https://xmlvm.svn.sourceforge.net/svnroot/xmlvm xmlvm

Warning: This is a generic Subversion checkout command which will pull all modules, tags and/or branches of the project. In most cases, you will want to add '/trunk' to the HTTPS URL above to check out only trunk (main development line).

Each of the boxes in the diagram above represents an artifact while the arrows denote the various transformations between those artifacts. The input to the XMLVM toolchain is either a Java class file or a .NET executable. A Java class file is translated to XMLVMJVM which is an XML-document describing the contents of that class file. Likewise XMLVMCLR is an XML-document describing the contents of a .NET executable. XMLVMCLR can be cross-compiled to XMLVMJVM with the help of a data flow analysis (DFA) which is shown as XMLVMCLR-DFA in the figure below. XMLVMJVM serves as a canonical representation as it acts as a boundary between the front- and back-end of the cross-compiler. Once XMLVMJVM has been generated, it can be mapped to various high-level programming languages. It is also possible to map XMLVMJVM to a Java class file again.

Check it out. Also don't forget to read the detailed guide on how to install, compile & run Java applications on iPhone.

2008年11月4日 星期二

Digital Signal Processing (DSP) Tutorial

1468 Plotting Engineering and Scientific Data using Java
1489 Plotting 3D Surfaces using Java
1492 Plotting Large Quantities of Data using Java

100 Periodic Motion and Sinusoids
104 Sampled Time Series
108 Averaging Time Series

400 Processing Image Pixels using Java, Getting Started
402 Processing Image Pixels using Java, Creating a Spotlight
404 Processing Image Pixels Using Java: Controlling Contrast and Brightness
406 Processing Image Pixels, Color Intensity, Color Filtering, and Color Inversion
408 Processing Image Pixels, Performing Convolution on Images
410 Processing Image Pixels, Understanding Image Convolution in Java
412 Processing Image Pixels, Applying Image Convolution in Java, Part 1
414 Processing Image Pixels, Applying Image Convolution in Java, Part 2
416 Processing Image Pixels, An Improved Image-Processing Framework in Java
418 Processing Image Pixels, Creating Visible Watermarks in Java
450 A Framework for Experimenting with Java 2D Image-Processing Filters
452 Using the Java 2D LookupOp Filter Class to Process Images
454 Using the Java 2D AffineTransformOp Filter Class to Process Images
456 Using the Java 2D LookupOp Filter Class to Scramble and Unscramble Images
458 Using the Java 2D BandCombineOp Filter Class to Process Images
460 Using the Java 2D ConvolveOp Filter Class to Process Images
462 Using the Java 2D ColorConvertOp and RescaleOp Filter Classes to Process Images

1478 Fun with Java, How and Why Spectral Analysis Works
1482 Spectrum Analysis using Java, Sampling Frequency, Folding Frequency, and the FFT Algorithm
1483 Spectrum Analysis using Java, Frequency Resolution versus Data Length
1484 Spectrum Analysis using Java, Complex Spectrum and Phase Angle
1485 Spectrum Analysis using Java, Forward and Inverse Transforms, Filtering in the Frequency Domain
1486 Fun with Java, Understanding the Fast Fourier Transform (FFT) Algorithm
1487 Convolution and Frequency Filtering in Java
1488 Convolution and Matched Filtering in Java
1490 2D Fourier Transforms using Java
1491 2D Fourier Transforms using Java, Part 2
1510 A Recursive Filtering Workbench in Java
1511 The Driver Class for the Recursive Filtering Workbench in Java
1512 The User Input GUI for the Recursive Filtering Workbench in Java
1513 The Recursive Filtering Workbench in Java, Putting it all Together

...
Adaptive Filtering

2350 Adaptive Filtering in Java, Getting Started
2352 An Adaptive Whitening Filter in Java
2354 A General-Purpose LMS Adaptive Engine in Java
2356 An Adaptive Line Tracker in Java
2358 Adaptive Identification and Inverse Filtering using Java
2360 Adaptive Noise Cancellation using Java
2362 Adaptive Prediction using Java

...
2444 Understanding the Discrete Cosine Transform in Java
2446 Understanding the 2D Discrete Cosine Transform in Java
2448 Understanding the 2D Discrete Cosine Transform in Java, Part 2




http://www.dickbaldwin.com/tocdsp.htm

2008年10月28日 星期二

關於權限控制策略的討論

表結構為user--role--menu。
我要實現的功能是:
1.對系統菜單(頁面)的控制,不可訪問的不顯示;
2.對頁面上的具體操作進行控制,如該用戶對該模塊只有查詢權限,不能修改、刪除。
對於第一點,我可以做到。根據當前登錄的用戶,獲取他擁有的角色,進而獲取他可訪問的全部模塊列表,顯示這些可以訪問的模塊。
對 於第二點,我有個想法,在數據庫中,對模塊的訪問設定級別,1-全部操作;2-只能查詢。這樣的話,顯示頁面時,判斷該用戶對該頁面的訪問級別,若為1, 顯示“增加、刪除”按鈕,若為2,只顯示查詢按鈕。但這樣的話,實際上時把權限控制的代碼寫到了各個頁面,很不雅觀。


對合同管理模塊,我們在公司權限系統中新增了五種角色:合同錄入人、合同查閱人、合同審核人、合同管理員、超級管理員。在合同管理權 限設置中,對員工賦角色,一個角色可能有多個員工,而一個員工可能也有多個角色。然後設置一員工所能夠管理的部門。基本業務邏輯是,誰(員工)對何部門有 何權限(5種角色)。

上述系統涉及到以下幾張表:

1.角色表。 (ID),角色名,描述。
2.用戶表。 (HrID),描述。
3.部門表。 (DeptID),描述。
4.部門-角色-用戶表。 (ID,HrID,DeptID)。

在表4中,完成上述的業務邏輯,也即“誰對何部門有何權限”。這裡的權限是用角色名來標識,比如合同錄入人這個角色,擁有合同錄入的 權限,合同查閱人這個角色,擁有查閱合同的權限。而部門的樹形結構,則是依賴於DeptID。 DeptID由12位數字構成,每兩個1組,由左至右分別對應部門的級別。比如010500000000代表**公司**部門。實際使用時,通過like ‘01%’,like ’0105%‘判斷員工所管理的部門(個人認為,這里相當Cool)。

我們用公司現有的權限系統來管理角色,增加部門-角色-用戶映射表來管理權限,在前台頁面中完成用戶的授權。這種設計結構相對清 楚,但在應對高靈活的情況是,可能力不從心,比如要增加合同確認這一功能,那麼必須在增加合同確認人角色等。所以有以下一些考慮。

1.將角色和角色所具有的操作分離,常見的操作包括Insert(新增),Select(查看),Update(更新),Delete等操作。用一個素數 對應這四個操作,分別為2,3,5,7。將角色和操作的對應關係放入數據庫。比如合同錄入人所擁有的操作對應2,而合同查閱人對應3,合同審核人對應3, 合同管理員對應3*7。在Unix系統中,採用1,2,4對應讀、寫、執行三種操作,將這三種標識碼相加,對應組合操作。
2.角色體現在業務流程上,如審核人只有讀的操作,流程上可以對一個合同審核通過,或者是駁回重填。

在《關於權限系統的探討》一文中,還考慮了“限定內容列表”,以區分能夠被操作的表、字段。由(ID)、名稱、描述構成。比如在我們的這個合同管理系統中,可能就是A用戶可以修改數據庫裡的這幾個表,而B用戶只能修改數據庫裡的那幾個表。

Simple is beautiful! 發覺自己思路開始混亂。這樣設計複雜,同時和原有的系統並不兼容,純屬遐想。

http://topic.csdn.net/t/20030413/09/1653829.html

2008年10月24日 星期五

FFT - Fast Fourier Transform Program (Algorithm)

Copy From http://people.csail.mit.edu/hammond/teaching/hide/fft/

public class fft
{
private double[] YREAL;
private double[] YIMAG;
private double[] XREAL;
private double[] AFFT;
private double[] BFFT;
private double[] COSX;
private double[] SINX;
private int[] POW;

fft(String[] datapoints)
{

try
{

// put the given values in to an array
YREAL = makeRealArray(datapoints);
YIMAG = makeImaginaryArray(datapoints);

// make array of x values
XREAL = makeXArray(Integer.parseInt(datapoints[0]));

// the given values function are starting values for
// Fourier Results
AFFT = YREAL;
BFFT = YIMAG;

// make cos(x) array and sin(x) array
COSX = makeCosXArray(XREAL);
SINX = makeSinXArray(XREAL);

// generate power array
POW = makePowerArray(Integer.parseInt(datapoints[0]));

// actual fft calculation done here
calculateABValues(Integer.parseInt(datapoints[0]));

// unscramble the vertices according to POW values
unscramble();

}
catch (Exception e)
{
System.out.println("Exception " + e.toString());
e.printStackTrace();
System.exit(-1);
}

for(int i = 0; i < realarray =" new" i =" 0;" imaginaryarray =" new" i="0;" xarray =" new" i =" 0;" cosxarray =" new" i =" 0;" sinxarray =" new" i =" 0;" powerarray =" new" i =" 0;" totalnumberofruns =" (int)" i =" 1;" j =" 1;" j =" 0;" i =" 0;" stage =" 1;" numberofsets =" 1;" cyclelength =" NumberOfData/2;" k =" 0;" tempa =" AFFT;" tempb =" BFFT;" setnumber =" 1;" i =" 0;" j =" (i" l =" POW[(int)(k/cycleLength)];"> AFFT.length || l > AFFT.length || j+cycleLength > AFFT.length)
System.out.println("HELP");
TEMPA[k] = AFFT[j] + COSX[l]*AFFT[j+cycleLength] - SINX[l]*BFFT[j+cycleLength];
TEMPB[k] = BFFT[j] + COSX[l]*BFFT[j+cycleLength] - SINX[l]*AFFT[j+cycleLength];
k++;
}
}
AFFT = TEMPA;
BFFT = TEMPB;
stage++;
NumberOfSets *= 2;
cycleLength /= 2;
k = 0;
} while (stage <= (int)(Math.log(NumberOfData)/Math.log(2))); } /** * Method: unscramble * Input: none * Output: none * Function: Rearranges the A and B values */ private void unscramble() { double[] tempA = AFFT; double[] tempB = BFFT; for (int i = 0; i < length ="=" data1 =" {" alg =" new" i =" 0;"> Integer.parseInt(args[0]))
printUsage();
} while (true);

// make sure number entered equals the number of
// datapoints
if ((args.length - 1)/2 != Integer.parseInt(args[0]))
printUsage();

}
catch (Exception e){
// probably error in input
printUsage();
}

// all is good.
// start the program (Fast Fourier Transform)
fft alg = new fft(args);

}

private static void printUsage()
{
System.out.println("Fast Fourier Transform");
System.out.println("Returns the fft of a list of data points");
System.out.println("--usage");
System.out.println(" fft number datapoints");
System.out.println();
System.out.println("Number must be the number of datapoints");
System.out.println("Number must be power of 2");
System.out.println("Datapoints must be written as: y1real y1imaginary y2real y2imaginary...");
System.out.println("X values are considered to be standardized on [0,2*pi]");
System.out.println();
System.exit(0);
}
}

2008年10月20日 星期一

Java Focus 簡談

視窗系統一般包含一個桌面GUI若干應用程序GUI。每個GUI都由組件構成,每個組 件都可以獲得focus,獲得focus的組件將獲得之後的鍵盤事件,而任意時刻只有一個組件能獲得focus。這個設計適用在當前所有的視窗系統,而跨 各種系統的JAVA應用,其focus的表現也要遵循這個設計目標。

JAVA的組件分為重量級和輕量級組件,區別在於重量級組件實例的成員peer-對等體,其行為緊密依託本地系統的GUI行為函數庫來進行實現。比如一個 JFRAME,當setvisible時,會依托peer.show進行屏幕繪製行為,該行為會通過本地系統GUI行為函數庫完成;這樣一來,當其被點擊 時,本地系統會依據最初調用本地GUI函數繪製時留下的信息,從而能夠經底層處理後(比如將該鼠標事件附加peer標記信息,同時可能經底層分析需要構造 出一個可能的focus_gain事件,則在操作系統層面登記當前聚焦GUI組件等)準確將底層GUI事件派送給該JVM進程,該事件因而在jvm進程中 的AWT-Windows線程loop獲取到,並通過事件提供的peer標記最終確定目標為重量級組件JFRAME,因此一個source== JFRAME的AWTEvent被構造出來並最終分派給EDT進行後續處理。

事件機制是程序中家喻戶曉的設計模式了。但是,看java的focus實現中對這個機制似乎多少有些不那麼絕對的清晰J。

個 人理解,事件的含義就是某種定義的情況發生了。比如點擊鼠標這個動作可以說觸發了多個事件,如press,release,click等,分別指發生了鼠 標button1按下,放開,完成點擊的情況。 button1按下這個事件比起完成點擊就要更基礎一些,因為完成點擊指的是一個由按下,放開動作序列組合的情況發生了。

那麼對於focus,focus_gained,focus_lost這兩個事件應該是指某組件獲得焦點或失去焦點的情況發生了,反映在機器裡,應該是某種指向當前聚焦組件的全局變量發生了更新。

然而在java awt實現裡,概念混亂出現啦。

如 果awt_windows loop到了focus事件,一,這個事件一定是目標向重量級組件的;二,此時,這個事件對於底層系統的對等組件,focus_gainded是發生了 (底層系統標記當前聚焦組件的全局變量已經更新;底層操作系統沒有mess,總是在真正focus改變後才分發focus事件),然而在java層面,截 至到awt_windows loop到底層focus事件並包裝成FocusEvent放置到EVENT QUEUE時,java層面並沒有更新jvm裡的全局變量。所以我個人認為這個時候就不應該包裝成FocusEvent,至少不應該叫這個名字,應該叫 PrepareFocusEvent,嘿嘿。

澄清事件機制的概念後,回頭看java focus要實現的目標。

1.當用戶從別處聚焦點切換到某文本框時(通過約定好的一些鍵盤鼠標操作,比如鼠標點擊或其他可能的動作),需要更新JAVA全局變量使該文本框成為聚焦組件,而後通知該組件的事件監聽focusgainedlistener。

當 前的難點是,輕量級組件雖可以設計在組件切換操作(如mouse_press)的listener中實現全局變量更新,然而問題是如果輕量級組件的容器是 一個重量級組件,比如一個Panel,而此時它的本地對等組件在本地系統中很可能還沒有獲得焦點。若實現上只是在切換操作監聽中簡單的把java的全局變 量更新了,那系統中就會在此時間出現兩個聚焦組件:一個是底層系統承認的原來的某底層對等組件,一個是java裡認為的現在的jtextfield。在這 個時空裡界面將很難不混亂,你很可能會看到最顯眼的是有一個亮亮的TextField,而那個上面有“已經聚焦”的jtextfield的panel面板 卻灰灰的,而你輸入的一個個字符竟然在灰灰的jtextfield中顯示出來。

2.可以提供某方法供應用調用,比如setfocus指定某組件聚焦。

難 點是根據前面的分析,指定輕量級組件聚焦,則要在處理中要通知其重量級容器對應的本地對等組件聚焦並等到它確實聚焦完成了再更新JAVA的全局變量。若實 現上真就是在setfocus調用中直接調用底層setfocus,問題出現在即使底層系統根據調用通知更新了focus,馬上還會繼續對外設可能的焦點 切換操作響應(可以認為有一個系統進程在處理外設的響應),很有可能別的C應用就在此時再要求focus,於是接著就更新了底層的focus登記;而我們 的setfocus調用卻是在jvm進程的某線程中,顯然這就是個並發的情景,這樣,很有可能我們的對本地對等組件的通知發過去並返回了,那邊底層系統就 馬上切換到了C的某個組件focus,而我們的線程繼續更新JAVA的全局focus變量並隨後發布 focus_gained(target==jcomponent),於是又出現了不一致的場景。難道我們要同步這兩個進程,讓系統進程等待我們的調用 setfocus的線程返回再繼續運行,顯然那樣是不合理的。 (JAVA只能服從OS,不能讓OS服從JAVA。---出自《英雄亂語》J)

鑑於1,2的分析,java focus的實現是setfocus是requestfocus,意思是只是將這個切換焦點的請求登記上但並不實際切換focus;隨後如果重量級組件聚焦了再處理request並徹底完成focus切換。

3.聚焦組件後馬上獲得隨後的鍵盤事件。

難 點是按用戶的實際想法,mouse_press後,馬上就要鍵盤拼寫,鍵盤的輸入應該target到mouse_press的jtextfield。根據 前面的分析,mouse_press響應中requestfocus/setfocus後並沒有意味著切換焦點已經完成。若實現上對於後續的鍵盤事件只是 簡單地根據JAVA的那個全局focus變量target,則這些鍵盤事件將不會target到期待的組件上。

鑑於3的分 析,java focus的實現是requestfocus時,如果這個請求按普遍規則一定通過而只是在等待時機,那麼在處理這個請求返回前就登記一個時間戳,在這個時 間戳之後在下一個requestfocus時間戳之前,EDT逐個取的keyevent都將target到該組件並登記,直到該組件徹底聚焦完成後,馬上 把這些keyevent dispatch。

4.需要支持TAB鍵等焦點遍歷操作。

這一點JAVA有一個遍歷模型,如下:

具體參照http://java.sun.com/javase/6/docs/api/java/awt/doc-files/FocusSpec.html

該要求並沒有難點。實現上只要對keyevent監聽,並根據規則進行合適處理即可。

2008年10月18日 星期六

JAVA 6 讓 Webservice 變簡單

以前的經驗,開發 Webservice 的程式是一件相當麻煩的事情,環境設定、編輯 WSDL、程式佈署等等,即使用 IDE 的工具,都不是三言兩語就可以搞定。

JAVA 6 的出現,拯救了像我這種怕麻煩的人 ...

關鍵在於兩個 annotation: @WebService 和 @WebMethod

參考了 Vivek Pandey's Blog 学习Java6(一) WebServices(3)在tomcat中发布,簡單地整理開發 Webservice 的 Server 端和 Client 端程式的過程,以及如何部屬到 Tomcat:


參考 Vivek 的範例,寫一個加法的 Webservice
Server Side
WebServiceStarter.java

public class WebServiceStarter extends HttpServlet{

private static final long serialVersionUID = 5870534239093709659L;

public WebServiceStarter() {
super();
}

public void destroy() {
super.destroy();
}

public void init() throws ServletException{
System.out.println("\nStarting Calculator Service ......\n");
try{
Endpoint.publish("http://localhost:8088/calculator", new Calculator());
}catch (Exception e){
System.out.println("Caught Exception: " + e.toString());
}
System.out.println("\nCalculator Service is OK!\n");
}
}

在 Endpoint.publish 的部份,原本以為 Port 的設定應該與 Tomcat 的預設值 8080 一樣,但是在啟動 Tomcat 的時候發現會跟 Tomcat 搶 8080 Port,所以我改成 8088。

加法的 Service:Calculator.java

import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;

public class Calculator{
@WebService(targetNamespace = "http://localhost/sample")
@SOAPBinding(style = SOAPBinding.Style.RPC)
public class Calculator {

@WebMethod
public int add(int a, int b) {
return a+b;
}
}

Deploy
程式編譯好後,在 Tomcat 的 webapps 目錄下建立一個 Service 的目錄,如: sample,其內在建立 WEB-INF 目錄,在此目錄裡建立 web.xml:

web.xml


web.xml


WebServiceStarter
WebServiceStarter
1




在 WEB-INF 裡面在建立 classes 的目錄,把編譯好的 Calculator.class 和 WebServiceStarter.class 複製到裡面,重新啟動 Tomcat。檢視 Tomcat 的 log :

catalina.out

Jun 29, 2007 5:16:16 PM org.apache.catalina.core.AprLifecycleListener init
INFO: The Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: /usr/lib/jvm/java-6-sun-1.6.0.00/jre/lib/i386/client:/usr/lib/jvm/java-6-sun-1.6.0.00/jre/lib/i386:/usr/lib/jvm/java-6-sun-1.6.0.00/jre/../lib/i386:/usr/java/packages/lib/i386:/lib:/usr/lib
Jun 29, 2007 5:16:16 PM org.apache.coyote.http11.Http11Protocol init
INFO: Initializing Coyote HTTP/1.1 on http-8080
Jun 29, 2007 5:16:16 PM org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 875 ms
Jun 29, 2007 5:16:16 PM org.apache.catalina.core.StandardService start
INFO: Starting service Catalina
Jun 29, 2007 5:16:16 PM org.apache.catalina.core.StandardEngine start
INFO: Starting Servlet Engine: Apache Tomcat/6.0.13

Starting Calculator Service ......


Calculator Service is OK!

Jun 29, 2007 5:16:18 PM org.apache.coyote.http11.Http11Protocol start
INFO: Starting Coyote HTTP/1.1 on http-8080
Jun 29, 2007 5:16:18 PM org.apache.jk.common.ChannelSocket init
INFO: JK: ajp13 listening on /0.0.0.0:8009
Jun 29, 2007 5:16:18 PM org.apache.jk.server.JkMain start
INFO: Jk running ID=0 time=0/43 config=null
Jun 29, 2007 5:16:18 PM org.apache.catalina.startup.Catalina start
INFO: Server startup in 2077 ms

這樣 Server 端就 OK 了!

Java Client
先產生需要的 class: wsimport -keep
http://localhost:8088/calculator?wsdl

CalculatorApp.java

class CalculatorApp {
public static void main(String args[]){
/**
* Instantiate the generated Service
*/
CalculatorService service = new CalculatorService();

/**
* Get the port using port getter method generated in CaculatorService
*/
Calculator calculatorProxy = service.getCalculatorPort();

/**
* Invoke the remote method
*/
int result = calculatorProxy.add(10, 20);
System.out.println("Sum of 10+20 = "+result);
}
}

編譯,執行,結果應該是:Sum of 10+20 = 30

Flex Client
用 Flex 做一個比較好用的 GUI:

測試網址:http://ir.tmu.edu.tw/calc/

有沒有很簡單呢,呵呵!

2008年10月17日 星期五

50 Excellent AJAX Tutorials

一篇文章講 50 Excellent AJAX Tutorials,這篇文章列出了 50 則關於 AJAX 的教學文章,可以幫助剛要上手 AJAX 的人學習之用,每篇文章之間談到的技術領域也很廣,有 PHP, ASP.NET, Java, JavaScript, jQuery, MooTools, ... 等等,與許多各種不同的 AJAX 應用,我覺得蠻不錯的,有興趣的人可以去看看,挑一些自己有興趣的主題看看別人的文章吧(順便練練英文)。

其中有幾則跟 ASP.NET 有關的我列出來:

  1. How to Call Server-Side Function from Client-Side Code Using PageMethods in ASP.NET AJAX

    這篇文章教你如何透過 JavaScript 直接呼叫 Server 端的程式!

  2. Use jQuery and ASP.NET AJAX to Build a Client-Side Repeater

    這也是個蠻不錯的開發技巧,徹底將 Client 端與 Server 端分離,頁面的顯示效率將大幅的提升,另一方面也減輕 Server 端程式的運算負擔。

  3. ASP.NET AJAX Calendar Extender

    這篇介紹 AJAX Control Toolkit 中 Calendar Extender 的 7 種開發技巧。

  4. JavaScript Error Publishing using ASP.NET AJAX

    這 篇文章更酷了,他介紹如何讓你在 Client 發生 JavaScript Error 時如何自動將完整的錯誤訊息送回 Server 端,並讓你可以從 Server 端進行錯誤的儲存以利後續分析與追蹤。這一點通常也是 AJAX 網站最常犯的問題,因為 JavaScript 出錯時通常開發人員都不曉得,都一定要使用者才能通知,若實做此機制將可以進一步掌握 Web 應用程式的品質。

除了這幾篇以外,其他的文章大多也都有完整且詳細的程式碼範例與相關說明,真是個不錯的學習管道。

相關連結

2008年10月16日 星期四

實現簡單的Web容器

一個類似Tomcat的容器,不過只是模擬Web容器的解析過程,只做了簡單的解析HTML。
首先用Java IDE建立一個普通的Java Project,要解析web少不了Request和Response對象,所以在工程(項目)裡建立兩個類:MyHttpServletRequest(對應HttpServletRequest)、MyHttpServletResponse(對應HttpServletResponse),如下:

//
MyHttpServletRequest.java
package com.kalman03.servlet;

import java.io.BufferedReader;
import java.io.IOException;

public class MyHttpServletRequest{
private BufferedReader br;
private String header;
public MyHttpServletRequest(BufferedReader br){
try{
this.br = br;
this.header = br.readLine();// GET /index.html HTTP/1.1
}catch(IOException ex){
ex.printStackTrace();
}
}

public String getURL(){
String [] temp
= header.split(" ");
return temp[1].substring(1);
}
}





//MyHttpServletResponse.java
package com.kalman03.servlet;

import java.io.PrintWriter;

public class MyHttpServletResponse{
private PrintWriter out;
public MyHttpServletResponse(PrintWriter out){
this.out = out;
out.println(
"HTTP/1.1 200 OK");
}

public PrintWriter getWriter(){
return out;
}
}


構造一個抽像類MyHttpServlet:
//MyHttpServlet.java
package com.kalman03.servlet;

public abstract class MyHttpServlet{
public abstract void doGet(MyHttpServletRequest request,MyHttpServletResponse response)throws Exception;
public abstract void doPost(MyHttpServletRequest request,MyHttpServletResponse response)throws Exception;
}


用MyServlet類實現上面MyHttpServlet抽像類:
//MyServlet.java
package com.kalman03.servlet.ext;

import java.io.BufferedReader;
import java.io.PrintWriter;
import java.io.File;
import java.io.FileReader;
import com.kalman03.servlet.MyHttpServlet;
import com.kalman03.servlet.MyHttpServletRequest;
import com.kalman03.servlet.MyHttpServletResponse;

//该类继承MyHttpServlet类,实现其中的doGet(),doPost()方法
public class MyServlet extends MyHttpServlet {
private PrintWriter out;
private String url;

public void doGet(MyHttpServletRequest request,
MyHttpServletResponse response)
throws Exception {
this.out = response.getWriter();
url
= request.getURL();
if (url.equals("")) {
url
= "index.html";
}
File file
= new File(url);
FileReader fr
= new FileReader(file);
BufferedReader brR
= new BufferedReader(fr);
String temp;
while ((temp = brR.readLine()) != null) {
out.println(temp);
}
out.close();
brR.close();
fr.close();
}

public void doPost(MyHttpServletRequest request,
MyHttpServletResponse response)
throws Exception {
this.doGet(request, response);
}
}



跑一個線程監聽類MyWebService:
//MyWebService.java
package com.kalman03.servlet;

import java.net.ServerSocket;
import java.net.Socket;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;

public class MyWebService {
public MyWebService(MyHttpServlet ms) {
try {
ServerSocket ss
= new ServerSocket(2008);
while (true) {
Socket s
= ss.accept();
new myRunnable(s, ms).start();
}
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}



//線程監聽
class myRunnable extends Thread {
private Socket s;
private MyHttpServlet ms;
public myRunnable(Socket s, MyHttpServlet ms) {
this.s = s;
this.ms = ms;
}

public void run() {
try {
BufferedReader br
= new BufferedReader(new InputStreamReader(s.
getInputStream()));
PrintWriter out
= new PrintWriter(s.getOutputStream(), true);
MyHttpServletRequest req
= new MyHttpServletRequest(br);
MyHttpServletResponse rep
= new MyHttpServletResponse(out);
ms.doGet(req, rep);
br.close();
out.close();
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}


至此大工基本告成,再來一個main方法(MainClass類)就OK了:
//MainClass.java
package com.kalman03.test;

import com.kalman03.servlet.MyWebService;
import com.kalman03.servlet.ext.MyServlet;

public class MainClass {
public static void main (String[] args) {
new MyWebService(new MyServlet());
}
}

運行,OK!一個web容器已經啟動,當你在剛建的工程(項目)目錄下丟一個HTML(比如welcome.html),在瀏覽器裡輸入http://127.0.0.1:2008/welcome.html,即可解析welcome.html。

補充一下,這裡設置的默認端口為2008,當沒有指定具體頁面時候,尋找的是index.html

2008年10月13日 星期一

How to sort objects in Java: Comparator

以下是實踐Java排序的一些心得。

可排序的物件(例如Bean)需實作java.lang.Comparable interface,這個interface僅包含了單一方法 - compareTo,compareTo定義了該物件與其他同類型物件該如何排序的規則

compareTo的規則是:透過回傳值int來表示排序的大小,回傳值為負數表示本身物件要排序的屬性,比被比較的物件的該屬性,在邏輯上的地位較小,若為正則相反。回傳值若為0則表示兩物件相等


某些物件本身已經實作了compareTo這個method,像是String、File、Date和Time等物件


若 要排序多個屬性,可建立一個物件實作java.util.Comparator介面,Comparator僅包含compare一個方法,參數型態是 Object。方法內定義了兩個相同物件該如何排序的規則。實作時要經過轉型(有可能造成ClassCastException)。回傳值型態一樣為 int,若回傳值為正數,則obj1的排序在obj2之後,若回傳值為負數,則obj1的排序在obj2之前,若回傳值為0,則兩者相等。規則同 compareTo


同類型物件才能被排序(也才有意義)


實際執行排序的方法包括Arrays.sort和Collnections.sort,兩者都是static method,將該物件陣列及實作Comparator介面的物件傳入後,即可排序(不用回傳值)

==
方法
1

public class FileObject implements java.lang.Comparable {

private String filename;

private Long filesize;

public FileObject() { }

public String getFilename() {

return this.filename;

}

public Long getFilesize() {

return this.filesize;

}

public void setFilename(String name) {

this.filename = name;

}

public void setFilesize(Long size) {

this.filesize = size;

}

public int compareTo(Object obj) throws ClassCastException {

if (!(obj instanceof Example1))

throws new ClassCastException("Error msg here.");

// 先做轉型

FileObject fileobj = (FileObject) obj;

// 使用String內建的規則

return this.filename.compareTo(fileobj.getFilename());

}

}

用法

FileObject[] fileObj = new FileObject[10];

Arrays.sort(fileObj);

方法2 – 實作java.util.Comparator的方式

public class FilesizeComparator implements Comparator {

public int compare(Object obj1, Object obj2) {

File file1 = (File) obj1;

File file2 = (File) obj2;

// 這裡放置要比較的邏輯,不過回傳值要是int,要注意int溢位的問題

if (file1.getFilesize() > file2.getFilesize())

return 1;

if (file1.getFilesize() <>

return -1;

if (file1.getFilesize() = file2.getFilesize())

return 0;

}

}

用法

FileObjectp[] fileObj = new FileObject[10];

Arrays.sort(fileObj, new FilesizeComparator());

2008年10月11日 星期六

Java文件路徑問題

1.如何獲得當前文件路徑

常用:

字符串類型:System.getProperty("user.dir");

綜合:

public class Test {
public static void main(String[] args) throws Exception {
System.out.println(
Thread.currentThread().getContextClassLoader().getResource(""));

System.out.println(Test.class.getClassLoader().getResource(""));
System.out.println(ClassLoader.getSystemResource(""));
System.out.println(Test.class.getResource(""));
System.out.println(Test.class.getResource("/"));
System.out.println(new File("").getAbsolutePath());
System.out.println(System.getProperty("user.dir"));
}
}

2.Web服務中

(1).Weblogic

WebApplication的系統文件根目錄是你的weblogic安裝所在根目錄。
例如:如果你的weblogic安裝在c:\bea\weblogic700.....
那麼,你的文件根路徑就是c:\.
所以,有兩種方式能夠讓你訪問你的服務器端的文件:
a.使用絕對路徑:
比如將你的參數文件放在c:\yourconfig\yourconf.properties,
直接使用new FileInputStream("yourconfig/yourconf.properties");
b.使用相對路徑:
相對路徑的根目錄就是你的webapplication的根路徑,即WEB-INF的上一級目錄,將你的參數文件放在yourwebapp\yourconfig\yourconf.properties,
這樣使用:
new FileInputStream("./yourconfig/yourconf.properties");
這兩種方式均可,自己選擇。

(2).Tomcat

在類中輸出System.getProperty("user.dir");顯示的是%Tomcat_Home%/bin

(3).Resin

不是你的JSP放的相對路徑,是JSP引擎執行這個JSP編譯成SERVLET
的路徑為根.比如用新建文件法測試File f = new File("a.htm");
這個a.htm在resin的安裝目錄下

(4).如何讀相對路徑哪?

在Java文件中getResource或getResourceAsStream均可

例:getClass().getResourceAsStream(filePath);//filePath可以是"/filename",這裡的/代表web發布根路徑下WEB-INF/classes

(5).獲得文件真實路徑

string file_real_path=request.getRealPath("mypath/filename");

通常使用request.getRealPath("/");

3.文件操作的類

import java.io.*;
import java.net.*;
import java.util.*;
//import javax.swing.filechooser.*;
//import org.jr.swing.filter.*;

/**
*此類中封裝一些常用的文件操作。
*所有方法都是靜態方法,不需要生成此類的實例,
*為避免生成此類的實例,構造方法被申明為private類型的。
* @since 0.1
*/

public class FileUtil {
/**
*私有構造方法,防止類的實例化,因為工具類不需要實例化。
*/
private FileUtil() {

}

/**
*修改文件的最後訪問時間。
*如果文件不存在則創建該文件。
* 目前這個方法的行為方式還不穩定,主要是方法有些信息輸出,這些信息輸出是否保留還在考

慮中。

* @param file需要修改最後訪問時間的文件。
* @since 0.1
*/
public static void touch(File file) {
long currentTime = System.currentTimeMillis();
if (!file.exists()) {
System.err.println("file not found:" + file.getName());
System.err.println("Create a new file:" + file.getName());
try {
if (file.createNewFile()) {
// System.out.println("Succeeded!");
}
else {
// System.err.println("Create file failed!");
}
}
catch (IOException e) {
// System.err.println("Create file failed!");
e.printStackTrace();
}
}
boolean result = file.setLastModified(currentTime);
if (!result) {
// System.err.println("touch failed: " + file.getName());
}
}

/**
*修改文件的最後訪問時間。
*如果文件不存在則創建該文件。
* 目前這個方法的行為方式還不穩定,主要是方法有些信息輸出,這些信息輸出是否保留還在考

慮中。

* @param fileName需要修改最後訪問時間的文件的文件名。
* @since 0.1
*/
public static void touch(String fileName) {
File file = new File(fileName);
touch(file);
}

/**
*修改文件的最後訪問時間。
*如果文件不存在則創建該文件。
* 目前這個方法的行為方式還不穩定,主要是方法有些信息輸出,這些信息輸出是否保留還在考

慮中。

* @param files需要修改最後訪問時間的文件數組。
* @since 0.1
*/
public static void touch(File[] files) {
for (int i = 0; i <>目前這個方法的行為方式還不穩定,主要是方法有些信息輸出,這些信息輸出是否保留還在考

慮中。
* @param fileNames需要修改最後訪問時間的文件名數組。
* @since 0.1
*/
public static void touch(String[] fileNames) {
File[] files = new File[fileNames.length];
for (int i = 0; i < files =" new">注意:可能會在返回false的時候創建部分父目錄。
* @param file要創建的目錄
* @return完全創建成功時返回true,否則返回false。
* @since 0.1
*/
public static boolean makeDirectory(File file) {
File parent = file.getParentFile();
if (parent != null) {
return parent.mkdirs();
}
return false;
}

/**
*創建指定的目錄。
*如果指定的目錄的父目錄不存在則創建其目錄書上所有需要的父目錄。
* 注意:可能會在返回false的時候創建部分父目錄。
* @param fileName要創建的目錄的目錄名
* @return完全創建成功時返回true,否則返回false。
* @since 0.1
*/
public static boolean makeDirectory(String fileName) {
File file = new File(fileName);
return makeDirectory(file);
}

/**
*清空指定目錄中的文件。
*這個方法將盡可能刪除所有的文件,但是只要有一個文件沒有被刪除都會返回false。
*另外這個方法不會迭代刪除,即不會刪除子目錄及其內容。
* @param directory要清空的目錄
* @return目錄下的所有文件都被成功刪除時返回true,否則返回false.
* @since 0.1
*/
public static boolean emptyDirectory(File directory) {
boolean result = false;
File[] entries = directory.listFiles();
for (int i = 0; i < result =" false;" dir =" new" dir ="=" entries =" dir.listFiles();" sz =" entries.length;" i =" 0;" fileurl = "file:/" url =" new" file =" new" file =" new" file =" new" point =" fileName.lastIndexOf('.');" length =" fileName.length();" point ="=" point ="=" point =" getPathLsatIndex(fileName);" length =" fileName.length();" point ="=" point ="=" secondpoint =" getPathLsatIndex(fileName," secondpoint ="=" length ="=" point =" getPathLsatIndex(fileName);" length =" fileName.length();" point ="=" point ="=" secondpoint =" getPathLsatIndex(fileName," secondpoint ="=" point =" fileName.indexOf('/');" point ="=" point =" fileName.indexOf('\\');" point =" fileName.indexOf('/'," point ="=" point =" fileName.indexOf('\\'," point =" fileName.lastIndexOf('/');" point ="=" point =" fileName.lastIndexOf('\\');" point =" fileName.lastIndexOf('/'," point ="=" point =" fileName.lastIndexOf('\\'," index =" filename.lastIndexOf(" index =" fileName.indexOf(pathName);">store(output,string)。如果只是單純的讀,根本不存在煩惱的問題。 web層可以通過Thread.currentThread().getContextClassLoader().
getResourceAsStream("xx.properties")獲取;Application可以通過new FileInputStream("xx.properties");直接在classes一級獲取。關鍵是有時我們需要通過web修改配置文件,我們不能將路徑寫死了。經過測試覺得有以下心得:

1.servlet中讀寫。如果運用Struts或者Servlet可以直接在初始化參數中配置,調用時根據servlet的getRealPath("/")獲取真實路徑,再根據String file = this.servlet.getInitParameter("abc");獲取相對的WEB -INF的相對路徑。
例:
InputStream input = Thread.currentThread().getContextClassLoader().
getResourceAsStream("abc.properties");
Properties prop = new Properties();
prop.load(input);
input.close();
OutputStream out = new FileOutputStream(path);
prop.setProperty("abc", “test");
prop.store(out, “–test–");
out.close();

2.直接在jsp中操作,通過jsp內置對象獲取可操作的絕對地址。
例:
// jsp頁面
String path = pageContext.getServletContext().getRealPath("/");
String realPath = path+"/WEB-INF/classes/abc.properties";

//java程序
InputStream in = getClass().getClassLoader().getResourceAsStream("abc.properties"); // abc.properties放在webroot/WEB-INF/classes/目錄下
prop.load(in);
in.close();

OutputStream out = new FileOutputStream(path); // path為通過頁面傳入的路徑
prop.setProperty("abc", “abcccccc");
prop.store(out, “–test–");
out.close();

3.只通過Java程序操作資源文件
InputStream in = new FileInputStream("abc.properties"); //放在classes同級

OutputStream out = new FileOutputStream("abc.properties");關於Java文件路徑問題

2008年10月10日 星期五

Java dnd 拖拽實現分析紀要

既有的Swing組件都內置了拖拽的支持,是怎麼樣支持呢?

首先,在Windows 環境的jvm進程中,一個gui程序將啟動兩個線程:AWT-WINDOWS(AWT)和Event-Dispatch-Thread(EDT)。 AWT-WINDOWS線程不斷從windows操作系統中獲取GUI事件並進行初步的底層處理;其中一些事件會被包裝成高級的AWTEvent置入一個 地方,而EDT線程的處理過程就包括不斷在的適當時機從這個地方獲取這些AWTEvent並進行高級處理。

然後,拖拽的效果就是由以下幾個GUI操作事件及相應程序處理完成的。

1.拖拽開始,拖拽結束。

2.拖拽進入(源組件/目的組件),拖拽經過(源組件/目的組件),拖拽離開(源組件/目的組件),拖拽中鼠標的移動。

3.拖拽操作式樣變換。即隨鍵盤操作,可以指示3種操作式樣:剪切式,複製式,鏈接式。

這 些事件發生後,AWT線程即會獲取到事件通知並處理,底層處理後會包裝交給EDT繼續處理。而處理的程序邏輯一般設計為,對於鼠標圖標,會被設計為隨拖拽 的起始及移動的整個過程中不同事件的發生而發生變化(比如在dragover事件中可能根據當時情況將圖標變為一個叉表示不能拖入);同時,對於拖拽源組 件和目的組件,隨不同的事件通知也會被程序設計為產生不同的變化響應(比如,拖拽結束的事件處理中可能指令目的組件複製源組件的文字內容),從而最終實現 了拖拽的效果。

最後,看一些JRE7中拖拽的實現類。

Swing的JComponent組件將一些功能委託給其成員ComponentUI代理。比如JTextField在構造方法中即會通過 UIManager獲得合適的TextUI實例(UIManager將根據當前look and feel設置獲取)(此後JTextField的paint方法會調用該UI實例的update方法從而完成組件繪畫),並調用該UI實例的 installUI方法(在installUI中則包括給JTextField對象安裝一些監聽器,安裝TransferHandler這個支持拖拽的關 鍵成員,它包含DragHandler,DropHandler兩個內部類,而這兩個內部類是實現拖拽效果的核心邏輯,安裝droptarget)。

Swing將ui類劃分在幾個包中,其中javax.swing.plaf中存放一些接口;javax.swing.plaf.basic中存放對接口的 基本實現,即多種LAF的通用實現;javax.swing.plaf .metal中存放java默認LAF實現;另外還有javax.swing.plaf.multi用來實現多個LAF的綜合效果實 現;javax.swing.plaf.synth用來實現可通過配置xml文件更換顏色等皮膚的實現。

對於拖拽方面,BasicUI在installUI中一般會對組件安裝mouseListener:

editor.addMouseListener(dragListener);

editor.addMouseMotionListener(dragListener);

該 dragListener將監聽發生在組件上的鼠標事件,當發現可能是新啟動的拖拽鼠標動作並且組件dragEnable時,則立刻通知 DragRecognitionSupport單例進行組件拖拽識別。該support單例將辨別鼠標動作本身,確認是組件拖拽開始,再通知組件的 TransferHandler成員對象進行拖拽初始化,即,經其辨別headless環境和action支持後將初始化建立並委託調用 TransferHandler.SwingDragGestureRecognizer的全局單例(成員包括全局單例dragsource及 draghandler對象),該實例註冊拖拽識別listener及設置sourceAction,最終將通知 TransferHandler.DragHandler對象的dragGestureRecognized。在該方法中,將創建 transferable及初始化autoscroll;並通過dragSource全局單例完成創建DragContext,並獲取及初始化 DragContextPeer全局單例(給該單例註冊上該component作為拖拽trigger,以供native code可以在處理底層事件時,可以通過x,y判定是否contains,從而縮小事件處理範圍),並通知DragContextPeer單例拖拽開始, 而DragContextPeer單例則會調用底層native code進行進一步的處理。

此後AWT線程將通過windows- api獲取到系統底層的各種拖拽事件並進行底層處理,處理過程將會隨時引用DragContextPeer單例(處理邏輯包括根據trigger過濾), 並最終通知該單例合適的事件通知。 Peer會將這些事件封裝成合適的DragEvent並提交給EDT處理,提交後將促使AWT線程模擬等待EDT處理完該事件。 EDT的處理邏輯是將事件交給拖拽開始時給組件創建的DragContext處理,而該context對象的處理則會調用其dragHandler成員的 對應方法進行事件處理,以及給dragSource單例相應的監聽通知,最後updateCurrentCursor等,最後EDT返回到 AWT,peer處理返回給native code繼續處理。

當拖拽開始後,鼠標圖標在一個swing組件上游晃時,首先 windows會對其頂層容器(如jwindows)視作拖拽源,經native code過濾後,如果該swing組件是此次拖拽trigger(源),則DragContextPeer能得到dragover的通知,進而進行後續處 理;同時從另一個方面,這個也被視作一個拖拽目的,即AWT線程還會對每次拖拽啟動建立一個DropContextPeer (為將來支持並發),並調用該peer的handle事件方法,該方法會將此底層事件包裝後提交給EDT並促使AWT等待;EDT處理該事件時將 track到該事件發生時的頂層組件,以及事件發生的坐標位置,由頂層容器組件的LightweightDispatcher進行初步處理。這個處理將由 該事件產生新事件,其event source將從container(比如JFRAME)變為精確的jcomponent(比如JTextField),同時對於 eventId=dragover的事件,有可能根據具體情況再增加dragExit,dragEnter兩個事件(比如對jframe窗體是 dragover,但鼠標實際是從一個jtextfield到另外一個jtextfield),這些精確的事件的處理會再次回到 DropContextPeer中得到對應的process。這時的process會處理本身的一些成員數據(當前context,當前 droptarget等),再將事件委託給source jcomponent的droptarget進行處理(如果已安裝),此時的處理將是傳遞給對應組件的drophandler進行處理,同時會通知 droptarget的註冊監聽,最後initializeAutoscrolling等。 drophandler在處理過程中對event可以進行accept或reject,這兩個動作會再去調用dropcontext進行處理,並最終轉到 peer處理成員數據。最後edt返回到AWT,peer handle處理結束返回native code當前drop action值,native code繼續處理。

通過以上的分析,如果需要定制swing組件的拖拽邏輯,一個比較基礎的入口是 transferhandler;因為所有事件的處理都將經過其兩個內部類邏輯處理(DragHandler和DropHandler);而swing包 中的TransferHandler的具體實現,是這兩個內部類的方法都把一些控制劃分給了componet的一些屬性設置或 TransferHandler本身的回調方法,所以只需對組件設置合適的屬性,或繼承並override TransferHandler合適的方法並給此swing組件重新setTransferHandler,即可以定制新的邏輯。如果需要更深層次的定 制,則需要細緻考慮上述分析,選擇合適的定制點。