開發我們的例子程序
jackrabbit已經配置好了,現在讓我們來創建我們的示例程序。這個例子程序將調用JCR-170 API。很顯然,我們需要做兩件事情:一個是作為后臺的對數據進行增刪改查(持久層),另一個是開發相對應的UI界面(WEB 層)。首先,讓我們定義一個DAO接口。這個接口BlogEntryDAO.java 如下:
public?interface?BlogEntryDAO?{
????public?void?insertBlogEntry(BlogEntryDTO?blogEntryDTO)
????????throws?BlogApplicationException;
????public?void?updateBlogEntry(BlogEntryDTO?blogEntryDTO)
????????throws?BlogApplicationException;
????public?ArrayList?getBlogList()
????????throws?BlogApplicationException;
????public?BlogEntryDTO?getBlogEntry(String?blogTitle)
????????throws?BlogApplicationException;
????public?void?removeBlogEntry(String?blogTitle)
????????throws?BlogApplicationException;
????public?ArrayList?searchBlogList(String?userName)
????????throws?BlogApplicationException;
????public?void?attachFileToBlogEntry(String?blogTitle,?InputStream?uploadInputStream)
????????throws?BlogApplicationException;
????public?InputStream?getAttachedFile(String?blogTitle)
????????throws?BlogApplicationException;
}
正如你看到的,這個接口提供了增刪改查的方法,同時還提供了兩個方法來處理附件。接下來,我們需要一個DTO對象用來在兩個層之間傳遞數據。
public?class?BlogEntryDTO?{
????private?String?userName;
????private?String?title;
????private?String?blogContent;
????private?Calendar?creationTime;
????//Getter?and?setter?methods?for?each?of?these?properties????????
}
這里我們將僅僅討論持久層。
連接jackrabbit現在,第一件事情是開發一個組件,獲得一個到jackrabbit內容倉庫的連接。為了簡單,我們將在程序啟動的時候獲得這個連接,然后在程序停止的時候釋放這個連接。這里我們使用了Struts ,所以我們需要開發一個PlugIn 類。如下:
public?class?JackrabbitPlugin?implements?PlugIn{
????public?static?Session?session;
????public?void?destroy()?{
????????session.logout();
????}
????public?void?init(ActionServlet?actionServlet,?ModuleConfig?moduleConfig)?
????throws?ServletException?{
????????try?{
????????????System.setProperty("org.apache.jackrabbit.repository.home",
????????????????"c:/temp/Blogging");
????????????Repository?repository?=?new?TransientRepository();
????????????session?=?repository.login(new?SimpleCredentials("username",
????????????????????"password".toCharArray()));
????????}?catch?(LoginException?e)?{
????????????throw?new?ServletException(e);
????????}?catch?(IOException?e)?{
????????????throw?new?ServletException(e);
????????}?catch?(RepositoryException?e)?{
????????????throw?new?ServletException(e);????????????
????????}
????}
????public?static?Session?getSession()?{
????????return?session;
????}
}
init()方法將會在程序啟動的時候調用,destroy()將會在程序停止的時候調用。我們在init()方法里獲得了到jackrabbit內容倉庫的連接。看看代碼,我們做的第一件事是設定了org.apache.jackrabbit.repository.home這個系統屬性,在上篇文章里提到,這個屬性是用來指向我們的內容倉庫主目錄。這里我們設定它為c:/temp/blogging。接下來,我們創建了TransientRepository的一個實例。這是jackrabbit提供的類,它提供了一個到內容倉庫的代理。它在第一個session 打開的時候自動啟動內容倉庫,在最后一個session 關閉的時候自動關閉內容倉庫。
一旦我們獲得了一個內容倉庫對象,我們就可以調用它的login() 方法來打開一個連接。login() 方法需要一個Credential 對象作為參數。如果Credential 對象是NULL,jackrabbit會認為其他的機制做了這個驗證(比如JAAS)。login() 方法還可以傳入一個workspace名字作為參數,如果不傳入這個參數,jackrabbit會返回一個session對象指向默認的workspace。注意workspace和session是一對一的,即一個session僅對應一個workspace。(注:如果不傳入Credential對象,返回的session對workspace是只讀的)
增加內容連接已經建立起來了,下面讓我們實現BlogEntryDAO這個接口。第一個我們想實現的方法是插入數據 insertBlogEntry()
public?void?insertBlogEntry(BlogEntryDTO?blogEntryDTO)
????????????throws?BlogApplicationException?{
????????Session?session?=?JackrabbitPlugin.getSession();
????????Node?rootNode?=?session.getRootNode();
????????Node?blogEntry?=?rootNode.addNode("blogEntry");
????????blogEntry.setProperty("title",?blogEntryDTO.getTitle());
????????blogEntry.setProperty("blogContent",?blogEntryDTO.getBlogContent());
????????blogEntry.setProperty("creationTime",?blogEntryDTO.getCreationTime());
????????blogEntry.setProperty("userName",?blogEntryDTO.getUserName());????????????
????????session.save();
}
首先獲得session 對象,即到內容倉庫特定workspace的連接。然后,我們在這個session 對象上調用getRootNode() 方法,獲得這個workspace的根節點,這個根節點的路徑是("/").一旦我們獲得這個根節點,我們就可以通過addNode()方法在這個根節點下增加新的子節點。新節點的名字是blogEntry. 通過setProperty() 方法我們把數據存儲到節點的property里。正如我們先前說明的,真實的數據是存儲在property元素里,property元素是葉子。
注意session.save() 這行代碼。這個方法是必須調用的,這個方法調用之前,任何 Node,Property的改變都被保存在這個session的一個臨時區域里,其他的和該session連接到相同workspace的session都看不到這些改變。當這個方法被調用并被成功執行后,這些Node,Property的改變才會被持久化到這個session關聯的workspace里,同時所有與這個workspace關聯的session才可見這些變化。相對應的,Session.refresh(false)將會丟棄所有這些改變。item.save()和Item.refresh(false)作用相似,只是影響范圍限定在單個Item上(注意,包括它的子節點)
posted @
2007-01-25 23:12 ronghao 閱讀(3831) |
評論 (0) |
編輯 收藏
內容倉庫模型
JSR-170 是這樣定義內容倉庫的,內容倉庫由一組 workspace(工作空間)組成,這些workspace通常應該包含相似的內容。一個內容倉庫有一個到多個 workspace。每個workspace都是一個樹狀結構,都有一個唯一的樹根節點(root node)。樹上的item(元素)或者是個node(節點)或者是個property(屬性)。每個node都可以有零個到多個子節點和零個到多個子屬性。只有根節點沒有父節點,其余所有的節點都有一個父節點。property 也必須有一個父節點,但它沒有子節點或是子屬性,property 是葉子元素。property是真正存儲數據的元素。
下圖描述了一個blog應用程序的內容倉庫模型。每個root node(根節點)的子節點都代表了一個blog實體。與這個blog實體有關的數據都存儲在 bolgEntry 節點的屬性里,其中一個 blogAttachment property 存儲了一個二進制圖片文件。

根據內容倉庫實現的功能,JSR-170定義了三種級別:
Level 1:定義了一個只讀的內容倉庫。功能包括讀取內容,將內容導出為XML和查找內容。
Level 2:定義了可寫的內容倉庫。Level 2是Level 1的擴展,新增的功能包括往內容倉庫里寫入內容,和從XML導入數據到倉庫。
Advanced options:定義實現五種附加功能,版本控制、JTA、SQL查詢、清晰的內容鎖定和監視。
什么是Apache JackRabbit?Apache JackRabbit是一個開放源碼的JSR-170 實現,實現了Level 2,但它還有許多擴展的功能。詳細可以去它的官方網站。
下面我們決定用Apache JackRabbit來作為我們示例程序的內容倉庫。
如何配置Apache JackRabbitJackRabbit需要兩個參數來配置一個內容倉庫實例。
1.內容倉庫主目錄:這個文件目錄下通常包含了所有的內容,搜索索引,內部配置文件和其他持久化信息。它的結構看起來會像下面這個樣子:
???c:/temp
????????|
????????|--Blogging
????????????????|
????????????????|-repository
????????????????|???????|
????????????????|???????|-index
????????????????|???????|-meta
????????????????|???????|-namespaces
????????????????|???????|-nodetypes?????????????
????????????????|
????????????????|-version
????????????????|
????????????????|-workspace
????????????????????????|
????????????????????????|--default
? 在上面的情況下,內容倉庫主目錄是c:/temp/Blogging.
2.內容倉庫配置文件:一個典型的配置文件如下:
<Repository>
?<FileSystem?class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
??<param?name="path"?value="${rep.home}/repository"/>
?</FileSystem>
?<Security?appName="Jackrabbit">
??<AccessManager?class="org.apache.jackrabbit.core.security.SimpleAccessManager"/>
??<LoginModule?class="org.apache.jackrabbit.core.security.SimpleLoginModule">
????<param?name="anonymousId"?value="anonymous"/>
??</LoginModule>
?</Security>
?<Workspaces?rootPath="${rep.home}/workspaces"?defaultWorkspace="default"/>
?<Workspace?name="${wsp.name}">
??<FileSystem?class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
???<param?name="path"?value="${wsp.home}"/>
??</FileSystem>
??<PersistenceManager?
????????class="org.apache.jackrabbit.core.state.db.DerbyPersistenceManager">
???<param?name="url"?value="jdbc:derby:${wsp.home}/db;create=true"/>
???<param?name="schemaObjectPrefix"?value="${wsp.name}_"/>
??</PersistenceManager>
??<SearchIndex?class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
???<param?name="path"?value="${wsp.home}/index"/>
??</SearchIndex>
?</Workspace>
?<Versioning?rootPath="${rep.home}/version">
??<FileSystem?class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
???<param?name="path"?value="${rep.home}/version"?/>
??</FileSystem>
??<PersistenceManager?
????????class="org.apache.jackrabbit.core.state.db.DerbyPersistenceManager">
???<param?name="url"?value="jdbc:derby:${rep.home}/version/db;create=true"/>
???<param?name="schemaObjectPrefix"?value="version_"/>
??</PersistenceManager>
??</Versioning>
??<SearchIndex?class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
???<param?name="path"?value="${rep.home}/repository/index"/>
??</SearchIndex>
</Repository>
?
? 在這個配置文件里,<Repository>元素是根元素,它包含了下面這些元素:
?
a,<FileSystem>: 該元素配置了內容倉庫的全局數據存儲位置,這些全局數據包括已注冊的命名空間,定制的節點類型等等。??? ??? JackRabbit 提供了幾種選擇,一種是像上面例子里配置的存儲在本地文件里,LocalFileSystem. 如果你想把它們存儲在數據庫里,你可以使用 DbFileSystem.
?
b,<Security>:內容倉庫的安全配置,它有兩個子元素:<AccessManager>和<LoginModule>。<AccessManager>配置的類用來判斷用戶有沒有權限來對特定數據執行特定的操作。
?
c,<Workspaces>:這個元素的配置對所有的workspace都通用。它的rootPath 屬性是所有workspace文件夾的根目錄,在我們的例子里它是c:/temp/Blogging/Workspace;defaultWorkspace 屬性則包含了workspace的默認名。
?
d,<Workspace>:這個元素是所有workspace的默認配置模板。去每個workspace文件夾下你都會發現一個workspace.xml文件,這個文件和這個元素的配置一模一樣。三個子元素:<FileSystem>,和這個workspace相關數據的存儲位置;<PersistenceManager> ,這個workspace內容節點存儲策略;<SearchIndex>,可選,全文檢索。
?
e,<Versioning>:配置一個版本相關的對象。其實JackRabbit也是把它作為節點來處理的。
這兩個參數可以通過兩種方式設置,一種是在倉庫實例創建時直接傳到Jackrabbit里去,一種是間接的通過設置JNDI object factory。
你可以設置org.apache.jackrabbit.repository.home 這個系統屬性的值來指定你的內容倉庫主目錄;也可以設置
org.apache.jackrabbit.repository.conf 這個系統屬性的值來指定你的內容倉庫配置文件repository.xml。如果你不設定這兩個
參數,Jackrabbit會把當前目錄作為內容倉庫主目錄,同時,它有一個默認的內容倉庫配置文件。
posted @
2007-01-23 23:57 ronghao 閱讀(6817) |
評論 (25) |
編輯 收藏
原文地址:http://www.onjava.com/pub/a/onjava/2006/10/04/what-is-java-content-repository.html?page=4
JSR-170把自己定義為一個能與內容倉庫互相訪問的,獨立的,標準的方式。同時它也對內容倉庫做出了自己的定義,它認為內容倉庫是一個高級的信息管理系統,該系統是是傳統的數據倉庫的擴展,它提供了諸如版本控制、全文檢索,訪問控制,內容分類、訪問控制、內容事件監視等內容服務。
Java Content Repository? API(JSR-170)試圖建立一套標準的API去訪問內容倉庫。如果你對內容管理系統(CMS)不熟悉的話,你一定會對內容倉庫是什么感到疑惑。你可以這樣去理解,把內容倉庫理解為一個用來存儲文本和二進制數據(圖片,word文檔,PDF等等)的數據存儲應用程序。一個顯著的特點是你不用關心你真正的數據到底存儲在什么地方,是關系數據庫?是文件系統?還是XML?不僅僅是數據的存儲和讀取,大多數的內容倉庫還提供了更加高級的功能,例如訪問控制,查找,版本控制,鎖定內容等等。
一段時間以來市場上出現了各個廠家開發的不同的CMS系統,這些系統都建立在他們各自的內容倉庫之上。
問題出現了,每個CMS開發商都提供了他們自己的API來訪問內容倉庫。這對應用程序的開發者帶來了困擾,因為他們要學習不同的開發商提供的API,同時,他們的代碼也與這些特定的API產生了綁定。
JSR-170正是為解決這一問題而出現的,它提供了一套標準的API來訪問任何數據倉庫。通過JSR-170,你開發代碼只需要引用 javax.jcr.* 這些類和接口。它適用于任何兼容JSR-170規范的內容倉庫。
我們將通過一個例子來逐步了解JSR-170。
為什么需要 Java Content Repository API隨著各個廠家各自的內容倉庫實現數量的增長,人們越來越需要一組通用的編程接口來使用這些內容倉庫,這就是JSR-170所要做的東西。它提供一組通用的編程接口來連接內容倉庫。你可以把JSR-170理解為和JDBC類似的API,這樣你可以不依賴任何具體的內容倉庫實現來開發你的程序。你可以直接使用支持JSR-170的內容倉庫;或者如果一些廠家的內容倉庫不支持JSR-170則可以通過這些廠家提供的JSR-170驅動來完成從JSR-170與廠家特定的內容倉庫的轉換。
下面這張圖描述了使用JSR-170開發的應用系統的結構。在該系統運行的時候,它可以操作內容倉庫1,2,3中的任意一個。在這些內容倉庫當中,只有2是直接支持JSR-170的,剩下的兩個都需要JSR-170驅動來和應用系統交互。注意:你的應用系統完全不用關心你的數據是如何存儲的。1可能使用了關系數據庫來存儲,而2使用了文件系統,至于上,它甚至更前衛的使用了XML。

JSR-170 API對不同的人員提供了不同的好處。
●對于開發者無需了解廠家的倉庫特定的API,只要兼容JSR-170就可以通過JSR-170訪問其倉庫。
●對于使用CMS的公司則無需花費資金用于在不同種類CMS的內容倉庫之間進行轉換。
●對于CMS廠家,無需自己開發內容倉庫,而專注于開發CMS應用。
posted @
2007-01-23 15:13 ronghao 閱讀(5113) |
評論 (3) |
編輯 收藏
2006年馬上就要過去,在06年的最后一天總結一下自己一年來的生活工作,自己覺得還是挺有意義的,盡管上學時最煩的就是各種各樣的總結了。
工作技術上:
1、可以比較熟練的使用webwork、spring和hibernate.這是和05年做的對比,05年做的東西完全是jsp+servlet+jdbc.盡管自己那時也用過,但那還限于demo。
2、對一個不算復雜的WEB項目有比較清晰的開發思路/架構。三層、封裝、抽象、領域對象。
3、有過一次和最終用戶打交道的經歷,有了一些經驗。
4、負責開發了公司產品的權限系統。對ACL、RBAC都有了談不上深入的理解。最后的實現是基于?acegi的擴展。包括數據范圍權限、單條數據權限都實現了控制。只是對所謂的大集中模式下的權限沒有一個很好的解決方法,也是一個遺憾。
5、初步的學習了ajax。05年自己對javascript還是很不屑的,也僅僅把它用于表單的驗證。今年買了本權威指南,也算是瀏覽過一遍。在開發中用到了prototype.js,dwr,觀念發生了很大的變化。寫了個outlookbar.js以及把xloadtree進行了很多的擴展。最后還模仿了google的日程表也做了個日程表,比較丑,css還得加強。
6、基于jackrabbit實現了產品的CMS。對jsr170有了理解。一度想數據倉庫可否替代數據庫在一定應用中。
7、有了一些工作流理論和實踐。
生活中:
1、世界觀發生了一點變化。什么是民主,什么是人權,什么叫自由,你真的經過你自己的思考了嗎?
2、關注了一些以前沒有關注的聲音。知道了一句話叫用腳投票。
3、關注了高房價、人民幣升值、股票、基金。了解了一些財政金融方面知識,對自己每月把工資存入?銀行產生了懷疑。
4、給自己配了臺臺式機,然后又給老婆買了臺筆記本。
展望:
1、年底開始注意敏捷開發,明年能不能敏捷到我們團隊?
2、很顯然,ajax剛剛會用的階段,上升到模式?我們的頁面能不能xhtml規范?
3、OSGI應用到我們的產品中?
4、具有架構的能力?
5、明年我能買的起房嗎?
呵呵,不管怎樣,希望明年會更好。
posted @
2006-12-31 16:22 ronghao 閱讀(944) |
評論 (1) |
編輯 收藏
似乎到了年末,心情也跟著莫名的煩躁起來了。CMS基本算是開發完畢,現在主要是改改產品的BUG。BUG單總是那么長,讓人打不起精神。產品的發布已經幾次延期,看不到海的對岸。其實還有好多的問題要去解決。想著對acegi 的ACL進行進一步的擴展,CMS的頁面模板要實現可視化的編輯,對頁面的javascript進行重新整理,把頁面由table換成div...確實還有很多的工作。沒有覺得充實而是雜亂沒有條理。
也許也和生活有關。
浮躁的年末的一個傍晚,我坐在那里,看著外邊的天慢慢黑透...
posted @
2006-12-29 18:30 ronghao 閱讀(442) |
評論 (0) |
編輯 收藏