隨筆 - 14, 文章 - 0, 評論 - 15, 引用 - 0
          數據加載中……

          java&XML學習第三天,cocoon2

                由于對于cocoon 2的內容特別的感興趣,所以跳過了對sax的學習就直接開始了cocoon 2的學習,事實證明這樣是不對的,如果你只是想對cocoon 2作一個簡單的了解,可以不學sax,但是如果想要深入了解cocoon 2的話,還是應該先學習sax。
                首先,關于cocoon入門的資料網上比較少,一個是ibm上提供的三個cocoon的教程,比較不錯,另外就是cocoon自己的文檔,還有就是必須研究cocoon的源代碼了。

                一、cocoon是什么?
                按照我的理解,cocoon是一個整套的java web開發框架,象struts里面可以實現的功能,在cocoon里面其實都可以實現,但是,我覺得他的側重點應該是用于在web以各種樣式上發布xml內容(Html,pdf,SVG),他提供了內容、邏輯、表現在很大程度上的分離,這一點不是struts這種MVC框架的強項。
                至于說有人將cocoon和struts進行比較,我覺得應該是不恰當的,因為兩者著重解決的問題是不同的,如果你是一個新聞網站,以發布內容為主,那么你可以考慮cocoon,但是如果你是一個信息管理系統,側重于事物的處理,那么你可以選擇struts以及webwork2等框架。

                二、cocoon能干什么?
          • 提供靜態文件和動態生成的響應
          • 使用任意數量的處理將用戶請求透明地映射到物理資源
          • 執行簡單和多級 XSLT 轉換
          • 將參數動態傳遞到 XSLT 變換
          • 生成各種各樣的輸出格式,包括 XML、HTML、PNG、JPEG、SVG 和 PDF

                以上是ibm教程上的原話,可能只有最后的一條比較容易理解,不過希望您在讀完本文以后可以對上述的特性都有一個大概的理解。

                三、為什么是cocoon 2?
                cocoon1和cocoon2是cocoon的兩個不同的版本,其主要的區別是cocoon1是圍繞dom接口開發的,這是一種效率較低的api,而cocoon2是圍繞sax的。所以在學習cocoon2之前,建議了解sax和xml的相關知識。

                四、開始進入cocoon 2的世界,管道模型
                安裝配置就不說了,網上可以找到相應的說明,而且熟悉java web的人應該可以知道如何安裝。
                下面就說一說cocoon 2里面最重要的一個概念:管道
                一個管道是由一個輸入開始,一個輸出結束,其中您可以加入任意多的對輸入數據的處理模塊。所以,在cocoon 2中,一個管道應該是1輸入+n處理+1輸出。所有這些模塊,在cocoon中被稱為“components”。
                下面是cocoon 2中內置的幾個較為常用的模塊:
                管道輸入 — 生成器(如FileGenerator,HTMLGenerator,DirectoryGenerator)和閱讀器(常用來讀靜態文件)
            處理步驟 — 轉換器(如XSLT 轉換器)和操作
            管道輸出 — 序列化器(如XML,HTML,SVG,PDF序列化器 )
            條件的處理 — 匹配器和選擇器 
                cocoon的管道通常至少有生成器和序列化器,也就是我們說的輸入和輸出。這里面有個感念前面在學習xsl的時候提到過,就是對xml的轉換和格式化輸出是分開的,在cocoon里面很好的體現了這一點。

                五、站點地圖
                實際上,一個最簡單的管道應該是使用匹配器來接受用戶請求(URL請求),使用生成器生成xml,使用各種轉換器,使用序列化器輸出。所有這些,將體現在cocoon的一個配置文件里面sitemap.xmap,就構成了所謂的“站點地圖”。
                下面是我做測試使用的站點地圖:

          <?xml version="1.0" encoding="UTF-8"?>
          <map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0">

            
          <map:components>(1)
              
          <!-- component declarations -->
              
          <map:generators default="file">
                    
          <map:generator name="file" src="org.apache.cocoon.generation.FileGenerator"/>
                    
          <map:generator  name="xsp" src="org.apache.cocoon.generation.ServerPagesGenerator"/>
                    
          <map:generator name="helloWorld" src="simpletest.SimpleTest"/>
                  
          </map:generators>
                  
                  
          <map:transformers default="xslt">
                    
          <map:transformer  name="xslt" src="org.apache.cocoon.transformation.TraxTransformer"/>
                  
          </map:transformers>
                  
                  
          <map:readers default="resource">
                    
          <map:reader name="resource" src="org.apache.cocoon.reading.ResourceReader"/>
                  
          </map:readers>
                  
                  
          <map:serializers default="html">
                    
          <map:serializer name="xml" mime-type="text/xml" src="org.apache.cocoon.serialization.XMLSerializer"/>
                    
          <map:serializer name="html" mime-type="text/html" src="org.apache.cocoon.serialization.HTMLSerializer"/>
                    
          <map:serializer name="svg2png" src="org.apache.cocoon.serialization.SVGSerializer" mime-type="image/png"/>
                    
          <map:serializer name="fo2pdf" src="org.apache.cocoon.serialization.FOPSerializer" mime-type="application/pdf"/>
                  
          </map:serializers>
                  
                  
          <map:matchers default="wildcard">
                    
          <map:matcher name="wildcard" src="org.apache.cocoon.matching.WildcardURIMatcher"/>
                  
          </map:matchers>

              
          <map:actions/>
              
          <map:selectors/>
            
          </map:components>

           
          <map:pipelines>
           
            
          <map:pipeline>
             
          <map:match pattern="*.xml">(4)
                
          <map:generate type="xsp" src="{1}.xsp"/>
                
          <map:serialize type="xml"/>
             
          </map:match>
             
          <map:match pattern="welcome">(2)
              
          <map:generate src="samples.xml"/>
              
          <map:transform src="simple-samples2html.xsl"/>
              
          <map:serialize type="html"/>
             
          </map:match>
             
          <map:match pattern="heyThere">(3)
                
          <map:generate type="helloWorld"/>
                
          <map:serialize type="xml"/>
             
          </map:match>
             
            
          </map:pipeline>
            
           
          </map:pipelines>

          </map:sitemap>

                為了節省篇幅,我把后面的東西也放進來,以后會慢慢解釋這個文件,先看圖中的(1),是所有的組件的定義。
                (2)就是一個簡單的管道。從他的內容可以看出,首先,他匹配welcome的用戶請求,假使是:http://localhost:8089/cocoon-dev/welcome,然后,有一個生成器,使用的是默認的FileGenerator生成器,這個生成器將會讀取samples.xml文件,把它作為這個管道的輸入。
                之后,有一個xsl的轉換器,他使用simple-samples2html.xsl來轉化生成器生成的xml,最后由一個html的序列化器生成輸出。simples.xml和simple-samples2html.xsl的代碼就不給出了,熟悉xml&xslt的朋友應該明白。
                在瀏覽器中輸入http://localhost:8089/cocoon-dev/welcome后就會得到輸出的html頁面。當然,如果你將轉換器和序列化器的定義修改成:
                  <map:transform src="transforms/content2rss.xsl"/>
                    <map:serialize type="xml"/>
                   或者
                   <map:transform src="transforms/content2fo.xsl"/>
                   <map:serialize type="fo2pdf"/>
          的話,你將會得到rss和pdf格式的輸出。個人認為這應該是cocoon的最主要的功能,這也是我了解cocoon的主要原因。

                六、使用cocoon進行開發
                在cocoon 2的tutorial里面有這樣的一個章節介紹使用cocoon進行web的開發,但是其中只講到了自定義生成器的部分,個人認為cocoon 2的建議是把查詢數據庫,邏輯運算,商業邏輯等功能都放在生成器里面、xsp就是一種生成器他的寫法類似于jsp,但是不管是自定義的生成器還是xsp,其接口都比較復雜,我覺得并沒有struts來的方便,當然這又回到了開始的話題,應用的地方不同,沒有好壞之分,這里只是為了研究一下cocoon2的內部結構。
              下面是一個自定義的生成器:

          package simpletest;

          import org.apache.cocoon.generation.AbstractGenerator;
          import org.xml.sax.helpers.AttributesImpl;
          import org.xml.sax.SAXException;

          public class SimpleTest extends AbstractGenerator 
          {

              AttributesImpl emptyAttr 
          = new AttributesImpl();

              
          /**
               * Override the generate() method from AbstractGenerator.
               * It simply generates SAX events using SAX methods.  
               * I haven't done the comparison myself, but this 
               * has to be faster than parsing them from a string.
               
          */


              
          public void generate() throws SAXException
              
              
          {
                 
                
          // the org.xml.sax.ContentHandler is inherited 
                
          // through org.apache.cocoon.xml.AbstractXMLProducer 

                contentHandler.startDocument();
                
                contentHandler.startElement(
          """example""example", emptyAttr);
                
                contentHandler.characters(
          "Hello World!".toCharArray(),0,
                                            
          "Hello World!".length());

                contentHandler.endElement(
          "","example""example");

                contentHandler.endDocument();

              }

          }
                可以看到生成器的接口并不那么簡單,這里只寫一個generate方法是因為繼承了很多的類,他們給你提供了好多方法。
                第二點就是我們的generate方法里面寫的是sax事件的調用,也就是說,在執行generate方法的時候,contentHandler就好像在讀取一個xml文件一樣。為了證明這一點,我們有了管道中(3)的配置。運行http://localhost:8089/cocoon-dev/heyThere之后,我們有了如下結果:
            <?xml version="1.0" encoding="UTF-8" ?> 
            
          <example>Hello World!</example> 
                我們可以理解以上的xml文件就是generate的輸出,原因是序列化器是個xml序列化器,他其實并沒有對generate的輸出作什么操作。
                更進一步的說,我們可以這樣理解,generate輸出一個xml,管道的下一個處理器接受到這個xml以后進行一些操作,生成另外一個xml,以此類推,直到序列化器的出現,把xml轉化成了想要的格式。這其實就是cocoon的基本工作原理。

                七、實際原理
                上面說的工作原理可以通過依次取掉generate后面的處理器,而在最后加裝xml的序列化器來驗證,但是在cocoon的內部,卻沒有什么xml被傳來傳去,那么管道的各個組件之間是怎樣協作的呢?在教程上有句話說是通過互相傳遞sax事件實現的,乍一聽來非常難以理解,經過了無數次調試后,終于得知了實情。
                我們來看如下的代碼:
          private void connectPipeline(Environment   environment,
                                           ArrayList     usedTransformers,
                                           XMLSerializer xmlSerializer)
              throws ProcessingException 
          {
                  XMLProducer prev 
          = this.producer;
                  XMLConsumer next;

                  boolean configuredSAXConnector 
          = this.manager.hasComponent(SAXConnector.ROLE);

                  
          try {
                      
          int cacheableTransformerCount = this.firstNotCacheableTransformerIndex;

                      Iterator itt 
          = usedTransformers.iterator();
                      
          while ( itt.hasNext() ) {
          .......................
                          next = (XMLConsumer) itt.next();
          .......................
              
                          prev.setConsumer(next);
                          prev 
          = (XMLProducer) next;
                      }


          ........................
                      }

                      prev.setConsumer(next);

                  }
           catch .............

              }
                上面是cocoon代碼中的一些片斷,從中我們可以看出,cocoon把一個管道里面的所有的組件進行一次循環,把前一個組件的XMLConsumer設成后一個組件,也就是后面的組件是前面組件的XML消費者,而對于后一個組件來說,前一個是XMLProducer ,也就是XML生產者。
                而且,通過調試得知,每一個組件,不管是什么類型,都會有一個XMLConsumer的屬性,另外,還都會有一個contentHandler的屬性。ContentHandler這個類是標準的sax接口,從這一點分析,XMLConsumer有可能是cocoon1的殘留物,而真正在cocoon2里面其作用的是ContentHandler這個接口的一些實現類。
                后面又進行了一些調試,結果卻是驗證了上面的說法,為了測試做了如下的配置:
                <map:match pattern="welcome">
                  <map:generate type="helloWorld"/>
                  <map:transform src="simple-samples2html.xsl"/>
                  <map:transform src="simple-samples2html2.xsl"/>
                  <map:serialize type="xml"/>
                </map:match>
          結果是這樣的,自定義的generate類的generate()方法中的contentHandler.startDocument();一句的實現代碼如下:這段代碼在AbstractXMLPipe這個類中
          public void startDocument()
              throws SAXException 
          {
                  
          if (contentHandler != null) contentHandler.startDocument();
              }
          也就是說,generate的屬性contentHandler中還有個contentHandler屬性,依次遞歸調用,后續的測試得出如下的結論:
          generate的對象我們稱之為g1,
          generate的contentHandler屬性就是TraxTransformer類的一個對象,也就是
          <map:transform src="simple-samples2html.xsl"/>這一句的實現載體,我們暫且稱這之對象為t1,
          而<map:transform src="simple-samples2html2.xsl"/>的實現載體對象我們暫稱之為t2,
          <map:serialize type="xml"/>的實現載體是XMLSerializer類的一個對象,我們暫稱之為s1
          他們之間的關系是g1.contentHandler = t1.contentHandler = t2.contentHandler = s1.contentHandler,而且所有的contentHandler都是AbstractXMLPipe這個類的某一個子類型,也就是說他們的startDocument()等方法的實現都是完全一樣的。
          這樣一來,每一個sax的事件將會在generate.generate()方法中被開始調用,并不斷地遞歸g1,t1,t2.....s1,這就是cocoon管道之間各個組件互相傳遞數據的真相。

                八、其他一些技術的了解:
                cocoon中比較有用的一些技術還有xsp和esql,其中xsp是一個類似jsp的組件,他在cocoon中的地位應該是一種generate,用來生成最初的xml,并且,他可以內嵌java代碼,就像jsp那樣,取得request參數,查詢數據庫等,如站點地圖中的(4)所示,我們可以把這樣的一個組件作為管道的起點,這樣我們查詢或者業務處理的結果就可以通過管道被發布成各種樣式了!
                下面給出一個xsp的簡單例子:
          <xsp:page language="java"
                            xmlns:xsp
          ="http://apache.org/xsp">
             
          <xsp:structure>
                
          <xsp:include>java.util.Calendar</xsp:include>
                
          <xsp:include>java.text.*</xsp:include>
             
          </xsp:structure>

             
          <document>

                
          <xsp:logic>
                   SimpleDateFormat format = new SimpleDateFormat("EEE, MMM d, yyyy");
                   String timestamp = format.format(
                                             java.util.Calendar.getInstance().getTime()
                                             );
                
          </xsp:logic>

                
          <time><xsp:expr>timestamp</xsp:expr></time>
                
          <time><xsp:expr>request</xsp:expr></time>

                
          <!-- additional elements -->
             
          </document>
          </xsp:page>
          其中:<xsp:logic>標簽和<xsp:expr>標簽就類似于jsp中的<%%>和<%=%>
                esql是在xsp上使用的一項技術,他應該類似于jsp的一些標簽庫,實現的功能是操作數據庫,直接寫在xsp文件中的,這樣可以很方便的生成一個由數據庫驅動的動態的xml,配合上cocoon的其他組件,也就是說可以很方便的把數據庫中的東西發布成各種版本。
                下面是他的一些語法定義:
          <xsp:page
            
          language="java"
            xmlns:xsp
          ="http://apache.org/xsp"
            xmlns:esql
          ="http://apache.org/cocoon/SQL/v2">

          <root>
            
          <esql:connection>

             
          <esql:execute-query>

               
          <!-- connection
               information 
          -->
               
          <esql:pool/>

               
          <!-- SQL query -->
               
          <esql:query/>

               
          <!-- result processing
               elements 
          -->
               
          <esql:results/>
               
          <esql:update-results/>
               
          <esql:no-results/>
               
          <esql:error-results/>

              
          </esql:execute-query>

             
          </esql:connection>

          </root>

          </xsp:page>

                九、struts&cocoon
                目前,已經有人想到了struts和cocoon的整合,用struts來處理邏輯層的事物,用cocoon來實現多種表現形式,操作方法大概提供一個struts的plugin,可以把struts最終的jsp作為cocoon的xml源來使用。
                地址:http://struts.sourceforge.net/struts-cocoon/
                不過個人認為這種結合的方式還是比較生硬,記得以前看到過關于strutsX的有關介紹,希望這種事物處理層和表現層同樣強大的框架可以早點出來,順便說一句,cocoon 2項目以前是屬于apache xml項目下的,現在已經是一個獨立的項目http://cocoon.apache.org,在這里也祝愿cocoon能夠飛的更高,飛得更遠。

                第一次寫那么多,試試發布一下,純粹是可望志同道合的人交流,各位高手見笑了^_^

          posted on 2005-03-10 15:38 Boris-Java 閱讀(2179) 評論(2)  編輯  收藏 所屬分類: java&xml

          評論

          # re: java&XML學習第三天,cocoon2  回復  更多評論   

          很好哦!謝謝!
          2006-05-09 09:57 | popoer

          # re: java&XML學習第三天,cocoon2  回復  更多評論   

          寫的很有深度,對作者表示敬佩
          2006-11-09 16:44 | guest
          主站蜘蛛池模板: 宿州市| 永安市| 鸡泽县| 吉隆县| 定日县| 灯塔市| 益阳市| 高唐县| 资源县| 龙口市| 松阳县| 克什克腾旗| 固始县| 龙井市| 体育| 郑州市| 梅河口市| 安多县| 杨浦区| 安宁市| 社会| 上杭县| 蒙自县| 望奎县| 泰安市| 镇宁| 象山县| 利辛县| 博白县| 岳池县| 中山市| 天气| 湟中县| 高台县| 六枝特区| 大同市| 合阳县| 连平县| 杭州市| 九台市| 营山县|