http://jcp.org/aboutJava/communityprocess/final/jsr170/index.html
何で今更こんな仕様をナナメ読み!
1 Preface
とばす
2 INTRODUCTION
いろんなベンダーが独自コンテントリポジトリを作ってるから共通APIが必要だと。このAPIは実装アーキテクチャ、データソース、プロトコルには依存しません。
2つの compliance level と、オプショナルなfeaturesを定義します。
Level 1 : read-only リポジトリ
Level 2 : 書き込み
Optional Features : トランザクションとか
3 USE CASES
共通APIがあれば便利だぜ(それ以上のこと言ってるか?この章)
4 THE REPOSITORY MODEL
ワークスペースはアイテムのツリーを持ちます。アイテムはノード、またはプロパティーです。ノードは子ノードと子プロパティを持ちます。ワークスペースには親のいないひとつのルートノードがあって、そこから木構造が始まります。プロパティは子供を持ちません。 --- XMLとかと同じ、普通の木構造ですね。このスタイルの源流って何なんだろう?
4.1 API Basics
Repository をどっかから(JNDIとか)もらってきて、 Credentials と ワークスペース名で login し、 Session を受け取る。 あとは Session が大活躍。
Session.getRootNode() とか、Node.getNode(String relPath), Node.getProperty(String relPath)とかで相対パスでアクセス。Session.getItem(String abspath) で絶対パスでアクセス。Session.getNodeByUUID(String uuid)でUUIDでアクセス。addNode(), setProperty() で書き込み。あとremove()とか。
Session.save()でValidationと永続化。save前の状態の変更点は"pending changes"と呼ぶ。Session.refresh(false)で破棄。トランザクションがある場合は、永続化はコミット時。ただしsave()はいずれにせよ必要。Validationはsave時に行われる。
4.2 Compliance Levels
Level 1 includes:
- Retrieval and traversal of nodes and properties
- Reading the values of properties
- Transient namespace remapping
- Export to XML/SAX
- Query facility with XPath syntax
- Discovery of available node types
- Discovery of access control permissions
Level 2 adds:
- Adding and removing nodes and properties
- Writing the values of properties
- Persistent namespace changes
- Import from XML/SAX
- Assigning node types to nodes
Optional:
Any combination of the following features may be added to an implementation of either level.
- Transactions
- Versioning
- Observation (Events)
- Locking
- SQL syntax for query
まあ普通Level2までは実装するんじゃね?あとOptionalでもTransactionとVersioningはかなり欲しいところだろう。
4.3 Same–Name Siblings
同じ親に同じnameのノードが許されるノードタイプがある(プロパティはダメ)。Node.getNodes(String namePattern)でiteratorが返ってくる。パスは添字つけて /a/b[2]/c[3] とかになる。そのリスト内の順序も要考慮(Orderable Child Nodes)。
めんどくせーな、禁止すればいいのに。と言いたいが、「Portalノードの下に複数のPageノードがあります」って言われると、まあそうか、仕方ないな。
4.4 Orderable Child Nodes
Node.getNodes()で返ってくるノードの順番はNode.orderBefore()で変更できる。できるかどうかはノードタイプに依存。
4.5 Namespaces
built-in Namespaceは
4.6 Path Syntax
Name と Path は違うので注意。Name は添字無し ( myapp:paragraph )で、 Path は添字あり ( myapp:paragraph[3] )。
4.7 Properties
複数の値を持つプロパティあり。めんどくせーな。
PropertyTypeで、REFERENCE, PATH, NAME プロパティは特別。
NAME : ノードタイプ名とか。Namespace-aware
PATH : パス。Namespace-aware
REFERENCE : UUID
4.7.3 No Null Values
nullは不可。Multi-value propertyの場合は、nullをsetすると、リストからの削除を意味する。
4.8 Node Types
ノードは必ずひとつだけ、primary type を持つ。 -> プロパティ jcr:primaryType
primaryに加えて、さらに複数の mixin types を持つことが可能。 -> プロパティ jcr:mixinTypes
4.9 Referenceable Nodes
Referenceable Node は mix:referenceable を mixin する。プロパティ jcr:uuid を持つ。なのでUUIDで参照できる。
Referenceable Nodeが削除されるとき、そのノードに対するリファレンス(PropertyType.REFERENCEによってされているはず)も削除されていること。frozen version state の場合は例外。
4.10 Workspaces
ひとつのリポジトリで、複数のワークスペースがある場合、あるワークスペースのノードは、別ワークスペースにcorresponding nodesを持つことができる。次のVersioningの仕様でサポートされる。。。がこの機能自体は重要ではないように思う。本当に必要か?
4.11 Versioning
Versioningをサポートする場合、ノードは mix:versionable を mixin。versionのsaveをchecking inと呼ぶ。Version historyはVersion storageに保存される。ひとつのrepositoryにひとつのVersion storageがある。各Workspaceには /jcr:system/jcr:versionStorage というノードがあり、そこから参照できる。
4.12 Metadata
結局「コンテンツ」はプロパティの中にある。APIは「コンテンツ」と「メタデータ」を区別しないが、アプリ的には区別したい。APIには"primary child item"というコンセプトがある。Node.getPrimaryItem()を呼べば、そのノードの"primary child item"が取れるので、一般的には(ノードタイプによるが)、そのノードの「コンテンツ」がとれるはず。
4.13 Hierarchical versus Direct Access
UUIDがあるので、Hierarchicalな構造は必須ではないよ、という話。
5 EXAMPLE IMPLEMENTATIONS
いろんな実装例。もちろん普通はDB。
6 LEVEL 1 REPOSITORY FEATURES
ここからが本番。。。だけどマジ長いのでナナメ読み度が増す。
Level 1 は read-only repository.
- Retrieval and traversal of nodes and properties
- Reading the values of properties
- Transient namespace remapping
- Export to XML/SAX
- Query facility with XPath syntax
- Discovery of available node types
6.1 Accessing the Repository
Repository.login(Credentials credentials, String workspaceName) でログインしたら Session が返ってくる。
6.2 Reading Repository Content
Session のメソッドでいろいろアクセス。getWorkspace()でWorkspaceオブジェクトも取れる。Node のメソッドでノードからいろいろ取ったり、相対パスアクセス。Propertyからプロパティ読む。プロパティの値はValueオブジェクト。ItemはNode, Propertyの親インターフェース。
6.3 Namespaces
Workspace.getNamespaceRegistry() で NamespaceRegistry オブジェクトが取れる。URIとprefixのマッピングを持っている。ビルトインのマッピングは
- jcr -> http://www.jcp.org/jcr/1.0
ビルトインのノードタイプ内で定義されるItem(つまりNodeまたはProperty)用
プライマリノードタイプの名前用
mixinノードタイプの名前用
XMLの互換性のためにあるけどクライアントは使っちゃダメらしい
- “” (the empty prefix) -> “” (the empty URI)
デフォルト名前空間。普通に使われるのかよくわからん
Session.setNamespacePrefix(String prefix, String uri) で当該セッションのみマッピングを変えられる。たぶん重要じゃない。
6.4 XML Mappings
リポジトリをXMLで表現できる。system view と document view の2種類のマッピング方式がある。
system view はリポジトリの完全なSerialization。名前空間は xmlns:sv="http://www.jcp.org/jcr/sv/1.0" で、XMLは
document viewはもっとhuman-readable。system view と比べて冗長さが無い感じ。細かいルールがいろいろ。
あと、文字のエスケープについて。
6.5 Exporting Repository Content
Session.exportSystemView()やSession.exportDocumentView()でexportできます。
6.6 Searching Repository Content
XPathやSQL(optional)で検索可能。XPathはdocument viewに対してかける。
クエリの文法とか。jcr:like みたいな function が XPath内で使える。きもい。
Workspace.getQueryManager()でQueryManagerオブジェクトを取って、QueryManager.createQuery(String statement, String language)でQueryオブジェクトを作る。
6.7 Node Types
ノードタイプとは、そのノードがどのような子ノードもしくはプロパティを持つことができるか/持たなければいけないか、を定義したものです。
ノードタイプは Name, Supertypes, Mixin status, Orderable child nodes status, Property definitions, Child node definitions, Primary Item Name を持ちます。
すべてのノードはただ一つの primary node type を持ちます。さらに mixin node type を持つことができます。
Property Definition は name, type, value constraints, default value, auto-createdかどうか, mandatoryかどうか, onParentVersion, protectedかどうか, multiple valuesかどうか、を持ちます。
Child Node Definition は name, required primary node types, default primary node type, auto-createdかどうか, mandatoryかどうか, onParentVersion, protectedかどうか, same-name siblingsかどうか、を持ちます。
note type は supertype から継承可能。
NodeTypeオブジェクトから、いろいろ取れる。
nt:base はすべてのノードタイプの親タイプ。
mix:referenceable, mix:versionable, mix:lockable が定義されている(optional)
6.7.22 Predefined Primary Node Types にpredefined ノードタイプの詳細が! これを書き留める気は。。。無いです。ヒエラルキーもあります。nt:unstructured は nt:base の子なんですね。
6.8 System Node
/jcr:system はシステムフォルダ。/jcr:system/jcr:nodeTypes とか /jcr:system/jcr:versionStorage とか。
6.9 Access Control
JAASも使えるよ。
7 LEVEL 2 REPOSITORY FEATURES
Level 2 は書く方。
- Adding and removing nodes and properties
- Writing the values of properties
- Persistent namespace changes
- Import from XML/SAX
- Assigning node types to nodes
7.1 Writing Repository Content
Sessionで行った更新処理は 'Transient Storage' に書き込まれ、Session.save()でWorkspaceに書き込まれる(Transactionサポートの時はcommit時)。Session.refresh(false)を呼べば捨てることができる。Item.save、 Item.refresh(false)でItemレベルでもできる。
以下のメソッドはダイレクトにWorkspaceに書き込む。
- Node.checkin, checkout, restore, restoreByLabel, merge, cancelMerge, doneMerge, update, lock and unlock.
- Workspace.move, copy, clone, restore and importXML
- VersionHistory.addVersionLabel, removeVersionLabel, removeVersion.
Validationは可能ならすぐやるが、遅くともsave時に行う。
7.1.3.4 Seeing Changes Made by Other Sessions に複数Sessionのconcurrencyの記述。Copy-on-Read にするか Copy-on-Write にするかは実装依存。
ValueFactory.createValue(String)でValueを作る。
7.2 Adding and Deleting Namespaces
アプリケーション固有のノードタイプ、プロパティ定義などを追加するには必須かな?
7.3 Importing Repository Content
system view のXMLはリポジトリの完全なSerializationだからいいとして、document viewの場合はここにある細かいルールにしたがってimportされる。暗黙にノードを追加したりノードタイプを決めたりしたりして、怪しい。
7.4 Assigning Node Types
ノード作成時に primary/mixin node type を決める。自動的につけても良い。
7.5 Thread-Safety Requirements
javax.jcr.Repository のすべてのメソッドはスレッドセーフでなければならない。あとは必須ではない。のでSessionのマルチスレッド操作に注意!
8 OPTIONAL REPOSITORY FEATURES
Level 1/2 以外のオプショナルな機能です。各JCR実装がこれらの機能をサポートしてるかどうかは注意しましょう。
8.1 Transactions
JTAのトランザクションに乗っかってcommit/rollbackされるということ。
8.1.1 Container Managed Transactions: Sample Request Flow のシーケンス図は重要かな。実際はXARepositoryなどというインターフェースは無く、XASession自身がXAResourceをimplementsするのが普通と思われる。
Sessionの処理が複数のトランザクションにまたがる場合、Session内のsave前のtransient storageはどうなるかという話。
8.2 Versioning
The versioning system is modelled after the Workspace Versioning and Configuration Management (WVCM) API defined by JSR 147. えー、これ読まないとだめすかねえ。
ノードは要mix:versionable。Node.checkin() でバージョンが作られる。
8.2.2 Version Storage でバージョンのノード構造が語られている。。。頭がぐるぐるするよ。
うーん、ここかなり重いです。
8.3 Observation
普通にEventListenerとかでやるみたい
8.4 Locking
mix:lockable なノードに対して、Node.lock() したら、他のユーザはwriteオペレーションができない、ということ。ロック取りっぱなし問題が発生しそうですね!タイムアウトは可能。