很久很久以前

            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            34 隨筆 :: 4 文章 :: 17 評(píng)論 :: 0 Trackbacks

          2006年2月14日 #

          Winsock 10053錯(cuò)誤分析

           WSAGetLastError可能會(huì)返回10053錯(cuò)誤,查msdn的解釋是:

          WSAECONNABORTED 10053

          Software caused connection abort.

          An established connection was aborted by the software in your host computer, possibly due to a data transmission time-out or protocol error.

          神馬?軟件原因造成的連接中斷,這是什么意思,不跟沒(méi)說(shuō)一樣的么?
          google一下唄

          Berkeley description:

          A connection abort was caused internal to your host machine. The software caused

          a connection abort because there is no space on the socket’s queue and the socket

           cannot receive further connections.

                 

          WinSock description:

          Partly the same as Berkeley. The error can occur when the local network system aborts

          a connection. This would occur if WinSock aborts an established connection after data

          retransmission fails  (receiver never acknowledges data sent on a datastream socket).

                 

          TCP/IP scenario:

          A connection will timeout if the local system doesn’t receive an (ACK)nowledgement for

          data sent.  It would also timeout if a (FIN)ish TCP packet is not ACK’d

          (and even if the FIN is ACK’d, it will eventually timeout if a FIN is not returned).

           

          伯克利說(shuō)這種連接中斷是因?yàn)樗拗鳈C(jī)器的內(nèi)部原因,因?yàn)檐浖?dǎo)致的連接中斷,可能是因?yàn)閟ocket的隊(duì)列滿并且這個(gè)socket不能接收更多的連接了。
          這還不如不說(shuō),越說(shuō)越糊涂了。
          winsocket的描述,似乎還靠譜一些,這種錯(cuò)誤一般發(fā)生在一個(gè)建立的連接被重發(fā)失敗的情況下產(chǎn)生,接收方?jīng)]有響應(yīng)數(shù)據(jù)發(fā)回來(lái)。但還是比較模糊。
          再看看tcp ip標(biāo)準(zhǔn)文檔的說(shuō)法,如果本地系統(tǒng)沒(méi)有收到發(fā)送數(shù)據(jù)的響應(yīng)(ack)那么這連接就會(huì)超時(shí)。如果tcp的fin包沒(méi)有被ack(或者fin包被ack了但fin沒(méi)有返回)那么也會(huì)超時(shí)。但是,但是,超時(shí)跟這個(gè)10053有神馬關(guān)系?
          再看后續(xù)的解釋:
          從參考1中找到如下的描述:

          The Scenario: 
          An HTTP POST is to be sent to an HTTP server.
          The server begins reading the POST and notices that the HTTP request header is invalid.
          It immediately sends an HTTP response (with an error status, perhaps status=400) and closes the connection without trying to continue reading the remainder of the HTTP request that is forthcoming.

          Meanwhile, the client is still happily writing the remainder of the HTTP request to the socket. (Remember a TCP/IP socket connection needs to be closed from both sides. In this case, the server has closed its side, but the client is still pumping data into the half-open connection.)
          The client finishes writing the HTTP POST to the socket — meaning that data has been buffered to Winsock. The client application then tries to read the HTTP response, but it cannot because the outgoing retransmission (of the buffered data by WinSock) failed and the socket connection was shutdown on the client side (by Winsock). Even though the HTTP server sent the response, it is lost and cannot be retrieved. The error your application will receive when
          trying to read the HTTP response on the socket is WSAECONNABORTED. The word "software" in any of the above error messages refers to "WinSock".

          Go back and re-read the original error explanations. Hopefully, after that explanation, you’ll say "Aha! I understand what they’re talking about!".

           

          啊哈,又有http了,大概意思就是http server收到請(qǐng)求了,但發(fā)現(xiàn)有問(wèn)題,那么回一個(gè)http錯(cuò)誤碼,然后就關(guān)閉了socket,但與此同時(shí),client端還在很開(kāi)心地向socket寫(xiě)數(shù)據(jù),注意哦,tcp是全雙工的。client寫(xiě)完畢后,實(shí)際上數(shù)據(jù)只是放到了發(fā)送方的緩沖區(qū)中,不一定已經(jīng)發(fā)出去了,如果寫(xiě)得不好的程序,這個(gè)時(shí)候就開(kāi)始從socket讀數(shù)據(jù)了,這時(shí)候就會(huì)產(chǎn)生一個(gè)WSACONNECTABORTED錯(cuò)誤,windows上對(duì)應(yīng)的就是10053錯(cuò)誤。

          但這個(gè)解釋實(shí)際上是不能讓人滿意的,只是舉出了一種場(chǎng)景,但為什么會(huì)產(chǎn)生還沒(méi)有解釋。后面又搜到了個(gè)參考2,首先解釋10053錯(cuò)誤是收到fin后client會(huì)放棄發(fā)送緩沖區(qū)中的數(shù)據(jù),同時(shí)上報(bào)錯(cuò)誤。雖然說(shuō)法還有點(diǎn)一頭霧水。

          不過(guò)這兩個(gè)參考給我們一個(gè)思路,重現(xiàn)這個(gè)問(wèn)題。

          于是簡(jiǎn)單寫(xiě)個(gè)測(cè)試用的c-s程序,大概流程如下

           

           

          圖1 CS程序簡(jiǎn)化流程圖

          這個(gè)簡(jiǎn)單程序演示如何出現(xiàn)10053錯(cuò)誤(以及10054錯(cuò)誤)。

          如果server在收到client發(fā)送的數(shù)據(jù)后立即關(guān)閉socket,那么client再讀時(shí),會(huì)收到10053錯(cuò)誤;如果server收到發(fā)送數(shù)據(jù)后,立即crash,那么隨后client再讀取時(shí)會(huì)收到10054錯(cuò)誤。

          ok,能夠重現(xiàn)場(chǎng)景了,那么我們來(lái)分析一下更細(xì)節(jié)的方面,網(wǎng)絡(luò)問(wèn)題自然是抓包,本問(wèn)題處理抓包還要看一下tcp的狀態(tài)以便輔助分析,我們?cè)赾lient端每次操作之前都打印當(dāng)前的tcp狀態(tài)。

          下面是client端發(fā)送記錄和對(duì)應(yīng)的netstat情況

          圖2 10053錯(cuò)誤client端tcp狀態(tài)流轉(zhuǎn)

          client在發(fā)送之前tcp狀態(tài)是established,在發(fā)送之后,server會(huì)立即關(guān)閉,tcp狀態(tài)也變?yōu)閏lose_wait,但這只是單方向的關(guān)閉,client可以繼續(xù)發(fā)數(shù)據(jù),但client發(fā)送后,server立即退出了,導(dǎo)致后續(xù)recv會(huì)失敗并且返回10053。對(duì)應(yīng)抓包情況如下:



          圖3 10053錯(cuò)誤client端tcp抓包

          整個(gè)通信過(guò)程如下:
          1-3.三次握手建立連接
          4.客戶端(10.10.86.93)向服務(wù)器端(10.10.86.98)發(fā)送數(shù)據(jù),1字節(jié)
          5.server 中止 發(fā)送fin(同時(shí)ack之前那個(gè)push)
          6.client ack 那個(gè)fin
          7.client再發(fā)送兩個(gè)字節(jié)
          8.server此時(shí)已經(jīng)關(guān)閉socket,屬于非正常情況,回復(fù)復(fù)位命令

          整個(gè)過(guò)程可以重現(xiàn)10053情況,tcp發(fā)送分組數(shù)據(jù)的情況也一目了然,事情到此就可以了么?顯然不是,你也看到了后面還有很多文字,不知此時(shí)你心中的問(wèn)題是否跟我一樣,先說(shuō)我自己的吧,通過(guò)抓包發(fā)現(xiàn)這里的異常關(guān)閉有個(gè)reset,但reset一般是10054(Connection reset by peer)的錯(cuò)誤,那么10053與10054的區(qū)別在哪里。要搞清楚問(wèn)題也不難,重現(xiàn)場(chǎng)景抓包分析。
          以下是修改上面的cs程序,在client發(fā)送的1字節(jié)包后,立即crash,這導(dǎo)致的問(wèn)題是操作系統(tǒng)會(huì)立即回收所有資源,包括socket資源。




          圖4 10054錯(cuò)誤client端tcp狀態(tài)流轉(zhuǎn)

          可以看到在crash之前這個(gè)tcp都是established狀態(tài)。crash之后,client端接收數(shù)據(jù)時(shí)會(huì)收到10054錯(cuò)誤,場(chǎng)景重現(xiàn)了,我們?cè)倏匆幌伦グ闆r



          圖5 10054錯(cuò)誤client端tcp抓包

          這個(gè)抓包情況跟10053很像,1-7也同10053,在8時(shí),client收到server發(fā)過(guò)來(lái)的reset,表示當(dāng)前連接被強(qiáng)制復(fù)位了。
          對(duì)比10053和10054可以發(fā)現(xiàn),如果srv返回fin標(biāo)志后再reset那么對(duì)應(yīng)的錯(cuò)誤就是10053,如果直接reset就是10054錯(cuò)誤?;剡^(guò)頭來(lái)在看參考2中的說(shuō)法也就有點(diǎn)感覺(jué)了。

          總結(jié)一下:
          1.遇到不了解的問(wèn)題,google是非常好的方法
          2.對(duì)于一般問(wèn)題,重現(xiàn)之很重要,可以反復(fù)發(fā)現(xiàn)問(wèn)題并驗(yàn)證問(wèn)題。自己寫(xiě)程序或者搭環(huán)境盡量重現(xiàn)。
          3.網(wǎng)絡(luò)問(wèn)題抓包是利器,包括各種工具的使用netstat wireshark ping traceroute等。
          4.多重問(wèn)題對(duì)比其中的差異,這里對(duì)比10053錯(cuò)誤和10054錯(cuò)誤。
          5.理論基礎(chǔ)要搭好,本次問(wèn)題主要是tcp的異常斷開(kāi)問(wèn)題,熟悉tcp斷開(kāi)的半關(guān)閉和復(fù)位邏輯,不過(guò)理論還是理論,同樣是復(fù)位在不同場(chǎng)景下的錯(cuò)誤碼不同。并且實(shí)現(xiàn)上也跟具體的操作系統(tǒng)相關(guān)。
          6.實(shí)際工作中,
          10053錯(cuò)誤時(shí),用戶主要是處于透明代理情況,那么這一般是又有用戶所在的代理服務(wù)器異常關(guān)閉導(dǎo)致的,可能跟我們的離線文件私有協(xié)議被用戶所在的代理服務(wù)器拒絕掉導(dǎo)致的。

          7.回過(guò)頭來(lái)在看一開(kāi)始的解釋,所謂軟件原因造成的連接終端,就是本例子中,server端在shoutdown本方向傳輸時(shí),立即關(guān)閉了socket,導(dǎo)致本應(yīng)該等待對(duì)方發(fā)送fin來(lái)完全結(jié)束的正常邏輯被打破,編程單方向強(qiáng)制中止本次tcp,導(dǎo)致client端之后向上報(bào)錯(cuò),就是所謂的10053錯(cuò)誤了,這里的軟件就是server端的那個(gè)程序。(不過(guò)也有種說(shuō)法是,客戶端發(fā)送錯(cuò)誤數(shù)據(jù),導(dǎo)致server端保護(hù)機(jī)制而強(qiáng)制關(guān)閉)


          參考:

          1. http://www.chilkatsoft.com/p/p_299.asp   
          2. http://bbs.csdn.net/topics/360024280#post-361829232
          3. 《TCP/IP詳解(卷一)》18章 TCP連接的建立和中止

           

           

          posted @ 2013-11-28 11:22 Long Long Ago 閱讀(29206) | 評(píng)論 (1)編輯 收藏

          最近改造文件傳輸,參考libcurl,考慮到他支持那么多協(xié)議,但我只關(guān)心http的,所以考慮是否可以只生成http支持的版本,查了一下,果然可以。
          下載,如果不需要最新的,那么只要下載個(gè)zip包就好了。
          通過(guò)download wizard可以指引你下載不同的版本:http://curl.haxx.se/dlwiz/
          選擇
          source code - 平臺(tái)無(wú)關(guān)- 找到最新版本下載,解壓縮
          編譯比較簡(jiǎn)單有build指令
          不過(guò)我從vs目錄下找到一個(gè)2005版本的vcproj文件,用這個(gè)也可以編譯,不過(guò)要設(shè)置一下include目錄為../../../include
           上面是廢話了,關(guān)鍵的怎么值生成對(duì)http的支持呢
          只要在編譯指令中增加定義HTTP_ONLY宏就可以了,就這么簡(jiǎn)單。
          詳細(xì)說(shuō)明在這里http://curl.haxx.se/docs/install.html
          posted @ 2013-11-21 20:40 Long Long Ago 閱讀(705) | 評(píng)論 (0)編輯 收藏

          路由器軟件部分的幾個(gè)概念:CFE、固件(Firmware)、NVRAM
          CFE的作用跟PC的BIOS一樣是負(fù)責(zé)引導(dǎo)操作系統(tǒng)的;固件就是路由器的操作系統(tǒng),就像PC上的Windows一樣;NVRAM則用于存儲(chǔ)路由器的設(shè)置,相當(dāng)于PC的CMOS。
          當(dāng)路由器插上電后自動(dòng)進(jìn)入CFE,CFE進(jìn)行類(lèi)似PC的BIOS那樣進(jìn)行自檢,自檢通過(guò)后就引導(dǎo)路由器的固件了(相當(dāng)于的PC的Windows了),正常情況下最多一分鐘路由器的固件就會(huì)引導(dǎo)完畢,并且Power燈是常亮的。如果Power燈一閃一閃,那一般是CFE沒(méi)有引導(dǎo)成功路由器的固件(固件不存在、不正確、已損壞等等)。
          那么我們平常刷固件會(huì)把CFE也刷了嗎?呵呵,不會(huì)的,就像你平時(shí)裝Windows一樣,不管你是裝XP也好,Vista也好,Win7也好,都不會(huì)對(duì)你的BIOS進(jìn)行更新。那我想刷CFE該用什么方法?一般用戶用路由器原廠的CFE即可,如果要玩的深入一些想刷CFE,那么可以通過(guò)JTAG或者telnet方式來(lái)刷(比較危險(xiǎn),而且受固件限制,有些固件不支持)。
          主要是對(duì)硬件環(huán)境進(jìn)行初始化,image的更新,加載kernel等
          posted @ 2013-11-13 20:34 Long Long Ago 閱讀(256) | 評(píng)論 (0)編輯 收藏

          好久沒(méi)有更新這個(gè)blog了,java也放下了許久?,F(xiàn)在開(kāi)始重新更新本blog
          posted @ 2010-10-30 13:44 Long Long Ago 閱讀(241) | 評(píng)論 (0)編輯 收藏

          本文主要介紹了JXTA中的各種概念。
          1.Peer。一個(gè)peer就是實(shí)現(xiàn)了一個(gè)或多個(gè)JXTA協(xié)議的網(wǎng)絡(luò)設(shè)備。比如傳感器,電話, PDA,PC,服務(wù)器,巨型機(jī)等等。每一個(gè)peer與其他peer都是獨(dú)立操作并且是異步的。有peer ID來(lái)唯一標(biāo)識(shí)一個(gè)peer。peer使用JXTA協(xié)議公開(kāi)一個(gè)或多個(gè)網(wǎng)絡(luò)接口(network interface),每一個(gè)公開(kāi)的接口都被廣告為一個(gè)peer端點(diǎn)(peer endpoint),這個(gè)peer端點(diǎn)唯一標(biāo)識(shí)了一個(gè)網(wǎng)絡(luò)接口。peer之間不需要有直接的點(diǎn)對(duì)點(diǎn)的網(wǎng)絡(luò)連接??梢允褂弥虚g的peer作為peer的消息路由,將由于硬件網(wǎng)絡(luò)或者網(wǎng)絡(luò)配置(NATs,防火墻或者代理)而造成的兩個(gè)通信peer進(jìn)行互聯(lián)。peer通常被設(shè)計(jì)成網(wǎng)絡(luò)中自然地互相發(fā)現(xiàn),從而構(gòu)成暫時(shí)的或持久的關(guān)系成為peer組(peer gorup)。
          2.Peer Group.一個(gè)peer組是一個(gè)peer的集合,這些peer都有一組相同的服務(wù)。peer自組織的加入到peer組中,并通過(guò)一個(gè)唯一的peer組id來(lái)區(qū)別這些peer組。每一個(gè)peer組都可以建立一個(gè)屬于自己的memebership policy,從任何人可以加入到最嚴(yán)格的安全驗(yàn)證以及受保護(hù)方式(需要完全的認(rèn)證書(shū)來(lái)加入)。一個(gè)peer可以同時(shí)屬于多于一個(gè)peer組。默認(rèn)地,第一個(gè)peer組被實(shí)例的組是Net Peer Group。所有的peer都屬于Net Peer Group。peer可以選擇加入其他的peer group。JXTA協(xié)議描述了peer如何公開(kāi),發(fā)現(xiàn),加入以及監(jiān)控peer組。
               如下幾點(diǎn)說(shuō)明了創(chuàng)建peer組的目的。
          1. 建立安全的環(huán)境。peer組可以創(chuàng)建一個(gè)本地控制域,在這個(gè)域中使用一個(gè)特定的安全策略。這個(gè)安全策略可以簡(jiǎn)單的只是一個(gè)明文的帳號(hào) /口令交換,也可以像PKI一樣成熟。peer組界定認(rèn)證的成員訪問(wèn)和公開(kāi)受保護(hù)的內(nèi)容(content)。peer組在建立了一個(gè)邏輯上的區(qū)域,從而對(duì)訪問(wèn)peer組的資源進(jìn)行界定。
          2. 創(chuàng)建一個(gè)范圍環(huán)境。peer組裕興建立一個(gè)本地的專用域。比如,peer可以組織起來(lái)實(shí)現(xiàn)一個(gè)文檔共享網(wǎng)絡(luò)或者一個(gè)CPU共享網(wǎng)絡(luò)。 peer組提供細(xì)分網(wǎng)絡(luò)成抽象的區(qū)域來(lái)提供內(nèi)在范圍機(jī)制(implicit scoping mechanism)。比如,當(dāng)搜索一個(gè)組內(nèi)容的時(shí),peer組可以界定定義一個(gè)搜索范圍。
          3. 創(chuàng)建一個(gè)監(jiān)視環(huán)境。peer組允許一個(gè)peer為了任何目的去監(jiān)視一組peer(比如,心跳,traffic introspection或者accountability)。peer組也可以構(gòu)建一個(gè)父子層次結(jié)構(gòu),其中任何一個(gè)組都有一個(gè)唯一的父親。查詢請(qǐng)求能偶在這個(gè)組中傳播。對(duì)于這個(gè)組中的廣告也可以在其父組中公開(kāi),當(dāng)然也包裹這個(gè)組本身。
          peer組提供了一組服務(wù)成為peer組服務(wù)。在JXTA中敵營(yíng)了一個(gè)核心peer組服務(wù)集合。兩個(gè)peer如果要通過(guò)一個(gè)服務(wù)進(jìn)行交互,他們配需位于同一個(gè)peer中。
              核心的組服務(wù)有如下:
          1. 發(fā)現(xiàn)服務(wù)(Discovery Service)。本服務(wù)被組中的peer用來(lái)查詢per組資源,比如peer,peer組,通道和服務(wù)等。
          2. 成員關(guān)系服務(wù)(Membership Service)。本服務(wù)被當(dāng)前成員用來(lái)拒絕或接受一個(gè)新的組成員應(yīng)用。一個(gè)peer想要加入到一個(gè)group前,首先要確定一個(gè)當(dāng)前的成員,并請(qǐng)求加入。當(dāng)前成員的集合可以拒絕或者接受某個(gè)想加入的應(yīng)用(application)。本服務(wù)可能會(huì)發(fā)起一個(gè)所有peer或者指定組代表的一次投票來(lái)決定是否接受或者聚居新的成員應(yīng)用。
          3. 訪問(wèn)服務(wù)(Access Service)。使用訪問(wèn)服務(wù)可以用來(lái)驗(yàn)證一個(gè)peer對(duì)另一個(gè)peer的請(qǐng)求(request)。如果訪問(wèn)被允許,那么接受請(qǐng)求的peer會(huì)提供給請(qǐng)求peer關(guān)于該請(qǐng)求所要知道的信息的信任和相關(guān)信息。(注意,在peer組中,不是所有的行為(action)都需要通過(guò)訪問(wèn)服務(wù)的檢查,只有那些在某些peer中被限制的行為在需要調(diào)用時(shí),才被檢查。)
          4. 管道服務(wù)(Pipe Service)。本服務(wù)用于在peer組成員間的鏈接管道的建立和管理。
          5. Resolver服務(wù)。本服務(wù)用來(lái)發(fā)送一般的查詢請(qǐng)求到其他的peer。peer可以定義和交換請(qǐng)求以便發(fā)現(xiàn)任何需要的信息(比如一個(gè)服務(wù)的狀態(tài)或者一個(gè)管道端點(diǎn)的信息。)
          6. 監(jiān)視服務(wù)(Monitoring Service)。本服務(wù)用來(lái)讓一個(gè)peer監(jiān)視本組中的其他成員服務(wù)。
              不是所有上面提到的服務(wù)都必須要被每個(gè)peer實(shí)現(xiàn)。一個(gè)peer組可以自由的實(shí)現(xiàn)那些它認(rèn)為有用的服務(wù),并可以依賴于默認(rèn)的Net Peer Group來(lái)提供非關(guān)鍵核心服務(wù)的一般實(shí)現(xiàn)。
          3.Network Services。peer之間可以協(xié)作并通信以發(fā)布,發(fā)現(xiàn)和啟動(dòng)網(wǎng)絡(luò)服務(wù)。peer可以發(fā)布多個(gè)服務(wù)。peer通過(guò)Peer Discovery Protocol來(lái)發(fā)現(xiàn)network service。在JXTA協(xié)議中組織了兩個(gè)層次上的network service。
          • Peer Service。一個(gè)peer service只有當(dāng)peer公布了自己的service時(shí)才能被訪問(wèn)。如果這個(gè)peer失敗了,那么它的service也失敗了。不同的peer可以運(yùn)行某個(gè)服務(wù)的多個(gè)實(shí)例,但每個(gè)實(shí)例都必須公開(kāi)自己的廣告(advertisement).
          • Peer Group Service。peer組服務(wù)是這個(gè)組中成員所運(yùn)行服務(wù)的實(shí)例的集合的組織形式,其中這些實(shí)例是互相合作的。如果其中任何一個(gè)peer失敗了,那么這個(gè) peer組服務(wù)將不會(huì)收到影響(假定這個(gè)服務(wù)可以從其他peer獲得)。peer group服務(wù)通過(guò)peer 組廣告的以部分來(lái)發(fā)布。
              服務(wù)可以是事先被安裝到peer上或者通過(guò)網(wǎng)絡(luò)安裝的。為了真正的運(yùn)行一個(gè)服務(wù),peer必須為定位一個(gè)適合當(dāng)前peer運(yùn)行環(huán)境的一個(gè)實(shí)現(xiàn)。這個(gè)從網(wǎng)絡(luò)上查找,下載和安裝一個(gè)服務(wù)的過(guò)程很類(lèi)似于在Internet上搜索一個(gè)Web頁(yè)面,取回這個(gè)頁(yè)面然后再安裝需要的插件的過(guò)程。
          4.Modules。JXTA的module用來(lái)描述任何一段用來(lái)實(shí)現(xiàn)JXTA world中一個(gè)行為的“代碼”的抽象表示(Abstraction)。Network Service就是在一個(gè)peer上實(shí)現(xiàn)的行為的一個(gè)最一般的例子。這個(gè)Module Abstraction不一定特指什么“代碼”,它可以是一個(gè)Java類(lèi),也可以是Java jar,或者動(dòng)態(tài)鏈接庫(kù)dll,一個(gè)XML消息或是一個(gè)腳本。這個(gè)module的行為交給了module的實(shí)現(xiàn)者。對(duì)于一個(gè)實(shí)例(instance), module表示了一個(gè)網(wǎng)絡(luò)服務(wù)(network service)在不同平臺(tái)上的不同實(shí)現(xiàn),這些平臺(tái)比如說(shuō)在java平臺(tái),MS windows平臺(tái),Solaris 平臺(tái)。
              Module允許peer實(shí)現(xiàn)一個(gè)新的行為,通過(guò)提供了一個(gè)一般的抽象。當(dāng)peer瀏覽或者加入一個(gè)peer組時(shí),他可以查找新的其打算實(shí)現(xiàn)的行為。比如,當(dāng)加入一個(gè)peer組后,一個(gè)peer可能必須學(xué)習(xí)新的搜索服務(wù),這個(gè)服務(wù)只能在本peer組中使用。為了加入到這個(gè)組,這個(gè)peer必須實(shí)現(xiàn)這個(gè)新的搜索服務(wù)。這個(gè)module框架可以啟動(dòng)平臺(tái)無(wú)關(guān)行為的表示(representation)和廣告(advertisement)。并允許peer描述和實(shí)現(xiàn)任何形式這個(gè)行為(behavior)的是實(shí)現(xiàn)。比如,一個(gè)peer使用java或者c實(shí)現(xiàn)一個(gè)行為的實(shí)現(xiàn)。
          & amp; nbsp;   描述和公告一個(gè)平臺(tái)獨(dú)立的行為的能力能有有效的支持peer組包含異構(gòu)的peer。module的廣告可以使JXTA的peer能夠采用平臺(tái)獨(dú)立的方式描述一個(gè)行為。JXTA平臺(tái)使用module廣告來(lái)自描述。
              module抽象(Module abstractIon)包括一個(gè)module class,module specification和一個(gè)moduleimplementation。
          • Module Class。module class主要用于廣告一個(gè)行為(behavior)的存在。這個(gè)class的定義表述了一個(gè)期望的行為和一個(gè)期望的對(duì)所支持的module的綁定。每一個(gè)module class都有一個(gè)唯一的ID,成為MoudleClassID
          • Module Specification。Module Specification主要用于訪問(wèn)這個(gè)module。它包含了訪問(wèn)或者啟動(dòng)這個(gè)module的所有必要的信息。比如,一個(gè)服務(wù),他的module specification可能包含了一個(gè)用于和其他服務(wù)相通信的管道的廣告。一個(gè)module specification用于提供module class所指明的功能。對(duì)于一個(gè)module class可能有多個(gè)module specification。每一個(gè)module specification都有一個(gè)唯一的id,ModuleSpecID。ModuleSpecID包含了ModuleClass ID,并指明了所使用的module class。一個(gè)module specification暗含了對(duì)網(wǎng)絡(luò)的兼容性。對(duì)于一個(gè)給定的module specification的所有實(shí)現(xiàn)都必須使用相同的協(xié)議,這些實(shí)現(xiàn)都需要是兼容的,即使使用不同的語(yǔ)言實(shí)現(xiàn)的。
          • Module Implementation。Module Implement是一給定module specification的實(shí)現(xiàn)。對(duì)于一個(gè)module specification可以有多個(gè)module implementation。每一個(gè)module implementation都包含了它所實(shí)現(xiàn)的與specification相關(guān)聯(lián)的ModuleSpecID。
              Module可以被peer組服務(wù)使用,也可以被獨(dú)立的服務(wù)所使用。JXTA服務(wù)通過(guò)module abstraction來(lái)區(qū)別存在的服務(wù)(他的Module Class),服務(wù)的specification(Module Specification),或者服務(wù)的實(shí)現(xiàn)(Service Implementation)。所有的這些都有一個(gè)聯(lián)合的廣告,并且可以通過(guò)其他JXTA peer來(lái)公告和發(fā)現(xiàn)的。作為一個(gè)例子,考慮JXTA的發(fā)現(xiàn)服務(wù)。它包含一個(gè)唯一的ModuleClassID,標(biāo)識(shí)了他作為一個(gè)發(fā)現(xiàn)服務(wù)——他的抽象功能。對(duì)于這個(gè)發(fā)現(xiàn)服務(wù)可以有多個(gè)不同的規(guī)范(Specification),并伴隨著不同的實(shí)現(xiàn)。對(duì)于組的大小和在網(wǎng)絡(luò)中的傳播方式可以使用不同的裁剪策略。每一個(gè)Specification都有唯一的MdouleSpecID,其中指明了發(fā)現(xiàn)發(fā)現(xiàn)服務(wù)的ModuleClassID。對(duì)于每個(gè)規(guī)范,都可能有多種實(shí)現(xiàn),每種實(shí)現(xiàn)都包含了相同的ModuleSpceID。
              總之,對(duì)于一個(gè)給定的module Class都可能有多種規(guī)范,這些規(guī)范可能是完全不同的。然而任何給定規(guī)范的所有實(shí)現(xiàn)都是假定可以互相兼容的。
          posted @ 2007-05-19 23:11 Long Long Ago 閱讀(963) | 評(píng)論 (0)編輯 收藏

          JFace的單獨(dú)使用很久都沒(méi)有做過(guò),基本上都是在開(kāi)發(fā)elcipse插件時(shí)用JFace。今天使用JFace作為Java Application時(shí)遇到了 Exception in thread "main" java.lang.NoClassDefFoundError: org/eclipse/core/runtime/IStatus 錯(cuò)誤,雖然已經(jīng)添加了org.eclipse.jface,org.eclipse.core.runtime,org.eclipse.osgi包,但仍然出錯(cuò),后來(lái)發(fā)現(xiàn)org.eclipse.core.runtime.IStatus是在org.eclipse.equonix.common包中,添加后發(fā)現(xiàn) ,還需要添加org.eclipse.core.command包,再添加后搞定。
          posted @ 2007-05-17 14:33 Long Long Ago 閱讀(1064) | 評(píng)論 (2)編輯 收藏

              以前實(shí)現(xiàn)SWT中的模式和非模式窗體(modal or non-modal window )是通過(guò)在子窗體中是否截取父窗體的消息循環(huán)來(lái)實(shí)現(xiàn)的,現(xiàn)在發(fā)現(xiàn)這樣好像不行了,但可以通過(guò)指定子窗體的樣式(style)來(lái)制定子窗體是否是模式窗體。
          Shell child = new Shell(shell,SWT.SHELL_TRIM|SWT.APPLICATION_MODAL);
          上面的語(yǔ)句指定了子窗體child為模式窗體。在上面的style中指定SWT.SHELL_TRIM 是為了顯示窗體的三個(gè)默認(rèn)按鈕(最大,最小和關(guān)閉),也可以用SWT.DIALOG_TRIM,不過(guò)此時(shí)為對(duì)話框樣式,只有一個(gè)默認(rèn)按鈕(關(guān)閉)。默認(rèn)的Shell是非模式窗體,并且是有默認(rèn)系統(tǒng)按鈕的,即樣式為:SWT.SHELL_TRIM|SWT.MODELESS。
          順便說(shuō)一下,在JFace的Dialog中使用模式對(duì)話框只要簡(jiǎn)單的設(shè)置該對(duì)話框setBlockOnOpen(true)即可。
          posted @ 2007-05-17 14:27 Long Long Ago 閱讀(2136) | 評(píng)論 (0)編輯 收藏

              在JXTA中分為三個(gè)層次,如下圖所示。

               下面分別介紹各個(gè)層次:
          1. 平臺(tái)層(platform layer)。平臺(tái)層即所謂的JXTA核心(JXTA core),專門(mén)包裝了最小最精華的部分,這部分主要完成了對(duì)P2P網(wǎng)絡(luò)最一般的使用。包括,為P2P應(yīng)用程序的關(guān)鍵機(jī)制構(gòu)建模塊,傳輸(包括防火墻穿透),創(chuàng)建peer和peer group以及和安全部分的結(jié)合。
          2. 服務(wù)層(Service layer)。服務(wù)層包含了一些網(wǎng)絡(luò)服務(wù),這些服務(wù)不一定是P2P程序中必須的,但卻是P2P環(huán)境中通常和值得提供的。比如搜索,索引,目錄,存儲(chǔ)系統(tǒng),文件共享,分布式文件系統(tǒng),資源聚合和租借等應(yīng)用服務(wù),以及協(xié)議傳輸服務(wù)和認(rèn)證和PKI服務(wù)等等。
          3. 應(yīng)用層(Application layer)。應(yīng)用層包括了綜合應(yīng)用的實(shí)現(xiàn),比如P2P的及時(shí)消息,文檔和資源的共享,娛樂(lè)內(nèi)容管理和分發(fā),P2P的email系統(tǒng),分布式拍賣(mài)系統(tǒng)以及很多其他的應(yīng)用。
              實(shí)際上,服務(wù)層和應(yīng)用層之間的界限并不是明顯的。一個(gè)用戶的應(yīng)用程序可以作為另一個(gè)用戶的服務(wù)。整個(gè)系統(tǒng)被實(shí)際成模塊化的,允許開(kāi)發(fā)者選擇一個(gè)服務(wù)和應(yīng)用的集合來(lái)定制自己的需求。
              在JXTA中有三個(gè)主要方面是它區(qū)別一其他分布式網(wǎng)絡(luò)模型的:
          1. 使用XML文檔(廣告)來(lái)描述網(wǎng)絡(luò)資源。
          2. 針對(duì)peer間和peer與端點(diǎn)(endpoint)間的抽象管道(abstraction pipe)不需要使用一個(gè)可信賴的中心名字/地址認(rèn)真,比如DNS。
          3. 唯一的peer地址方案(peer IDs)。
          在下面的部分將詳細(xì)介紹JXTA的各個(gè)組成部分。
          posted @ 2007-05-13 14:13 Long Long Ago 閱讀(815) | 評(píng)論 (0)編輯 收藏

              JXTA是一個(gè)為P2P計(jì)算而開(kāi)發(fā)設(shè)計(jì)的開(kāi)發(fā)網(wǎng)路計(jì)算平臺(tái)。它的目標(biāo)是通過(guò)創(chuàng)建基本組件和服務(wù)來(lái)為peer group創(chuàng)造新的應(yīng)用。JXTA是juxtpose的簡(jiǎn)稱,指并列并排,這里是說(shuō)P2P的方式和C/S方式以及B/S方式是同等地位了,都是傳統(tǒng)的分布式計(jì)算模型。 JXTA為開(kāi)發(fā)應(yīng)用程序提供了一組開(kāi)發(fā)協(xié)議集合和一個(gè)開(kāi)放源碼的參考實(shí)現(xiàn)。JXTA協(xié)議標(biāo)準(zhǔn)化了peer的風(fēng)格:
          1. 互相發(fā)現(xiàn);
          2. 在peer group中的自組織;
          3. 廣告和發(fā)現(xiàn)網(wǎng)絡(luò)服務(wù);
          4. peer間的通訊;
          5. peer間的交互。
              JXTA協(xié)議被設(shè)計(jì)成獨(dú)立于程序設(shè)計(jì)語(yǔ)言和獨(dú)立于傳輸協(xié)議的。這些協(xié)議可以使用Java或者C/C++或者perl實(shí)現(xiàn)。同樣,也能在TCP/IP,HTTP,Bluetooth或者其他傳輸協(xié)議上實(shí)現(xiàn)。JXTA協(xié)議使得開(kāi)發(fā)者可以構(gòu)建和部署P2P的服務(wù)或者應(yīng)用程序,因?yàn)檫@些協(xié)議是獨(dú)立于程序語(yǔ)言和傳輸協(xié)議,所以可以使得采用完全不同軟件體系的異構(gòu)終端設(shè)備能夠交互通訊。使用JXTA技術(shù),開(kāi)發(fā)人員可以開(kāi)發(fā)出基于網(wǎng)絡(luò)的,能夠交互的應(yīng)用程序,這些應(yīng)用程序有如下特點(diǎn):
          1. 通過(guò)動(dòng)態(tài)查詢和防火墻穿越來(lái)發(fā)現(xiàn)本網(wǎng)絡(luò)中的其他peer;
          2. 任何訪問(wèn)網(wǎng)絡(luò)的節(jié)點(diǎn)都可以方便地共享文檔;
          3. 在網(wǎng)絡(luò)站點(diǎn)中查找minute content;
          4. 創(chuàng)建一個(gè)peer group來(lái)提供服務(wù);
          5. 遠(yuǎn)端監(jiān)視peer的行為;
          6. 在網(wǎng)絡(luò)中同其他peer進(jìn)行安全的通信。
          posted @ 2007-05-12 23:59 Long Long Ago 閱讀(865) | 評(píng)論 (0)編輯 收藏

          今天打算試試yaws,這是一個(gè)使用erlang實(shí)現(xiàn)的web服務(wù)器,參照blog:
          http://yarivsblog.com/articles/2006/07/12/the-hitchhiker
          首先需要安裝erlang環(huán)境,windows和linux下都有,但yaws好像只給了個(gè)linux下的安裝文件,于是在ubuntu6.06上安裝。
          從erlang主頁(yè)www.erlang.org上下載源碼,編譯步驟:
          tar -xzvf xxx.tar.gz
          cd xxx
          sudo ./configure
          (sudo make clean)#可選的,用于非首次編譯的情況
          sudo make
          sudo make install (as root)
          但configure時(shí)出錯(cuò):(類(lèi)似如下)
          configure: error: No curseslibraryfunctions found
          There is a problem with $ERL_TOP/erts/configure not passing the LDFLAGS
          environment variable for test compiles, so ALL library tests fail. I
          modified files $ERL_TOP/erts/aclocal.m4 and $ERL_TOP/configure.in in order
          to locate pthread_create in the standard C runtime library. The
          $ERL_TOP/configure.in produces a configure that works, wheras the
          $ERL_TOP/erts/configure.in does not. At the top of file erts/configure.in:

          AC_PREREQ(2.13)
          AC_INIT(vsn.mk)
          應(yīng)該是一些curses庫(kù)沒(méi)有安裝,但apt-get install curses提示找不到,google了一下發(fā)現(xiàn)需要安裝
          ncurses-devel包,在網(wǎng)上只找到了相應(yīng)的rpm包,使用alien命令,將rpm保轉(zhuǎn)換為deb包安裝:
          sudo apt-get install alien
          sudo?alien?*.rpm,轉(zhuǎn)成deb后,用dpkg?-i?*.deb
          或者
          sudo?alien?-i?*.rpm
          進(jìn)行安裝
          (注意,下載rpm包的時(shí)候我將包改名了,導(dǎo)致alien時(shí)出錯(cuò),改成原來(lái)的名字就正常了,不知道為什么:P)
          這時(shí)候cofigure可以過(guò)去了,但make又出錯(cuò)了,提示erlc找不到,類(lèi)似如下的錯(cuò)誤信息:
          erlc -W +debug_info -I../include -o../ebin otp_ring0.erl
          make[4]: erlc: Command not found
          make[4]: ***[../ebin/otp_ring0.beam]Error127
          make[4]: Leaving directory `/usr/src/packages/erlang-10.b.5/lib/kernel/src'
          make[3]: *** [/usr/src/packages/erlang-10.b.5/lib/kernel/ebin/otp_ring0.beam] Error 2
          make[3]: Leaving directory `/usr/src/packages/erlang-10.b.5/erts/emulator'
          make[2]: *** [generate] Error 2
          make[2]: Leaving directory `/usr/src/packages/erlang-10.b.5/erts/emulator'
          make[1]: *** [depend] Error 2
          make[1]: Leaving directory `/usr/src/packages/erlang-10.b.5'
          make: *** [build-stamp] Error 2
          make: *** [debs] Error 2

          看網(wǎng)上有介紹說(shuō)使用make clean并不完全,
          于是將源碼刪除,重新解壓縮,再configure后,make,沒(méi)有提示erlc找不到了,又有提示類(lèi)似如下的錯(cuò)誤信息:
          > otp_src_R11B-1/lib/kernel/ebin/erlang.beam > i686-pc-linux-gnu/preload.c
          > m4 -DTARGET=i686-pc-linux-gnu -DOPSYS=linux -DARCH=x86 hipe/
          > hipe_x86_asm.m4 > i686-pc-linux-gnu/opt/plain/hipe_x86_asm.h
          > /bin/sh: m4: command not found
          > make[2]: *** [i686-pc-linux-gnu/opt/plain/hipe_x86_asm.h] Error 127
          > make[2]: Leaving directory `/home/jhancock/otp_src_R11B-1/erts/emulator'
          > make[1]: *** [generate] Error 2
          > make[1]: Leaving directory `/home/jhancock/otp_src_R11B-1/erts/emulator'
          > make: *** [depend] Error 2
          這是m4包沒(méi)有找到(http://www.erlang.org/pipermail/erlang-questions/2006-November/023942.html)
          安裝m4包后,繼續(xù)make出現(xiàn)如下錯(cuò)誤:
          hipe/hipe_mkliterals.c:351: error: 'X86_LEAF_WORDS' undeclared here (not in a function)
          hipe/hipe_mkliterals.c:352: error: 'X86_NR_ARG_REGS' undeclared here (not in a function)
          網(wǎng)上搜索結(jié)果:http://forum.trapexit.org/viewtopic.php?t=6815
          將源碼刪除,再解壓縮 再make終于過(guò)去了
          提示:如下的包最好是在erlang安裝之前就安裝好的: perl, debhelper (>= 4.0.0), autoconf (>= 2.50), openssl, libssl-dev, m4, libncurses5-dev, dpatch, autotools-dev, unixodbc-dev
          make過(guò)程大概有1個(gè)小時(shí),之后是make install很快。
          打開(kāi)終端,輸入erl,出現(xiàn)提示符1>
          后面將yaws的安裝和使用
          yaws的安裝挺簡(jiǎn)單的,主要是他的編譯是基于erlang的。
          需要注意的是,安裝好后,如果沒(méi)有安裝相應(yīng)的ssl模塊的話,需要更改一下conf文件,將其中關(guān)于ssl的部分注釋掉,既如下部分:
          <server xxx>
          ????? ....
          ??? ??? ? <ssl>
          ??? ?? ?? ?? ?? ...
          ??? ?? ?? </ssl>
          </server>
          在windows下的安裝,在yaws的主頁(yè)上有說(shuō)明,需要下載一個(gè)bat文件,不過(guò)這個(gè)文件好像有問(wèn)題,需要將一些安裝的環(huán)境變量改一下,在(SET ERLC_FLAGS=)這行之后添加:
          SET ProgramFiles=G:\erlang\yaws\yaws_program
          SET HOME=G:\erlang\yaws\yaws_data
          SET APPDATA=G:\erlang\yaws\yaws_configure
          ProgramFiles 為yaws的程序位置,HOME為yaws的數(shù)據(jù)位置,包括www,log,wiki,ssl等,APPDATA為yaws的配置位置。
          如果使用默認(rèn)安裝參數(shù)的話,需要將IF NOT DEFINED ProgramFiles SET ProgramFiles="c:\Program Files"和
          HOME="%HOMEDRIVE%%HOMEPATH%\My Documents"中的雙引號(hào)去掉(感覺(jué)這個(gè)bat文件寫(xiě)的比較亂)
          同時(shí)不要忘了,在安裝好之后注釋掉conf文件中關(guān)于ssl的部分。
          安裝好后,默認(rèn)就可以在%home/www目錄或者/tmp(windows下為%home%\www? or C:\tmp)目錄添加yaws文件(ehtml)來(lái)顯示了。
          btw:如果在ubuntu or debian上安裝,最簡(jiǎn)單,只要apt-get install yaws 就可以了。運(yùn)行yaws需要root權(quán)限。
          posted @ 2007-01-18 23:22 Long Long Ago 閱讀(4472) | 評(píng)論 (2)編輯 收藏

          今天看到一個(gè)朋友的Blog, 就忍不住把以前寫(xiě)的這個(gè)代碼拿出來(lái)了, 不然這代碼閑著也是閑著. 當(dāng)然沒(méi)有必要照搬全部, 只要中間的那個(gè) zoomImage() 方法即可. 當(dāng)然還有設(shè)置圖片部分透明的方法.

          ?

          /*
          * @(#)BlogMailHandler.java 1.00 2004-10-4
          *
          * Copyright 2004 . All rights reserved.
          * PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
          */
          import java.awt.Color;
          import java.awt.Graphics2D;
          import java.awt.RenderingHints;
          import java.awt.image.BufferedImage;
          import java.io.BufferedInputStream;
          import java.io.ByteArrayInputStream;
          import java.io.ByteArrayOutputStream;
          import java.io.File;
          import java.io.FileOutputStream;
          import java.io.InputStream;
          import java.sql.Timestamp;
          import java.util.Properties;

          import javax.imageio.ImageIO;
          import javax.mail.Address;
          import javax.mail.FetchProfile;
          import javax.mail.Flags;
          import javax.mail.Folder;
          import javax.mail.Message;
          import javax.mail.MessagingException;
          import javax.mail.Multipart;
          import javax.mail.Part;
          import javax.mail.Session;
          import javax.mail.Store;
          import javax.mail.internet.InternetAddress;
          import javax.mail.internet.MimeUtility;

          import studio.beansoft.jsp.StringUtil;
          import com.keypoint.PngEncoder;
          import com.keypoint.PngEncoderB;

          import moblog.*;

          /**
          * BlogMailHandler, 彩E博客郵件的處理程序.
          * 每 15 分鐘更新一次郵件, 發(fā)布博客并更新用戶產(chǎn)量.
          * 郵件 POP3 帳戶信息位于 /blogmail.properties 文件中.
          *
          * @author 劉長(zhǎng)炯
          * @version 1.00 2004-10-4
          */
          public class BlogMailHandler extends Thread {
          /**
          * @alias 文件根目錄 : String
          */
          private String rootDirectory;

          // 郵件帳戶配置屬性
          private static Properties props = new Properties();

          static {
          try {
          InputStream in = BlogMailHandler.class
          .getResourceAsStream("/blogmail.properties");
          props.load(in);
          in.close();
          } catch (Exception ex) {
          System.err.println("無(wú)法加載配置文件 blogmail.properties:"
          + ex.getMessage());
          ex.printStackTrace();
          }
          }

          // 圖像加載的共享實(shí)例, 在 Linux 平臺(tái)上有可能無(wú)法生成圖形對(duì)象
          // private static Frame sharedFrame = new Frame();
          private boolean shouldExit = false;

          public BlogMailHandler() {
          }
          /** 定時(shí)開(kāi)始讀取郵件信息 */
          public void startMailProcessCycle() {
          start();
          }
          public void run() {
          while(!shouldExit) {
          doProcess();
          try {
          // 每15分鐘讀取一次
          Thread.currentThread().sleep(60 * 15 * 1000);
          } catch (Exception e) {
          e.printStackTrace();
          }
          }
          }
          /** 處理進(jìn)程 */
          private void doProcess() {
          try {
          Store store = openStore();
          Folder inbox = openInbox(store);

          processAllMessages(inbox);
          inbox.close(true);
          store.close();
          } catch (Exception e) {
          e.printStackTrace();
          }
          }
          protected void finalize() throws Throwable {
          shouldExit = true;
          }
          /**
          * 縮放原始圖片到合適大小.
          *
          * @param srcImage - 原始圖片
          * @return BufferedImage - 處理結(jié)果
          */
          private BufferedImage zoomImage(BufferedImage srcImage) {
          int MAX_WIDTH = 100;// TODO: 縮放后的圖片最大寬度
          int MAX_HEIGHT = 160;// TODO: 縮放后的圖片最大高度
          int imageWidth = srcImage.getWidth(null);
          int imageHeight = srcImage.getHeight(null);

          // determine thumbnail size from MAX_WIDTH and MAX_HEIGHT
          int thumbWidth = MAX_WIDTH;
          int thumbHeight = MAX_HEIGHT;
          double thumbRatio = (double)thumbWidth / (double)thumbHeight;
          double imageRatio = (double)imageWidth / (double)imageHeight;
          if (thumbRatio < imageRatio) {
          thumbHeight = (int)(thumbWidth / imageRatio);
          } else {
          thumbWidth = (int)(thumbHeight * imageRatio);
          }
          // 如果圖片小于所略圖大小, 不作處理
          if(imageWidth < MAX_WIDTH && imageHeight < MAX_HEIGHT) {
          thumbWidth = imageWidth;
          thumbHeight = imageHeight;
          }

          // draw original image to thumbnail image object and
          // scale it to the new size on-the-fly (drawImage is quite powerful)
          BufferedImage thumbImage = new BufferedImage(thumbWidth,
          thumbHeight, BufferedImage.TYPE_INT_RGB);
          //thumbImage.getsc
          Graphics2D graphics2D = thumbImage.createGraphics();
          graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
          RenderingHints.VALUE_INTERPOLATION_BILINEAR);
          graphics2D.drawImage(srcImage, 0, 0, thumbWidth, thumbHeight, null);
          System.out.println("thumbWidth=" + thumbWidth);
          System.out.println("thumbHeight=" + thumbHeight);
          return thumbImage;
          }

          // Open mail Store
          private Store openStore() throws Exception {
          Store store;
          //--[ Set up the default parameters
          props.put("mail.transport.protocol", "pop");
          props.put("mail.pop.port", "110");
          // props.put("mail.debug", "true");

          Session session = Session.getInstance(props);
          store = session.getStore("pop3");
          // void javax.mail.Service.connect(String host, String user, String
          // password) throws
          // MessagingException
          store.connect(props.getProperty("mail.pop3.host"), props
          .getProperty("username"), props.getProperty("password"));
          return store;
          }

          // Open Inbox
          private Folder openInbox(Store store) throws Exception {
          Folder folder = store.getDefaultFolder();
          if (folder == null) {
          System.out.println("Problem occurred");
          System.exit(1);
          }

          Folder popFolder = folder.getFolder("INBOX");
          popFolder.open(Folder.READ_WRITE);
          return popFolder;
          }

          /** Close mail store. */
          private void closeStore(Store store) {
          try {
          store.close();
          } catch (MessagingException e) {
          e.printStackTrace();
          }
          }

          /**
          * 處理賬號(hào)中的所有郵件并刪除這些郵件.
          *
          * @param folder - Folder, 收件箱
          * @throws Exception
          */
          private void processAllMessages(Folder folder) throws Exception {

          Message[] listOfMessages = folder.getMessages();
          FetchProfile fProfile = new FetchProfile();
          fProfile.add(FetchProfile.Item.ENVELOPE);
          folder.fetch(listOfMessages, fProfile);

          for (int i = 0; i < listOfMessages.length; i++) {
          try {
          processSingleMail(listOfMessages[i]);
          } catch (Exception e) {
          e.printStackTrace();
          }

          // Delete mail
          listOfMessages[i].setFlag(Flags.Flag.DELETED, true);
          }
          }

          /**
          * 處理單個(gè) Email, 將文章發(fā)表, 并將附件圖片轉(zhuǎn)換為 PNG 后存入用戶目錄.
          *
          * @param message -
          * Message, email 消息
          */
          private void processSingleMail(Message message) throws Exception {
          BlogContent content = new BlogContent();
          BlogUser user = new BlogUser();
          BlogPicture picture = new BlogPicture();

          // 1. 假定發(fā)件人為手機(jī)號(hào), 并嘗試根據(jù)手機(jī)號(hào)查找用戶
          Address[] addList = message.getFrom();
          if (addList.length > 0) {
          String userMail = ((InternetAddress) addList[0]).getAddress();
          // 取出 彩E 郵件用戶手機(jī)號(hào), 格式: 手機(jī)號(hào)@someone.com
          String mobileNumber = userMail.substring(0, userMail.indexOf("@"));
          System.out.println("用戶手機(jī)號(hào)為:" + mobileNumber);
          if (!user.findByMDN(mobileNumber)) {
          // Not found user, then return
          System.err.println("user " + ((InternetAddress) addList[0]).getAddress() + " not found.");
          return;
          }
          }

          // 2. 嘗試讀取郵件正文
          // 復(fù)合郵件
          if (message.isMimeType("multipart/*")) {
          // 標(biāo)記是否處理過(guò)圖片
          boolean imageHasProcessed = false;
          Multipart multipart = (Multipart) message.getContent();
          for (int i = 0, n = multipart.getCount(); i < n; i++) {
          // System.err.println("Reading multipart " + i);
          Part part = multipart.getBodyPart(i);
          // System.err.println("ContentType = " + part.getContentType());

          // 3. 處理附件圖片, 只處理第一個(gè)圖片
          String disposition = part.getDisposition();
          // System.err.println("disposition = " + disposition);
          if (disposition != null
          && (disposition.equals(Part.ATTACHMENT) || disposition
          .equals(Part.INLINE)) && !imageHasProcessed) {
          // 需要反編碼郵件文件名, 有的郵件的附件的文件名是經(jīng)過(guò)編碼的,
          // 但是 JavaMail 并不能處理出來(lái)(BeanSoft, 2004-10-13)
          String fileName = MimeUtility.decodeText(part.getFileName());
          String ext = StringUtil.getExtension(fileName)
          .toLowerCase();
          System.err.println("part.getFileName() = " + fileName);

          if ("gif".equals(ext) || "jpg".equals(ext)
          || "png".equals(ext)) {
          BufferedInputStream dataIn = null;
          // 轉(zhuǎn)換非 PNG 格式圖片為 PNG 格式 -- 取消
          // if (!"png".equals(ext)) {
          ByteArrayOutputStream pngOut = new ByteArrayOutputStream();
          try {
          // Convert image file to PNG file
          BufferedImage buffImg = ImageIO.read(part
          .getInputStream());
          // Read image file from attachment
          // 縮放圖片
          buffImg = zoomImage(buffImg);

          int imageWidth = buffImg.getWidth(null);
          int imageHeight = buffImg.getHeight(null);
          BufferedImage outImg = new BufferedImage(
          imageWidth, imageHeight,
          // BufferedImage.TYPE_4BYTE_ABGR 是 24 位色深, TYPE_BYTE_INDEXED 是 8 位
          BufferedImage.TYPE_INT_RGB);
          // 使圖片透明
          // embossImage(buffImg, outImg);
          outImg.getGraphics().drawImage(buffImg, 0, 0, imageWidth, imageHeight, null);
          // Save image to PNG output stream
          // ImageIO.write(outImg, "png", pngOut);
          // Save using keypoint PNG encoder
          PngEncoderB pngb = new PngEncoderB(outImg,
          PngEncoder.NO_ALPHA, 0, 9);
          pngOut.write(pngb.pngEncode());
          dataIn = new BufferedInputStream(
          new ByteArrayInputStream(pngOut
          .toByteArray()));
          } catch (Exception e) {
          }
          // } else {
          // dataIn = new BufferedInputStream(part
          // .getInputStream());
          // }
          // All pictures change to png format
          ext = "png"
          // Insert picture info into database
          picture.setBlogID(user.getId());
          picture.setCreationTime(new Timestamp(System
          .currentTimeMillis()));
          picture.setFileEXName(ext);
          picture.setTitle(fileName);
          picture.create();
          // Save png file to user directory, /users/userId/pictureId.png
          FileOutputStream outFile = new FileOutputStream(
          rootDirectory + File.separatorChar + user.getId() + File.separatorChar
          + picture.getId() + "." + ext);
          int c;
          while ((c = dataIn.read()) != -1) {
          outFile.write(c);
          }

          outFile.close();
          imageHasProcessed = true;
          }
          }
          // 純文本郵件, 帶附件
          else if (part.isMimeType("text/plain")) {
          String body = part.getContent().toString();
          String title = message.getSubject();

          content.setBlogID(user.getId());
          content.setCreationTime(new Timestamp(System.currentTimeMillis()));
          content.setTitle(title);
          content.setNote(body);
          }

          // 典型的 HTML 和 文本郵件可選形式, 進(jìn)一步分析
          if (part.getContent() instanceof Multipart) {
          Multipart subPart = (Multipart) part.getContent();

          for (int j = 0, m = subPart.getCount(); j < m; j++) {
          Part mailText = subPart.getBodyPart(j);

          if (mailText.isMimeType("text/plain")) {
          String body = mailText.getContent().toString();
          String title = message.getSubject();

          content.setBlogID(user.getId());
          content.setCreationTime(new Timestamp(System.currentTimeMillis()));
          content.setTitle(title);
          content.setNote(body);
          break;
          }
          }
          }

          }// End of multipart parse

          // 4. 創(chuàng)建博客記錄
          content.setPictureId(picture.getId());
          if(content.create() > 0) {
          // 更新用戶產(chǎn)量
          user.setPostTimes(user.getPostTimes() + 1);
          user.update();
          }
          }
          // 純文本郵件, 無(wú)附件
          else if (message.isMimeType("text/plain")) {
          String body = message.getContent().toString();
          String title = message.getSubject();

          content.setBlogID(user.getId());
          content.setCreationTime(new Timestamp(System.currentTimeMillis()));
          content.setTitle(title);
          content.setNote(body);

          if(content.create() > 0) {
          // 更新用戶產(chǎn)量
          user.setPostTimes(user.getPostTimes() + 1);
          user.update();
          }
          }
          }

          // 測(cè)試, 嘗試連接一次到郵件服務(wù)器
          public static void main(String[] args) {
          BlogMailHandler handler = new BlogMailHandler();

          // TODO: debug, 請(qǐng)?jiān)?JSP 里面設(shè)置圖片目錄的根路徑
          handler.rootDirectory = "F:/Moblog/users/"
          handler.doProcess();
          }

          /**
          * @return Returns the rootDirectory.
          */
          public String getRootDirectory() {
          return rootDirectory;
          }

          /**
          * @param rootDirectory
          * The rootDirectory to set.
          */
          public void setRootDirectory(String property1) {
          this.rootDirectory = property1;
          }

          /** Make image transparent */
          private void embossImage(BufferedImage srcImage, BufferedImage destImage) {
          int width = srcImage.getWidth();
          int height = srcImage.getHeight();

          for (int i = 0; i < height; i++) {
          for (int j = 0; j < width; j++) {
          int newColor = handlesinglepixel(j, i, srcImage.getRGB(j, i));
          destImage.setRGB(j, i, newColor);
          }
          }
          }

          // Handle picture single pixel, change 0xff00ff color to transparent
          private int handlesinglepixel(int x, int y, int pixel) {
          int alpha = (pixel >> 24) & 0xff;
          int red = (pixel >> 16) & 0xff;
          int green = (pixel >> 8) & 0xff;
          int blue = (pixel) & 0xff;
          // Deal with the pixel as necessary...
          // alpha 為 0 時(shí)完全透明, 為 255 時(shí)不透明
          Color back = new Color(0xFF00FF);
          // 將與背景色相同(此處PNG圖片為紫色)的像素點(diǎn)的透明度設(shè)為透明
          if (isDeltaInRange(back.getRed(), red, 2)
          && isDeltaInRange(back.getGreen(), green, 2)
          && isDeltaInRange(back.getBlue(), blue, 2)) {
          // System.out.println("x=" + x + "y=" + y + " is transparent.");
          alpha = 0;
          }
          // red = red / 2;
          // //green = green / 2 + 68;
          // blue = blue / 2;

          return alpha << 24 | red << 16 | green << 8 | blue;
          }

          // 判斷兩個(gè)整數(shù)的差是否在一定范圍之內(nèi)
          private boolean isDeltaInRange(int first, int second, int range) {
          if (first - second <= range && second - first <= range)
          return true;
          return false;
          }
          }

          • #?re: Java 中收取郵件并自動(dòng)縮放圖片的代碼(原創(chuàng))
            冷面閻羅
            Posted @ 2006-12-29 18:31
            不錯(cuò)!
            自己也寫(xiě)過(guò)java收發(fā)郵件的程序!??回復(fù)??
          • #?re: Java 中收取郵件并自動(dòng)縮放圖片的代碼(原創(chuàng))
            托托姆
            Posted @ 2006-12-30 12:10
            不知道BeanSoft兄是不是看了我昨天的帖子有此感想。。。:)
            我測(cè)試了一下BeanSoft兄的zoomImage() 方法,如果按原代碼執(zhí)行,原本圖片透明的部分將變成黑色。如果修改TYPE_INT_RGB為T(mén)YPE_INT_ARGB,則能避免這個(gè)問(wèn)題。
          posted @ 2006-12-30 13:27 Long Long Ago 閱讀(586) | 評(píng)論 (0)編輯 收藏

          寫(xiě)程序中遇到一個(gè)問(wèn)題?如下:
          mySoc?=?new?Socket(svrAddress,5555);
          
          
          myInput?=?new?ObjectInputStream(mySoc.getInputStream());//有問(wèn)題
          myOutput?=?new?ObjectOutputStream(mySoc.getOutputStream());//有問(wèn)題
          //myInput?=?new?DataInputStream(mySoc.getInputStream());
          //myOutput?=?new?DataOutputStream(mySoc.getOutputStream());?
          注銷(xiāo)的語(yǔ)句運(yùn)行可以成功
          但是未注銷(xiāo)的那部分?運(yùn)行時(shí)就卡在那里了
          但是卻沒(méi)有拋出異常
          請(qǐng)教原因是什么?有什么問(wèn)題
          該怎么解決呢?

          找了好久終于再網(wǎng)上找到關(guān)于這個(gè)問(wèn)題的說(shuō)明了?因?yàn)閱?wèn)題比較特殊?所以貼出來(lái)希望對(duì)大家
          有幫助
          
          主機(jī)端先建立ObjectInputStream后建立ObjectOutputStream,則對(duì)應(yīng)地客戶端要先建立
          ObjectOutputStream后建立ObjectInputStream,否則會(huì)造成兩方互相等待數(shù)據(jù)而導(dǎo)致死
          鎖。
          
          原因是建立ObjectInputStream對(duì)象是需要先接收一定的header數(shù)據(jù),接收到這些數(shù)據(jù)之前
          會(huì)處于阻塞狀態(tài)。故而為了防止這種死鎖狀態(tài),通訊兩方的
          ObjectInputStraem,ObjectOutputStream必須注意順序?qū)?yīng)使用。
          
          
          目前相應(yīng)的解決辦法還沒(méi)有找到?如果要解決?可以嘗試重載對(duì)象輸入輸出流
          posted @ 2006-12-30 12:46 Long Long Ago 閱讀(956) | 評(píng)論 (1)編輯 收藏

          ?????? Tabbed Property是eclipse3.2中新加入一個(gè)view,可以使屬性編輯器的功能近乎無(wú)限的擴(kuò)大。這里說(shuō)明一些Tabbed Property的使用方法。Tabbed Property中分成三個(gè)部分,Contributer,Tabs,Sections,一個(gè)Contributor包含若干個(gè)Tabs,一個(gè)Tabs又可以包含若干個(gè)sections。下面我們來(lái)分別進(jìn)行描述。
          ????? 1。Contributor 這需要擴(kuò)展org.eclipse.ui.views.properties.tabbed.PropertyContributor擴(kuò)展點(diǎn),定義時(shí),最重要的是定義contributId,這個(gè)id必須是全局唯一的,這樣在加載屬性頁(yè)時(shí),才能找到這個(gè)我們定義的屬性頁(yè),一般地,我們都將對(duì)應(yīng)于這個(gè)屬性頁(yè)的workbenchpart的id作為本contributor的id,這樣我們?cè)诖a中可以不硬編碼本id字符串,而使用getSite().getId()就可以得到這個(gè)id了(當(dāng)然,這樣定義id不是必須的)。一個(gè)property view可以被多個(gè)workbench part共享,但 一個(gè)workbench part只能有一個(gè)property view,這個(gè)workbench part需要實(shí)現(xiàn)ITabbedPropertySheetPageContributor?接口,這個(gè)接口只有一個(gè)方法,要求返回本part對(duì)應(yīng)的tabbed property Contributor id,一般只要return getSite().getId();
          ?? contributor有如下幾個(gè)attribute:
          ???1)typeMapper,這個(gè)類(lèi)需要實(shí)現(xiàn)org.eclipse.ui.views.properties.tabbed.ITypeMapper,主要是實(shí)現(xiàn)類(lèi)型的映射,因?yàn)槲覀冞x擇的元素并不一定是實(shí)現(xiàn)IPropertySource的元素(即能夠給property view提供內(nèi)容的元素),比如在GEF中,我們選擇的finger實(shí)際上是選擇了對(duì)應(yīng)的EditPart,而實(shí)際上實(shí)現(xiàn)了IPropertySource一般的是model部分的元素,所以這時(shí)候我們要將Editpart映射到對(duì)應(yīng)的model元素。
          ???2)labelProvider,需要一個(gè)實(shí)現(xiàn)org.eclipse.jface.viewers.ILabelProvider的類(lèi),主要是在各個(gè)tabs的最上面顯示文字和圖片。
          ???3)propertyCategory,用于聚合多個(gè)tabs,注意至少要定義一個(gè)category,來(lái)聚合tabs,否則,可能會(huì)顯示property失敗。

          ???2。Tabs,這個(gè)需要擴(kuò)展org.eclipse.ui.views.properties.tabbed.propertyTabs擴(kuò)展點(diǎn),其中contributorId就是與之相關(guān)聯(lián)的Contributor的id,然后我們可以定義多個(gè)tab,這些tab的屬性如下:
          ???1)label,用于顯示在property view的tab bar上的字
          ???2)category,填入的就是在Contributor擴(kuò)展點(diǎn)中定義的那些category,用于聚合tabs
          ???3)id,本tab的唯一標(biāo)識(shí)
          ???4)afterTab,用于tab之間的排序,如果這是第一個(gè)tab,則沒(méi)有afterTab,afterTab指的是在本tab之前的那個(gè)tab,并且afterTab描述的是在同一個(gè)category中的tabs,不同category之間的順序是按照在contributor中定義category的順序來(lái)定義的。
          ???5)indented,如果為ture,則各個(gè)tabs是有縮進(jìn)的
          ???6)image,本tab的圖片

          ???3。section ,需要擴(kuò)展 org.eclipse.ui.views.properties.tabbed.PropertySections擴(kuò)展點(diǎn),它的contributionId就是本section所在的Contribution的id,針對(duì)每個(gè)tab,我們可以定義多個(gè)section,每個(gè)section的attribut描述如下:
          ???1)id,本secation的唯一標(biāo)識(shí)
          ???2)tab,本section所屬tab的標(biāo)識(shí)
          ???3)class,實(shí)現(xiàn)了org.eclipse.ui.views.properties.tabbed.AbstractPropertySection抽象類(lèi)的類(lèi),用于描述這個(gè)section的控件和布局。
          ???4)aftersection和上面的aftertab差不多,描述的是同一個(gè)tab中的section的順序,注意afterserction描述的是本section之前的section的id
          ???5)filter:一個(gè)實(shí)現(xiàn)org.eclipse.jface.viewers.IFilter接口的過(guò)濾器,對(duì)選中元素進(jìn)行過(guò)濾。
          ???6)enableFor:一個(gè)用于只是選擇數(shù)目的值,必須要符合這個(gè)舒服才能使能這個(gè)section。如果不符合,則這個(gè)section就被過(guò)濾了,如果省略本值,則section的使能器就不會(huì)工作了。這是一個(gè)自然數(shù),比如,當(dāng)enableFor=1時(shí),僅僅只有一個(gè)元素被選擇的時(shí)候,本section才會(huì)被使能。

          some notes:
          ??? 上面說(shuō)過(guò)實(shí)現(xiàn)ITabbedPropertySheetPageContributor接口的workbench part除了要實(shí)現(xiàn)getContributeId方法外,還需要重載getAdapter方法,因?yàn)閑clipse的默認(rèn)加載的property veiw時(shí)原來(lái)的那個(gè)view,為了使tabbed property view能夠加載,我們就需要重載getAdapter方法,返回一個(gè)TabbedPropertySheetPage對(duì)象。

          ??? 在實(shí)現(xiàn)section class的時(shí)候需要注意,createcontrol時(shí)首先應(yīng)該先創(chuàng)建一個(gè)composite,一般是 Composite composite = getWidgetFactory().createFlatFormComposite(parent); 然后各個(gè)控件在這個(gè)composite上創(chuàng)建。


          posted @ 2006-09-17 22:24 Long Long Ago 閱讀(2889) | 評(píng)論 (1)編輯 收藏

          安裝subversion
          基本命令:
          ??$?sudo?apt-get?install?subversion
          ??$?sudo?apt-get?install?libapache2-svn
          可以安裝的包:
          ?apache2
          ?apache2-common
          ?apache2-mpm-prefork
          ?apache2-utils
          ?libapache2-svn
          ?libapache2-mod-auth-pam
          ?libapache2-mod-auth-sys-group
          ?subversion
          ?subversion-tools


          創(chuàng)建一個(gè)名為subversion的組:groupadd subversion
          將自己(eg.:user)和www-data(apapch2帳號(hào))用戶添加入subversion組,可以編輯/etc/group文件,在最后找到subversion添加入帳號(hào)名(eg:user,www-data),看上去就像這樣:subversion:x:1001:www-data,exp
          然后是創(chuàng)建subversion庫(kù),并賦予subversion組中用戶有讀寫(xiě)subversion庫(kù)的權(quán)限:
          ???$?sudo?mkdir?/home/svn??#創(chuàng)建svn庫(kù)的父路徑
          ???$?cd?/home/svn
          ???$?sudo?mkdir?myproject??#創(chuàng)建本svn庫(kù)的目錄
          ???$?sudo?svnadmin?create?/home/svn/myproject?#使用svn命令,創(chuàng)建svn庫(kù)
          ???$?sudo?chown?-R?root:subversion?myproject?#更改本目錄的組
          ???$?sudo?chmod?-R?g+rws?myproject?#給本目錄的組用戶增加讀寫(xiě)和遞歸增加新加目錄的讀寫(xiě)權(quán)限
          注意上面提到的命令順序,如果最后再執(zhí)行創(chuàng)建庫(kù)的命令(svnadmin create ....)則創(chuàng)建的文件沒(méi)有獲得組用戶寫(xiě)的權(quán)限,這樣在外部訪問(wèn)提交的時(shí)候會(huì)出錯(cuò).
          對(duì)于本機(jī),可以直接使用file命令來(lái)訪問(wèn):
          ??$?svn?co(or?checkout)?file:///home/svn/myproject
          #or
          ??$?svn?co?file://localhost/home/svn/myproject
          注意:如果您并不確定主機(jī)的名稱,您必須使用三個(gè)斜杠(///),而如果您指定了主機(jī)的名稱,則您必須使用兩個(gè)斜杠(//).
          此時(shí)對(duì)svn庫(kù)的權(quán)限是基于文件系統(tǒng)的,只要是subversion組中的用戶都可以訪問(wèn)本svn庫(kù)。

          接下來(lái),講述如何使用apache服務(wù)器來(lái)提供對(duì)svn庫(kù)的訪問(wèn)
          編輯文件/etc/apache2/mods-available/dav_svn.conf
          增加如下的內(nèi)容:
          ??<Location?/svn/myproject>
          ?????DAV?svn
          ?????SVNPath?/home/svn/myproject
          ?????AuthType?Basic
          ?????AuthName?"myproject?subversion?repository"
          ?????AuthUserFile?/etc/subversion/passwd
          ?????
          <LimitExcept?GET?PROPFIND?OPTIONS?REPORT>
          ????????Require?valid-user
          ?????
          </LimitExcept>
          ??
          </Location>

          apache會(huì)解析url中的/svn/myproject部分,來(lái)定位svn庫(kù),當(dāng)收到此請(qǐng)求時(shí),會(huì)查詢svn庫(kù):/home/svn/myproject,這里的認(rèn)證方式是basic,對(duì)于訪問(wèn)要求valid-user,帳號(hào)文件在/etc/subversion/passwd中。
          注意重新設(shè)置后要重啟apache2:sudo /etc/init.d/apache2 restart
          編輯生成帳號(hào)文件: sudo htpasswd2 -c /etc/subversion/passwd user? #給user帳號(hào)創(chuàng)建口令
          這時(shí)候可以通過(guò)瀏覽器來(lái)瀏覽svn庫(kù)了
          在我的設(shè)置中發(fā)現(xiàn),apache2會(huì)自動(dòng)綁定ipv6地址,可能會(huì)有些問(wèn)題,可以強(qiáng)制apache綁定v4地址,在/etc/apache2/port.conf中改成:Listen [bindedip]:[port]的形式

          通過(guò)https來(lái)訪問(wèn)svn庫(kù)
          首先生成一個(gè) SSL 簽名,使用命令

          ?# apache2-ssl-certificate

          這里會(huì)有一系列關(guān)于你的個(gè)人隱私的問(wèn)題,回答完了,自然的簽名也就生成了,然
          后我們就要在 apache2 里面打開(kāi) SSL 了,現(xiàn)在要做的是開(kāi)啟 ssl 模塊

          ?# a2enmod ssl

          然后,使用 apache2 的虛擬主機(jī)功能來(lái)添加 SSL 的支持,將

          ?/etc/apache2/sites-available/default

          復(fù)制一份,叫

          ?/etc/apache2/sites-available/ssl

          好啦

          修改 default 文件的開(kāi)頭為

          ?NameVirtualHost *:80
          ?<VirtualHost *:80>

          修改 ssl 文件的開(kāi)頭為

          ?NameVirtualHost *:443
          ?<VirtualHost *:443>

          這里 443 是 SSL 的標(biāo)準(zhǔn)端口。

          并在 ssl 文件中加入如下內(nèi)容,在<VirtualHost></VirtualHost>內(nèi)

          ?SSLEngine On
          ?SSLCertificateFile /etc/apache2/ssl/apache.pem

          保存文件后,運(yùn)行命令

          ?? # a2ensite ssl

          來(lái)激活這個(gè)虛擬主機(jī)

          現(xiàn)在,修改文件

          ?/etc/apache2/ports.conf

          加上一行

          ?Listen 443

          好了,到此為止,SSL 服務(wù)器配置完成,重新啟動(dòng) apache 吧。

          ?

          一些問(wèn)題:
          可能出現(xiàn) RA layer request failed svn: MKACTIVITY of 400 Bad Request 之類(lèi)的錯(cuò)誤,這可能是因?yàn)槭褂昧舜淼脑?,代理不支持svn的擴(kuò)展命令,see:http://subversion.tigris.org/faq.html#proxy
          還有種原因,就是可能是你的客戶端使用的是windowsxp,其他版本的windows我沒(méi)試過(guò),也是這樣的錯(cuò)誤,在linux下正常,解決方法不太清楚。
          RA layer request failed svn: MKACTIVITY of 400 Bad Request,無(wú)論什么原因都可以用https代替http來(lái)暫時(shí)解決這樣的問(wèn)題。

          參考:
          http://fanqiang.chinaunix.net/app/web/2005-05-18/3257.shtml
          http://wiki.ubuntu.org.cn/SubVersion?highlight=%28subversion%29

          posted @ 2006-09-05 17:00 Long Long Ago 閱讀(3002) | 評(píng)論 (0)編輯 收藏

          在sources.list中添加如下幾個(gè)源:
          deb?http://www.beerorkid.com/compiz/?dapper?main
          deb?http://xgl.compiz.info/?dapper?main
          deb-src?http://xgl.compiz.info/?dapper?main
          添加代理:
          export?http_proxy="http://xxx.xxx.xxx.xxx:xxxx"
          獲取pgp密鑰:
          wget?http://www.beerorkid.com/compiz/quinn.key.asc?-O?-?|?sudo?apt-key?add?-?

          nivida的驅(qū)動(dòng):
          sudo?apt-get?install?nvidia-kernel-common?nvidia-glx
          編輯文件:/etc/X11/xorg.conf
          在module部分中確定lode xgl,有如下代碼:
          Load?"glx"
          在devices部分修改除了Identifier行的其他各行,修改后如下:
          Section?"Device"
          ????Identifier-?leave?this?line?alone!
          ????Driver????????"nvidia"
          ????BusID????????"PCI:1:0:0"
          ????Option?????????"RenderAccel"?????????"true"
          EndSection
          在最下面添加Extensions部分,代碼如下:
          Section?"Extensions"
          ??????????Option??"Composite"?"Enable"
          EndSection
          下面是安裝必要的庫(kù)文件:
          sudo?apt-get?install?compiz?xserver-xgl?libgl1-mesa?xserver-xorg?libglitz-glx1?compiz-gnome
          以上是引文http://www.ubuntuforums.org/showthread.php?t=131267 中的方法,此文所講的后面是加載方法,我沒(méi)有采用,用的是這里講的方法:http://forum.ubuntu.org.cn/viewtopic.php?t=16777 不過(guò)這里講的安裝方法中少了一個(gè)庫(kù)文件,呵呵
          設(shè)置xgl啟動(dòng)入口:
          新建一個(gè)xgl啟動(dòng)腳本/usr/bin/startxgl.sh,內(nèi)容如下:
          Xgl?-fullscreen?:1?-ac?-accel?glx:pbuffer?-accel?xv:pbuffer?&?sleep?2?&&?DISPLAY=:1
          #?Start?GNOME
          exec?gnome-session?
          使腳本可執(zhí)行: sudo chmod 755 /usr/bin/startxgl.sh
          新建一個(gè)compiz腳本/usr/bin/startcompiz,內(nèi)容如下:
          #!/bin/sh
          killall?gnome-window-decorator
          wait
          gnome-window-decorator?&?LD_PRELOAD=/usr/lib/fglrx/libGL.so.1.2.xlibmesa
          compiz?--replace?gconf?miniwin?decoration?transset?wobbly?fade?minimize?cube?rotate?zoom?scale?move?resize?place?switcher?trailfocus?water?&?
          使得腳本可執(zhí)行:sudo chmod 755 /usr/bin/startcompiz
          在登陸管理器里建一個(gè)XGL會(huì)話: 建立一個(gè)文件/usr/share/xsessions/xgl.desktop ,內(nèi)容如下:
          [Desktop?Entry]
          Encoding=UTF-8
          Name=XGl
          Exec=/usr/bin/startxgl.sh
          Icon=
          Type=Application?

          打開(kāi)桌面菜單-〉系統(tǒng)-〉首選項(xiàng)-〉會(huì)話
          在最右邊的“啟動(dòng)程序”里添加 /usr/bin/startcompiz 這句話
          最后不要忘了

          sudo aptitude update
          sudo aptitude upgrade
          關(guān)閉所有程序
          ctrl-alt-backspace啟動(dòng)X
          登錄時(shí)在會(huì)話中選擇xgl
          會(huì)提示是否為默認(rèn)會(huì)話,建議選擇僅本次
          哦,差點(diǎn)忘了,怎么使用:
          CTRL + ALT + Left/right arrow key. Switches to the new side of the cube for me.

          CTRL + ALT + SHIFT + Left/Right arrow key- Takes the in focused app around cube.

          CTRL + ALT + Left Click on Desktop - allows you to use the mouse to rotate cube.

          F12 - uses the Expose like trick

          Alt- Tab - switcher Vista-style
          看起來(lái)有點(diǎn)暈,尤其是輸入法的浮動(dòng)窗體
          posted @ 2006-08-31 13:03 Long Long Ago 閱讀(922) | 評(píng)論 (3)編輯 收藏

          java.lang.NoClassDefFoundError: com/sun/tools/javac/Main
          最近在使用java的動(dòng)態(tài)編譯的時(shí)候出現(xiàn)的問(wèn)題,主要是由于在使用類(lèi)com.sun.tool.javac.Main時(shí),總是出現(xiàn)NoClassDefFoundError的錯(cuò)誤,后來(lái)找到如下的文章,分析,可能是由于對(duì)于包tools.jar的加載問(wèn)題,雖然我在classpath中聲明了這個(gè)包,但在eclipse環(huán)境下,始終都還是出現(xiàn)運(yùn)行時(shí)異常,對(duì)于編譯時(shí)正確,運(yùn)行時(shí)異常的情況,eclipse一般都是由于其自身的加載機(jī)制造成的.在eclipse下,對(duì)于一般的java工程,只要設(shè)置了系統(tǒng)的classpath,在其中添加了tools.jar包,即可;對(duì)于plugin工程,我是將tools.jar包,直接拷貝到本工程下,并在property中引用,而且在META-INF/MANIFEST.MF文件中的Runtime頁(yè)的classpath中添加了這個(gè)tool.jar包,這樣在運(yùn)行時(shí)就沒(méi)有異常了,可以正常編譯了.

          理解Java?ClassLoader機(jī)制

          Java?ClassLoader

          2006-5-23
          當(dāng)JVM(Java虛擬機(jī))啟動(dòng)時(shí),會(huì)形成由三個(gè)類(lèi)加載器組成的初始類(lèi)加載器層次結(jié)構(gòu):

          ? ? ? ?bootstrap classloader
          ? ? ? ? ? ? ? ? |
          ? ? ? ?extension classloader
          ? ? ? ? ? ? ? ? |
          ? ? ? ?system classloader

          bootstrap classloader -引導(dǎo)(也稱為原始)類(lèi)加載器,它負(fù)責(zé)加載Java的核心類(lèi)。在Sun的JVM中,在執(zhí)行java的命令中使用-Xbootclasspath選項(xiàng)或使用- D選項(xiàng)指定sun.boot.class.path系統(tǒng)屬性值可以指定附加的類(lèi)。這個(gè)加載器的是非常特殊的,它實(shí)際上不是 java.lang.ClassLoader的子類(lèi),而是由JVM自身實(shí)現(xiàn)的。大家可以通過(guò)執(zhí)行以下代碼來(lái)獲得bootstrap classloader加載了那些核心類(lèi)庫(kù):
          ? ?URL[] urls=sun.misc.Launcher.getBootstrapClassPath().getURLs();
          ? ?for (int i = 0; i < urls.length; i++) {
          ? ? ?System.out.println(urls.toExternalform());
          ? ?}
          在我的計(jì)算機(jī)上的結(jié)果為:
          文件:/C:/j2sdk1.4.1_01/jre/lib/endorsed/dom.jar
          文件:/C:/j2sdk1.4.1_01/jre/lib/endorsed/sax.jar
          文件:/C:/j2sdk1.4.1_01/jre/lib/endorsed/xalan-2.3.1.jar
          文件:/C:/j2sdk1.4.1_01/jre/lib/endorsed/xercesImpl-2.0.0.jar
          文件:/C:/j2sdk1.4.1_01/jre/lib/endorsed/xml-apis.jar
          文件:/C:/j2sdk1.4.1_01/jre/lib/endorsed/xsltc.jar
          文件:/C:/j2sdk1.4.1_01/jre/lib/rt.jar
          文件:/C:/j2sdk1.4.1_01/jre/lib/i18n.jar
          文件:/C:/j2sdk1.4.1_01/jre/lib/sunrsasign.jar
          文件:/C:/j2sdk1.4.1_01/jre/lib/jsse.jar
          文件:/C:/j2sdk1.4.1_01/jre/lib/jce.jar
          文件:/C:/j2sdk1.4.1_01/jre/lib/charsets.jar
          文件:/C:/j2sdk1.4.1_01/jre/classes
          這時(shí)大家知道了為什么我們不需要在系統(tǒng)屬性CLASSPATH中指定這些類(lèi)庫(kù)了吧,因?yàn)镴VM在啟動(dòng)的時(shí)候就自動(dòng)加載它們了。

          extension classloader -擴(kuò)展類(lèi)加載器,它負(fù)責(zé)加載JRE的擴(kuò)展目錄(JAVA_HOME/jre/lib/ext或者由java.ext.dirs系統(tǒng)屬性指定的)中JAR的類(lèi)包。這為引入除Java核心類(lèi)以外的新功能提供了一個(gè)標(biāo)準(zhǔn)機(jī)制。因?yàn)槟J(rèn)的擴(kuò)展目錄對(duì)所有從同一個(gè)JRE中啟動(dòng)的JVM都是通用的,所以放入這個(gè)目錄的 JAR類(lèi)包對(duì)所有的JVM和system classloader都是可見(jiàn)的。在這個(gè)實(shí)例上調(diào)用方法getParent()總是返回空值null,因?yàn)橐龑?dǎo)加載器bootstrap classloader不是一個(gè)真正的ClassLoader實(shí)例。所以當(dāng)大家執(zhí)行以下代碼時(shí):
          ? ?System.out.println(System.getProperty("java.ext.dirs"));
          ? ?ClassLoader extensionClassloader=ClassLoader.getSystemClassLoader().getParent();
          ? ?System.out.println("the parent of extension classloader : "+extensionClassloader.getParent());
          結(jié)果為:
          C:\j2sdk1.4.1_01\jre\lib\ext
          the parent of extension classloader : null
          extension classloader是system classloader的parent,而bootstrap classloader是extension classloader的parent,但它不是一個(gè)實(shí)際的classloader,所以為null。

          system classloader -系統(tǒng)(也稱為應(yīng)用)類(lèi)加載器,它負(fù)責(zé)在JVM被啟動(dòng)時(shí),加載來(lái)自在命令java中的-classpath或者java.class.path系統(tǒng)屬性或者 CLASSPATH操作系統(tǒng)屬性所指定的JAR類(lèi)包和類(lèi)路徑??偰芡ㄟ^(guò)靜態(tài)方法ClassLoader.getSystemClassLoader()找到該類(lèi)加載器。如果沒(méi)有特別指定,則用戶自定義的任何類(lèi)加載器都將該類(lèi)加載器作為它的父加載器。執(zhí)行以下代碼即可獲得:
          ? ?System.out.println(System.getProperty("java.class.path"));
          輸出結(jié)果則為用戶在系統(tǒng)屬性里面設(shè)置的CLASSPATH。
          classloader 加載類(lèi)用的是全盤(pán)負(fù)責(zé)委托機(jī)制。所謂全盤(pán)負(fù)責(zé),即是當(dāng)一個(gè)classloader加載一個(gè)Class的時(shí)候,這個(gè)Class所依賴的和引用的所有 Class也由這個(gè)classloader負(fù)責(zé)載入,除非是顯式的使用另外一個(gè)classloader載入;委托機(jī)制則是先讓parent(父)類(lèi)加載器 (而不是super,它與parent classloader類(lèi)不是繼承關(guān)系)尋找,只有在parent找不到的時(shí)候才從自己的類(lèi)路徑中去尋找。此外類(lèi)加載還采用了cache機(jī)制,也就是如果 cache中保存了這個(gè)Class就直接返回它,如果沒(méi)有才從文件中讀取和轉(zhuǎn)換成Class,并存入cache,這就是為什么我們修改了Class但是必須重新啟動(dòng)JVM才能生效的原因。


          每個(gè)ClassLoader加載Class的過(guò)程是:
          1.檢測(cè)此Class是否載入過(guò)(即在cache中是否有此Class),如果有到8,如果沒(méi)有到2
          2.如果parent classloader不存在(沒(méi)有parent,那parent一定是bootstrap classloader了),到4
          3.請(qǐng)求parent classloader載入,如果成功到8,不成功到5
          4.請(qǐng)求jvm從bootstrap classloader中載入,如果成功到8
          5.尋找Class文件(從與此classloader相關(guān)的類(lèi)路徑中尋找)。如果找不到則到7.
          6.從文件中載入Class,到8.
          7.拋出ClassNotFoundException.
          8.返回Class.

          其中5.6步我們可以通過(guò)覆蓋ClassLoader的findClass方法來(lái)實(shí)現(xiàn)自己的載入策略。甚至覆蓋loadClass方法來(lái)實(shí)現(xiàn)自己的載入過(guò)程。

          類(lèi)加載器的順序是:
          先是bootstrap classloader,然后是extension classloader,最后才是system classloader。大家會(huì)發(fā)現(xiàn)加載的Class越是重要的越在靠前面。這樣做的原因是出于安全性的考慮,試想如果system classloader“親自”加載了一個(gè)具有破壞性的“java.lang.System”類(lèi)的后果吧。這種委托機(jī)制保證了用戶即使具有一個(gè)這樣的類(lèi),也把它加入到了類(lèi)路徑中,但是它永遠(yuǎn)不會(huì)被載入,因?yàn)檫@個(gè)類(lèi)總是由bootstrap classloader來(lái)加載的。大家可以執(zhí)行一下以下的代碼:
          ? ?System.out.println(System.class.getClassLoader());
          將會(huì)看到結(jié)果是null,這就表明java.lang.System是由bootstrap classloader加載的,因?yàn)閎ootstrap classloader不是一個(gè)真正的ClassLoader實(shí)例,而是由JVM實(shí)現(xiàn)的,正如前面已經(jīng)說(shuō)過(guò)的。

          下面就讓我們來(lái)看看JVM是如何來(lái)為我們來(lái)建立類(lèi)加載器的結(jié)構(gòu)的:
          sun.misc.Launcher,顧名思義,當(dāng)你執(zhí)行java命令的時(shí)候,JVM會(huì)先使用bootstrap classloader載入并初始化一個(gè)Launcher,執(zhí)行下來(lái)代碼:
          ? System.out.println("the Launcher's classloader is "+sun.misc.Launcher.getLauncher().getClass().getClassLoader());
          結(jié)果為:
          ? the Launcher's classloader is null (因?yàn)槭怯胋ootstrap classloader加載,所以class loader為null)
          Launcher 會(huì)根據(jù)系統(tǒng)和命令設(shè)定初始化好class loader結(jié)構(gòu),JVM就用它來(lái)獲得extension classloader和system classloader,并載入所有的需要載入的Class,最后執(zhí)行java命令指定的帶有靜態(tài)的main方法的Class。extension classloader實(shí)際上是sun.misc.Launcher$ExtClassLoader類(lèi)的一個(gè)實(shí)例,system classloader實(shí)際上是sun.misc.Launcher$AppClassLoader類(lèi)的一個(gè)實(shí)例。并且都是 java.net.URLClassLoader的子類(lèi)。

          讓我們來(lái)看看Launcher初試化的過(guò)程的部分代碼。

          Launcher的部分代碼:
          public class Launcher ?{
          ? ?public Launcher() {
          ? ? ? ?ExtClassLoader extclassloader;
          ? ? ? ?try {
          ? ? ? ? ? ?//初始化extension classloader
          ? ? ? ? ? ?extclassloader = ExtClassLoader.getExtClassLoader();
          ? ? ? ?} catch(IOException ioexception) {
          ? ? ? ? ? ?throw new InternalError("Could not create extension class loader");
          ? ? ? ?}
          ? ? ? ?try {
          ? ? ? ? ? ?//初始化system classloader,parent是extension classloader
          ? ? ? ? ? ?loader = AppClassLoader.getAppClassLoader(extclassloader);
          ? ? ? ?} catch(IOException ioexception1) {
          ? ? ? ? ? ?throw new InternalError("Could not create application class loader");
          ? ? ? ?}
          ? ? ? ?//將system classloader設(shè)置成當(dāng)前線程的context classloader(將在后面加以介紹)
          ? ? ? ?Thread.currentThread().setContextClassLoader(loader);
          ? ? ? ?......
          ? ?}
          ? ?public ClassLoader getClassLoader() {
          ? ? ? ?//返回system classloader
          ? ? ? ?return loader;
          ? ?}
          }

          extension classloader的部分代碼:
          static class Launcher$ExtClassLoader extends URLClassLoader {

          ? ?public static Launcher$ExtClassLoader getExtClassLoader()
          ? ? ? ?throws IOException
          ? ?{
          ? ? ? ?File afile[] = getExtDirs();
          ? ? ? ?return (Launcher$ExtClassLoader)AccessController.doPrivileged(new Launcher$1(afile));
          ? ?}
          ? private static File[] getExtDirs() {
          ? ? ? ?//獲得系統(tǒng)屬性“java.ext.dirs”
          ? ? ? ?String s = System.getProperty("java.ext.dirs");
          ? ? ? ?File afile[];
          ? ? ? ?if(s != null) {
          ? ? ? ? ? ?StringTokenizer stringtokenizer = new StringTokenizer(s, File.pathSeparator);
          ? ? ? ? ? ?int i = stringtokenizer.countTokens();
          ? ? ? ? ? ?afile = new File;
          ? ? ? ? ? ?for(int j = 0; j < i; j++)
          ? ? ? ? ? ? ? ?afile[j] = new File(stringtokenizer.nextToken());

          ? ? ? ?} else {
          ? ? ? ? ? ?afile = new File[0];
          ? ? ? ?}
          ? ? ? ?return afile;
          ? ?}
          }

          system classloader的部分代碼:
          static class Launcher$AppClassLoader extends URLClassLoader
          {

          ? ?public static ClassLoader getAppClassLoader(ClassLoader classloader)
          ? ? ? ?throws IOException
          ? ?{
          ? ? ? ?//獲得系統(tǒng)屬性“java.class.path”
          ? ? ? ?String s = System.getProperty("java.class.path");
          ? ? ? ?File afile[] = s != null ? Launcher.access$200(s) : new File[0];
          ? ? ? ?return (Launcher$AppClassLoader)AccessController.doPrivileged(new Launcher$2(s, afile, classloader));
          ? ?}
          }

          看了源代碼大家就清楚了吧,extension classloader是使用系統(tǒng)屬性“java.ext.dirs”設(shè)置類(lèi)搜索路徑的,并且沒(méi)有parent。system classloader是使用系統(tǒng)屬性“java.class.path”設(shè)置類(lèi)搜索路徑的,并且有一個(gè)parent classloader。Launcher初始化extension classloader,system classloader,并將system classloader設(shè)置成為context classloader,但是僅僅返回system classloader給JVM。

            這里怎么又出來(lái)一個(gè)context classloader呢?它有什么用呢?我們?cè)诮⒁粋€(gè)線程Thread的時(shí)候,可以為這個(gè)線程通過(guò)setContextClassLoader方法來(lái)指定一個(gè)合適的classloader作為這個(gè)線程的context classloader,當(dāng)此線程運(yùn)行的時(shí)候,我們可以通過(guò)getContextClassLoader方法來(lái)獲得此context classloader,就可以用它來(lái)載入我們所需要的Class。默認(rèn)的是system classloader。利用這個(gè)特性,我們可以“打破”classloader委托機(jī)制了,父classloader可以獲得當(dāng)前線程的context classloader,而這個(gè)context classloader可以是它的子classloader或者其他的classloader,那么父classloader就可以從其獲得所需的 Class,這就打破了只能向父classloader請(qǐng)求的限制了。這個(gè)機(jī)制可以滿足當(dāng)我們的classpath是在運(yùn)行時(shí)才確定,并由定制的 classloader加載的時(shí)候,由system classloader(即在jvm classpath中)加載的class可以通過(guò)context classloader獲得定制的classloader并加載入特定的class(通常是抽象類(lèi)和接口,定制的classloader中是其實(shí)現(xiàn)),例如web應(yīng)用中的servlet就是用這種機(jī)制加載的.


          好了,現(xiàn)在我們了解了classloader的結(jié)構(gòu)和工作原理,那么我們?nèi)绾螌?shí)現(xiàn)在運(yùn)行時(shí)的動(dòng)態(tài)載入和更新呢?只要我們能夠動(dòng)態(tài)改變類(lèi)搜索路徑和清除classloader的cache中已經(jīng)載入的Class就行了,有兩個(gè)方案,一是我們繼承一個(gè)classloader,覆蓋loadclass方法,動(dòng)態(tài)的尋找Class文件并使用defineClass方法來(lái);另一個(gè)則非常簡(jiǎn)單實(shí)用,只要重新使用一個(gè)新的類(lèi)搜索路徑來(lái)new一個(gè)classloader就行了,這樣即更新了類(lèi)搜索路徑以便來(lái)載入新的Class,也重新生成了一個(gè)空白的cache(當(dāng)然,類(lèi)搜索路徑不一定必須更改)。噢,太好了,我們幾乎不用做什么工作,java.netURLClassLoader正是一個(gè)符合我們要求的classloader!我們可以直接使用或者繼承它就可以了!

          這是j2se1.4 API的doc中URLClassLoader的兩個(gè)構(gòu)造器的描述:
          URLClassLoader(URL[] urls)
          ? ? ? ? ?Constructs a new URLClassLoader for the specified URLs using the default delegation parent ClassLoader.
          URLClassLoader(URL[] urls, ClassLoader parent)
          ? ? ? ? ?Constructs a new URLClassLoader for the given URLs.
          其中URL[] urls就是我們要設(shè)置的類(lèi)搜索路徑,parent就是這個(gè)classloader的parent classloader,默認(rèn)的是system classloader。


          好,現(xiàn)在我們能夠動(dòng)態(tài)的載入Class了,這樣我們就可以利用newInstance方法來(lái)獲得一個(gè)Object。但我們?nèi)绾螌⒋薕bject造型呢?可以將此Object造型成它本身的Class嗎?

          首先讓我們來(lái)分析一下java源文件的編譯,運(yùn)行吧!javac命令是調(diào)用“JAVA_HOME/lib/tools.jar”中的“com.sun.tools.javac.Main”的compile方法來(lái)編譯:

          ? ?public static int compile(String as[]);

          ? ?public static int compile(String as[], PrintWriter printwriter);

          返回0表示編譯成功,字符串?dāng)?shù)組as則是我們用javac命令編譯時(shí)的參數(shù),以空格劃分。例如:
          javac -classpath c:\foo\bar.jar;. -d c:\ c:\Some.java
          則字符串?dāng)?shù)組as為{"-classpath","c:\\foo\\bar.jar;.","-d","c:\\","c:\\Some.java"},如果帶有PrintWriter參數(shù),則會(huì)把編譯信息出到這個(gè)指定的printWriter中。默認(rèn)的輸出是System.err。

          其中 Main是由JVM使用Launcher初始化的system classloader載入的,根據(jù)全盤(pán)負(fù)責(zé)原則,編譯器在解析這個(gè)java源文件時(shí)所發(fā)現(xiàn)的它所依賴和引用的所有Class也將由system classloader載入,如果system classloader不能載入某個(gè)Class時(shí),編譯器將拋出一個(gè)“cannot resolve symbol”錯(cuò)誤。

          所以首先編譯就通不過(guò),也就是編譯器無(wú)法編譯一個(gè)引用了不在CLASSPATH中的未知Class的java源文件,而由于拼寫(xiě)錯(cuò)誤或者沒(méi)有把所需類(lèi)庫(kù)放到CLASSPATH中,大家一定經(jīng)??吹竭@個(gè)“cannot resolve symbol”這個(gè)編譯錯(cuò)誤吧!

          其次,就是我們把這個(gè)Class放到編譯路徑中,成功的進(jìn)行了編譯,然后在運(yùn)行的時(shí)候不把它放入到CLASSPATH中而利用我們自己的 classloader來(lái)動(dòng)態(tài)載入這個(gè)Class,這時(shí)候也會(huì)出現(xiàn)“java.lang.NoClassDefFoundError”的違例,為什么呢?

          我們?cè)賮?lái)分析一下,首先調(diào)用這個(gè)造型語(yǔ)句的可執(zhí)行的Class一定是由JVM使用Launcher初始化的system classloader載入的,根據(jù)全盤(pán)負(fù)責(zé)原則,當(dāng)我們進(jìn)行造型的時(shí)候,JVM也會(huì)使用system classloader來(lái)嘗試載入這個(gè)Class來(lái)對(duì)實(shí)例進(jìn)行造型,自然在system classloader尋找不到這個(gè)Class時(shí)就會(huì)拋出“java.lang.NoClassDefFoundError”的違例。

          OK,現(xiàn)在讓我們來(lái)總結(jié)一下,java文件的編譯和Class的載入執(zhí)行,都是使用Launcher初始化的system classloader作為類(lèi)載入器的,我們無(wú)法動(dòng)態(tài)的改變system classloader,更無(wú)法讓JVM使用我們自己的classloader來(lái)替換system classloader,根據(jù)全盤(pán)負(fù)責(zé)原則,就限制了編譯和運(yùn)行時(shí),我們無(wú)法直接顯式的使用一個(gè)system classloader尋找不到的Class,即我們只能使用Java核心類(lèi)庫(kù),擴(kuò)展類(lèi)庫(kù)和CLASSPATH中的類(lèi)庫(kù)中的Class。

          還不死心!再嘗試一下這種情況,我們把這個(gè)Class也放入到CLASSPATH中,讓system classloader能夠識(shí)別和載入。然后我們通過(guò)自己的classloader來(lái)從指定的class文件中載入這個(gè)Class(不能夠委托 parent載入,因?yàn)檫@樣會(huì)被system classloader從CLASSPATH中將其載入),然后實(shí)例化一個(gè)Object,并造型成這個(gè)Class,這樣JVM也識(shí)別這個(gè)Class(因?yàn)?system classloader能夠定位和載入這個(gè)Class從CLASSPATH中),載入的也不是CLASSPATH中的這個(gè)Class,而是從 CLASSPATH外動(dòng)態(tài)載入的,這樣總行了吧!十分不幸的是,這時(shí)會(huì)出現(xiàn)“java.lang.ClassCastException”違例。

          為什么呢?我們也來(lái)分析一下,不錯(cuò),我們雖然從CLASSPATH外使用我們自己的classloader動(dòng)態(tài)載入了這個(gè)Class,但將它的實(shí)例造型的時(shí)候是JVM會(huì)使用system classloader來(lái)再次載入這個(gè)Class,并嘗試將使用我們的自己的classloader載入的Class的一個(gè)實(shí)例造型為system classloader載入的這個(gè)Class(另外的一個(gè))。大家發(fā)現(xiàn)什么問(wèn)題了嗎?也就是我們嘗試將從一個(gè)classloader載入的Class的一個(gè)實(shí)例造型為另外一個(gè)classloader載入的Class,雖然這兩個(gè)Class的名字一樣,甚至是從同一個(gè)class文件中載入。但不幸的是JVM 卻認(rèn)為這個(gè)兩個(gè)Class是不同的,即JVM認(rèn)為不同的classloader載入的相同的名字的Class(即使是從同一個(gè)class文件中載入的)是不同的!這樣做的原因我想大概也是主要出于安全性考慮,這樣就保證所有的核心Java類(lèi)都是system classloader載入的,我們無(wú)法用自己的classloader載入的相同名字的Class的實(shí)例來(lái)替換它們的實(shí)例。

          看到這里,聰明的讀者一定想到了該如何動(dòng)態(tài)載入我們的Class,實(shí)例化,造型并調(diào)用了吧!

          那就是利用面向?qū)ο蟮幕咎匦灾坏亩嘈涡?。我們把我們?dòng)態(tài)載入的Class的實(shí)例造型成它的一個(gè)system classloader所能識(shí)別的父類(lèi)就行了!這是為什么呢?我們還是要再來(lái)分析一次。當(dāng)我們用我們自己的classloader來(lái)動(dòng)態(tài)載入這我們只要把這個(gè)Class的時(shí)候,發(fā)現(xiàn)它有一個(gè)父類(lèi)Class,在載入它之前JVM先會(huì)載入這個(gè)父類(lèi)Class,這個(gè)父類(lèi)Class是system classloader所能識(shí)別的,根據(jù)委托機(jī)制,它將由system classloader載入,然后我們的classloader再載入這個(gè)Class,創(chuàng)建一個(gè)實(shí)例,造型為這個(gè)父類(lèi)Class,注意了,造型成這個(gè)父類(lèi) Class的時(shí)候(也就是上溯)是面向?qū)ο蟮膉ava語(yǔ)言所允許的并且JVM也支持的,JVM就使用system classloader再次載入這個(gè)父類(lèi)Class,然后將此實(shí)例造型為這個(gè)父類(lèi)Class。大家可以從這個(gè)過(guò)程發(fā)現(xiàn)這個(gè)父類(lèi)Class都是由 system classloader載入的,也就是同一個(gè)class loader載入的同一個(gè)Class,所以造型的時(shí)候不會(huì)出現(xiàn)任何異常。而根據(jù)多形性,調(diào)用這個(gè)父類(lèi)的方法時(shí),真正執(zhí)行的是這個(gè)Class(非父類(lèi) Class)的覆蓋了父類(lèi)方法的方法。這些方法中也可以引用system classloader不能識(shí)別的Class,因?yàn)楦鶕?jù)全盤(pán)負(fù)責(zé)原則,只要載入這個(gè)Class的classloader即我們自己定義的 classloader能夠定位和載入這些Class就行了。

          這樣我們就可以事先定義好一組接口或者基類(lèi)并放入CLASSPATH中,然后在執(zhí)行的時(shí)候動(dòng)態(tài)的載入實(shí)現(xiàn)或者繼承了這些接口或基類(lèi)的子類(lèi)。還不明白嗎?讓我們來(lái)想一想Servlet吧,web application server能夠載入任何繼承了Servlet的Class并正確的執(zhí)行它們,不管它實(shí)際的Class是什么,就是都把它們實(shí)例化成為一個(gè)Servlet Class,然后執(zhí)行Servlet的init,doPost,doGet和destroy等方法的,而不管這個(gè)Servlet是從web- inf/lib和web-inf/classes下由system classloader的子classloader(即定制的classloader)動(dòng)態(tài)載入。說(shuō)了這么多希望大家都明白了。在applet,ejb等容器中,都是采用了這種機(jī)制.

          對(duì)于以上各種情況,希望大家實(shí)際編寫(xiě)一些example來(lái)實(shí)驗(yàn)一下。

          最后我再說(shuō)點(diǎn)別的, classloader雖然稱為類(lèi)加載器,但并不意味著只能用來(lái)加載Class,我們還可以利用它也獲得圖片,音頻文件等資源的URL,當(dāng)然,這些資源必須在CLASSPATH中的jar類(lèi)庫(kù)中或目錄下。我們來(lái)看API的doc中關(guān)于ClassLoader的兩個(gè)尋找資源和Class的方法描述吧:
                  public URL getResource(String name)
                  用指定的名字來(lái)查找資源,一個(gè)資源是一些能夠被class代碼訪問(wèn)的在某種程度上依賴于代碼位置的數(shù)據(jù)(圖片,音頻,文本等等)。
          ? ? ? ? ? ? ? ?一個(gè)資源的名字是以'/'號(hào)分隔確定資源的路徑名的。
          ? ? ? ? ? ? ? ?這個(gè)方法將先請(qǐng)求parent classloader搜索資源,如果沒(méi)有parent,則會(huì)在內(nèi)置在虛擬機(jī)中的classloader(即bootstrap classloader)的路徑中搜索。如果失敗,這個(gè)方法將調(diào)用findResource(String)來(lái)尋找資源。
                  public static URL getSystemResource(String name)
          ? ? ? ? ? ? ? ?從用來(lái)載入類(lèi)的搜索路徑中查找一個(gè)指定名字的資源。這個(gè)方法使用system class loader來(lái)定位資源。即相當(dāng)于ClassLoader.getSystemClassLoader().getResource(name)。

          例如:
          ? ?System.out.println(ClassLoader.getSystemResource("java/lang/String.class"));
          的結(jié)果為:
          ? ?jar:文件:/C:/j2sdk1.4.1_01/jre/lib/rt.jar!/java/lang/String.class
          表明String.class文件在rt.jar的java/lang目錄中。
          因此我們可以將圖片等資源隨同Class一同打包到j(luò)ar類(lèi)庫(kù)中(當(dāng)然,也可單獨(dú)打包這些資源)并添加它們到class loader的搜索路徑中,我們就可以無(wú)需關(guān)心這些資源的具體位置,讓class loader來(lái)幫我們尋找了!
          posted @ 2006-08-20 17:28 Long Long Ago 閱讀(12607) | 評(píng)論 (5)編輯 收藏

          最近做的gef編輯器在刪除時(shí)遇到了一些問(wèn)題,就是不能通過(guò)delete鍵刪除,到處搜集資料,解決了,
          首先需要在相應(yīng)rcp工程中的ActionBarAdviser類(lèi)中注冊(cè)相應(yīng)的Action,比如對(duì)應(yīng)于deleteAction,我在方法org.eclipse.ui.application.ActionBarAdvisor#makeAction(IWorkbenchWindow)中注冊(cè)deleteAction,如下:
          protected?void?makeAction(final?IWorkbenchWindow?window){
          ????IAction?delAction?
          =?ActionFactory.DELETE.create(window);
          ????register(delAction);
          }


          只是這么設(shè)置還是不能刪除相應(yīng)的圖形元素,需要在相應(yīng)的編輯器中重載init方法,添加如下的代碼
          public?void?init(IEditorSite?site,?IEditorInput?input)?throws?PartInitException?{
          ????
          //?TODO?Auto-generated?method?stub
          ????super.init(site,?input);
          ????ActionRegistry?registry?
          =?getActionRegistry();
          ????IActionBars?bar?
          =?site.getActionBars();
          ????String?id?
          =?ActionFactory.DELETE.getId();
          ????bar.setGlobalActionHandler(id,registry.getAction(id));
          ????bar.updateActionBars();
          }

          在這里仔細(xì)研究會(huì)發(fā)現(xiàn),在第一段代碼中實(shí)際上時(shí)創(chuàng)建了一個(gè)action,這是一個(gè)RetargetAction,而在super.init()方法會(huì)調(diào)用一個(gè)createAction方法,這里創(chuàng)建的是gef默認(rèn)的redoAction?undoAction selectionAction deleteAction saveAction.需要注意的是RetargetAction是一種可以跟蹤當(dāng)前活動(dòng)的部分,由于retargetAction含有一個(gè)id,如果這個(gè)活動(dòng)部分提供的handler的id和retargetAction的id相同,那么相應(yīng)的對(duì)retargetAction的調(diào)用就轉(zhuǎn)嫁成對(duì)當(dāng)前這個(gè)活動(dòng)部分的handle的調(diào)用,(當(dāng)然如果根本就沒(méi)有handle,那么這個(gè)action會(huì)disable).所以,我們可以看出來(lái),這個(gè)retargetAction會(huì)在gef編輯器激活后調(diào)用gef的deleteAction.
          posted @ 2006-08-19 17:35 Long Long Ago 閱讀(1209) | 評(píng)論 (0)編輯 收藏

          http://www.approc.com/

          [Java|Eclipse|GEF]Figure是如何定位和設(shè)置大???

          有兩種會(huì)創(chuàng)建圖元:
          1、打開(kāi)圖形文件時(shí),先會(huì)創(chuàng)建所有的model,這樣圖元的定位和設(shè)置大小是依據(jù)圖元model的size和location屬性,通過(guò)圖元EditPart.refreshVisuals()來(lái)設(shè)置的
          2、通過(guò)拖放托盤(pán)里面的圖標(biāo)來(lái)建立的圖元,會(huì)先設(shè)置model的size,然后通過(guò)model對(duì)應(yīng)的figure.setPreferredSize()來(lái)設(shè)置了,而location則是通過(guò)鼠標(biāo)的位置來(lái)確定的
          posted @ 2006-08-14 11:18 Long Long Ago 閱讀(688) | 評(píng)論 (0)編輯 收藏

          http://www.approc.com/
          現(xiàn)在在3.1里面訪問(wèn)資源文件變得比較簡(jiǎn)單了,用戶可以通過(guò)繼承osgi.util.NLS,典型例子:
          public?class?MsgBoundle?extends?NLS{
          ??????
          private?final?static?String?BOUNDLE_NAME?
          ???????????????????????
          =?"resource.msg";
          ??????
          public?static?String?mo_1;
          ??????
          public?static?String?mo_2;

          ??????
          static{
          ?????????NLS.initializeMessage(BOUNDLE_NAME,
          ???????????????????????MsgBoundle.
          class);
          ??????}

          }


          好啦,現(xiàn)在就可以建立資源文件了,文件應(yīng)該建在哪里呢?跟蹤代碼發(fā)現(xiàn),這個(gè)由BOUNDLE_NAME決定,在MessageResourceBoundle.buildVariants()中,會(huì)將BOUNDLE_NAME中的“."替換成"/",然后再根據(jù)地區(qū)設(shè)定組合幾種不同的資源文件名稱,比如我的就是:

          1、resource/msg_zh_CN.properties
          2、resource/msg_zh.properties
          3、resource/msg.properties
          注意:這三個(gè)文件是有順序的哦

          然后通過(guò)EclipseClassLoader.getResource()來(lái)查找這些文件,并將文件中的值賦予給MsgBoundle對(duì)應(yīng)的成員變量。
          posted @ 2006-08-14 11:16 Long Long Ago 閱讀(845) | 評(píng)論 (0)編輯 收藏

          在linux(ubuntu)下引入了在windows工作時(shí)建立的一個(gè)pluginProject,但是發(fā)現(xiàn),在plugin.xml中require包都沒(méi)有了,在3.0以后這些require都是放在MANIFEST.MF文件中的,這兩個(gè)文件是同步的,即在編輯plugin.xml文件視圖時(shí)會(huì)看到MANIFEST.MF文件中的require,不過(guò)在從windows引入后就看不到了,不過(guò)這是發(fā)現(xiàn)MANIFEST.MF和他所在的目錄META-INF都變成了小寫(xiě),改成大寫(xiě)后,再u(mài)pdate classpath就可以了。
          posted @ 2006-07-19 10:26 Long Long Ago 閱讀(353) | 評(píng)論 (0)編輯 收藏

          http://dev.eclipse.org/mhonarc/lists/gef-dev/msg00183.html
          Ask:
          How to add a double click event or Request on a figure?when double click on a figure, a dialog pop up and do some actions.for example when double click on
          a UML class figure, a dialog pop up, user can Add a method to the class.
          Answer:
          This is already done in GEF. Your editpart will receive a performRequest(req) with the type RequestConstants.REQ_OPEN.
          See SelectEditPartTRacker#performOpen()

          -randy
          就是在figure對(duì)應(yīng)的editpart中重載方法performRequest(Request req),并判斷req的type是否為RequestConstants.REQ_OPEN,如果是,則處理這個(gè)雙擊事件.
          這個(gè)方法是個(gè)回調(diào)方法,在SelectEditPartTRacker#performOpen() 中調(diào)用的.
          posted @ 2006-06-08 22:21 Long Long Ago 閱讀(1390) | 評(píng)論 (0)編輯 收藏

          在GEF中一個(gè)容器圖形,其中可以盛放其他圖形,但我在實(shí)現(xiàn)是總是在坐標(biāo)計(jì)算上出問(wèn)題,就是其子圖形的坐標(biāo)并不是相對(duì)于此容器的坐標(biāo),而是畫(huà)布的坐標(biāo),后來(lái)參考了Logical的例子,發(fā)現(xiàn)它在org.eclipse.gef.examples.logicdesigner.figures.CircuitFigure類(lèi)中重載了useLocalCoordinates方法,返回了true(默認(rèn)是false),在我的容器圖形(繼承于org.eclipse.draw2d.Figure)也重載這個(gè)函數(shù),子圖形的坐標(biāo)問(wèn)題就解決了.
          posted @ 2006-05-15 14:04 Long Long Ago 閱讀(731) | 評(píng)論 (0)編輯 收藏

          獲得插件的絕對(duì)路徑:
          ????/**
          ?????*?得到插件的絕對(duì)路徑
          ?????*?
          ?????*?
          @return?路徑
          ?????
          */

          ????
          public?static?String?getPath()?{
          ????????String?path;
          ????????
          try?{
          ????????????path?
          =?FileLocator.toFileURL(
          ????????????????????Platform.getBundle(pluginId).getEntry(
          "")).getPath();
          ????????????path?
          =?path.substring(path.indexOf("/")?+?1,?path.length());
          ????????}
          ?catch?(IOException?e)?{
          ????????????path?
          =?"";
          ????????????e.printStackTrace();
          ????????}

          ????????
          return?path;
          ????}
          其中FileLocator#toFileURL是在3.2中添加的,代替了原來(lái)的Platform#asLocalURL,并且對(duì)于FileLocator#toFileURL,if the plugin was a jar, it will extract the file into a temporary location
          posted @ 2006-05-01 22:45 Long Long Ago 閱讀(780) | 評(píng)論 (0)編輯 收藏

               摘要: http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=125&threadID=27195 Design Pattern Practice 1.序 本文從一個(gè)簡(jiǎn)單的多列排序的例子入手,由淺入深地講解Design Pattern(設(shè)計(jì)模式)的目的、分析和實(shí)踐。 文中的例子用到Compositor Pattern和Decora...  閱讀全文
          posted @ 2006-04-24 09:23 Long Long Ago 閱讀(442) | 評(píng)論 (0)編輯 收藏

          上文提到的GEF工作過(guò)程中還有一些不太詳細(xì)的地方,這里做些補(bǔ)充。
          再GEF中UI的操作交互都是通過(guò)構(gòu)建Request,并調(diào)用EditPart中的API來(lái)完成相應(yīng)的操作,這些API可以分為四類(lèi):
          1。??EditPart getTargetEditPart(Request)
          ???boolean understandsRequest(Request)
          再我們進(jìn)行交互操作時(shí),首先要確定激活的是那個(gè)EditPart,經(jīng)常是一個(gè)當(dāng)前被選中的viewer和通過(guò)單擊選擇的EditPart的復(fù)合體。這個(gè)被選擇的部件通過(guò)詢問(wèn)每個(gè)被選擇的EditPart是否處理這個(gè)request(通過(guò)understandsRequest方法)。那個(gè)在鼠標(biāo)單擊確定的EditPart是通過(guò)viewer的幫助和getTargetEditPart方法來(lái)找到的。并不是所有的交互都有target。
          2。
          void showSourceFeedback(Request)
          void eraseSourceFeedback(Request)
          void showTargetFeedback(Request)
          void eraseTargetFeedback(Request)

          在我們的交互操作特別是托拽圖形時(shí),就需要EditPart來(lái)回顯(Feedback),托拽源被認(rèn)為是起作用的那個(gè)editpart,目的部件被認(rèn)為是鼠標(biāo)的目的地。showXXXFeedback可能是在鼠標(biāo)移到目的地,但未作用于目的part時(shí)調(diào)用,eraseXXXFeedback則可能是在鼠標(biāo)作用于目的part后調(diào)用的。
          3。Command getCommand(Request)
          這個(gè)方法用于獲得可執(zhí)行的命令列表,命令可以對(duì)模型進(jìn)行操作,Editpart通過(guò)request詢問(wèn)Editpolicy來(lái)獲得相應(yīng)的command列表。同時(shí)command也可以判斷這個(gè)交互操作是否時(shí)可能的。如果沒(méi)有command或者command不能執(zhí)行,則ui會(huì)指出這個(gè)操作是不能執(zhí)行的(鼠標(biāo)變成禁止操作的樣子)。如果一個(gè)editpart返回null作為command則它不會(huì)阻止這個(gè)交互操作,除非沒(méi)有一個(gè)command被提供。為了指示某個(gè)操作是不能執(zhí)行的則EditPart需要返回一個(gè)不能執(zhí)行的command。
          4。void performRequest(Request)
          還有一種API,它讓EditPart去do something,可能是一些并不會(huì)立即就改變model的改變,比如打開(kāi)對(duì)話框或者激活直接編輯模式。

          ??????? EditPart并不直接進(jìn)行編輯,它將操作委托給EditPolicy,每個(gè)EditPolicy專著于一種編輯任務(wù)或者一組相關(guān)的操作。當(dāng)上面的API被調(diào)用后(除了performRequest方法),EditPart便委托給它的EditPolicy來(lái)處理這個(gè)request。對(duì)于不同的方法,EditPart可能是在第一個(gè)能處理request的policy處就停止調(diào)用了或者每個(gè)policy都有機(jī)會(huì)執(zhí)行這個(gè)request。GEF提供了幾個(gè)默認(rèn)的policy,不過(guò)還是需要實(shí)現(xiàn)其中的一些特定方法。

          ???????? 這里再?gòu)U話一點(diǎn),在注冊(cè)相應(yīng)的EditPolicy時(shí),需要指定Role,這是一個(gè)字符串,用來(lái)標(biāo)示這個(gè)EditPolicy,相同的Role對(duì)應(yīng)的EditPolicy會(huì)被替換,例如子類(lèi)可以通過(guò)Role這個(gè)Key來(lái)覆蓋其父類(lèi)所安裝的EditPolicy。EditPolicy(Role)分成兩種類(lèi)型,一種是圖形的,一種是非圖形的,上文中有提到,這里詳細(xì)的描述一下:
          Non-Graphical Roles:
          1) COMPONENT_ROLE: 一個(gè)Component存在于一個(gè)parent中,并且可以從parent中刪除。更為一般的,它可以使任何只涉及到這個(gè)EditPart,而與View無(wú)關(guān)的東西。(More generally, it is anything that involves only this EditPart.)
          2) CONNECTION_ROLE 這是ConnectionEditParts應(yīng)該有的一個(gè)基本角色。Connections同Components有一點(diǎn)不同,刪除Connections時(shí)通常還需要其從其source和target節(jié)點(diǎn)中刪除,而不是從其parent中刪除。
          3) CONTAINER_ROLE 大部分擁有children的EditParts都應(yīng)該具有這個(gè)角色。一個(gè)Container會(huì)涉及到adds/orphans以及creates/deletes等操作。
          4) NODE_ROLE 如果一個(gè)EditParts用戶Connection,則其應(yīng)該具有這個(gè)角色,它可以用來(lái)創(chuàng)建,刪除,重新連接一個(gè)Connection。
          Graphical Roles:
          1) PRIMARY_DRAG_ROLE: 用來(lái)允許用戶拖動(dòng)這個(gè)EditPart。用戶可以通過(guò)點(diǎn)擊這個(gè)EditPart然后拖動(dòng),或者點(diǎn)擊這個(gè)EditPart所創(chuàng)建的一個(gè)Handle來(lái)進(jìn)行拖動(dòng)。
          2) LAYOUT_ROLE: Layout角色用來(lái)放在一個(gè)Container的EditPart上,這個(gè)EditPart擁有一個(gè)graphical layout。如果這個(gè)layout有constraints,則它需要通過(guò)計(jì)算來(lái)得到這個(gè)constraints。
          3) GRAPHICAL_NODE_ROLE: A node supports connections to terminals. When creating and manipulating connections, EditPolicies with this role might analyze a Request's data to perform "hit testing" on the graphical view and determine the semantics of the connection. 用于支持連接到重點(diǎn)的node,當(dāng)創(chuàng)建、操作連接時(shí),包含這個(gè)Role的Editpolicy會(huì)分析request的數(shù)據(jù),來(lái)在圖形view上做“hit testing”,并且判斷這個(gè)connection的語(yǔ)義。
          4) CONNECTION_ENDPOINTS_ROLE: 這個(gè)Role允許用戶拖動(dòng)一個(gè)ConnectionEditPart的端點(diǎn)。
          5) CONNECTION_BENDPOINTS_ROLE: 這個(gè)Role允許用戶能夠在一個(gè)Connection中間拖動(dòng)和創(chuàng)建bendpoints。
          6) SELECTION_FEEDBACK_ROLE: 這個(gè)角色只是用來(lái)顯示feedback。當(dāng)鼠標(biāo)進(jìn)入或者在一個(gè)EditPart上暫停時(shí),Selection Tool會(huì)發(fā)送兩個(gè)類(lèi)型的request給EditPart。安裝了這個(gè)角色的EditPart能夠在此時(shí)接受這些請(qǐng)求來(lái)改變view的樣子,或者彈出tip,label等。
          7) TREE_CONTAINER_ROLE: SWT Tree的Layout Role。 本地SWT Tree的Layout Role的等價(jià)物。這個(gè)EditPolicy應(yīng)該在樹(shù)上顯示反饋并計(jì)算索引,就像在file explorer里拖拽一樣。
          over。

          posted @ 2006-04-09 14:38 Long Long Ago 閱讀(767) | 評(píng)論 (0)編輯 收藏

          ??????? GEF中的起到關(guān)鍵作用的是EditPart,而EditPart中起到關(guān)鍵作用的是EditPolicy,現(xiàn)在來(lái)描述一下GEF是如何創(chuàng)建一個(gè)圖形并顯示顯示出來(lái)的。
          ??????? 首先通過(guò)單擊調(diào)色板,會(huì)調(diào)用一個(gè)實(shí)現(xiàn)org.eclipse.gef.requests.CreationFactory接口的工廠類(lèi),這個(gè)是我們?cè)谧?cè)相應(yīng)的ToolEntry時(shí)聲明的,通過(guò)傳入的參數(shù)這個(gè)工廠類(lèi)就知道應(yīng)該創(chuàng)建一個(gè)什么類(lèi)型的model元素。(注意,這時(shí)候因?yàn)槲覀冎皇羌儎?chuàng)建了一個(gè)模型元素,對(duì)于它的父元素,位置信息等等都還不清楚,所以一般我們?cè)谠O(shè)置模型元素的構(gòu)造函數(shù)時(shí)需要有個(gè)無(wú)參數(shù)的構(gòu)造方法(或者有默認(rèn)參數(shù)的構(gòu)造函數(shù))。)
          ??????? 當(dāng)單擊畫(huà)布上的某個(gè)位置后,相應(yīng)的信息比如 模型的父元素,位置信息等等都已經(jīng)可以確定,將這些信息以及新創(chuàng)建的模型元素本身包裝成request傳給相應(yīng)的EditPart(就是鼠標(biāo)單擊處所在的圖形元素對(duì)應(yīng)的EditPart)。
          ??????? 這個(gè)EditPart會(huì)將這個(gè)request傳給相應(yīng)的EditPolicy(至于怎么傳遞,還不清楚,估計(jì)是這樣的,EditPart會(huì)傳給注冊(cè)在其上的所有EditPolicy,而每個(gè)EditPolicy都有個(gè)getCommand方法,通過(guò)request的type交給相應(yīng)的getXXXCommand方法。查看了一下源代碼,發(fā)現(xiàn)在AbastractEditPart中有個(gè)getCommand方法正是將每個(gè)EditPolicy中的getCommand方法都調(diào)用了一遍)。
          ???????然后EditPolicy處理相應(yīng)的request,具體的就是調(diào)用getXXXCommad方法得到處理相應(yīng)request的Command,Command是可以改變模型。上面提到的這種EditPolicy屬于NonGraphical類(lèi)型,GEF中還包括了一種稱為Graphical類(lèi)型的EditPolicy,這種EditPolicy不對(duì)模型進(jìn)行處理,只是用來(lái)修改圖形顯示(似乎這種說(shuō)法不正確,它可以更改視圖元素的位置,在業(yè)務(wù)模型和視圖模型統(tǒng)一的情況下,這種圖形EditPolicy也會(huì)更改模型);而NonGraphical的EditPolicy則是不清楚圖形元素的,但它可以對(duì)模型進(jìn)行更改,因此這種EditPolicy在不同view之間是可以通用的。
          ?????? 當(dāng)模型發(fā)生改變后,注冊(cè)再其上的EditPart將會(huì)得到相應(yīng)的通知,此時(shí),通過(guò)通知中的property信息,EditPart會(huì)refreshVisual或者refreshChildren,從而使視圖發(fā)生改變。
          posted @ 2006-04-09 12:33 Long Long Ago 閱讀(638) | 評(píng)論 (0)編輯 收藏

          最近在用javasvn做一個(gè)svn的管理程序,用rcp實(shí)現(xiàn),在實(shí)現(xiàn)過(guò)程中發(fā)現(xiàn),如果只是單純的用java程序?qū)崿F(xiàn)目錄列表的時(shí)候,一切正常,但使用rcp后始終出錯(cuò),認(rèn)證錯(cuò)誤,觀察javasvn源代碼后發(fā)現(xiàn),在定義認(rèn)證manager的時(shí)候javasvn會(huì)檢測(cè)是否在使用eclipse,如果是,則定義一個(gè)eclipseAuth××manger,后來(lái)修改了相應(yīng)的代碼,不調(diào)用那個(gè)檢測(cè)是否為eclipse的方法后就ok了,估計(jì)是在eclipse中使用javasvn會(huì)有特殊性,故加了此段代碼,不過(guò)簡(jiǎn)單的rcp是不需要的。

          posted @ 2006-03-23 11:22 Long Long Ago 閱讀(801) | 評(píng)論 (1)編輯 收藏

          Draw2D學(xué)習(xí)
          Draw2D is a lightweight system.輕量級(jí)系統(tǒng),指這個(gè)繪圖系統(tǒng)全部建立在一個(gè)重量級(jí)的控件上。對(duì)于Draw2D他是建立在SWT的Canvas上的。
          Draw2D的幾個(gè)部分
          1.figures
          主要功能:
             1。給一個(gè)figure注冊(cè)和去注冊(cè)監(jiān)聽(tīng)器。這個(gè)figure會(huì)通知在這個(gè)figure中的鼠標(biāo)時(shí)間給監(jiān)聽(tīng)器。
             2。結(jié)構(gòu)化的事件。比如figure層次的結(jié)構(gòu)化變化,figure的移動(dòng)和大小調(diào)整。
             3。當(dāng)光標(biāo)從figure上移過(guò)時(shí),光標(biāo)的改變和顯示。
             4。在figure的層次中操作figure的位置,包括添加移除訪問(wèn)子節(jié)點(diǎn),或者訪問(wèn)他們的父節(jié)點(diǎn)。
             5。存取:figure的layout manager;figure的size和location;還有tooltips。
             6。設(shè)置獲得焦點(diǎn)。
             7。設(shè)置figure的透明度和可視性。
             8。進(jìn)行坐標(biāo)變換,figure的交疊和碰撞檢測(cè)。
             9。繪制。
             10。確認(rèn)。
          figure有很多subclass,提供了很多附加的功能。比如
            1。shape,它包含了非矩形的figure,可以知道如何填充,并提供了對(duì)邊界的寬和類(lèi)型的配置,并提供了異或的繪制方法。比如有橢圓,幾何線,多邊形,矩形,圓角矩形和三角形。
            2。widget,draw2d包含的figure允許你創(chuàng)建輕量級(jí)(lightweight)的部件(widget),從而在你的draw2d應(yīng)用程序中需要輸入控制時(shí)提供支持。這包含大量的按鈕,選擇框和文本圖形,標(biāo)簽。
            3。layer and pane,這些使用來(lái)作為子類(lèi)的容器,他們提供了縮放,滾動(dòng)和講figure放置在不同layer上的能力。
          圖形上下文(the graphics context)
            當(dāng)一個(gè)figuer需要被繪制的時(shí)候輕量系統(tǒng)會(huì)調(diào)用fiuger的一個(gè)paint方法。每一個(gè)figure都會(huì)得到一個(gè)graphical context,他是Graphics的一個(gè)實(shí)例。作為參數(shù)傳給paint方法。這個(gè)繪圖上下文支持圖形操作包括繪制,填充圖形繪制它的文字。它也提供了圖形的狀態(tài),這些可以影響圖形操作。這些狀態(tài)包括當(dāng)前字體,背景前景顏色等等。
          2.LightweightSystem
          LightweightSystem時(shí)draw2d的核心。它提供了SWT Canvas控件和在其上建立的draw2d系統(tǒng)之間的映射。包含三個(gè)方面:
            1。the root figure.這個(gè)是LightweightSystem$RootFigure類(lèi)的一個(gè)實(shí)例。這個(gè)是用戶的root figure的父類(lèi)。它繼承了一些基于SWT Canvas的圖形環(huán)境,比如字體,前景背景顏色。
            2。the event dispatcher:SWTEventDispatcher類(lèi)將SWT事件傳給Draw2D的root figure中相應(yīng)的部件。
            3。the update manager.它負(fù)責(zé)繪制并更新Draw2dfigure。當(dāng)一個(gè)繪制請(qǐng)求從下層的SWTcanvas傳來(lái)時(shí),LightWeightSystem將會(huì)調(diào)用updatemanager中的performUpdate方法。update manager將會(huì)維護(hù)一個(gè)非法的或者需要重畫(huà)的figure的worklist。upate manager會(huì)設(shè)法盡量連續(xù)的它的work list,這樣可以盡量的提高效率。默認(rèn)的update manager:DaferredUpdateManager允許通過(guò)再Display上的用戶線程來(lái)使工作隊(duì)列異步的更新。
          對(duì)于一個(gè)figure的生存周期中,繪制(painting)和確認(rèn)(validating)是主要的處理過(guò)程。draw2d會(huì)要求一個(gè)figure,調(diào)用繪制方法來(lái)遞歸的繪制自己。paint()方法會(huì)調(diào)用多個(gè)繪制方法:
            1。paintFigure():figure遞歸的繪制自己
            2。paintclientarea(): figure遞歸的繪制子圖
            3。paintborder():figure繪制邊界。
           當(dāng)一個(gè)figure的size或者location需要重新計(jì)算時(shí),將會(huì)調(diào)用確認(rèn)。
            1。validate():要求figure的layout manager去重新布局它的子圖
            2。revalidate():調(diào)用invalidate;添加一個(gè)圖形和它的祖先去更新update manager的invalid list。
          posted @ 2006-02-23 22:40 Long Long Ago 閱讀(1076) | 評(píng)論 (0)編輯 收藏


          現(xiàn)在來(lái)討論一下emf所生成的幾個(gè)plugin。一般通過(guò)ecore模型可以生成三個(gè)插件分別是emf模型,emf.edit和emf.editor。
          讓我們現(xiàn)在看模型插件
              對(duì)于所有的EPackage,都會(huì)生成兩個(gè)或三個(gè)java package,本別是base package(*),implemention package(*.impl),tool package(*.util)。其中,第三個(gè)包是可選的,這取決于生成屬性的設(shè)置,默認(rèn)是生成。包名(*)也是在生成屬性中設(shè)置的。
              對(duì)于所有EClass,在base package中生成相應(yīng)的interface,而其java實(shí)現(xiàn)則在impl包中,如果一個(gè)EClass繼承于另一個(gè)EClass,那么生成的interface和implemention都繼承于相應(yīng)的超類(lèi)的interface和implemention。如果這個(gè)類(lèi)有多個(gè)超類(lèi),那么在eSuperTypes中的第一個(gè)class將作為主超類(lèi)(primary supertype)。對(duì)于這個(gè)子類(lèi)的實(shí)現(xiàn)它將繼承主超類(lèi)的實(shí)現(xiàn),并且實(shí)現(xiàn)其他超類(lèi)接口中的方法。
              對(duì)于Feature,getter和setter方法在類(lèi)和接口中被定義。如果一個(gè)一個(gè)feature(成員變量)不是volatile,那么它的值會(huì)被存儲(chǔ)在一個(gè)量值(field)中。如果一個(gè)feature是只讀的,那么只生成它對(duì)應(yīng)的getter方法。對(duì)于多值屬性一般使用EList表示,而單值就用那個(gè)屬性的類(lèi)型表示。EList的類(lèi)型取決于模型的約束,例如,一個(gè)non-containment reference將會(huì)使用EObjectWithInverseResolvingEList,對(duì)于一個(gè)containment reference將會(huì)使用EObjectContainmentWithInverseEList表示。
              對(duì)于Operation,在包含類(lèi)(containing class)的接口中生成一個(gè)公共方法標(biāo)簽,在對(duì)應(yīng)的實(shí)現(xiàn)中生成實(shí)現(xiàn)骨架。
              對(duì)于DataType,其中EEnum產(chǎn)生于一個(gè)繼承了org.eclipse.common.util.AbstractEnumerator的實(shí)現(xiàn)。對(duì)于其他的EDataType,是沒(méi)有接口和實(shí)現(xiàn)生成的,它們的實(shí)例化類(lèi)就是直接使用了EAttribute的類(lèi)型。
          再來(lái)看看edit插件:
              對(duì)于edit插件provider package中的所有類(lèi)都有相應(yīng)的ItemProviders類(lèi)生成。更進(jìn)一步,對(duì)于整個(gè)插件有一個(gè)EMFPluginClass生成。ItemProvider類(lèi)繼承于org.eclipse.emf.edit.provider.ItemProviderAdaptor,用于適配模型中相應(yīng)的EObject(所有emf類(lèi)的基類(lèi))。當(dāng)模型對(duì)象由于fireNotifyChanged()改變,ItemProvider會(huì)傳送相應(yīng)的通知,并過(guò)濾其他的。當(dāng)你生成插件時(shí),你可以控制哪些通知被過(guò)濾。
              ItemProvider也管理屬性描述(property descriptors)對(duì)于所有的featur of the class,通過(guò)getImage和getText方法來(lái)管理類(lèi)的icon和descrition。
              對(duì)于所有的ItemProvider都有一個(gè)ItemProviderAdaptorFactory。
          最后時(shí)editor插件:
              對(duì)于所有的模型都會(huì)再presentation package中生成三個(gè)類(lèi)。
               一個(gè)多頁(yè)編輯器,它給模型創(chuàng)建幾個(gè)不同的jface viewer,包含一個(gè)TreeViewer,使用edit插件中的ItemProvider作為這個(gè)treeviewer的content和label的provider。這個(gè)editor還創(chuàng)建outline和property來(lái)顯示在viewer中選中對(duì)象的屬性。
               一個(gè)ActionBarContributor,它被用于對(duì)編輯器視圖中選中的item所創(chuàng)建的context menu添加選項(xiàng)。
               最后是一個(gè)向?qū)?,允許你創(chuàng)建一個(gè)包含模型對(duì)象的一個(gè)實(shí)例的資源(resource)。

             

           

          posted @ 2006-02-19 20:46 Long Long Ago 閱讀(703) | 評(píng)論 (0)編輯 收藏

          EMF中的三個(gè)部分:元數(shù)據(jù)meta-data,代碼生成code generation,默認(rèn)序列化default serialization.
          EMF is part of the Model Driver Architecture(MDA).MDA是將整個(gè)應(yīng)用軟件生存周期的開(kāi)發(fā)管理都集中于模型上。這種模型是用元模型(meta-model)定義的。然后,使用映射,模型被用于生成software artefacts, 這就實(shí)現(xiàn)了整個(gè)系統(tǒng)。
          EMF所能做的:emf能夠用于描述和構(gòu)建模型。所實(shí)現(xiàn)的模型可以被用于任何java應(yīng)用程序的開(kāi)發(fā)。
          對(duì)于ecore模型我們有幾點(diǎn)需要注意:
          1。在ecore文件的xmi描述中沒(méi)有各個(gè)元素之間的聯(lián)系,我們使用EReference來(lái)表示各個(gè)元素之間的聯(lián)系。
             對(duì)于兩個(gè)方向上的聯(lián)系,通過(guò)兩個(gè)成對(duì)的EReference來(lái)表示,每個(gè)聯(lián)系的類(lèi),都有一個(gè)eOpposite來(lái)保存它自己在所聯(lián)系類(lèi)中的名字(引用)。
             對(duì)于單方向上的聯(lián)系,使用一個(gè)單獨(dú)的EReference,并且這個(gè)reference沒(méi)有eOpposite(因?yàn)閷?duì)方并沒(méi)有對(duì)自己的引用)。
             連接的多重性通過(guò)upperBound和lowerBound來(lái)表示。多個(gè)用-1。
          2。使用EPackage可以像java中的package一樣用。
          3。兩種模型,一種是業(yè)務(wù)模型,一種是視圖模型。一般將兩種模型放在不同的package中。兩種方法將兩種模型聯(lián)系起來(lái):
             一是構(gòu)建一個(gè)新package,構(gòu)建一個(gè)多重繼承的新package來(lái)將兩個(gè)package聯(lián)系起來(lái)。
             二是將兩種模型分開(kāi)存儲(chǔ),添加從視圖模型到業(yè)務(wù)模型的引用。這種方法兩個(gè)模型是松耦合的。這種單方向的引用也不會(huì)破壞(污染)業(yè)務(wù)模型。注意,由于這種引用是兩個(gè)package之間的,所以在移用的eType類(lèi)型中需要指明包名。  

          除此之外,ecore還提供了一種遞歸的定義方法。就是使用eSubPackage來(lái)分別包含業(yè)務(wù)模型和視圖模型,并且在這兩個(gè)subPackage間建立reference(對(duì)于package來(lái)說(shuō)是自己引用自己)。
          4。我們可以有多種方法來(lái)生成ecore模型。通過(guò)注釋的java接口(annotated java interface),通過(guò)rantional rose創(chuàng)建模型,通過(guò)XML Schema等等。

          posted @ 2006-02-19 15:32 Long Long Ago 閱讀(656) | 評(píng)論 (0)編輯 收藏

          上文已經(jīng)說(shuō)過(guò)了,GMF中,那些generator,definition,mapping model都是最后要合成為diagram runtime(or notation)model。
          以下是簡(jiǎn)單的步驟:
          簡(jiǎn)單的使用方法,首先應(yīng)該定義ecore模型文件有很多種方法,比如用EclipseUML插件,或者使用gmf的example種的Ecore Diagram,這些圖形化的類(lèi)圖編輯工具都可以方便的生成我們所需要的Ecore文件。這里我們使用的是EclipseUML的免費(fèi)版本。是針對(duì)eclipse3.1的,不過(guò)好像3.2m1m2都可以用。
          生成ecore文件后 File/new/other/Eclipse Modeling Framwork/EMF Model 生成相應(yīng)的genmodel文件,通過(guò)它來(lái)生成模型和.edit插件,這些都是GMF所需要的。然后再File/New/other/Example EMF Model Creation Wizards/GMFGraph Model 注意名字應(yīng)該都是一樣的(擴(kuò)展名不同)最后的Model Object選擇Canvas。在生成的gmfgraph文件中給canvas命名,canvas就相當(dāng)于我們的畫(huà)布。在canvas下創(chuàng)建一個(gè)figure gallery(圖庫(kù)),在這里我們保存所需要的圖形。
          然后創(chuàng)建gmftool文件File/New/other/Example EMF Model Creation Wizards/GMFTool Model,可以使用File/New/other/GMF/GMFTool Simple Model來(lái)簡(jiǎn)單的構(gòu)造。
          再創(chuàng)建gmfmap文件,建立模型和圖形之間的映射關(guān)系。File/New/other/Example EMF Model Creation Wizards/GMFMap Model,名字應(yīng)該和前面的一樣,最后的Model Object選擇Mapping。在生成的gmfmap文件中右鍵選擇Load Resource,選擇ecore,gmfgraph,gmftool文件。并且生成相應(yīng)的映射信息,比如node mapping和canvas mapping。
          最后生成emf模型代碼和edit代碼,使用genmodel文件。
          使用gmfmap文件右鍵生成gmfgen文件,注意我們要有g(shù)enmode文件才能生成gmfgen文件。
          最后用gmfgen生成editor插件。這時(shí)候共有三個(gè)插件 模型 edit和editor。
          使用時(shí)File/New/other/Example/中有個(gè)相應(yīng)的diagram,一般再最上面,給一個(gè)名字,無(wú)擴(kuò)展名,就打開(kāi)相應(yīng)的編輯器了。
          posted @ 2006-02-15 10:37 Long Long Ago 閱讀(983) | 評(píng)論 (1)編輯 收藏

          GMF有可能成為一個(gè)標(biāo)準(zhǔn)的Eclipse圖形模型編輯器,它分為兩個(gè)部分:運(yùn)行時(shí)(the runtime)和工具(tooling),工具是由一些創(chuàng)建和編輯符號(hào)語(yǔ)義模型的編輯器組成的,工具還包含了圖形編輯器,并且有圖形編輯器的生成器。

          使用GMF開(kāi)發(fā)一個(gè)類(lèi)圖形模型編輯器的步驟如下:

          1。創(chuàng)建域模型,這個(gè)模型描述了通過(guò)編輯器編輯的非圖形信息。
          2。創(chuàng)建圖定義模型,這個(gè)模型描述了顯示在圖形編輯器中的圖形元素。
          3。創(chuàng)建圖映射模型,這個(gè)模型定義了域模型元素和圖形元素之間的對(duì)應(yīng)關(guān)系。
          4。生成圖形編輯器。
          5。通過(guò)改進(jìn)生成的代碼來(lái)提高圖形編輯器。
          介紹一點(diǎn)GMF的圖形編輯器的特性:
          1。折疊
          2。label的直接編輯
          3。提示
          4。彈出bar
          5。連接柄
          6。通用繪圖工具
          7。通用菜單命令
          8。通用工具條
          9。自動(dòng)縮放和布局
          10。通用屬性編輯
          11。打印和打印預(yù)覽
          12。SVG和剪貼板支持

          http://www.eclipse.org/articles/Article-Introducing-GMF/article.html

          posted @ 2006-02-14 11:38 Long Long Ago 閱讀(1188) | 評(píng)論 (0)編輯 收藏

          主站蜘蛛池模板: 新宁县| 泰和县| 赞皇县| 揭西县| 兴业县| 孟村| 新丰县| 南京市| 榕江县| 宁河县| 七台河市| 江门市| 巴东县| 广州市| 鹿邑县| 鲁山县| 亳州市| 舒城县| 偏关县| 鲜城| 赞皇县| 永德县| 金堂县| 宁乡县| 肥城市| 昔阳县| 剑阁县| 铁岭市| 资中县| 繁峙县| 天全县| 准格尔旗| 昌图县| 祥云县| 肃南| 盘锦市| 永修县| 巴东县| 富顺县| 县级市| 克拉玛依市|