corda/docs/build/html/persistence.html
2016-10-11 11:31:20 +02:00

416 lines
26 KiB
HTML

<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Persistence &mdash; R3 Corda latest documentation</title>
<link rel="stylesheet" href="_static/css/custom.css" type="text/css" />
<link rel="top" title="R3 Corda latest documentation" href="index.html"/>
<link rel="next" title="Creating a Cordapp" href="creating-a-cordapp.html"/>
<link rel="prev" title="Networking and messaging" href="messaging.html"/>
<script src="_static/js/modernizr.min.js"></script>
</head>
<body class="wy-body-for-nav" role="document">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search">
<a href="index.html" class="icon icon-home"> R3 Corda
</a>
<div class="version">
latest
</div>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
<input type="text" name="q" placeholder="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
<br>
<a href="api/index.html">API reference</a>
</div>
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
<p class="caption"><span class="caption-text">Overview</span></p>
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="inthebox.html">What&#8217;s included?</a></li>
<li class="toctree-l1"><a class="reference internal" href="getting-set-up.html">Getting set up</a></li>
<li class="toctree-l1"><a class="reference internal" href="data-model.html">Data model</a></li>
<li class="toctree-l1"><a class="reference internal" href="transaction-data-types.html">Data types</a></li>
<li class="toctree-l1"><a class="reference internal" href="consensus.html">Consensus model</a></li>
<li class="toctree-l1"><a class="reference internal" href="messaging.html">Networking and messaging</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">Persistence</a><ul>
<li class="toctree-l2"><a class="reference internal" href="#schemas">Schemas</a></li>
<li class="toctree-l2"><a class="reference internal" href="#object-relational-mapping">Object Relational Mapping</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="creating-a-cordapp.html">Creating a Cordapp</a></li>
<li class="toctree-l1"><a class="reference internal" href="running-the-demos.html">Running the demos</a></li>
<li class="toctree-l1"><a class="reference internal" href="node-administration.html">Node administration</a></li>
<li class="toctree-l1"><a class="reference internal" href="corda-configuration-files.html">The Corda Configuration File</a></li>
</ul>
<p class="caption"><span class="caption-text">Tutorials</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="where-to-start.html">Where to start</a></li>
<li class="toctree-l1"><a class="reference internal" href="tutorial-contract.html">Writing a contract</a></li>
<li class="toctree-l1"><a class="reference internal" href="tutorial-contract-clauses.html">Writing a contract using clauses</a></li>
<li class="toctree-l1"><a class="reference internal" href="tutorial-test-dsl.html">Writing a contract test</a></li>
<li class="toctree-l1"><a class="reference internal" href="tutorial-clientrpc-api.html">Client RPC API</a></li>
<li class="toctree-l1"><a class="reference internal" href="protocol-state-machines.html">Protocol state machines</a></li>
<li class="toctree-l1"><a class="reference internal" href="oracles.html">Writing oracle services</a></li>
<li class="toctree-l1"><a class="reference internal" href="tutorial-attachments.html">Using attachments</a></li>
<li class="toctree-l1"><a class="reference internal" href="event-scheduling.html">Event scheduling</a></li>
<li class="toctree-l1"><a class="reference internal" href="secure-coding-guidelines.html">Secure coding guidelines</a></li>
</ul>
<p class="caption"><span class="caption-text">Contracts</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="contract-catalogue.html">Contract catalogue</a></li>
<li class="toctree-l1"><a class="reference internal" href="contract-irs.html">Interest Rate Swaps</a></li>
</ul>
<p class="caption"><span class="caption-text">Node API</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="clientrpc.html">Client RPC</a></li>
</ul>
<p class="caption"><span class="caption-text">Appendix</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="release-process.html">Release process</a></li>
<li class="toctree-l1"><a class="reference internal" href="release-process.html#steps-to-cut-a-release">Steps to cut a release</a></li>
<li class="toctree-l1"><a class="reference internal" href="release-notes.html">Release notes</a></li>
<li class="toctree-l1"><a class="reference internal" href="network-simulator.html">Network Simulator</a></li>
<li class="toctree-l1"><a class="reference internal" href="codestyle.html">Code style guide</a></li>
<li class="toctree-l1"><a class="reference internal" href="building-the-docs.html">Building the documentation</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
<nav class="wy-nav-top" role="navigation" aria-label="top navigation">
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="index.html">R3 Corda</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="breadcrumbs navigation">
<ul class="wy-breadcrumbs">
<li><a href="index.html">Docs</a> &raquo;</li>
<li>Persistence</li>
<li class="wy-breadcrumbs-aside">
<a href="_sources/persistence.txt" rel="nofollow"> View page source</a>
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<div class="section" id="persistence">
<h1>Persistence<a class="headerlink" href="#persistence" title="Permalink to this headline"></a></h1>
<p>Corda offers developers the option to expose all or some part of a contract state to an <em>Object Relational Mapping</em> (ORM) tool
to be persisted in a RDBMS. The purpose of this is to assist <em>vault</em> development by effectively indexing
persisted contract states held in the vault for the purpose of running queries over them and to allow relational joins
between Corda data and private data local to the organisation owning a node.</p>
<p>The ORM mapping is specified using the <a class="reference external" href="https://en.wikipedia.org/wiki/Java_Persistence_API">Java Persistence API</a> (JPA)
as annotations and is converted to database table rows by the node automatically every time a state is recorded in the
node&#8217;s local vault as part of a transaction.</p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">Presently the node includes an instance of the H2 database but any database that supports JDBC is a candidate and
the node will in the future support a range of database implementations via their JDBC drivers. Much of the node
internal state is also persisted there. You can access the internal H2 database via JDBC, please see the info
in &#8220;<a class="reference internal" href="node-administration.html"><span class="doc">Node administration</span></a>&#8221; for details.</p>
</div>
<div class="section" id="schemas">
<h2>Schemas<a class="headerlink" href="#schemas" title="Permalink to this headline"></a></h2>
<p>Every <code class="docutils literal"><span class="pre">ContractState</span></code> can implement the <code class="docutils literal"><span class="pre">QueryableState</span></code> interface if it wishes to be inserted into the node&#8217;s local
database and accessible using SQL.</p>
<div class="highlight-kotlin"><div class="highlight"><pre><span></span><span class="cm">/**</span>
<span class="cm"> * A contract state that may be mapped to database schemas configured for this node to support querying for,</span>
<span class="cm"> * or filtering of, states.</span>
<span class="cm"> */</span>
<span class="k">interface</span> <span class="nc">QueryableState</span> <span class="p">:</span> <span class="n">ContractState</span> <span class="p">{</span>
<span class="cm">/**</span>
<span class="cm"> * Enumerate the schemas this state can export representations of itself as.</span>
<span class="cm"> */</span>
<span class="k">fun</span> <span class="nf">supportedSchemas</span><span class="p">():</span> <span class="n">Iterable</span><span class="p">&lt;</span><span class="n">MappedSchema</span><span class="p">&gt;</span>
<span class="cm">/**</span>
<span class="cm"> * Export a representation for the given schema.</span>
<span class="cm"> */</span>
<span class="k">fun</span> <span class="nf">generateMappedObject</span><span class="p">(</span><span class="n">schema</span><span class="p">:</span> <span class="n">MappedSchema</span><span class="p">):</span> <span class="n">PersistentState</span>
<span class="p">}</span>
</pre></div>
</div>
<p>The <code class="docutils literal"><span class="pre">QueryableState</span></code> interface requires the state to enumerate the different relational schemas it supports, for instance in
cases where the schema has evolved, with each one being represented by a <code class="docutils literal"><span class="pre">MappedSchema</span></code> object return by the
<code class="docutils literal"><span class="pre">supportedSchemas()</span></code> method. Once a schema is selected it must generate that representation when requested via the
<code class="docutils literal"><span class="pre">generateMappedObject()</span></code> method which is then passed to the ORM.</p>
<p>Nodes have an internal <code class="docutils literal"><span class="pre">SchemaService</span></code> which decides what to persist and what not by selecting the <code class="docutils literal"><span class="pre">MappedSchema</span></code>
to use.</p>
<div class="highlight-kotlin"><div class="highlight"><pre><span></span><span class="cm">/**</span>
<span class="cm"> * A configuration and customisation point for Object Relational Mapping of contract state objects.</span>
<span class="cm"> */</span>
<span class="k">interface</span> <span class="nc">SchemaService</span> <span class="p">{</span>
<span class="cm">/**</span>
<span class="cm"> * Represents any options configured on the node for a schema.</span>
<span class="cm"> */</span>
<span class="k">data</span> <span class="k">class</span> <span class="nc">SchemaOptions</span><span class="p">(</span><span class="k">val</span> <span class="py">databaseSchema</span><span class="p">:</span> <span class="n">String</span><span class="p">?,</span> <span class="k">val</span> <span class="py">tablePrefix</span><span class="p">:</span> <span class="n">String</span><span class="p">?)</span>
<span class="cm">/**</span>
<span class="cm"> * Options configured for this node&#39;s schemas. A missing entry for a schema implies all properties are null.</span>
<span class="cm"> */</span>
<span class="k">val</span> <span class="py">schemaOptions</span><span class="p">:</span> <span class="n">Map</span><span class="p">&lt;</span><span class="n">MappedSchema</span><span class="p">,</span> <span class="n">SchemaOptions</span><span class="p">&gt;</span>
<span class="cm">/**</span>
<span class="cm"> * Given a state, select schemas to map it to that are supported by [generateMappedObject] and that are configured</span>
<span class="cm"> * for this node.</span>
<span class="cm"> */</span>
<span class="k">fun</span> <span class="nf">selectSchemas</span><span class="p">(</span><span class="n">state</span><span class="p">:</span> <span class="n">QueryableState</span><span class="p">):</span> <span class="n">Iterable</span><span class="p">&lt;</span><span class="n">MappedSchema</span><span class="p">&gt;</span>
<span class="cm">/**</span>
<span class="cm"> * Map a state to a [PersistentState] for the given schema, either via direct support from the state</span>
<span class="cm"> * or via custom logic in this service.</span>
<span class="cm"> */</span>
<span class="k">fun</span> <span class="nf">generateMappedObject</span><span class="p">(</span><span class="n">state</span><span class="p">:</span> <span class="n">QueryableState</span><span class="p">,</span> <span class="n">schema</span><span class="p">:</span> <span class="n">MappedSchema</span><span class="p">):</span> <span class="n">PersistentState</span>
<span class="p">}</span>
</pre></div>
</div>
<div class="highlight-kotlin"><div class="highlight"><pre><span></span><span class="cm">/**</span>
<span class="cm"> * A database schema that might be configured for this node. As well as a name and version for identifying the schema,</span>
<span class="cm"> * also list the classes that may be used in the generated object graph in order to configure the ORM tool.</span>
<span class="cm"> *</span>
<span class="cm"> * @param schemaFamily A class to fully qualify the name of a schema family (i.e. excludes version)</span>
<span class="cm"> * @param version The version number of this instance within the family.</span>
<span class="cm"> * @param mappedTypes The JPA entity classes that the ORM layer needs to be configure with for this schema.</span>
<span class="cm"> */</span>
<span class="k">abstract</span> <span class="k">class</span> <span class="nc">MappedSchema</span><span class="p">(</span><span class="n">schemaFamily</span><span class="p">:</span> <span class="n">Class</span><span class="p">&lt;*&gt;,</span>
<span class="k">val</span> <span class="py">version</span><span class="p">:</span> <span class="n">Int</span><span class="p">,</span>
<span class="k">val</span> <span class="py">mappedTypes</span><span class="p">:</span> <span class="n">Iterable</span><span class="p">&lt;</span><span class="n">Class</span><span class="p">&lt;*&gt;&gt;)</span> <span class="p">{</span>
<span class="k">val</span> <span class="py">name</span><span class="p">:</span> <span class="n">String</span> <span class="p">=</span> <span class="n">schemaFamily</span><span class="p">.</span><span class="n">name</span>
<span class="k">override</span> <span class="k">fun</span> <span class="nf">toString</span><span class="p">():</span> <span class="n">String</span> <span class="p">=</span> <span class="s">&quot;${this.javaClass.simpleName}(name=$name, version=$version)&quot;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>The <code class="docutils literal"><span class="pre">SchemaService</span></code> can be configured by a node administrator to select the schemas used by each app. In this way the
relational view of ledger states can evolve in a controlled fashion in lock-step with internal systems or other
integration points and not necessarily with every upgrade to the contract code.
It can select from the <code class="docutils literal"><span class="pre">MappedSchema</span></code> offered by a <code class="docutils literal"><span class="pre">QueryableState</span></code>, automatically upgrade to a
later version of a schema or even provide a <code class="docutils literal"><span class="pre">MappedSchema</span></code> not originally offered by the <code class="docutils literal"><span class="pre">QueryableState</span></code>.</p>
<p>It is expected that multiple different contract state implementations might provide mappings to some common schema.
For example an Interest Rate Swap contract and an Equity OTC Option contract might both provide a mapping to a common
Derivative schema. The schemas should typically not be part of the contract itself and should exist independently of it
to encourage re-use of a common set within a particular business area or Cordapp.</p>
<p><code class="docutils literal"><span class="pre">MappedSchema</span></code> offer a family name that is disambiguated using Java package style name-spacing derived from the class name
of a <em>schema family</em> class that is constant across versions, allowing the <code class="docutils literal"><span class="pre">SchemaService</span></code> to select a preferred version
of a schema.</p>
<p>The <code class="docutils literal"><span class="pre">SchemaService</span></code> is also responsible for the <code class="docutils literal"><span class="pre">SchemaOptions</span></code> that can be configured for a particular <code class="docutils literal"><span class="pre">MappedSchema</span></code>
which allow the configuration of a database schema or table name prefixes to avoid any clash with other <code class="docutils literal"><span class="pre">MappedSchema</span></code>.</p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">It is intended that there should be plugin support for the <code class="docutils literal"><span class="pre">SchemaService</span></code> to offer the version upgrading and
additional schemas as part of Cordapps, and that the active schemas be confgurable. However the present implementation
offers none of this and simply results in all versions of all schemas supported by a <code class="docutils literal"><span class="pre">QueryableState</span></code> being persisted.
This will change in due course. Similarly, it does not currently support configuring <code class="docutils literal"><span class="pre">SchemaOptions</span></code> but will do so in
the future.</p>
</div>
</div>
<div class="section" id="object-relational-mapping">
<h2>Object Relational Mapping<a class="headerlink" href="#object-relational-mapping" title="Permalink to this headline"></a></h2>
<p>The persisted representation of a <code class="docutils literal"><span class="pre">QueryableState</span></code> should be an instance of a <code class="docutils literal"><span class="pre">PersistentState</span></code> subclass, constructed
either by the state itself or a plugin to the <code class="docutils literal"><span class="pre">SchemaService</span></code>. This allows the ORM layer to always associate a
<code class="docutils literal"><span class="pre">StateRef</span></code> with a persisted representation of a <code class="docutils literal"><span class="pre">ContractState</span></code> and allows joining with the set of unconsumed states
in the vault.</p>
<p>The <code class="docutils literal"><span class="pre">PersistentState</span></code> subclass should be marked up as a JPA 2.1 <em>Entity</em> with a defined table name and having
properties (in Kotlin, getters/setters in Java) annotated to map to the appropriate columns and SQL types. Additional
entities can be included to model these properties where they are more complex, for example collections, so the mapping
does not have to be <em>flat</em>. The <code class="docutils literal"><span class="pre">MappedSchema</span></code> must provide a list of all of the JPA entity classes for that schema in order
to initialise the ORM layer.</p>
<p>Several examples of entities and mappings are provided in the codebase, including <code class="docutils literal"><span class="pre">Cash.State</span></code> and
<code class="docutils literal"><span class="pre">CommercialPaper.State</span></code>. For example, here&#8217;s the first version of the cash schema.</p>
<div class="highlight-kotlin"><div class="highlight"><pre><span></span><span class="k">package</span> <span class="nn">com.r3corda.schemas</span>
<span class="k">import</span> <span class="nn">com.r3corda.core.schemas.MappedSchema</span>
<span class="k">import</span> <span class="nn">com.r3corda.core.schemas.PersistentState</span>
<span class="k">import</span> <span class="nn">javax.persistence.Column</span>
<span class="k">import</span> <span class="nn">javax.persistence.Entity</span>
<span class="k">import</span> <span class="nn">javax.persistence.Table</span>
<span class="cm">/**</span>
<span class="cm"> * An object used to fully qualify the [CashSchema] family name (i.e. independent of version).</span>
<span class="cm"> */</span>
<span class="k">object</span> <span class="nc">CashSchema</span>
<span class="cm">/**</span>
<span class="cm"> * First version of a cash contract ORM schema that maps all fields of the [Cash] contract state as it stood</span>
<span class="cm"> * at the time of writing.</span>
<span class="cm"> */</span>
<span class="k">object</span> <span class="nc">CashSchemaV1</span> <span class="p">:</span> <span class="n">MappedSchema</span><span class="p">(</span><span class="n">schemaFamily</span> <span class="p">=</span> <span class="n">CashSchema</span><span class="p">.</span><span class="n">javaClass</span><span class="p">,</span> <span class="n">version</span> <span class="p">=</span> <span class="m">1</span><span class="p">,</span> <span class="n">mappedTypes</span> <span class="p">=</span> <span class="n">listOf</span><span class="p">(</span><span class="n">PersistentCashState</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">))</span> <span class="p">{</span>
<span class="n">@Entity</span>
<span class="n">@Table</span><span class="p">(</span><span class="n">name</span> <span class="p">=</span> <span class="s">&quot;cash_states&quot;</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">PersistentCashState</span><span class="p">(</span>
<span class="n">@Column</span><span class="p">(</span><span class="n">name</span> <span class="p">=</span> <span class="s">&quot;encumbrance&quot;</span><span class="p">)</span>
<span class="k">var</span> <span class="py">encumbrance</span><span class="p">:</span> <span class="n">Int</span><span class="p">?,</span>
<span class="n">@Column</span><span class="p">(</span><span class="n">name</span> <span class="p">=</span> <span class="s">&quot;owner_key&quot;</span><span class="p">)</span>
<span class="k">var</span> <span class="py">owner</span><span class="p">:</span> <span class="n">String</span><span class="p">,</span>
<span class="n">@Column</span><span class="p">(</span><span class="n">name</span> <span class="p">=</span> <span class="s">&quot;pennies&quot;</span><span class="p">)</span>
<span class="k">var</span> <span class="py">pennies</span><span class="p">:</span> <span class="n">Long</span><span class="p">,</span>
<span class="n">@Column</span><span class="p">(</span><span class="n">name</span> <span class="p">=</span> <span class="s">&quot;ccy_code&quot;</span><span class="p">,</span> <span class="n">length</span> <span class="p">=</span> <span class="m">3</span><span class="p">)</span>
<span class="k">var</span> <span class="py">currency</span><span class="p">:</span> <span class="n">String</span><span class="p">,</span>
<span class="n">@Column</span><span class="p">(</span><span class="n">name</span> <span class="p">=</span> <span class="s">&quot;issuer_key&quot;</span><span class="p">)</span>
<span class="k">var</span> <span class="py">issuerParty</span><span class="p">:</span> <span class="n">String</span><span class="p">,</span>
<span class="n">@Column</span><span class="p">(</span><span class="n">name</span> <span class="p">=</span> <span class="s">&quot;issuer_ref&quot;</span><span class="p">)</span>
<span class="k">var</span> <span class="py">issuerRef</span><span class="p">:</span> <span class="n">ByteArray</span>
<span class="p">)</span> <span class="p">:</span> <span class="n">PersistentState</span><span class="p">()</span>
<span class="p">}</span>
</pre></div>
</div>
</div>
</div>
</div>
</div>
<footer>
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
<a href="creating-a-cordapp.html" class="btn btn-neutral float-right" title="Creating a Cordapp" accesskey="n">Next <span class="fa fa-arrow-circle-right"></span></a>
<a href="messaging.html" class="btn btn-neutral" title="Networking and messaging" accesskey="p"><span class="fa fa-arrow-circle-left"></span> Previous</a>
</div>
<hr/>
<div role="contentinfo">
<p>
&copy; Copyright 2016, Distributed Ledger Group, LLC.
</p>
</div>
Built with <a href="http://sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT:'./',
VERSION:'latest',
COLLAPSE_INDEX:false,
FILE_SUFFIX:'.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<script type="text/javascript" src="_static/js/theme.js"></script>
<script type="text/javascript">
jQuery(function () {
SphinxRtdTheme.StickyNav.enable();
});
</script>
</body>
</html>