<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<section id="JCR.WorkspaceDataContainer">
  <title>JCR Workspace Data Container (architecture contract)</title>

  <para>The goals of this section are:</para>

  <itemizedlist>
    <listitem>
      <para>Coverage of the requirements of Workspace Data Container
      implementation</para>
    </listitem>

    <listitem>
      <para>Description of container life cycle</para>
    </listitem>

    <listitem>
      <para>Description relations between container and high-level
      DataManagers</para>
    </listitem>
  </itemizedlist>

  <section id="JCR.WorkspaceDataContainer.Concepts">
    <title>Concepts</title>

    <section id="JCR.WorkspaceDataContainer.Concepts.ContainerAndConnection">
      <title>Container and connection</title>

      <para>Workspace Data Container (container) serves Repository Workspace
      persistent storage. WorkspacePersistentDataManager (data manager) uses
      container to perform CRUD operation on the persistent storage. Accessing
      to the storage in the data manager is implemented via storage connection
      obtained from the container (WorkspaceDataContainer interface
      implemenatiton). Each connection represents a transaction on the
      storage. Storage Connection (connection) should be an implementation of
      WorkspaceStorageConnection.</para>

      <itemizedlist>
        <listitem>
          <para>Container acts as a factory of a new storage connections.
          Usually, this method is designed to be synchronized to avoid
          possible concurrent issues.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">WorkspaceStorageConnection openConnection() throws RepositoryException;
</programlisting>

      <itemizedlist>
        <listitem>
          <para>Open read-only WorkspaceStorageConnection. Read-only
          connections can be potentially a bit faster in some cases.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">WorkspaceStorageConnection openConnection(boolean readOnly) throws RepositoryException;
</programlisting>

      <note>
        <title>*EXPERIMENTAL*</title>

        <para>Read-only WorkspaceStorageConnection is experimental feature and
        not currently handled in JCR. Actually, such connections didn't prove
        their performance, so JCR Core doesn't use them.</para>
      </note>

      <itemizedlist>
        <listitem>
          <para>Storage connection might also be reused. This means reuse of
          physical resource (e.g. JDBC Connection) allocated by one connection
          in another. This feature is used in a data manager for saving
          ordinary and system changes on the system Workspace. But the reuse
          is an optional feature and it can work, otherwise a new connection
          will open.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">WorkspaceStorageConnection reuseConnection(WorkspaceStorageConnection original) throws RepositoryException;
</programlisting>

      <itemizedlist>
        <listitem>
          <para>When checking Same-Name Siblings (SNS) existence, JCR Core can
          use new connection or not. This is defined via Workspace Data
          Container configuration and retrieved by using a special
          method.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">boolean isCheckSNSNewConnection();
</programlisting>

      <para>Container initialization is only based on a configuration. After
      the container has been created, it's not possible to change parameters.
      Configuration consists of implementation class and set of properties and
      Value Storages configuration.</para>
    </section>

    <section id="JCR.WorkspaceDataContainer.Concepts.ValueStorages">
      <title>Value storages</title>

      <para>Container provides optional special mechanism for Value storing.
      It's possible to configure external Value Storages via container
      configuration (available only via configuration). Value Storage works as
      fully independent pluggable storage. All required parameters storage
      obtains from its configuration. Some storages are possible for one
      container. Configuration describes such parameters as
      ValueStoragePluginimplementation class, set of implementation specific
      properties and filters. The filters declares criteria for Value matching
      to the storage. Only matched Property Values will be stored. So, in
      common case, the storage might contains only the part of the Workspace
      content. Value Storages are very useful for BLOB storing. E.g. storing
      on the File System instead of a database.</para>

      <para>Container obtains Values Storages from ValueStoragePluginProvider
      component. Provider acts as a factory of Value channels
      (ValueIOChannel). Channel provides all CRUD operation for Value Storage
      respecting the transaction manner of work (how it can be possible due to
      implementation specifics of the storages).</para>
    </section>

    <section id="JCR.WorkspaceDataContainer.Concepts.Lifecycle">
      <title>Lifecycle</title>

      <para>Container is used for read and write operations by data manager.
      Read operations (getters) uses connection once and close it on the
      finally. Write operations performs in commit method as a sequence of
      creating/ updating calls and final commit (or rollback on error). Writes
      uses one connection (or two - another for system workspace) per commit
      call. One connection guaranties transaction support for write
      operations. Commit or rollback should free/clean all resources consumed
      by the container (connection).</para>
    </section>

    <section id="JCR.WorkspaceDataContainer.Concepts.ValueStorageLifecycle">
      <title>Value storage lifecycle</title>

      <para>Value storage is used from the container inside. Reads are related
      to a container reads. Writes are commit-related. Container (connection)
      implementation should use transaction capabilities of the storages in
      the same way as for other operations.</para>
    </section>
  </section>

  <section id="JCR.WorkspaceDataContainer.Requirements">
    <title>Requirements</title>

    <para>Connection creation and reuse should be a thread safe operation.
    Connection provides CRUD operations support on the storage.</para>

    <section id="JCR.WorkspaceDataContainer.Requirements.ReadOperations">
      <title>Read operations</title>

      <itemizedlist>
        <listitem>
          <para>Read ItemData from the storage by item identifier.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">ItemData getItemData(String identifier) throws RepositoryException, IllegalStateException;</programlisting>

      <itemizedlist>
        <listitem>
          <para>Find Item by parent (id) and name (with path index) of a given
          type.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">ItemData getItemData(NodeData parentData, QPathEntry name, ItemType itemType) throws RepositoryException, IllegalStateException;</programlisting>

      <itemizedlist>
        <listitem>
          <para>Get child Nodes of the parent node.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">List&lt;NodeData&gt; getChildNodesData(NodeData parent) throws RepositoryException, IllegalStateException;</programlisting>

      <itemizedlist>
        <listitem>
          <para>Get child Nodes of the parent node.ItemDataFilter used to
          reduce count of returned items. But not guarantee that only items
          matching filter will be returned.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">List&lt;NodeData&gt; getChildNodesData(NodeData parent, ListList&lt;QPathEntryFilter&gt; pattern) throws RepositoryException, IllegalStateException;</programlisting>

      <itemizedlist>
        <listitem>
          <para>Reads List of PropertyData from the storage by using the
          parent location of the item.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">List&lt;PropertyData&gt; getChildPropertiesData(NodeData parent) throws RepositoryException, IllegalStateException;</programlisting>

      <itemizedlist>
        <listitem>
          <para>Get child Properties of the parent node. ItemDataFilter used
          to reduce count of returned items. But not guarantee that only items
          matching filter will be returned.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">List&lt;PropertyData&gt; getChildPropertiesData(NodeData parent, List&lt;QPathEntryFilter&gt; pattern) throws RepositoryException, IllegalStateException;</programlisting>

      <itemizedlist>
        <listitem>
          <para>Reads List of PropertyData with empty ValueData from the
          storage by using the parent location of the item.</para>
        </listitem>
      </itemizedlist>

      <para>This methiod specially dedicated for non-content modification
      operations (e.g. Items delete).</para>

      <programlisting language="java">List&lt;PropertyData&gt; listChildPropertiesData(NodeData parent) throws RepositoryException, IllegalStateException;</programlisting>

      <itemizedlist>
        <listitem>
          <para>Reads List of PropertyData from the storage by using the
          parent location of the item.</para>
        </listitem>
      </itemizedlist>

      <para>It's REFERENCE type: Properties referencing Node with given
      nodeIdentifier. See more in javax.jcr.Node.getReferences()</para>

      <programlisting language="java">List&lt;PropertyData&gt; getReferencesData(String nodeIdentifier) throws RepositoryException, IllegalStateException, UnsupportedOperationException;</programlisting>

      <itemizedlist>
        <listitem>
          <para>Get child Nodes of the parent node whose value of order number
          is between fromOrderNum and toOrderNum. Return true if there are
          data to retrieve for next request and false in other case.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">boolean getChildNodesDataByPage(NodeData parent, int fromOrderNum, int toOrderNum, List&lt;NodeData&gt; childs) throws RepositoryException;</programlisting>

      <itemizedlist>
        <listitem>
          <para>Get children nodes count of the parent node.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">int getChildNodesCount(NodeData parent) throws RepositoryException;</programlisting>

      <itemizedlist>
        <listitem>
          <para>Get order number of parent's last child node.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">int getLastOrderNumber(NodeData parent) throws RepositoryException;</programlisting>
    </section>

    <section id="JCR.WorkspaceDataContainer.Requirements.WriteOperations">
      <title>Write operations</title>

      <itemizedlist>
        <listitem>
          <para>Add single NodeData.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">void add(NodeData data) throws RepositoryException,UnsupportedOperationException,InvalidItemStateException,IllegalStateException;
</programlisting>

      <itemizedlist>
        <listitem>
          <para>Add single PropertyData.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">void add(PropertyData data) throws RepositoryException,UnsupportedOperationException,InvalidItemStateException,IllegalStateException;
</programlisting>

      <itemizedlist>
        <listitem>
          <para>Update NodeData.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">void update(NodeData data) throws RepositoryException,UnsupportedOperationException,InvalidItemStateException,IllegalStateException;
</programlisting>

      <itemizedlist>
        <listitem>
          <para>Update PropertyData.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">void update(PropertyData data) throws RepositoryException,UnsupportedOperationException,InvalidItemStateException,IllegalStateException;
</programlisting>

      <itemizedlist>
        <listitem>
          <para>Rename NodeData by using Node identifier and new name and
          indexing from the data.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">void rename(NodeData data) throws RepositoryException,UnsupportedOperationException,InvalidItemStateException,IllegalStateException;
</programlisting>

      <itemizedlist>
        <listitem>
          <para>Delete NodeData.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">void delete(NodeData data) throws RepositoryException,UnsupportedOperationException,InvalidItemStateException,IllegalStateException;
</programlisting>

      <itemizedlist>
        <listitem>
          <para>Delete PropertyData.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">void delete(PropertyData data) throws RepositoryException,UnsupportedOperationException,InvalidItemStateException,IllegalStateException;
</programlisting>

      <itemizedlist>
        <listitem>
          <para>Prepare the commit phase.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">void prepare() throws IllegalStateException, RepositoryException;</programlisting>

      <itemizedlist>
        <listitem>
          <para>Persist changes and closes connection. It can be database
          transaction commit for instance etc.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">void commit() throws IllegalStateException, RepositoryException;</programlisting>

      <itemizedlist>
        <listitem>
          <para>Refuse persistent changes and closes connection. It can be
          database transaction rollback for instance etc.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">void rollback() throws IllegalStateException, RepositoryException;</programlisting>

      <para>All methods throw IllegalStateException if connection is closed.
      UnsupportedOperationException if the method is not supported (e.g. JCR
      Level 1 implementation etc). RepositoryException if some errors occur
      during preparation, validation or persistence.</para>
    </section>

    <section id="JCR.WorkspaceDataContainer.Requirements.StateOperations">
      <title>State operations</title>

      <itemizedlist>
        <listitem>
          <para>Return true if connection can be used.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">boolean isOpened();</programlisting>
    </section>

    <section id="JCR.WorkspaceDataContainer.Requirements.ValidationOfWriteOperations">
      <title>Validation of write operations</title>

      <para>Container has to care about storage consistency (JCR constraints)
      on write operations: (InvalidItemStateException should be thrown
      according the spec). At least, the following checks should be
      performed:</para>

      <itemizedlist>
        <listitem>
          <para>On ADD errors</para>

          <itemizedlist>
            <listitem>
              <para>Parent not found. Condition: Parent ID (Item with ID is
              not exists).</para>
            </listitem>

            <listitem>
              <para>Item already exists. Condition: ID (Item with ID already
              exists).</para>
            </listitem>

            <listitem>
              <para>Item already exists. Condition: Parent ID, Name, Index
              (Item with parent ID, name and index already exists).</para>
            </listitem>
          </itemizedlist>
        </listitem>
      </itemizedlist>

      <itemizedlist>
        <listitem>
          <para>On DELETE errors</para>

          <itemizedlist>
            <listitem>
              <para>Item not found. Condition ID.</para>
            </listitem>

            <listitem>
              <para>Can not delete parent till children exists.</para>
            </listitem>
          </itemizedlist>
        </listitem>
      </itemizedlist>

      <itemizedlist>
        <listitem>
          <para>On UPDATE errors</para>

          <itemizedlist>
            <listitem>
              <para>Item not found. Condition ID.</para>
            </listitem>

            <listitem>
              <para>Item already exists with higher Version. Condition: ID,
              Version (Some Session had updated Item with ID prior this
              update).</para>
            </listitem>
          </itemizedlist>
        </listitem>
      </itemizedlist>
    </section>

    <section id="JCR.WorkspaceDataContainer.Requirements.ConsistencyOfSave">
      <title>Consistency of save</title>

      <para>The container (connection) should implement consistency of Commit
      (Rollback) in <emphasis role="bold">transaction manner</emphasis>. I.e.
      If a set of operations was performed <emphasis
      role="bold">before</emphasis> the future <emphasis
      role="bold">Commit</emphasis> and another next operation <emphasis
      role="bold">fails</emphasis>. <emphasis role="bold">It should be
      possible to</emphasis> rollback applied changes using <emphasis
      role="bold">Rollback</emphasis> command.</para>
    </section>
  </section>

  <section id="JCR.WorkspaceDataContainer.ValueStoragesAPI">
    <title>Value storages API</title>

    <section id="JCR.WorkspaceDataContainer.ValueStoragesAPI.StoragesProvider">
      <title>Storages provider:</title>

      <para>Container implementation obtains Values Storages option via
      ValueStoragePluginProvider component. Provider acts as a factory of
      Value channels (ValueIOChannel) and proposes two methods for this
      purpose:</para>

      <itemizedlist>
        <listitem>
          <para>Return the ValueIOChannel that matches with this property and
          valueOrderNumer. Null will be returned if no channel matches.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">ValueIOChannel getApplicableChannel(PropertyData property, int valueOrderNumer) throws IOException;
</programlisting>

      <itemizedlist>
        <listitem>
          <para>Returns the ValueIOChannel associated with given
          storageId.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">ValueIOChannel getChannel(String storageId) throws IOException, ValueStorageNotFoundException;
</programlisting>

      <itemizedlist>
        <listitem>
          <para>Runs the consistency check operation on each registered
          plug-in.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">void checkConsistency(WorkspaceStorageConnection dataConnection);
</programlisting>

      <para>Please note that the method checkConsistency is in practice rarely
      implemented, most of the time it doesn't do anything.</para>

      <itemizedlist>
        <listitem>
          <para>Gives the ValueStorageURLConnection corresponding to the given
          storageId and idResource if and only if the corresponding value
          storage supports URL, otherwise an UnsupportedOperationException
          will be thrown.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">ValueStorageURLConnection createURLConnection(String storageId, URL url) throws ValueStorageNotFoundException, IOException;;
</programlisting>

      <para>This method is actually used to be able to access to the content
      of a resource that is managed by a value storage that is not based on a
      file system.</para>
    </section>

    <section id="JCR.WorkspaceDataContainer.ValueStoragesAPI.ValueStoragePlugin">
      <title>Value storage plugin</title>

      <para>Provider implementation should use ValueStoragePlugin abstract
      class as a base for all storage implementations. Plugin provides support
      for provider implementation methods. Plugin's methods should be
      implemented:</para>

      <itemizedlist>
        <listitem>
          <para>Initialize this plugin. Used at start time in
          ValueStoragePluginProvider.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">public abstract void init(Properties props, ValueDataResourceHolder resources) throws RepositoryConfigurationException, IOException;
</programlisting>

      <itemizedlist>
        <listitem>
          <para>Open a ValueIOChannel. Used in
          ValueStoragePluginProvider.getApplicableChannel(PropertyData, int)
          and getChannel(String)</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">public abstract ValueIOChannel openIOChannel() throws IOException;
</programlisting>

      <itemizedlist>
        <listitem>
          <para>Return true if this storage has the same storageId.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">public boolean isSame(String storageId);
</programlisting>

      <itemizedlist>
        <listitem>
          <para>Runs the consistency check operation, by default it doesn't do
          anything.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">public void checkConsistency(WorkspaceStorageConnection dataConnection);
</programlisting>

      <itemizedlist>
        <listitem>
          <para>In case the value storage supports the URL, this method will
          provide the ValueStorageURLConnection managed by the value storage
          corresponding to the given URL. If it doesn't support URL an
          UnsupportedOperationException will be thrown.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">public ValueStorageURLConnection createURLConnection(URL u) throws IOException;
</programlisting>

      <itemizedlist>
        <listitem>
          <para>In case the value storage supports the URL, this method will
          return an URL corresponding to the given resource within the context
          of the current ValueStoragePlugin. If it doesn't support URL an
          UnsupportedOperationException will be thrown.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">public URL createURL(String resourceId) throws MalformedURLException;
</programlisting>

      <itemizedlist>
        <listitem>
          <para>In case the value storage supports the URL, this method will
          gives the ValueStorageURLStreamHandler corresponding to the current
          ValueStoragePlugin. If it doesn't support URL an
          UnsupportedOperationException will be thrown.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">protected ValueStorageURLStreamHandler getURLStreamHandler();
</programlisting>
    </section>

    <section id="JCR.WorkspaceDataContainer.ValueStoragesAPI.ValueIOChannel">
      <title>Value I/O channel</title>

      <para>Channel should implement ValueIOChannel interface. CRUD operation
      for Value Storage:</para>

      <itemizedlist>
        <listitem>
          <para>Read Property value.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">ValueDataWrapper read(String propertyId, int orderNumber, int type, SpoolConfig spoolConfig) throws IOException;
</programlisting>

      <itemizedlist>
        <listitem>
          <para>Returns value data size.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">long getValueSize(String propertyId, int orderNumber) throws IOException;
</programlisting>

      <itemizedlist>
        <listitem>
          <para>Returns value data size. Property may contains several values
          differing only order number. This method returns value size of
          them.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">long getValueSize(String propertyId) throws IOException;
</programlisting>

      <itemizedlist>
        <listitem>
          <para>Add or update Property value.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">void write(String propertyId, ValueData data, ChangedSizeHandler sizeHandler) throws IOException;
</programlisting>

      <itemizedlist>
        <listitem>
          <para>Delete Property all values.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">void delete(String propertyId) throws IOException;
</programlisting>
    </section>

    <section id="JCR.WorkspaceDataContainer.ValueStoragesAPI.CheckNRepair">
      <title>Consistency Management</title>

      <para>The interface ValueIOChannel proposes a set of methods allowing to
      check the consistency and repair the data.</para>

      <itemizedlist>
        <listitem>
          <para>Inspects whether corresponding resource exists in value
          storage or not.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">void checkValueData(String propertyId, int orderNumber) throws ValueDataNotFoundException, IOException;</programlisting>

      <itemizedlist>
        <listitem>
          <para>Repairs the value data generally by setting the resource to an
          empty content.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">void repairValueData(String propertyId, int orderNumber) throws IOException;</programlisting>
    </section>

    <section id="JCR.WorkspaceDataContainer.ValueStoragesAPI.TransactionSupportViaChannel">
      <title>Transaction support via channel</title>

      <para>The interface ValueIOChannel proposes a set of methods allowing to
      support transaction at value storage level. Two modes are proposed, the
      single phase commit and the two phase commit, the first one will only
      call commit() and the second one will call first prepare() then
      twoPhaseCommit().</para>

      <itemizedlist>
        <listitem>
          <para>Commit channel changes.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">void commit() throws IOException;</programlisting>

      <itemizedlist>
        <listitem>
          <para>Rollback channel changes.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">void rollback() throws IOException;</programlisting>

      <itemizedlist>
        <listitem>
          <para>Prepare Value content.</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">void prepare() throws IOException;</programlisting>

      <itemizedlist>
        <listitem>
          <para>Commit Value content (two phases).</para>
        </listitem>
      </itemizedlist>

      <programlisting language="java">void twoPhaseCommit() throws IOException;</programlisting>
    </section>

    <section id="JCR.WorkspaceDataContainer.ValueStoragesAPI.VSNonFSBased">
      <title>Specificity of Value Storages non File System based </title>

      <para>An implementation of a Value Storage that doesn't rely on a File
      System needs to implement the method
      <emphasis>ValueStoragePlugin.getURLStreamHandler()</emphasis> but also a
      sub class of <emphasis>ValueStorageURLStreamHandler</emphasis> that
      needs to override at least the method <emphasis>createURLConnection(URL
      u, String repository, String workspace, String
      valueStorageId)</emphasis> for performance reason. Finally, a sub class
      of <emphasis>ValueStorageURLConnection</emphasis> will be needed to
      allow to access to the content of the resource from the
      <emphasis>URL</emphasis>.</para>
    </section>
  </section>
</section>
