You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by mr...@apache.org on 2019/05/20 11:23:20 UTC

svn commit: r1859550 [12/26] - in /jackrabbit/site/live/archive: ./ wiki/ wiki/JCR/ wiki/JCR/attachments/ wiki/JCR/attachments/115513387/ wiki/JCR/attachments/115513390/ wiki/JCR/attachments/115513408/ wiki/JCR/attachments/115513413/ wiki/JCR/attachmen...

Added: jackrabbit/site/live/archive/wiki/JCR/ItemStateManagement_115513413.html
URL: http://svn.apache.org/viewvc/jackrabbit/site/live/archive/wiki/JCR/ItemStateManagement_115513413.html?rev=1859550&view=auto
==============================================================================
--- jackrabbit/site/live/archive/wiki/JCR/ItemStateManagement_115513413.html (added)
+++ jackrabbit/site/live/archive/wiki/JCR/ItemStateManagement_115513413.html Mon May 20 11:23:18 2019
@@ -0,0 +1,327 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Apache Jackrabbit : ItemStateManagement</title>
+        <link rel="stylesheet" href="styles/site.css" type="text/css" />
+        <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+    </head>
+
+    <body class="theme-default aui-theme-default">
+        <div id="page">
+            <div id="main" class="aui-page-panel">
+                <div id="main-header">
+                    <div id="breadcrumb-section">
+                        <ol id="breadcrumbs">
+                            <li class="first">
+                                <span><a href="index.html">Apache Jackrabbit</a></span>
+                            </li>
+                                                    <li>
+                                <span><a href="Home_70731.html">Home</a></span>
+                            </li>
+                                                </ol>
+                    </div>
+                    <h1 id="title-heading" class="pagetitle">
+                                                <span id="title-text">
+                            Apache Jackrabbit : ItemStateManagement
+                        </span>
+                    </h1>
+                </div>
+
+                <div id="content" class="view">
+                    <div class="page-metadata">
+                        
+        
+    
+        
+    
+        
+        
+            Created by <span class='author'> ASF Infrabot</span> on May 20, 2019
+                        </div>
+                    <div id="main-content" class="wiki-content group">
+                    
+
+
+
+
+
+<h1 id="ItemStateManagement-management"><a class="createlink" href="/confluence/pages/createpage.action?spaceKey=JCR&amp;title=ItemState&amp;linkCreation=true&amp;fromPageId=115513413">ItemState</a> management</h1>
+
+<p><strong>Note:</strong> This documentation has been created based on jackrabbit-core-1.6.1.</p>
+
+<p>The JCR API evolves around <em>Nodes</em> and <em>Properties</em> (which are called <em>Items</em>). Internally, these <em>Items</em> have an <em>ItemState</em> which may or may not be persistent. Modifications to <em>Items</em> through the JCR <em>Session</em> act on the <em>ItemState</em>, and saving the JCR <em>Session</em> persists the touched <em>ItemStates</em> to the persistent store, and makes the changes visible to other JCR <em>Sessions</em>. The management of <em>ItemState</em> instances over various concurrent sessions is an important responsibility of the Jackrabbit core. The following picture shows some of the relevant components in the management of <em>ItemStates</em>.</p>
+
+<p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="attachments/115513413/115513419.png" data-image-src="attachments/115513413/115513419.png" data-unresolved-comment-count="0" data-linked-resource-id="115513419" data-linked-resource-version="1" data-linked-resource-type="attachment" data-linked-resource-default-alias="ISM Components.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="115513413" data-linked-resource-container-version="1"></span></p>
+
+<p>Core components and their responsibilities:</p>
+<ul>
+	<li>A <em>Session</em> implementation is the starting point for interaction with a JCR instance. It is obtained by  logging in through the <em>Repository</em> instance, which is not shown in the picture above. A <em>Session</em> reflects the clients view on the repository state, and manages transient changes of the client to the repository state which can be persisted by calling <em>Sesssion.save()</em>. A <em>SessionImpl</em> instance has a <em>SessionItemStateManager</em>, a <em>HierarchyManager</em> and an <em>ItemManager</em>.</li>
+	<li>The <em>SessionItemStateManager</em> implements the <em>UpdatableItemStateManager</em> type (which extends the <em>ItemManager</em> type). Its main responsibilities are to provide access to persistent items, and to manage transient items (i.e., items that have been modified through the session but which have not yet been saved).</li>
+	<li>The <em>ItemManager</em> is responsible for providing access to <em>NodeImpl</em> and <em>PropertyImpl</em> instances by path (e.g., the call Session.getNode(&quot;/A&quot;) will end up in the <em>ItemManager</em>. It uses the <em>SessionItemStateManager</em> to get access to <em>ItemStates</em> which it needs to create <em>Node</em> and <em>Property</em> instances for the client of the API.</li>
+	<li>A <em>HierarchyManager</em> is responsible for translating paths to internal <em>ItemId</em> instances (a UUID for Nodes and a UUID + property name for Properties) and vice versa. It typically is session local as it must take the transient changes into account.</li>
+	<li>The <em>LocalItemStateManager</em> isolates changes to persistent states from other clients. It does this by wrapping states obtained from the <em>SharedItemStateManager</em>. It also builds a <em>ChangeLog</em> instance that is passed on to the <em>SharedItemStateManager</em> when the session is saved.</li>
+	<li>The <em>SharedItemStateManager</em> manages persistent states and stores states when sessions are saved using a <em>PersistenceManager</em> instance. It also updates the search index, synchronizes with the cluster and triggers the observation mechanism (all on session save).
+<br class="atl-forced-newline"/></li>
+</ul>
+
+
+<p>Miscellaneous concepts:</p>
+<ul>
+	<li>The <em>ItemData</em> type and subtypes are a thin wrapper around the <em>ItemState</em> type and subtypes. The <em>ItemManager</em> creates new <em>Item</em> instances every time it is asked for an item (e.g., via <em>session.getNode(&quot;/A&quot;)</em>). These items, however, point to the same <em>NodeData</em> instance which keeps track of whether the item has been modified (via its status field).</li>
+	<li>Shareable nodes are a JCR 2.0 feature (see section 3.9 of the spec). It touches at least the <em>ItemState</em>, <em>AbstractNodeData</em> and <em>ItemManager</em> types.</li>
+	<li>The <em>NodeStateMerger</em> type is a helper class whose responsibility it is to merge changes from other <em>Sessions</em> to the current <em>Session</em>. It is used in the <em>SessionItemStateManager</em> and the <em>SharedItemStateManager</em>. In the first case it is used in a callback function (called from the <em>SharedItemStateManager</em>) to merge changes in the persistent state to the transient state of the <em>Session</em>. In the second case it is used just before a <em>ChangeLog</em> is persisted to merge differences between the given <em>ChangeLog</em> and the persistent state.
+<br class="atl-forced-newline"/></li>
+</ul>
+
+
+<p>Remarks:</p>
+<ul>
+	<li>There are a number of implementations of the <em>PersistenceManager</em> interface. The managers from the <em>bundle</em> package are recommended. The <em>AbstractBundlePersistenceManager</em> also has a cache (the <em>BundleCache</em>) which caches persistent states.</li>
+	<li>The locking strategy of the <em>SharedItemStateManager</em> is per workspace configurable through the <em>ISMLocking</em> entry in the repository descriptor.
+<br class="atl-forced-newline"/></li>
+</ul>
+
+
+<p>The next sections show collaboration diagrams for various use cases that read and/or modify content.</p>
+
+<h2 id="ItemStateManagement-Usecase1:simpleread">Use case 1: simple read</h2>
+
+<p>The following is a collaboration diagram of what happens w.r.t. <em>ItemState</em> management in the Jackrabbit core when a <em>Session</em> reads a single existing node just after startup (i.e., Jackrabbit caches are empty).</p>
+
+<p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="attachments/115513413/115513417.png" data-image-src="attachments/115513413/115513417.png" data-unresolved-comment-count="0" data-linked-resource-id="115513417" data-linked-resource-version="1" data-linked-resource-type="attachment" data-linked-resource-default-alias="Session load.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="115513413" data-linked-resource-container-version="1"></span></p>
+
+<ol>
+	<li>The client of the API has a <em>Session</em> already and asks it to get the node at path &quot;/A&quot;.</li>
+	<li>The <em>Session</em> delegates this to its <em>ItemManager</em>.</li>
+	<li>The <em>ItemManager</em> does not have <em>ItemData</em> in its cache (a plain <em>Map</em>) for the requested item. It asks its <em>SessionItemStateManager</em> for the <em>ItemState</em>.</li>
+	<li>The <em>SessionItemStateManager</em> does not have the item in its caches and delegates to the <em>LocalItemStateManager</em>.</li>
+	<li>The <em>LocalItemStateManager</em> does not have the item in its caches and delegates to the <em>SharedItemStateManager</em>.</li>
+	<li>The <em>SharedItemStateManager</em> does not have the item in its caches and delegates to the <em>PersistenceManager</em> which returns the &quot;shared&quot; <em>ItemState</em> after reading it from the persistent store (database).</li>
+	<li>The <em>SharedItemStateManager</em> puts the item in its cache and returns it to the calling <em>LocalItemStateManager</em>.</li>
+	<li>The <em>LocalItemStateManager</em> creates a new &quot;local&quot; <em>ItemState</em> based on the returned (shared) <em>ItemState</em>. The former refers to the latter as the &quot;overlayed state&quot;. This basically is a copy-on-read action.</li>
+	<li>This local <em>ItemState</em> is put in the cache of the <em>LocalItemStateManager</em> and returned to the <em>SessionItemStateManager</em> which returns it to the <em>ItemManager</em>.</li>
+	<li>The <em>ItemManager</em> creates an <em>ItemData</em> instance and puts it in its cache,</li>
+	<li>then it creates a new <em>NodeImpl</em> instance based on the <em>ItemData</em> and returns that to the <em>Session</em> which gives it to the client.
+<br class="atl-forced-newline"/></li>
+</ol>
+
+
+<p>Remarks:</p>
+<ul>
+	<li>The <em>ItemManager</em> returns a new <em>Item</em> instance for every read call. Two of such instances that refer to the same <em>Item</em>, however, have the same <em>ItemData</em> reference. This ensures that changes to the state of one instance are immediately visible to the second instance.</li>
+	<li>The <em>LocalItemStateManager</em> creates a copy of the shared (persisted) <em>ItemState</em> managed by the <em>SharedItemStateManager</em>. The <em>local</em> state has the <em>shared</em> state as overlayed state. Similarly, if an <em>Item</em> is modified in the session, then a new <em>transient</em> state is created and managed by the <em>SessionItemStateManager</em> (see next use case). This transient state has the local state as overlayed state.</li>
+	<li>Each <em>ItemState</em> has a <em>container</em>. This is the <em>ItemStateManager</em> that created it. Shared states have the <em>SharedItemStateManager</em> as container, local states have the <em>LocalItemStateManager</em> as container, and transient states have the <em>SessionItemStateManager</em> as container.</li>
+	<li>A <em>LocalItemStateManager</em> registers itself as a listener with the <em>SharedItemStateManager</em> on creation. Similarly, a <em>SessionItemStateManager</em> registers itself as a listener with its <em>LocalItemStateManager</em> on creation. This listener structure is used for callbacks to make changes of other sessions visible (see next use cases).
+<br class="atl-forced-newline"/></li>
+</ul>
+
+
+<h2 id="ItemStateManagement-Usecase2:simplewrite">Use case 2: simple write</h2>
+
+<p>Consider the situation in which we have just executed use case  1. I.e., the client has a reference to a <em>NodeImpl</em>. The following shows what happens when the client adds a single property to that node.</p>
+
+<p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="attachments/115513413/115513414.png" data-image-src="attachments/115513413/115513414.png" data-unresolved-comment-count="0" data-linked-resource-id="115513414" data-linked-resource-version="1" data-linked-resource-type="attachment" data-linked-resource-default-alias="Session modify.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="115513413" data-linked-resource-container-version="1"></span></p>
+
+<ol>
+	<li>The client invokes <em>setProperty(&quot;prop A&quot;, &quot;value&quot;)</em> on the <em>NodeImpl</em>.</li>
+	<li>The <em>NodeImpl</em> delegates the creation of a transient property state to the <em>SessionItemStateManager</em>.</li>
+	<li>The <em>SessionItemStateManager</em> creates a new <em>PropertyState</em>,</li>
+	<li>puts it in the transient store cache and returns it to the <em>NodeImpl</em>.</li>
+	<li>The <em>NodeImpl</em> now must create a property item instance and calls the <em>ItemManager</em> for this with the new <em>PropertyState</em>.</li>
+	<li>The <em>ItemManager</em> creates new property data based on the given state, puts it in its local cache, and</li>
+	<li>creates a new <em>PropertyImpl</em> instance which it returns to the <em>NodeImpl</em>.</li>
+	<li>The <em>NodeImpl</em> must still modify the <em>NodeState</em> to which the property has been added and delegates the creation of a transient state to the <em>SessionItemStateManager</em>.</li>
+	<li>The <em>SessionItemStateManager</em> creates a new <em>NodeState</em>,</li>
+	<li>puts it in its transient store and returns it to the <em>NodeImpl</em> which sets the name of the new property in its now transient state and returns the created <em>PropertyImpl</em> instance.
+<br class="atl-forced-newline"/></li>
+</ol>
+
+
+<p>Remarks:</p>
+
+<ul>
+	<li>The <em>ItemManager</em> has a cache of <em>ItemData</em> instances.</li>
+	<li>Modification of a node creates a transient copy of the local <em>ItemState</em>.
+<br class="atl-forced-newline"/></li>
+</ul>
+
+
+<p>Now suppose that another <em>Session</em> also adds a property to the same node. The following picture shows the relations of the various item state managers and the existing item states in the caches of the <em>unsaved</em> sessions.</p>
+
+<p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="attachments/115513413/115513416.png" data-image-src="attachments/115513413/115513416.png" data-unresolved-comment-count="0" data-linked-resource-id="115513416" data-linked-resource-version="1" data-linked-resource-type="attachment" data-linked-resource-default-alias="Cache hierarchy.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="115513413" data-linked-resource-container-version="1"></span></p>
+
+<p>The <em>SharedItemStateManager</em> has the shared state of the persistent node. It has two listeners: the <em>LocalItemStateManagers</em> of the existing <em>Sessions</em>. Each <em>LocalItemStateManager</em> has a local copy of the shared state, the local state which has the shared state as overlayed state, and has a <em>SessionItemStateManager</em> as a listener. Both <em>SessionItemSTateManagers</em> have a transient copy of their local state (the overlayed state) which contains the modifications (addition of a property), and also a transient state for the new property.</p>
+
+<h2 id="ItemStateManagement-Usecase3:save">Use case 3: save</h2>
+
+<p>Consider the situation in which we have just executed use case 2. I.e., the client has added a single property to an existing node. The transient space contains two items: the new <em>PropertyState</em> and the modified <em>NodeState</em> of the <em>Node</em> to which the new property has been added. The following shows what happens when the session is saved. Note that only the modified <em>NodeState</em> instance is taken into account because otherwise the picture becomes even more unreadable. The handling of the new <em>PropertyState</em> however is approximately the same.</p>
+
+<p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="attachments/115513413/115513415.png" data-image-src="attachments/115513413/115513415.png" data-unresolved-comment-count="0" data-linked-resource-id="115513415" data-linked-resource-version="1" data-linked-resource-type="attachment" data-linked-resource-default-alias="Session save.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="115513413" data-linked-resource-container-version="1"></span></p>
+
+<ol>
+	<li>The client calls <em>Session.save()</em>.</li>
+	<li>The <em>SessionImpl</em> retrieves the root node from the <em>ItemManager</em>.</li>
+	<li>The <em>SessionImpl</em> calls the <em>save</em> method on the <em>ItemImpl</em> which represents the root node.</li>
+	<li>The root <em>NodeImpl</em> retrieves the transient <em>ItemStates</em> that are descendants of itself (in this case the states of the modified node and the new property).</li>
+	<li>The root <em>NodeImpl</em> does some validations on the transient space (checks that nodetype constraints are satisfied, that the set of dirty items is self-contained, etc.).</li>
+	<li>The root <em>NodeImpl</em> starts an edit operation by calling <em>edit</em> on the <em>SessionItemStateManager</em>.</li>
+	<li>The <em>SessionItemStateManager</em> delegates this to the <em>LocalItemStateManager</em>,</li>
+	<li>which resets its <em>ChangeLog</em> instance.</li>
+	<li>The root <em>NodeImpl</em> retrieves the first transient item from the <em>ItemManager</em> (assume that this is the modified node),</li>
+	<li>and calls <em>makePersistent</em> on it.</li>
+	<li>The <em>NodeImpl</em> instance of node &quot;A&quot; copies data from the transient <em>NodeState</em> to the local <em>NodeState</em> (i.e., to the overlayed state of the transient state).</li>
+	<li>The <em>NodeImpl</em> instance calls <em>store</em> on the <em>SessionItemStateManager</em> with the local <em>NodeState</em> as argument.</li>
+	<li>The <em>SessionItemStateManager</em> delegates this to the <em>LocalItemStateManager</em> which</li>
+	<li>calls <em>modified</em> on its <em>ChangeLog</em> instance with the local state as argument. The <em>ChangeLog</em> records the local state as modified and</li>
+	<li>disconnects the local state from its overlayed state (the shared state which is contained by the <em>SharedItemStateManager</em>).</li>
+	<li>The <em>NodeImpl</em> instance of node &quot;A&quot; now asks the <em>SessionItemStateManager</em> to diconnect the transient state and it</li>
+	<li>delegates this call to the state itself. Now the transient state of node &quot;A&quot; has no overlayed state.</li>
+	<li>The <em>NodeImpl</em> instance of node &quot;A&quot; now uses the local state for its <em>NodeData</em>.</li>
+	<li>The <em>NodeImpl</em> instance of the root node now disposes the transient item state of node &quot;A&quot; and</li>
+	<li>the <em>SessionItemStateManager</em> calls <em>discard</em> on the transient <em>NodeState</em> of node &quot;A&quot; and removes it from its cache.</li>
+	<li>The <em>NodeImpl</em> instance of the root node now calls <em>update</em> on the <em>SessionItemStateManager</em> which</li>
+	<li>delegates this to the <em>LocalItemStateManager</em>, which on its turn</li>
+	<li>delegates this to the <em>SharedItemStateManager</em> with the local <em>ChangeLog</em> as argument.</li>
+	<li>The <em>SharedItemStateManager</em> reconnects the local state to the shared state managed by itself, merges changes from the local state and the shared state, and</li>
+	<li>adds the shared state to the shared <em>ChangeLog</em>.</li>
+	<li>The shared <em>ChangeLog</em> disconnects the shared state from its overlayed state (which does nothing because the shared state has no overlayed state).</li>
+	<li>The <em>SharedItemStateManager</em> now pushes the changes from the local <em>ChangeLog</em> to the shared states.</li>
+	<li>The local <em>ChangeLog</em> calls <em>push</em> on the local <em>NodeState</em> contained in its set of modified states.</li>
+	<li>The local <em>NodeState</em> copies its own data to the overlayed shared state (which is contained in the shared <em>ChangeLog</em>).</li>
+	<li>The <em>SharedItemStateManager</em> stores the <em>ChangeLog</em> to the persistent store and</li>
+	<li>calls <em>persisted</em> on its shared <em>ChangeLog</em>. (<strong>Important note:</strong> this invokes callbacks that make the changes visible to other sessions. This is modeled in the next view.)</li>
+	<li>After control is returned to the <em>LocalItemStateManager</em> it also calls <em>persisted</em> on ist local <em>ChangeLog</em> to invoke <em>ItemStateListener</em> callbacks.
+<br class="atl-forced-newline"/></li>
+</ol>
+
+
+<p>Remarks:</p>
+<ul>
+	<li>There are two <em>ChangeLogs</em> in use. One is the local <em>ChangeLog</em> which is assembled by the <em>LocalItemStateManager</em>. The shared <em>ChangeLog</em> is constructed from the local <em>ChangeLog</em> by the <em>SharedItemStateManager</em>. These are both essentially the same; the local <em>ChangeLog</em> is based on local states whereas the shared <em>ChangeLog</em> is based on shared states.</li>
+	<li>During the save of a session information flows from the transient state to the shared state. The <em>ItemImpl</em> (and subtypes) copy transient item state information to the local state. The <em>SharedItemStateManager</em> calls <em>push</em> on the local <em>ChangeLog</em> to push the local changes to the shared states (and thus to the shared <em>ChangeLog</em>).</li>
+	<li>During a save of a session information also flows back from the shared state to the transient and local states in other sessions. This is modeled in the next view.
+<br class="atl-forced-newline"/></li>
+</ul>
+
+
+<p>Consider the situation in which we have just executed use case 2. I.e., the client has added a single property to an existing node. The transient space contains two items: the new <em>PropertyState</em> and the modified <em>NodeState</em> of the <em>Node</em> to which the new property has been added. Now suppose that there is another <em>Session</em> which also has added a property to that existing node. The following shows what happens when the session is saved (focus on callbacks from the <em>SharedItemStateManager</em> to the transient states in the second session).</p>
+
+<p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="attachments/115513413/115513418.png" data-image-src="attachments/115513413/115513418.png" data-unresolved-comment-count="0" data-linked-resource-id="115513418" data-linked-resource-version="1" data-linked-resource-type="attachment" data-linked-resource-default-alias="Session save callback.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="115513413" data-linked-resource-container-version="1"></span></p>
+
+<ol>
+	<li>The API client saves the session.</li>
+	<li>The <em>update</em> operation on the <em>LocalItemStateManager</em> is called (the local <em>ChangeLog</em> has already been constructed and the local states in that <em>ChangeLog</em> have been disconnected from their shared counterparts).</li>
+	<li>The <em>SharedItemStateManager</em> is called to process the update in the given local <em>ChangeLog</em>.</li>
+	<li>The states in the local <em>ChangeLog</em> are connected to their shared counter parts and merged (step 4') if they are <em>stale</em>. This is necessary because it could have happened that between step 22 and 23 another session on another thread was saved which changed states in the local <em>ChangeLog</em> (which are disconnected from their shared states). The detection of whether a state is <em>stale</em> is done via modification counter. If the merge fails, a <em>StaleItemStateException</em> is thrown and the save fails.</li>
+	<li>When the merge succeeds the shared state is added to the shared <em>ChangeLog</em> which</li>
+	<li>disconnects the shared state (which effectively does nothing as the shared state has no overlayed state).</li>
+	<li>The changes in the local <em>ChangeLog</em> are pushed to the shared <em>ChangeLog</em> by</li>
+	<li>invoking <em>push</em> on each local state in the local <em>ChangeLog</em> which</li>
+	<li>copies the local state to the shared state.</li>
+	<li>Then the shared <em>ChangeLog</em> is given to the <em>PersistenceManager</em> to persist.</li>
+	<li>Now the changes are pushed down to other sessions. This is started by invocation of the <em>persisted</em> method on the shared <em>ChangeLog</em>.</li>
+	<li>The shared <em>ChangeLog</em> calls <em>notifyStateUpdated</em> on each of its modified states.</li>
+	<li>The modified shared state calls <em>stateModified</em> with itself as argument on its container, the <em>SharedItemStateManager</em>.</li>
+	<li>The <em>SharedItemStateManager</em> calls <em>stateModified</em> with the shared state as argument on every of its listeners. These are at least <em>LocalItemStateManagers</em> of every session in the workspace.</li>
+	<li>The <em>SharedItemStateManager</em> calls <em>stateModified</em> with the shared state as argument on a <em>LocalItemStateManager</em> of the other session.</li>
+	<li>The <em>LocalItemStateManager</em> pulls in the changes by invoking <em>pull</em> on the local state (if it exists!).</li>
+	<li>The state copies the information from its shared counterpart.</li>
+	<li>The <em>LocalItemStateManager</em> now calls his listeners with as argument the local state.</li>
+	<li>The <em>SessionItemStateManager</em> sees that a local state has been changed which has a transient state. It invokes the <em>NodeStateMerger</em> to try to merge the changes to the transient state.</li>
+	<li>The <em>NodeStateMerger</em> tries to merge the local state with the transient state by e.g., merging the child node entries.</li>
+	<li>...
+<br class="atl-forced-newline"/></li>
+</ol>
+
+
+<p>Remarks:</p>
+<ul>
+	<li>The <em>NodeStateMerger</em> is used by the <em>SessionItemStateManager</em> to merge changes from other sessions to transient states. It is also used by the <em>SharedItemStateManager</em> to merge changes of other sessions to a local <em>ChangeLog</em>. This is also necessary because the states in a local <em>ChangeLog</em> are disconnected from their shared counterparts which prevents that persisted changes are pulled in.
+<br class="atl-forced-newline"/></li>
+</ul>
+
+
+<h2 id="ItemStateManagement-Stalenessdetection,mergingandsynchronizationconsiderations">Staleness detection, merging and synchronization considerations</h2>
+
+<p>Since different <em>Sessions</em> can be used concurrently (i.e., from different threads) it is possible that two <em>Sessions</em> modify the same node and save at the same moment. There is essentially a single lock that serializes <em>save</em> calls: the <em>ISMLocking</em> instance in the <em>SharedItemStateManager</em>. This is a Jackrabbit-specific read-write lock which supports write locks for <em>ChangeLog</em> instances and read locks for individual items. The read lock is acquired when the <em>SharedItemStateManager</em> needs to read from its <em>ItemStateReferenceCache</em> (typically when <em>Sessions</em> access items: the <em>LocalItemStateManagers</em> create a local copy of the shared state). The write lock is acquired in two places:</p>
+<ul>
+	<li>When a API client saves its <em>Session</em>: the write lock is acquired in the <em>update</em> method which is called on the <em>SharedItemStateManager</em> by the <em>LocalItemStateManager</em> of the <em>Session</em> that is saved. It is downgraded to a read lock after the changes have been persisted just before the other sessions are being notified. The read lock is released after that.</li>
+	<li>When an external update from another cluster node needs to be processed (see next section). The write lock is acquired and release in the <em>externalUpdate</em> method of the <em>SharedItemStateManager</em>. In between a <em>ChangeLog</em> from another cluster node is processed (i.e., applied to the shared states and pushed to the local states).
+<br class="atl-forced-newline"/></li>
+</ul>
+
+
+<p>Thus, two threads can concurrently build their local <em>ChangeLogs</em>, but they need exclusive access to the <em>SharedItemStateManager</em> for processing their <em>ChangeLog</em>. During this processing a saving thread invokes call backs on the <em>ItemStateListener</em> interface (<em>LocalItemStateManager</em> and <em>SessionItemStateManager</em> implement that type) in other open sessions (via the <em>persisted</em> call on the shared <em>ChangeLog</em> in step 11). The intention of this listener structure is that open sessions get immediate access to the saved changes. Of course, there can be collisions which must be detected. Therefore, every <em>ItemState</em> instance has the following fields:</p>
+<ul>
+	<li>an <em>isTransient</em> flag which indicates whether the state has been created by the <em>SessionItemStateManager</em></li>
+	<li>a <em>modCount</em> counter which essentially is a revision number of the underlying shared state (it is updated through the <em>touch</em> method called from the <em>SharedItemStateManager</em>)</li>
+	<li>a <em>status</em> field which indicates the status of the state (one of UNDEFINED, EXISTING, EXISTING_MODIFIED, EXISTING_REMOVED, NEW, STALE_MODIFIED, STALE_DESTROYED)
+<br class="atl-forced-newline"/></li>
+</ul>
+
+
+<p>The <em>isStale</em> method on the <em>ItemState</em> is used for determining whether an <em>ItemState</em> can be saved to the persistent store. The method of staleness detection depends on whether the state is transient. If it is, then a staleness is determined by checking the <em>status</em> field. If it is not transient, then staleness is determined by the <em>modCount</em> and the <em>modCount</em> of the overlayed state. It is used in three places:</p>
+<ul>
+	<li>The <em>makePersistent</em> methods on the <em>NodeImpl</em> and <em>PropertyImpl</em> use it to throw an <em>InvalidItemStateException</em> if the transient state of the item has become stale.</li>
+	<li>The <em>stateModified</em> call back method on the <em>SessionItemStateManager</em> uses it to determine whether a merge is attempted. If a merge failed, then the status is set to a stale value. In that way, merges are only tried if they have not yet failed for the state. (The <em>ItemImpl.save</em> method uses stale statusses to fail fast.)</li>
+	<li>The <em>SharedItemStateManager</em> uses the <em>isStale</em> method to try a merge just before saving if a local state has become stale. This can occur because a local <em>ChangeLog</em> has been disconnected from the shared states. If another session then saves, it is possible that states in the local <em>ChangeLog</em> become stale (detected by the <em>modCount</em>).
+<br class="atl-forced-newline"/></li>
+</ul>
+
+
+<p>Concurrency issues:</p>
+<ul>
+	<li>Lack of synchronization between client-triggered operations such as (re)moving a node and call backs from other sessions that may affect the transient states and disrupt the client-triggered operation (by interleaving).
+<br class="atl-forced-newline"/></li>
+</ul>
+
+
+<h2 id="ItemStateManagement-Clustering(externalupdates)">Clustering (external updates)</h2>
+
+<p>In clustered environments potentially every cluster node may write to the JCR. Because the JCR spec requires a certain level of consistency the synchronized access to the local <em>SharedItemStateManager</em> is not enough to make things work. The global idea of the clustering mechanism is the following:</p>
+<ul>
+	<li>When the <em>SharedItemStateManager</em> saves a <em>ChangeLog</em> to the persistent store, it also writes a cluster <em>revision</em> (a representation of the just persisted <em>ChangeLog</em>) to some place where other cluster nodes can read it. Such a revision has a number, and every cluster node has a <em>local revision</em> number which indicates which revision entries they have processed.</li>
+	<li>There is a <em>global revision</em> counter which act as a cluster-wide lock. Before a <em>SharedItemStateManager</em> can save a <em>ChangeLog</em> it must acquire this repository-wide lock. This happens at the begin of the <em>Update</em> operation with the call <em>eventChannel.updateCreated(this)</em>. The locked global revision then becomes the number of the revision that is about to be written. Other cluster nodes now cannot save because they are blocked on the global revision lock.</li>
+	<li>Just after the <em>SharedItemStateManager</em> (or actually the <em>ClusterNode</em> type) acquires the global revision lock it also reads revisions of other cluster nodes to get completely up-to-date. This might prevent the current <em>ChangeLog</em> from being saved because other cluster nodes may have saved incompatible changes.</li>
+	<li>At the end of the _Update) update operation the global lock is released and other cluster nodes can save.</li>
+	<li>In order to keep up to date with the latest revison, the <em>ClusterNode</em> type periodically reads revisions and pushes these via the <em>SharedItemStateManager</em> to any active <em>Sessions</em>.</li>
+</ul>
+                    </div>
+
+                                        <div class="pageSection group">
+                        <div class="pageSectionHeader">
+                            <h2 id="attachments" class="pageSectionTitle">Attachments:</h2>
+                        </div>
+
+                        <div class="greybox" align="left">
+                                                            <img src="images/icons/bullet_blue.gif" height="8" width="8" alt=""/>
+                                <a href="attachments/115513413/115513414.png">Session modify.png</a> (image/png)
+                                <br/>
+                                                            <img src="images/icons/bullet_blue.gif" height="8" width="8" alt=""/>
+                                <a href="attachments/115513413/115513415.png">Session save.png</a> (image/png)
+                                <br/>
+                                                            <img src="images/icons/bullet_blue.gif" height="8" width="8" alt=""/>
+                                <a href="attachments/115513413/115513416.png">Cache hierarchy.png</a> (image/png)
+                                <br/>
+                                                            <img src="images/icons/bullet_blue.gif" height="8" width="8" alt=""/>
+                                <a href="attachments/115513413/115513417.png">Session load.png</a> (image/png)
+                                <br/>
+                                                            <img src="images/icons/bullet_blue.gif" height="8" width="8" alt=""/>
+                                <a href="attachments/115513413/115513418.png">Session save callback.png</a> (image/png)
+                                <br/>
+                                                            <img src="images/icons/bullet_blue.gif" height="8" width="8" alt=""/>
+                                <a href="attachments/115513413/115513419.png">ISM Components.png</a> (image/png)
+                                <br/>
+                                                    </div>
+                    </div>
+                    
+                                                      
+                </div>             </div> 
+            <div id="footer" role="contentinfo">
+                <section class="footer-body">
+                    <p>Document generated by Confluence on May 20, 2019 11:11</p>
+                    <div id="footer-logo"><a href="http://www.atlassian.com/">Atlassian</a></div>
+                </section>
+            </div>
+        </div>     </body>
+</html>

Propchange: jackrabbit/site/live/archive/wiki/JCR/ItemStateManagement_115513413.html
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/site/live/archive/wiki/JCR/ItemStateManagement_115513413.html
------------------------------------------------------------------------------
    svn:executable = *

Added: jackrabbit/site/live/archive/wiki/JCR/JCR-Binary-Usecase_115513420.html
URL: http://svn.apache.org/viewvc/jackrabbit/site/live/archive/wiki/JCR/JCR-Binary-Usecase_115513420.html?rev=1859550&view=auto
==============================================================================
--- jackrabbit/site/live/archive/wiki/JCR/JCR-Binary-Usecase_115513420.html (added)
+++ jackrabbit/site/live/archive/wiki/JCR/JCR-Binary-Usecase_115513420.html Mon May 20 11:23:18 2019
@@ -0,0 +1,238 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Apache Jackrabbit : JCR Binary Usecase</title>
+        <link rel="stylesheet" href="styles/site.css" type="text/css" />
+        <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+    </head>
+
+    <body class="theme-default aui-theme-default">
+        <div id="page">
+            <div id="main" class="aui-page-panel">
+                <div id="main-header">
+                    <div id="breadcrumb-section">
+                        <ol id="breadcrumbs">
+                            <li class="first">
+                                <span><a href="index.html">Apache Jackrabbit</a></span>
+                            </li>
+                                                    <li>
+                                <span><a href="Home_70731.html">Home</a></span>
+                            </li>
+                                                </ol>
+                    </div>
+                    <h1 id="title-heading" class="pagetitle">
+                                                <span id="title-text">
+                            Apache Jackrabbit : JCR Binary Usecase
+                        </span>
+                    </h1>
+                </div>
+
+                <div id="content" class="view">
+                    <div class="page-metadata">
+                        
+        
+    
+        
+    
+        
+        
+            Created by <span class='author'> ASF Infrabot</span> on May 20, 2019
+                        </div>
+                    <div id="main-content" class="wiki-content group">
+                    <p><strong>NOTE</strong> - Any proposed solution should be added to section Solution Proposals</p>
+
+<p>Below are few usecases which have been seen in past which cannot be met with current Oak Binary support. All such cases are meant to improve performance by reducing IO in cases where possible. Feature wise current Stream based approach supported by JCR Binary meets all requirement. The objective of this document is to capture such usecases  and then come up with ways/solutions to meet these requirements. Which of the below requirements should we try to meet is something to be discussed. Objective here is to have some usecases to initiate the discussion</p>
+
+<p>Per current design some implementation details</p>
+
+<ol>
+	<li><code>S3DataStore</code>
+	<ol>
+		<li>While performing any read the stream from <code>S3Object</code> is first copied to a local cache and then a <code>FileInputStream</code> is provided from that</li>
+		<li>Due to above even if code needs to read initial few bytes (say video metadata) then also the whole file is first spooled to a file in local cache and then stream is opened on that</li>
+	</ol>
+	</li>
+	<li><code>FileDataStore</code>
+	<ol>
+		<li>The file are stored in a directory structure like /xx/yy/zz/&lt;contenthash&gt; where xx,yy,zz are the initial few letters of the hex encoded content hash
+<br class="atl-forced-newline"/></li>
+	</ol>
+	</li>
+</ol>
+
+
+<h2 id="JCRBinaryUsecase-Usecases">Usecases</h2>
+
+<p><span class="confluence-anchor-link" id="JCRBinaryUsecase-UC1"></span></p>
+<h3 id="JCRBinaryUsecase-UC1-processingabinaryinJCRwithanativelibrarythatonlyhasaccesstothefilesystem">UC1 - processing a binary in JCR with a native library that only has access to the file system</h3>
+
+<p><em>Need access to absolute path of the File which back JCR Binary when using <code>FileDataStore</code> for processing by native program</em></p>
+
+<p>There are deployments where lots of images gets uploaded to the repository and there are some conversions (rendition generation) which are performed by OS specific native executable. Such programs work directly on file handle.</p>
+
+<p>Without this change currently we need to first spool the file content into some temporary location and then pass that to the other program. This add unnecessary overhead and something which can be avoided in case there is a <a href="DataStore_115513387.html">DataStore</a> where binary content is already in form of a file on the file system like <code>FileDataStore</code></p>
+
+<p><span class="confluence-anchor-link" id="JCRBinaryUsecase-UC2"></span></p>
+<h3 id="JCRBinaryUsecase-UC2-EfficientreplicationacrossregionsinS3">UC2 - Efficient replication across regions in S3</h3>
+
+<p><em>For binary less replication between multiple Sling instances in non shared <a href="DataStore_115513387.html">DataStore</a> setup across multiple regions need access to <code>S3Object</code> ID backing the blob such that it can be efficiently copied to a bucket in different region via S3 Copy Command</em></p>
+
+<p><a href="DataStore_115513387.html">DataStore</a> - <code>S3DataStore</code></p>
+
+<p>This for setup which is running on Oak with <code>S3DataStore</code>. There we have global deployment where a Sling based app (running on Oak with <code>S3DataStore</code>) is running in 1 region and binary content is to be distributed to publish instances running in different regions. The <a href="DataStore_115513387.html">DataStore</a> size is huge say 100TB and for efficient operation we need to use Binary less replication. In most cases only a very small subset of binary content would need to be present in other regions. Current way (via shared <a href="DataStore_115513387.html">DataStore</a>) to support that would involve synchronizing the S3 bucket across all such regions which would increase the storage cost considerably. </p>
+
+<p>Instead of that plan is to replicate the specific assets via s3 copy operation. This would ensure that big assets can be copied efficiently at S3 level</p>
+
+<p>Note that such a case can also be present in other <a href="DataStore_115513387.html">DataStore</a> where a binary content can be retrieved from source <a href="DataStore_115513387.html">DataStore</a> and added to target <a href="DataStore_115513387.html">DataStore</a> in optimal way (copy the binary from one repository to another repository).</p>
+
+<p><span class="confluence-anchor-link" id="JCRBinaryUsecase-UC3"></span></p>
+<h3 id="JCRBinaryUsecase-UC3-TextExtractionwithouttemporaryFilewithTika">UC3 - Text Extraction without temporary File with Tika</h3>
+
+<p><em>Avoid creation of temporary file where possible</em></p>
+
+<p>While performing text extraction by Tika in many cases it would be creating a temporary file as many parser need random access to the binary. So while using <code>BlobStore</code> where per implementation the binary exist as File we can use a <a class="createlink" href="/confluence/pages/createpage.action?spaceKey=JCR&amp;title=TikaInputStream&amp;linkCreation=true&amp;fromPageId=115513420">TikaInputStream</a> backed by that file which would avoid creation of such temporary file and thus speed up text extraction performance</p>
+
+<p>Going forward if we need to make use of <a href="https://issues.apache.org/jira/browse/TIKA-416" class="external-link" rel="nofollow">Out of Process Text Extraction</a> then this aspect would be useful there also</p>
+
+<p><span class="confluence-anchor-link" id="JCRBinaryUsecase-UC4"></span></p>
+<h3 id="JCRBinaryUsecase-UC4-SpoolingthebinarycontenttosocketoutputviaNIO">UC4 - Spooling the binary content to socket output via NIO</h3>
+
+<p><em>Enable use of NIO based zero copy file transfers</em></p>
+
+<p><a href="DataStore_115513387.html">DataStore</a> - <code>S3DataStore</code>, <code>FileDataStore</code></p>
+
+<p>For some time <a href="https://github.com/eclipse/jetty.project/blob/a12fd9ea033678b51158949a886792b74b42d0a9/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FastFileServer.java" class="external-link" rel="nofollow">Jetty has support</a> for doing async io and do a <a href="http://www.ibm.com/developerworks/library/j-zerocopy/" class="external-link" rel="nofollow">zero copy</a> file transfer. This would allow transferring the file content to the HTTP socket without making it pass through jvm and thus should improve throughput.</p>
+
+<p>Key aspect here is that where possible we should be able to avoid IO. Also have a look at <a href="https://kafka.apache.org/08/design.html#maximizingefficiency" class="external-link" rel="nofollow">Kafka design</a> which tries to make use of OS cache as much as possible and avoid Io via jvm if possible thus providing much better throughputs</p>
+
+<p><span class="confluence-anchor-link" id="JCRBinaryUsecase-UC5"></span></p>
+<h3 id="JCRBinaryUsecase-UC5-Transferringthefiletowithminimaloverhead">UC5 - Transferring the file to <a class="createlink" href="/confluence/pages/createpage.action?spaceKey=JCR&amp;title=FileDataStore&amp;linkCreation=true&amp;fromPageId=115513420">FileDataStore</a> with minimal overhead</h3>
+
+<p>_ Need a way to construct JCR Binary via a File reference where File instance  &quot;ownership is transferred&quot; say via rename without spooling its content again_</p>
+
+<p><a href="DataStore_115513387.html">DataStore</a> - <code>FileDataStore</code></p>
+
+<p>In some deployments a customer would typically upload lots of files in a FTP folder and then from there the files are transferred to Oak. As mentioned in 2b above with NAS based storage  this would result in file being copied twice. So to avoid the extra overhead it would be helpful if one can create a File directly in the NFS as per <code>FileDataStore</code> structure (content hash -&gt; split 3 level) and then add the Binary via <code>ReferenceBinary</code> approach</p>
+
+<p><span class="confluence-anchor-link" id="JCRBinaryUsecase-UC6"></span></p>
+<h3 id="JCRBinaryUsecase-UC6-S3import">UC6 - S3 import</h3>
+
+<p>This somewhat similar to previous case but more around S3 support</p>
+
+<p>Usecase here is that a customer has lots of existing binaries and those need to be imported to Oak repository. The binary might already exist on S3 or on there existing systems. S3 has lots of tooling to import large data sets efficiently , so its faster to bulk upload such binaries to an S3 bucket and then somehow transfer them to Oak for further management</p>
+
+<p>The problem though: how to efficiently get them into the S3DS, ideally without moving them</p>
+
+
+
+<p><span class="confluence-anchor-link" id="JCRBinaryUsecase-UC7"></span></p>
+<h3 id="JCRBinaryUsecase-UC7-Randomwriteaccessinbinaries">UC7 - Random write access in binaries</h3>
+
+<p>Think: a video file exposed onto the desktop via WebDAV. Desktop tools would do random writes in that file. How can we cover this use case without up/downloading the large file. (essentially: random write access in binaries)</p>
+
+<p><span class="confluence-anchor-link" id="JCRBinaryUsecase-UC8"></span></p>
+<h3 id="JCRBinaryUsecase-UC8-X-SendFile">UC8 - X-SendFile</h3>
+
+<p><a href="https://tn123.org/mod_xsendfile/" class="external-link" rel="nofollow">X-SendFile</a> is module support in Apache which enabled spooling the file content from the OS via using Apache internals including all optimizations like caching-headers and sendfile or mmap if configured. So if the file is present on the filesystem which Apache can access then it would be spooled in much more efficient way and avoid add load to the JVM. </p>
+
+<p>For this feature to work the web layer like Sling needs to know the path to the binary. Note that path is not disclosed to the client. </p>
+
+<p>To an extent this feature is similar to UC1 however here the scope is more broader.</p>
+
+<p>NB Although mod_xsendfile in Apache needs a path on the file system local to the Apache instance to get the binary it is a pointer. It does not need to be the same path that Oak uses internally provided it is presented as the patch on the file system. Other variants of X-sendfile (<a href="https://www.nginx.com/resources/wiki/start/topics/examples/xsendfile/" class="external-link" rel="nofollow">https://www.nginx.com/resources/wiki/start/topics/examples/xsendfile/</a>) allow that pointer to be resoved to an http location for streaming. </p>
+
+<h3 id="JCRBinaryUsecase-UC9-S3datastoreinacluster">UC9 - S3 datastore in a cluster</h3>
+
+<p>Currently, each cluster node connects to S3 and has a &quot;local cache&quot; on the file system. Binaries are uploaded asynchronously to S3, that means first written to the local cache. If a binary is added in one cluster node, it is not immediately available on S3 to be read from another cluster node, if async upload is enabled. See also <a href="https://issues.apache.org/jira/browse/OAK-4903" class="external-link" rel="nofollow">OAK-4903</a>.</p>
+
+<h3 id="JCRBinaryUsecase-UC10-Efficientlyconcatenate/split/modifybinaries">UC10 - Efficiently concatenate / split / modify binaries</h3>
+
+<p>Multiple (some large) TIFF files are concatenated into a PTIFF file, and when reading, in some cases only a subset of the PTIFF is read, and sometimes the whole. Metadata of an existing (large) TIFF is changed.</p>
+
+<h3 id="JCRBinaryUsecase-UC11-Textextractionduringupload">UC11 - Text extraction during upload</h3>
+
+<p><strong>Thomas</strong> One possible option would be to do text extraction while uploading. It will not scale if all uploads happen on the same machine however.</p>
+
+<h3 id="JCRBinaryUsecase-UC12-Textextractionstored&quot;nextto&quot;binary">UC12 - Text extraction stored &quot;next to&quot; binary</h3>
+
+<p><strong>Thomas</strong> Extracted text (independent from who created it) could be stored in the datastore. Possibly other metadata.</p>
+
+
+<p><span class="confluence-anchor-link" id="JCRBinaryUsecase-UC13"></span></p>
+<h3 id="JCRBinaryUsecase-UC13-adopt-a-binary">UC13 - adopt-a-binary</h3>
+
+<p>Mentioned by Bertrand on <a href="https://lists.apache.org/thread.html/cac83071a7c547581bbf2f2ae2c603742fb2f582b6b9371ac4b33ce8@%3Coak-dev.jackrabbit.apache.org%3E" class="external-link" rel="nofollow">oak-dev</a>. Idea here is that files already exist somewhere and are hence not &quot;managed&quot; by Oak. The binary content just needs to be made accessible via JCR Binary API. Possibly can be implemented if we have hierarchical <a class="createlink" href="/confluence/pages/createpage.action?spaceKey=JCR&amp;title=BlobStore&amp;linkCreation=true&amp;fromPageId=115513420">BlobStore</a> support where one of them enables resolving &quot;external&quot; blobIds like this</p>
+
+<p><span class="confluence-anchor-link" id="JCRBinaryUsecase-UC14"></span></p>
+<h3 id="JCRBinaryUsecase-UC14-Hierarchical">UC14 - Hierarchical <a class="createlink" href="/confluence/pages/createpage.action?spaceKey=JCR&amp;title=BlobStore&amp;linkCreation=true&amp;fromPageId=115513420">BlobStore</a></h3>
+
+<p>Idea here is to have blobs stored in different <a class="createlink" href="/confluence/pages/createpage.action?spaceKey=JCR&amp;title=BlobStores&amp;linkCreation=true&amp;fromPageId=115513420">BlobStores</a> depending on type/usage/path. But read happens via same Binary API. Something like this existed in JR2 <a href="https://jackrabbit.apache.org/api/2.8/org/apache/jackrabbit/core/data/MultiDataStore.html" class="external-link" rel="nofollow">MultiDataStore</a>. Also see <a href="https://wiki.apache.org/jackrabbit/DataStore#Future_Ideas" class="external-link" rel="nofollow">JR2 Wiki</a></p>
+
+
+
+
+<h2 id="JCRBinaryUsecase-SolutionProposals">Solution Proposals</h2>
+
+<h3 id="JCRBinaryUsecase-UC1-processingabinaryinJCRwithanativelibrarythatonlyhasaccesstothefilesystem.1">UC1 - processing a binary in JCR with a native library that only has access to the file system</h3>
+
+<p><strong>Thomas</strong></p>
+
+<p>I assume the native library only requires read-only access and will not delete or move the file; could we somehow enforce this? Maybe using a symbolic link to the real file in a read-only directory?</p>
+
+<p>How to ensure Oak GC doesn't delete the binary too early. One solution is that if the native library reads the file (or knows it will need to read the file soon), it updates the last modified time. This should already work. Another solution might be to add the file name to a text file (read log), but it would probably be more complicated, and probably wouldn't improve performance much.</p>
+
+<p><strong>Ian</strong> This use case needs to cover file systems and other storage mechanisms like S3. Controlling access is outside the scope of what Oak can control and depends on deployment teams.</p>
+
+<h3 id="JCRBinaryUsecase-UC3-TextExtractionwithouttemporaryFilewithTika.1">UC3 - Text Extraction without temporary File with Tika</h3>
+
+<p><strong>Thomas</strong></p>
+
+<p>We could add random access features to the binary, and possibly change Tika so it doesn't require a <code>java.io.File</code> but maybe a <code>java.nio.channels.SeekableByteChannel</code>, or just <code>FileChannel</code>, or <code>ByteBuffer</code>, or so. We might still need to write a wrapper for Tika, but maybe not.</p>
+
+<h3 id="JCRBinaryUsecase-UC4-SpoolingthebinarycontenttosocketoutputviaNIO.1">UC4 - Spooling the binary content to socket output via NIO</h3>
+
+<p><strong>Thomas</strong> Similar to Tika, we could extend the binary and add the missing / required features (for example get a <code>ByteBuffer</code>, which might be backed by a memory mapped file).</p>
+
+<p><strong>Ian</strong> Transfers should drill down to the underlying stream to see if they support NIO and use it if present. An example being the DS is a File system DS which has NIO, as does S3 the Jetty stream also supports NIO, so it should be possible for a servlet to get hold of both streams and connect the channels. This requires that the streams are available directly which requires the rest of the implementation to be efficient enough to not require local caching and copies of the files. There are a number of issues in Sling that need addressing first, some of which are being worked on. Streaming uploads, Streamed downloads to IE11 etc. I dont think adding NIO capabilities to streams that dont natively support NIO is the right solution and will only hide a more fundamental issue. The biggest issue (imvho) is that JCR Binary doesn't provide both an <a class="createlink" href="/confluence/pages/createpage.action?spaceKey=JCR&amp;title=OutputStream&amp;linkCreation=true&amp;f
 romPageId=115513420">OutputStream</a> and an <a class="createlink" href="/confluence/pages/createpage.action?spaceKey=JCR&amp;title=InputStream&amp;linkCreation=true&amp;fromPageId=115513420">InputStream</a> directly connected to the raw underlying storage, blocking the client from performing zero cost transfers available to most other stacks. </p>
+
+<h3 id="JCRBinaryUsecase-UC5-TransferringthefiletoFileDataStorewithminimaloverhead">UC5 - Transferring the file to <code>FileDataStore</code> with minimal overhead</h3>
+
+<p><strong>Thomas</strong></p>
+
+<p>Or provide a way to create a JCR binary from a temp file. Oak might then move (File.renameTo or otherwise) the file or copy the content if needed. That way we don't expose the implementation details (hash algorithm, file name format).</p>
+
+<h3 id="JCRBinaryUsecase-UC6-S3import.1">UC6 - S3 import</h3>
+
+<p><strong>Thomas</strong> Or provide a way to create a JCR binary from a S3 binary. Moving from S3 to S3 might not be a problem.</p>
+
+<h3 id="JCRBinaryUsecase-UC7+UC10-Randomwriteaccessinbinaries">UC7 + UC10 - Random write access in binaries</h3>
+
+<p><strong>Thomas</strong></p>
+
+<p>The Oak <code>BlobStore</code> chunks binaries, so that chunks could be shared among binaries. Random writes could then copy just the references to the chunks if possible. That would make random write relatively efficient, but still binaries would be immutable. We would need to add the required API. Please note this only works when using the <code>BlobStore</code>, not the current <code>FileDataStore</code> and <code>S3DataStore</code> as is (at least a wrapper around the <code>FileDataStore</code> / <code>S3DataStore</code> would be needed). This includes efficiently cutting away some bytes in the middle of a binary, or inserting some bytes. Typical file system don't support this case efficiently, however with the <a class="createlink" href="/confluence/pages/createpage.action?spaceKey=JCR&amp;title=BlobStore&amp;linkCreation=true&amp;fromPageId=115513420">BlobStore</a> it is possible.</p>
+
+<h3 id="JCRBinaryUsecase-UC8-X-SendFile.1">UC8 - X-SendFile</h3>
+
+<p><strong>Ian</strong> The Aim of X-Sendfile is to offload the streaming of large binaries from an expensive server capable of performing complex authorizations to a less expensive farm of servers capable of streaming data to a large number of clients. The X-sendfile header provides a location where the upstream proxy can find the response. That location has to be resolvable to the upstream server, it may contain authZ for the response and it may not divulge the structure of the store of neighbouring resources. What can be achieved depends on the implementation of the upstream servers X-sendfile capability. The apache mod_xsendfile module only supports mapping the location to the filesystem, so the DS would have to be mounted. Other X-Sendfile implementations, like nginX X-Accel-redriect that created the concept, supports mapping the location through to any URI location including through to http locations. This would allow the X-Accel-Redirect location to be mapped through to a htt
 p location capable of serving &gt; C10K request all streaming. In AWS, ELBs support signed URLs, so if a S3 store needed to be exposed, the URL  X-Accel-Redirect location could be a S3 bucket location fronted by an ELB configured to only allow access to signed requests conforming to a ACL policy. That policy including token expiry. Other variants of this are possible including requiring signed urls and hosting the content behind an elastic farm of Node.js/Jetty or any C10K capable server, each one validating the signature and token on every request from the nginX front end.  To achieve this Oak or Sling would need to expose the pointer to the binary, and document a signing structure giving access to that binary. If the identifier of the Binary is already exposed, via JCR properties, this may already be possible, with knowledge of the DS without any changes to Oak.</p>
+
+<p>Documentation on the AWS ELB signed urls is here <a href="http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-signed-urls.html" class="external-link" rel="nofollow">http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-signed-urls.html</a> Documentation on nginX's original concept is here <a href="https://www.nginx.com/resources/wiki/start/topics/examples/xsendfile/" class="external-link" rel="nofollow">https://www.nginx.com/resources/wiki/start/topics/examples/xsendfile/</a> </p>
+
+
+<h3 id="JCRBinaryUsecase-UC9-S3datastoreinacluster.1">UC9 - S3 datastore in a cluster</h3>
+
+<p><strong>Thomas</strong> Possible solutions are: (1) disable async upload; (2) not sure if that works correctly: use a shared local cache (NFS for example). Other solutions (would need more work probably) could be to send / request the binary using the broadcasting cache mechanism.</p>
+
+<p><p><strong>Ian</strong> This has been partially addressed with streaming uploads in Sling Engine 2.4.6 and Sling Servlets Post 2.3.14. WHen async cache is disabled, the session.save() connects the request <a href="/confluence/pages/createpage.action?spaceKey=JCR&amp;title=InputStream&amp;linkCreation=true&amp;fromPageId=115513420" class="createlink">InputStream</a> for the upload directly to the S3 <a href="/confluence/pages/createpage.action?spaceKey=JCR&amp;title=OutputStream&amp;linkCreation=true&amp;fromPageId=115513420" class="createlink">OutputStream</a> performing the transfer with no local disk IO, using a byte[]. As noted under UC4, this should be done over NIO wherever possible. Downloads of the binary also need to be streamed in a similar way. Local Disk IO is reported to be an expensive commodity by those who are deploying Sling/AEM at scale.</p></p>
+                    </div>
+
+                    
+                                                      
+                </div>             </div> 
+            <div id="footer" role="contentinfo">
+                <section class="footer-body">
+                    <p>Document generated by Confluence on May 20, 2019 11:11</p>
+                    <div id="footer-logo"><a href="http://www.atlassian.com/">Atlassian</a></div>
+                </section>
+            </div>
+        </div>     </body>
+</html>

Propchange: jackrabbit/site/live/archive/wiki/JCR/JCR-Binary-Usecase_115513420.html
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/site/live/archive/wiki/JCR/JCR-Binary-Usecase_115513420.html
------------------------------------------------------------------------------
    svn:executable = *

Added: jackrabbit/site/live/archive/wiki/JCR/JNDI_115513422.html
URL: http://svn.apache.org/viewvc/jackrabbit/site/live/archive/wiki/JCR/JNDI_115513422.html?rev=1859550&view=auto
==============================================================================
--- jackrabbit/site/live/archive/wiki/JCR/JNDI_115513422.html (added)
+++ jackrabbit/site/live/archive/wiki/JCR/JNDI_115513422.html Mon May 20 11:23:18 2019
@@ -0,0 +1,475 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Apache Jackrabbit : JNDI</title>
+        <link rel="stylesheet" href="styles/site.css" type="text/css" />
+        <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+    </head>
+
+    <body class="theme-default aui-theme-default">
+        <div id="page">
+            <div id="main" class="aui-page-panel">
+                <div id="main-header">
+                    <div id="breadcrumb-section">
+                        <ol id="breadcrumbs">
+                            <li class="first">
+                                <span><a href="index.html">Apache Jackrabbit</a></span>
+                            </li>
+                                                    <li>
+                                <span><a href="Home_70731.html">Home</a></span>
+                            </li>
+                                                </ol>
+                    </div>
+                    <h1 id="title-heading" class="pagetitle">
+                                                <span id="title-text">
+                            Apache Jackrabbit : JNDI
+                        </span>
+                    </h1>
+                </div>
+
+                <div id="content" class="view">
+                    <div class="page-metadata">
+                        
+        
+    
+        
+    
+        
+        
+            Created by <span class='author'> ASF Infrabot</span> on May 20, 2019
+                        </div>
+                    <div id="main-content" class="wiki-content group">
+                    
+
+
+<h3 id="JNDI-PatchingtheandforusewithJNDI">Patching the <a class="createlink" href="/confluence/pages/createpage.action?spaceKey=JCR&amp;title=OracleFileSystem&amp;linkCreation=true&amp;fromPageId=115513422">OracleFileSystem</a> and <a class="createlink" href="/confluence/pages/createpage.action?spaceKey=JCR&amp;title=OraclePersistenceManager&amp;linkCreation=true&amp;fromPageId=115513422">OraclePersistenceManager</a> for use with JNDI</h3>
+
+<p>This patch was created by rkorbee at 2006-12-04 16:54:41:</p>
+
+<ul>
+	<li>Use this pacth in Eclipse against jackrabbit-core-1.1.1</li>
+	<li>This will fix jackrabbit-core to support an Oracle database over JNDI
+<br class="atl-forced-newline"/></li>
+</ul>
+
+
+<div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent">
+<pre>Index: /home/nick/workspace/jackrabbit/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db/DatabaseFileSystem.java
+===================================================================
+--- /home/nick/workspace/jackrabbit/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db/DatabaseFileSystem.java	(revision 480910)
++++ /home/nick/workspace/jackrabbit/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db/DatabaseFileSystem.java	(working copy)
+@@ -1251,6 +1251,9 @@
+             throws FileSystemException {
+         String parentDir = FileSystemPathUtil.getParentDir(folderPath);
+         String name = FileSystemPathUtil.getName(folderPath);
++        if (&quot;&quot;.equals(name)) {
++            name = &quot; &quot;;
++        }
+ 
+         if (!FileSystemPathUtil.denotesRoot(folderPath)) {
+             if (!exists(parentDir)) {
+Index: /home/nick/workspace/jackrabbit/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db/DbFileSystem.java
+===================================================================
+--- /home/nick/workspace/jackrabbit/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db/DbFileSystem.java	(revision 480910)
++++ /home/nick/workspace/jackrabbit/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db/DbFileSystem.java	(working copy)
+@@ -182,7 +182,7 @@
+      *
+      * @throws SQLException if an error occurs
+      */
+-    protected Connection getConnection() throws ClassNotFoundException, SQLException {
++    protected Connection getConnection() throws Exception {
+         Class.forName(driver);
+         return DriverManager.getConnection(url, user, password);
+     }
+Index: /home/nick/workspace/jackrabbit/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db/JNDIOracleDatabaseFileSystem.java
+===================================================================
+--- /home/nick/workspace/jackrabbit/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db/JNDIOracleDatabaseFileSystem.java	(revision 0)
++++ /home/nick/workspace/jackrabbit/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db/JNDIOracleDatabaseFileSystem.java	(revision 0)
+@@ -0,0 +1,97 @@
++/*
++ * Licensed to the Apache Software Foundation (ASF) under one or more
++ * contributor license agreements.  See the NOTICE file distributed with
++ * this work for additional information regarding copyright ownership.
++ * The ASF licenses this file to You under the Apache License, Version 2.0
++ * (the &quot;License&quot;); you may not use this file except in compliance with
++ * the License.  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++package org.apache.jackrabbit.core.fs.db;
++
++import java.sql.Connection;
++import java.sql.SQLException;
++
++import javax.naming.InitialContext;
++import javax.naming.NamingException;
++import javax.sql.DataSource;
++
++import org.slf4j.Logger;
++import org.slf4j.LoggerFactory;
++
++import oracle.jdbc.driver.OracleConnection;
++import oracle.jdbc.pool.OracleDataSource;
++
++/**
++ * Database file system that uses JNDI to acquire the database connection.
++ * The JNDI location of the {@link OracleDataSource} to be used in given as
++ * the &lt;code&gt;dataSourceLocation&lt;/code&gt; configuration property. See the
++ * {@link DbFileSystem} for more configuration details.
++ * &lt;p&gt;
++ * &lt;strong&gt;WARNING:&lt;/strong&gt; The acquired database connection is kept
++ * for the entire lifetime of the file system instance. The configured data
++ * source should be prepared for this.
++ */
++public class JNDIOracleDatabaseFileSystem extends OracleFileSystem {
++
++    private static Logger log = LoggerFactory.getLogger(JNDIOracleDatabaseFileSystem.class);
++    
++    /**
++     * JNDI location of the data source used to acquire database connections.
++     */
++    private String dataSourceLocation;
++
++    //----------------------------------------------------&lt; setters &amp; getters &gt;
++
++    /**
++     * Returns the JNDI location of the data source.
++     *
++     * @return data source location
++     */
++    public String getDataSourceLocation() {
++        return dataSourceLocation;
++    }
++
++    /**
++     * Sets the JNDI location of the data source.
++     *
++     * @param dataSourceLocation data source location
++     */
++    public void setDataSourceLocation(String dataSourceLocation) {
++        this.dataSourceLocation = dataSourceLocation;
++    }
++
++    //--------------------------------------------------&lt; DatabaseFileSystem &gt;
++
++    /**
++     * Returns a JDBC connection from a {@link OracleDataSource} acquired from JNDI
++     * with the configured data source location.
++     *
++     * @return new database connection
++     * @throws NamingException if the given data source location does not exist
++     * @throws SQLException if a database access error occurs
++     * @throws ClassNotFoundException 
++     */
++    protected Connection getConnection() throws NamingException, SQLException, ClassNotFoundException {
++        Class.forName(super.driver);
++        InitialContext ic = new InitialContext();
++
++        DataSource originalDS = (DataSource) ic.lookup(dataSourceLocation);
++        log.debug(&quot;Type of datasource is: &quot; + originalDS.getClass());
++
++        Connection conn = originalDS.getConnection();
++        log.debug(&quot;Type of Connection is: &quot; + conn.getClass());
++        if (conn instanceof OracleConnection) {
++            return conn;
++        } else {
++            throw new ClassNotFoundException(&quot;Wrong type for Connection, expected OracleConnection, got: &quot; + conn.getClass());
++        }
++    }
++}
+
+Property changes on: /home/nick/workspace/jackrabbit/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db/JNDIOracleDatabaseFileSystem.java
+___________________________________________________________________
+Name: svn:eol-style
+   + native
+Name: svn:keywords
+   + Id
+
+Index: /home/nick/workspace/jackrabbit/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db/OracleFileSystem.java
+===================================================================
+--- /home/nick/workspace/jackrabbit/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db/OracleFileSystem.java	(revision 480910)
++++ /home/nick/workspace/jackrabbit/jackrabbit/src/main/java/org/apache/jackrabbit/core/fs/db/OracleFileSystem.java	(working copy)
+@@ -16,36 +16,30 @@
+  */
+ package org.apache.jackrabbit.core.fs.db;
+ 
+-import org.apache.jackrabbit.util.Text;
+-import org.apache.jackrabbit.util.TransientFileFactory;
++import java.io.File;
++import java.io.FileInputStream;
++import java.io.FileOutputStream;
++import java.io.FilterOutputStream;
++import java.io.IOException;
++import java.io.InputStream;
++import java.io.OutputStream;
++import java.io.RandomAccessFile;
++import java.sql.Blob;
++import java.sql.Connection;
++import java.sql.PreparedStatement;
++import java.sql.SQLException;
++import java.util.LinkedList;
++import java.util.List;
++
++import oracle.sql.BLOB;
++
+ import org.apache.jackrabbit.core.fs.FileSystemException;
+ import org.apache.jackrabbit.core.fs.FileSystemPathUtil;
+ import org.apache.jackrabbit.core.fs.RandomAccessOutputStream;
++import org.apache.jackrabbit.util.TransientFileFactory;
+ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
+ 
+-import javax.jcr.RepositoryException;
+-import java.sql.DatabaseMetaData;
+-import java.sql.ResultSet;
+-import java.sql.Statement;
+-import java.sql.SQLException;
+-import java.sql.Blob;
+-import java.sql.Connection;
+-import java.sql.PreparedStatement;
+-import java.io.InputStream;
+-import java.io.BufferedReader;
+-import java.io.InputStreamReader;
+-import java.io.OutputStream;
+-import java.io.IOException;
+-import java.io.File;
+-import java.io.FilterOutputStream;
+-import java.io.FileOutputStream;
+-import java.io.FileInputStream;
+-import java.io.RandomAccessFile;
+-import java.util.List;
+-import java.util.LinkedList;
+-import java.lang.reflect.Method;
+-
+ /**
+  * &lt;code&gt;OracleFileSystem&lt;/code&gt; is a JDBC-based &lt;code&gt;FileSystem&lt;/code&gt;
+  * implementation for Jackrabbit that persists file system entries in an
+@@ -415,7 +409,9 @@
+                             stmt.executeUpdate();
+                         }
+ 
+-                    } catch (Exception e) {
++                    } catch (SQLException e) {
++                        throw new IOException(e.getMessage());
++                    } catch (FileSystemException e) {
+                         throw new IOException(e.getMessage());
+                     } finally {
+                         if (stmt != null) {
+@@ -469,28 +465,14 @@
+     /**
+      * Creates a temporary oracle.sql.BLOB instance via reflection and spools
+      * the contents of the specified stream.
++     * @throws SQLException 
++     * @throws IOException 
+      */
+-    protected Blob createTemporaryBlob(InputStream in) throws Exception {
+-        /*
++    protected Blob createTemporaryBlob(InputStream in) throws SQLException, IOException {
+         BLOB blob = BLOB.createTemporary(con, false, BLOB.DURATION_SESSION);
+         blob.open(BLOB.MODE_READWRITE);
+         OutputStream out = blob.getBinaryOutputStream();
+-        ...
+-        out.flush();
+-        out.close();
+-        blob.close();
+-        return blob;
+-        */
+-        Method createTemporary = blobClass.getMethod(&quot;createTemporary&quot;,
+-                new Class[]{Connection.class, Boolean.TYPE, Integer.TYPE});
+-        Object blob = createTemporary.invoke(null,
+-                new Object[]{con, Boolean.FALSE, DURATION_SESSION_CONSTANT});
+-        Method open = blobClass.getMethod(&quot;open&quot;, new Class[]{Integer.TYPE});
+-        open.invoke(blob, new Object[]{MODE_READWRITE_CONSTANT});
+-        Method getBinaryOutputStream =
+-                blobClass.getMethod(&quot;getBinaryOutputStream&quot;, new Class[0]);
+-        OutputStream out = (OutputStream) getBinaryOutputStream.invoke(blob, null);
+-        try {
++      try {
+             int read;
+             byte[] buf = new byte[8192];
+             while ((read = in.read(buf, 0, buf.length)) &gt; -1) {
+@@ -503,9 +485,34 @@
+             }
+             out.close();
+         }
+-        Method close = blobClass.getMethod(&quot;close&quot;, new Class[0]);
+-        close.invoke(blob, null);
+-        return (Blob) blob;
++        blob.close();
++        return blob;
++
++//        Method createTemporary = blobClass.getMethod(&quot;createTemporary&quot;,
++//                new Class[]{Connection.class, Boolean.TYPE, Integer.TYPE});
++//        Object blob = createTemporary.invoke(null,
++//                new Object[]{con, Boolean.FALSE, DURATION_SESSION_CONSTANT});
++//        Method open = blobClass.getMethod(&quot;open&quot;, new Class[]{Integer.TYPE});
++//        open.invoke(blob, new Object[]{MODE_READWRITE_CONSTANT});
++//        Method getBinaryOutputStream =
++//                blobClass.getMethod(&quot;getBinaryOutputStream&quot;, new Class[0]);
++//        OutputStream out = (OutputStream) getBinaryOutputStream.invoke(blob, null);
++//        try {
++//            int read;
++//            byte[] buf = new byte[8192];
++//            while ((read = in.read(buf, 0, buf.length)) &gt; -1) {
++//                out.write(buf, 0, read);
++//            }
++//        } finally {
++//            try {
++//                out.flush();
++//            } catch (IOException ioe) {
++//            }
++//            out.close();
++//        }
++//        Method close = blobClass.getMethod(&quot;close&quot;, new Class[0]);
++//        close.invoke(blob, null);
++//        return (Blob) blob;
+     }
+ 
+     /**
+@@ -511,9 +518,10 @@
+     /**
+      * Frees a temporary oracle.sql.BLOB instance via reflection.
+      */
+-    protected void freeTemporaryBlob(Object blob) throws Exception {
+-        // blob.freeTemporary();
+-        Method freeTemporary = blobClass.getMethod(&quot;freeTemporary&quot;, new Class[0]);
+-        freeTemporary.invoke(blob, null);
++    protected void freeTemporaryBlob(Blob blob) throws Exception {
++        BLOB obj = (BLOB) blob;
++        obj.freeTemporary();
++        //Method freeTemporary = blobClass.getMethod(&quot;freeTemporary&quot;, new Class[0]);
++        //freeTemporary.invoke(blob, null);
+     }
+ }
+Index: /home/nick/workspace/jackrabbit/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/db/JNDIOracleDatabasePersistenceManager.java
+===================================================================
+--- /home/nick/workspace/jackrabbit/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/db/JNDIOracleDatabasePersistenceManager.java	(revision 0)
++++ /home/nick/workspace/jackrabbit/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/db/JNDIOracleDatabasePersistenceManager.java	(revision 0)
+@@ -0,0 +1,83 @@
++/*
++ * Licensed to the Apache Software Foundation (ASF) under one or more
++ * contributor license agreements.  See the NOTICE file distributed with
++ * this work for additional information regarding copyright ownership.
++ * The ASF licenses this file to You under the Apache License, Version 2.0
++ * (the &quot;License&quot;); you may not use this file except in compliance with
++ * the License.  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++package org.apache.jackrabbit.core.state.db;
++
++import java.sql.Connection;
++import java.sql.SQLException;
++
++import javax.naming.InitialContext;
++import javax.naming.NamingException;
++import javax.sql.DataSource;
++
++/**
++ * Database persistence manager that uses JNDI to acquire the database
++ * connection. The JNDI location of the {@link DataSource} to be used in
++ * given as the &lt;code&gt;dataSourceLocation&lt;/code&gt; configuration property.
++ * See the {@link SimpleDbPersistenceManager} for more configuration
++ * details.
++ * &lt;p&gt;
++ * &lt;strong&gt;WARNING:&lt;/strong&gt; The acquired database connection is kept
++ * for the entire lifetime of the persistence manager instance. The
++ * configured data source should be prepared for this.
++ */
++public class JNDIOracleDatabasePersistenceManager extends OraclePersistenceManager{
++
++    /**
++     * JNDI location of the data source used to acquire database connections.
++     */
++    private String dataSourceLocation;
++
++    //----------------------------------------------------&lt; setters &amp; getters &gt;
++
++    /**
++     * Returns the JNDI location of the data source.
++     *
++     * @return data source location
++     */
++    public String getDataSourceLocation() {
++        return dataSourceLocation;
++    }
++
++    /**
++     * Sets the JNDI location of the data source.
++     *
++     * @param dataSourceLocation data source location
++     */
++    public void setDataSourceLocation(String dataSourceLocation) {
++        this.dataSourceLocation = dataSourceLocation;
++    }
++
++    //-------------------------------------------&lt; DatabasePersistenceManager &gt;
++
++    /**
++     * Returns a JDBC connection from a {@link DataSource} acquired from JNDI
++     * with the configured data source location.
++     *
++     * @return new database connection
++     * @throws NamingException if the given data source location does not exist
++     * @throws SQLException if a database access error occurs
++     * @throws ClassNotFoundException 
++     * @see DatabasePersistenceManager#getConnection()
++     */
++    protected Connection getConnection() throws NamingException, SQLException, ClassNotFoundException {
++        Class.forName(super.driver);
++        InitialContext ic = new InitialContext();
++        DataSource dataSource = (DataSource) ic.lookup(dataSourceLocation);
++        return dataSource.getConnection();
++    }
++
++}
+
+Property changes on: /home/nick/workspace/jackrabbit/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/db/JNDIOracleDatabasePersistenceManager.java
+___________________________________________________________________
+Name: svn:eol-style
+   + native
+Name: svn:keywords
+   + Id
+
+Index: /home/nick/workspace/jackrabbit/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/db/SimpleDbPersistenceManager.java
+===================================================================
+--- /home/nick/workspace/jackrabbit/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/db/SimpleDbPersistenceManager.java	(revision 480910)
++++ /home/nick/workspace/jackrabbit/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/db/SimpleDbPersistenceManager.java	(working copy)
+@@ -158,7 +158,7 @@
+      * @throws SQLException if a database access error occurs
+      * @see DatabasePersistenceManager#getConnection()
+      */
+-    protected Connection getConnection() throws ClassNotFoundException, SQLException {
++    protected Connection getConnection() throws Exception {
+         Class.forName(driver);
+         Connection connection = DriverManager.getConnection(url, user, password);
+         return connection;
+
+
+</pre>
+</div></div>
+                    </div>
+
+                    
+                                                      
+                </div>             </div> 
+            <div id="footer" role="contentinfo">
+                <section class="footer-body">
+                    <p>Document generated by Confluence on May 20, 2019 11:11</p>
+                    <div id="footer-logo"><a href="http://www.atlassian.com/">Atlassian</a></div>
+                </section>
+            </div>
+        </div>     </body>
+</html>

Propchange: jackrabbit/site/live/archive/wiki/JCR/JNDI_115513422.html
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/site/live/archive/wiki/JCR/JNDI_115513422.html
------------------------------------------------------------------------------
    svn:executable = *