First Hops
Hop 0: Getting started
新建Maven項目,修改pom.xml中的依賴
<dependencies>
<!-- The JCR API -->
<dependency>
<groupId>javax.jcr</groupId>
<artifactId>jcr</artifactId>
<version>2.0</version>
</dependency>
<!-- Jackrabbit contentrepository -->
<dependency>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>jackrabbit-core</artifactId>
<version>2.2.4</version>
</dependency>
<!-- Use Log4J for logging-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.5.11</version>
</dependency>
</dependencies>
你可能 ClassNotFoundException異常信息當試圖編譯和履行以下示例時候
Hop 1: Logging in toJackrabbit
創建1個jackrabbit內容存儲庫并啟動1個登錄會話來訪問它
import javax.jcr.Repository;
import javax.jcr.Session;
import org.apache.jackrabbit.core.TransientRepository;
/**
* First hop example. Logs in to a content repository and prints a
* status message.
*/
public class FirstHop {
/**
* The main entry point of theexample application.
*
* @param args command linearguments (ignored)
* @throws Exception if an erroroccurs
*/
public static void main(String[]args) throws Exception {
Repository repository = newTransientRepository();
Session session =repository.login();
try {
String user =session.getUserID();
String name =repository.getDescriptor(Repository.REP_NAME_DESC);
System.out.println(
"Logged in as "+ user + " to a " + name + " repository.");
} finally {
session.logout();
}
}
}
Run as->java application
Logged in as anonymous to a Jackrabbit repository.
詳解FirstHop.java文件
import javax.jcr.Repository;
import javax.jcr.Session;
JCR API的接口位于:jcr⑴.0.jar / javax.jcr,該包的所有接口與倉庫的實現方式無關
Repository接口代表1個的倉庫的實例
Session接口代表訪問倉庫1個登錄會話,該會話訪問倉庫內的任何內容
注意:如果多線程同時訪問內容,需要開啟多個會話(會話實例不能保證線程安全)
import org.apache.jackrabbit.core.TransientRepository;
部署jackrabbit推薦使用JNDI
或在1個使程序代碼不直接依賴jackrabbit的容器環境,使用其他配置機制,
如果僅做1個簡單獨立的利用可使用TransientRepository類
public class FirstHop
public static void main(String[] args) throws Exception
作為簡單利用示例,僅main()方法,使用jvm進行異常處理
實際利用通常是web利用或EJB組件,使用不同的設置和毛病處理模式
Repository repository = new TransientRepository();
TransientRepository類實現了Repository接口,可以通過簡單實例化TransientRepository對象,調用構造函數將在第1次啟動會話時進行進行初始配置和倉庫建設。
因此,除非你想通過庫設置進行直接控制,否則無需手動配置。
Session session = repository.login();
Repository.login()開啟1個使用默許工作空間且沒有用戶憑據的倉庫會話
Jackrabbit嘗試使用java認證和授權服務(JAAS)配置,但對匿名用戶默許JAAS沒法找到
使Repository接口對象進1步實例化
try { ... } finally { session.logout(); }
當順利履行house,需要釋放所有取得資源且保證JCR會話不產生異常
finally進行釋放資源:Session.logout()關閉唯1開啟的會話,transientrepository自動關閉
String user = session.getUserID();
The username or identifier of the user associated witha session is available using the 通過Session.getUserID()方法獲得用戶名或會話相干的用戶id,若為空則默許返回anonymous
String name = repository.getDescriptor(Repository.REP_NAME_DESC);
每一個內容倉庫實現都會產生大量的字符串描寫符來描寫各種實現屬性(比如:實現級別、JCR特性可支持的選項)
通過查看Repository接口的標準倉庫描寫列表:
REP_NAME_DESC描寫符的是repository實現的名稱"Jackrabbit".
Hop 2: Working withcontent
內容倉庫的主要功能是存儲和檢索內容,在JCR內容倉庫的內容包括:
結構化或非結構話數據模型作為1個包括實際數據屬性的層次結構的結點
下面示例利用程序功能:
1.將存用1些內容儲初始化為空內容倉庫
2.檢索存儲的內容并輸出
3.刪除存儲內容
import javax.jcr.Repository;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.jcr.Node;
import org.apache.jackrabbit.core.TransientRepository;
/**
* Second hop example. Stores, retrieves, and removes example content.
*/
public class SecondHop {
/**
* The main entry point of theexample application.
*
* @param args command linearguments (ignored)
* @throws Exception if an erroroccurs
*/
public static void main(String[]args) throws Exception {
Repository repository = newTransientRepository();
Session session =repository.login(
newSimpleCredentials("username", "password".toCharArray()));
try {
Node root =session.getRootNode();
// Store content
Node hello =root.addNode("hello");
Node world =hello.addNode("world");
world.setProperty("message", "Hello, World!");
session.save();
// Retrieve content
Node node =root.getNode("hello/world");
System.out.println(node.getPath());
System.out.println(node.getProperty("message").getString());
// Remove content
root.getNode("hello").remove();
session.save();
} finally {
session.logout();
}
}
}
運行
/hello/world
Hello, World!
以下是與FirstHop的差異部份:
import javax.jcr.SimpleCredentials;
import javax.jcr.Node;
這兩個類是這個示例中新添加的類:
SimpleCredentials類是Credentials接口的簡單實現:
使用Repository.login(Credentials)方法確認用戶憑證
Node接口用于管理倉庫中的內容結點。
有1個相干接口Property用于管理內容屬性,但在這個例子中只間接使用Property接口
new SimpleCredentials("username","password".toCharArray())
在第1個示例中討論的,在jackrabbit默許配置中Repository.login()方法返回1個匿名用戶只讀會話
我們需要通過1些認證,來創建寫訪問的會話來存儲和刪除內容
Repository.login(Credentials credentials) method.
默許的jackrabbit登錄機制接受任何用戶名和密碼作為有效憑據,并返回寫訪問會話
因此 我們只要構造和使用SimpleCredentials示例,1些虛擬的用戶名和密碼:比如"username"和 "password".
SimpleCredentials構造方法遵守JAAS:
用戶名作為1個普通的String類型,但是密碼需要作為1個char型數組String.toCharArray()
Node root = session.getRootNode();
每一個JCR會話與包括1個單結點樹的工作空間有關。
通過調用Session.getRootNode()來訪問根結點
根結點作為參考,可以輕松地存儲和檢索當前工作空間的內容
Node hello = root.addNode("hello");
Node world = hello.addNode("world");
新的內容結點可以通過使用Node.addNode(String relPath)添加
該方法用結點名字(或相對路徑)添加并創建與當前會話有關的臨時存儲相干命名結點,
在臨時存儲保存成功之前,被添加的結點僅在當前會話可見并,但在訪問內容庫的其他會話不能訪問
這段代碼創建了兩個新的結點:"hello"和 "world"
"hello"作為根結點的子結點
"world"作為"hello"結點的子結點
world.setProperty("message", "Hello, World!");
通過使用"hello"和 "world"結點,創建結構,添加1些內容
使用Node.setProperty(Stringname, String value)的方法添加1個屬性:
向world結點添加message屬性,該屬性值是String類型的"Hello,World!"
像這些被添加的節點,這個屬性在當前會話的臨時存儲中首次被創建
如果該屬性的名字已存在,那末這個方法將會改變屬性的值
session.save();
雖然我們的示例在單1會話的臨時存儲的進程中是正常工作的,但我們依然希望可以將到目前為止的修改內容進行持久化。這樣的話,其他的也能允許訪問我們剛剛創建的示例內容。如果你想要的話,你乃至可以把示例城辨別成3塊存儲,分別存儲,檢索,或刪除示例內容。但是條件是必須對修改內容進行持久化。Session.save()方法將保持所有在臨時存儲的所有提交的修改內容,修改內容將寫入持久的倉庫中存儲并將對訪問該工作空間的所有會話可見,如果不調用該方法,則會話關閉時所有修改內容將會丟失。
Node node = root.getNode("hello/world");
由于我們依然在同1個會話,我們通過援用現有的hello和world結點來訪問存儲內容。
但是讓我們假定已開啟了另外一個會話,需要檢索之前存儲的內容
Node.getNode(StringrelPath)方法返回1個給定路徑的參考節點
常見的文件系統路徑語法約定:用/分割節點名稱,用.表示當前節點,用..表示父節點
"hello/world"表示在根結點的子節點hello,hello的子節點world,world的子節點是當前的節點.
終究的結果是該方法返回:創建表示與word結點實例相同內容的結點
System.out.println(node.getPath());
每一個內容結點和屬性都是用他在工作空間的絕對路徑來唯1標識的。
這個絕對路徑開始于1個/和順次包括在當前節點或屬性名字之前所有父節點
這個節點或屬性的路徑可以通過Item.getPath()取得。這個Item接口是Node和Property的父接口
,包括所有結點和屬性同享的全部方法。結點變量相對"world"結點的, 所以輸出 "/hello/world".
System.out.println(node.getProperty("message").getString());
通過Node.getProperty(String relPath)方法,訪問屬性,并返回1個Property接口的實例。表示在相對當前節點給定的相對路徑的屬性。Message屬性是我們剛創建的1個屬性
JCR屬性可以包括指定類型的1個或多個值。屬性類型可以是字符串,數字,日期,2進制流,參考節點等等。我們僅需要單1的字符串值,所以調用Property.getString()方法。結果是輸出"Hello,World!"
root.getNode("hello").remove();
通過調用Item.remove()方法可以刪除結點和屬性.
這個方法將刪除全部內容子樹,我們只需要刪除最上面的"hello"節點,就能夠了刪除我們之前添加的所有內容
刪除操作會首先存儲在會話本地的臨時存儲,就像添加和修改內容。
像之前1樣,這個臨時的修改內容需要明確保存內容將被從持久化存儲中刪除。
Hop 3: Importing content ―――――――― TODO: Update tomatch the style of previous hops.
添加內容更有效果,可使用JCR導入配置,比如Seession.importxml.線面的xml文檔由Elliotte Rusty Harold提供1個又去的實例:演示1個庫的命名空間的作用
test.xml
<xhtml:html xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:mathml="http://www.w3.org/1998/Math/MathML">
<xhtml:head><xhtml:title>ThreeNamespaces</xhtml:title></xhtml:head>
<xhtml:body>
<xhtml:h1 align="center">An Ellipse and aRectangle</xhtml:h1>
<svg:svg xmlns:svg="http://www.w3.org/2000/svg"
width="12cm" height="10cm">
<svg:ellipse rx="110" ry="130" />
<svg:rect x="4cm" y="1cm" width="3cm"height="6cm" />
</svg:svg>
<xhtml:p>The equation for ellipses</xhtml:p>
<mathml:math>
<mathml:apply>
<mathml:eq/>
<mathml:cn> 1 </mathml:cn>
<mathml:apply>
<mathml:plus/>
<mathml:apply>
<mathml:divide/>
<mathml:apply>
<mathml:power/>
<mathml:ci> x </mathml:ci>
<mathml:cn> 2 </mathml:cn>
</mathml:apply>
<mathml:apply>
<mathml:power/>
<mathml:ci> a </mathml:ci>
<mathml:cn> 2 </mathml:cn>
</mathml:apply>
</mathml:apply>
<mathml:apply>
<mathml:divide/>
<mathml:apply>
<mathml:power/>
<mathml:ci> y </mathml:ci>
<mathml:cn> 2 </mathml:cn>
</mathml:apply>
<mathml:apply>
<mathml:power/>
<mathml:ci> b </mathml:ci>
<mathml:cn> 2 </mathml:cn>
</mathml:apply>
</mathml:apply>
</mathml:apply>
</mathml:apply>
</mathml:math>
<xhtml:hr/>
<xhtml:p>Last Modified January 10, 2002</xhtml:p>
</xhtml:body>
</xhtml:html>
下面的第3個實例程序將展現導入名為test.xml的xml文件。從當前目錄到1個名為importxml的新的內容倉庫節點。1旦xml內容導入,程序會調用dump()方法遞歸的輸出全部工作區的內容
import javax.jcr.*;
import org.apache.jackrabbit.core.TransientRepository;
import java.io.FileInputStream;
/**
* Third Jackrabbit example application. Imports an example XML file
* and outputs the contents of the entire workspace.
*/
public class ThirdHop {
/**
* The main entry point of theexample application.
*
* @param args command linearguments (ignored)
* @throws Exception if an erroroccurs
*/
public static void main(String[]args) throws Exception {
Repository repository = newTransientRepository();
Session session =repository.login(
newSimpleCredentials("username", "password".toCharArray()));
try {
Node root =session.getRootNode();
// Import the XML file unlessalready imported
if(!root.hasNode("importxml")) {
System.out.print("Importing xml... ");
// Create anunstructured node under which to import the XML
Node node =root.addNode("importxml", "nt:unstructured");
// Import thefile "test.xml" under the created node
FileInputStreamxml = new FileInputStream("test.xml");
session.importXML(
node.getPath(),xml, ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW);
xml.close();
session.save();
System.out.println("done.");
}
//output therepository content
dump(root);
} finally {
session.logout();
}
}
/** Recursively outputs thecontents of the given node. */
private static void dump(Nodenode) throws RepositoryException {
// First output the node path
System.out.println(node.getPath());
// Skip the virtual (andlarge!) jcr:system subtree
if(node.getName().equals("jcr:system")) {
return;
}
// Then output the properties
PropertyIterator properties =node.getProperties();
while (properties.hasNext()){
Property property =properties.nextProperty();
if(property.getDefinition().isMultiple()) {
// A multi-valuedproperty, print all values
Value[] values =property.getValues();
for (int i = 0; i< values.length; i++) {
System.out.println(
property.getPath() + " = " + values[i] .getString());
}
} else {
// A single-valuedproperty
System.out.println(
property.getPath() +" = " + property.getString());
}
}
// Finally output all thechild nodes recursively
NodeIterator nodes =node.getNodes();
while (nodes.hasNext()) {
dump(nodes.nextNode());
}
}
}
運行第3個示例,結果以下
Importing XML... done.
/
/jcr:primaryType=rep:root
/jcr:system
/importxml
/importxml/jcr:primaryType=nt:unstructured
/importxml/xhtml:html
/importxml/xhtml:html/jcr:primaryType=nt:unstructured
/importxml/xhtml:html/xhtml:head
/importxml/xhtml:html/xhtml:head/jcr:primaryType=nt:unstructured
/importxml/xhtml:html/xhtml:head/xhtml:title
/importxml/xhtml:html/xhtml:head/xhtml:title/jcr:primaryType=nt:unstructured
/importxml/xhtml:html/xhtml:head/xhtml:title/jcr:xmltext
/importxml/xhtml:html/xhtml:head/xhtml:title/jcr:xmltext/jcr:primaryType=nt:unstructured
/importxml/xhtml:html/xhtml:head/xhtml:title/jcr:xmltext/jcr:xmlcharacters=ThreeNamespaces
/importxml/xhtml:html/xhtml:body
/importxml/xhtml:html/xhtml:body/jcr:primaryType=nt:unstructured
/importxml/xhtml:html/xhtml:body/xhtml:h1
/importxml/xhtml:html/xhtml:body/xhtml:h1/jcr:primaryType=nt:unstructured
/importxml/xhtml:html/xhtml:body/xhtml:h1/align=center
/importxml/xhtml:html/xhtml:body/xhtml:h1/jcr:xmltext
/importxml/xhtml:html/xhtml:body/xhtml:h1/jcr:xmltext/jcr:primaryType=nt:unstructured
/importxml/xhtml:html/xhtml:body/xhtml:h1/jcr:xmltext/jcr:xmlcharacters=AnEllipse and a Rectangle
/importxml/xhtml:html/xhtml:body/svg:svg
/importxml/xhtml:html/xhtml:body/svg:svg/jcr:primaryType=nt:unstructured
/importxml/xhtml:html/xhtml:body/svg:svg/width=12cm
/importxml/xhtml:html/xhtml:body/svg:svg/height=10cm
這個示例和第2個示例相比有很多相似的地方:我們創建登錄1個寫訪問的新會話。接著插入數據到倉庫中。這次通過導入1個xml文件并且終究我們輸出全部庫的內容
現在你應當熟習登錄1個倉庫(Repository.login)
在倉庫根結點下(Session.getRootNode),創建1個新的節點(Node.addNode)
并在關閉保存會話時,將我們修改內容進行持久化,(Session.save)
讓我們看看這個例子中使用的新方法,如何導入xml內容
session.importXML(node.getPath(), xml, ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW);
將1個xml文檔解析,并添加解析的結果項目字段到給定路徑的1個子節點
ImportUUIDBehavior標志控制如何處理傳入的節點標示符
有以下4種選項
? ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW:
輸入節點將和Node.addNode方法1樣被添加。他們也能夠指定新創建的標示符添加或保存修改 在任何情況下標示符重復是不會產生的
? ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING:
如果輸入節點有1個相同的標示符結點在工作空間已存在,那末在輸入節點添加上前,不管在工作空間的甚么位置已存在的節點和子節點將被刪除, 請注意,該節點將從本地的工作空間消失,遠程獲得的輸入結點及子節點將會被寫入。刪除和添加都將分別被保存
? ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING:
如果輸入節點有1個相同的標示符結點在工作空間已存在,那末已存在的節點將會在相同的位置替換為輸入節點.請注意,這可能致使子節點作為輸入和向周圍傳播到不同位置的工作空間。在最極真個例子,可能會致使沒有節點會被添加在該父節點的絕對路徑的子節點.如果如數的xml的最頂真個元素有相同的標示符在現有的工作空間。這些改變將被分別保存.
? ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW:
如果輸入節點有1個相同的標示符結點在工作空間已存,那末將會拋出1ItemExistsException異常
另外一個有趣的方法是
voiddump(Node node)
調用該方法將解決如何遞歸遍歷示例的所有庫,并且檢查每一個節點屬性。
要注意多值的屬性,我們使用它們需要調用
property.getDefinition().isMultiple()
如果返回true那末就是1個多值屬性
Value[] values = property.getValues();
否則我們調用api 獲得需要的值
property.getString()
這相當于
property.getValue().getString()
對事務相干的代碼示例是JcrUtils.