Sophie

Sophie

distrib > Fedora > 14 > x86_64 > media > updates > by-pkgid > 71d40963b505df4524269198e237b3e3 > files > 846

virtuoso-opensource-doc-6.1.4-2.fc14.noarch.rpm

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
 <head profile="http://internetalchemy.org/2003/02/profile">
  <link rel="foaf" type="application/rdf+xml" title="FOAF" href="http://www.openlinksw.com/dataspace/uda/about.rdf" />
  <link rel="schema.dc" href="http://purl.org/dc/elements/1.1/" />
  <meta name="dc.title" content="14. RDF Data Access and Data Management" />
  <meta name="dc.subject" content="14. RDF Data Access and Data Management" />
  <meta name="dc.creator" content="OpenLink Software Documentation Team ;&#10;" />
  <meta name="dc.copyright" content="OpenLink Software, 1999 - 2009" />
  <link rel="top" href="index.html" title="OpenLink Virtuoso Universal Server: Documentation" />
  <link rel="search" href="/doc/adv_search.vspx" title="Search OpenLink Virtuoso Universal Server: Documentation" />
  <link rel="parent" href="rdfandsparql.html" title="Chapter Contents" />
  <link rel="prev" href="sparqlextensions.html" title="Extensions" />
  <link rel="next" href="rdfviews.html" title="Linked Data Views over RDBMS Data Source" />
  <link rel="shortcut icon" href="../images/misc/favicon.ico" type="image/x-icon" />
  <link rel="stylesheet" type="text/css" href="doc.css" />
  <link rel="stylesheet" type="text/css" href="/doc/translation.css" />
  <title>14. RDF Data Access and Data Management</title>
  <meta http-equiv="Content-Type" content="text/xhtml; charset=UTF-8" />
  <meta name="author" content="OpenLink Software Documentation Team ;&#10;" />
  <meta name="copyright" content="OpenLink Software, 1999 - 2009" />
  <meta name="keywords" content="" />
  <meta name="GENERATOR" content="OpenLink XSLT Team" />
 </head>
 <body>
  <div id="header">
    <a name="rdfgraphsecurity" />
    <img src="../images/misc/logo.jpg" alt="" />
    <h1>14. RDF Data Access and Data Management</h1>
  </div>
  <div id="navbartop">
   <div>
      <a class="link" href="rdfandsparql.html">Chapter Contents</a> | <a class="link" href="sparqlextensions.html" title="Extensions">Prev</a> | <a class="link" href="rdfviews.html" title="Linked Data Views over RDBMS Data Source">Next</a>
   </div>
  </div>
  <div id="currenttoc">
   <form method="post" action="/doc/adv_search.vspx">
    <div class="search">Keyword Search: <br />
        <input type="text" name="q" /> <input type="submit" name="go" value="Go" />
    </div>
   </form>
   <div>
      <a href="http://www.openlinksw.com/">www.openlinksw.com</a>
   </div>
   <div>
      <a href="http://docs.openlinksw.com/">docs.openlinksw.com</a>
   </div>
    <br />
   <div>
      <a href="index.html">Book Home</a>
   </div>
    <br />
   <div>
      <a href="contents.html">Contents</a>
   </div>
   <div>
      <a href="preface.html">Preface</a>
   </div>
    <br />
   <div class="selected">
      <a href="rdfandsparql.html">RDF Data Access and Data Management</a>
   </div>
    <br />
   <div>
      <a href="rdfdatarepresentation.html">Data Representation</a>
   </div>
   <div>
      <a href="rdfsparql.html">SPARQL</a>
   </div>
   <div>
      <a href="sparqlextensions.html">Extensions</a>
   </div>
   <div class="selected">
      <a href="rdfgraphsecurity.html">RDF Graphs Security</a>
    <div>
        <a href="#rdfgraphsecuritygroups" title="RDF Graph Groups">RDF Graph Groups</a>
        <a href="#rdfgraphsecuritynotfrom" title="NOT FROM and NOT FROM NAMED Clauses">NOT FROM and NOT FROM NAMED Clauses</a>
        <a href="#rdfgraphsecurity" title="Graph-Level Security">Graph-Level Security</a>
        <a href="#rdfgraphsecurityunddefperm" title="Understanding Default Permissions">Understanding Default Permissions</a>
        <a href="#rdfgraphsecurityintconfsec" title="Initial Configuration of SPARQL Security">Initial Configuration of SPARQL Security</a>
        <a href="#rdfgraphsecurityappcallb" title="Application Callbacks for Graph Level Security">Application Callbacks for Graph Level Security</a>
    </div>
   </div>
   <div>
      <a href="rdfviews.html">Linked Data Views over RDBMS Data Source</a>
   </div>
   <div>
      <a href="rdfrdfviewgnr.html">Automated Generation of RDF Views over Relational Data Sources</a>
   </div>
   <div>
      <a href="rdfviewsenterpr.html">Examples of Linked Data Views</a>
   </div>
   <div>
      <a href="rdfinsertmethods.html">RDF Insert Methods in Virtuoso</a>
   </div>
   <div>
      <a href="virtuososponger.html">RDFizer Middleware (Sponger)</a>
   </div>
   <div>
      <a href="virtuosospongerfacetinstall.html">Virtuoso Faceted Browser Installation and configuration</a>
   </div>
   <div>
      <a href="virtuosospongerfacent.html">Virtuoso Faceted Web Service</a>
   </div>
   <div>
      <a href="rdfiridereferencing.html">Linked Data</a>
   </div>
   <div>
      <a href="rdfsparqlrule.html">Inference Rules &amp; Reasoning</a>
   </div>
   <div>
      <a href="rdfsparqlgeospat.html">RDF and Geometry</a>
   </div>
   <div>
      <a href="rdfperformancetuning.html">RDF Performance Tuning</a>
   </div>
   <div>
      <a href="rdfnativestorageproviders.html">RDF Data Access Providers (Drivers)</a>
   </div>
   <div>
      <a href="rdfgraphreplication.html">RDF Graph Replication</a>
   </div>
    <br />
  </div>
  <div id="text">
    <a name="rdfgraphsecurity" />
    <h2>14.4. RDF Graphs Security</h2>
<a name="rdfgraphsecuritygroups" />
    <h3>14.4.1. RDF Graph Groups</h3>
<p>In some cases, the data-set of a SPARQL query is not known at compile time. It is possible to pass
IRIs of source graphs via parameters, but the method is not perfect as:</p>
<ul>
  <li>not all protocols are suitable for parameter passing, and no one is an interoperable standard</li>
  <li>passing list of IRIs as a parameter will usually require the use of Virtuoso-specific functions
in the text of SPARQL query, that&#39;s bad for some query builders.</li>
  <li>lack of knowledge about actual graphs may damage query optimization</li>
</ul>
<p>It would be nice to create named lists of graphs and a clause like &quot;SELECT from all graph names of the specified list&quot;.
<strong>&quot;Graph groups&quot;</strong> serve for this purpose. That is Virtuoso-specific SPARQL extension that let create a named list of IRIs such that
if name of the list is used in <strong>FROM</strong> clause like <strong>IRI</strong> of default
graph then it is equivalent to list of <strong>FROM</strong> clauses, one clause for each item of the
list.</p>
<p>Internally, descriptions of graph groups are kept in two tables:</p>
<strong>Table of graph groups:</strong>
<div>
      <pre class="programlisting">
create table DB.DBA.RDF_GRAPH_GROUP (
  RGG_IID IRI_ID not null primary key,	-- IRI ID of RGG_IRI field
  RGG_IRI varchar not null,		-- Name of the group
  RGG_MEMBER_PATTERN varchar,		-- Member IRI pattern
  RGG_COMMENT varchar			-- Comment
  )
create index RDF_GRAPH_GROUP_IRI on DB.DBA.RDF_GRAPH_GROUP (RGG_IRI)
;
</pre>
    </div>
<p>
      <strong>Table of contents of groups:</strong>
    </p>

<div>
      <pre class="programlisting">
create table DB.DBA.RDF_GRAPH_GROUP_MEMBER (
  RGGM_GROUP_IID IRI_ID not null,	-- IRI_ID of the group
  RGGM_MEMBER_IID IRI_ID not null,	-- IRI_ID of the group member
  primary key (RGGM_GROUP_IID, RGGM_MEMBER_IID)
  )
;
</pre>
    </div>

<p>Fields <strong>RGG_MEMBER_PATTERN</strong> and <strong>RGG_COMMENT</strong> are not used by system internals but applications may wish to write their data there for future reference.
<strong>RGG_COMMENT</strong> is supposed to be human-readable description of the group and <strong>RGG_MEMBER_PATTERN</strong> may be useful for functions that automatically add
IRIs of a given graph to all graph groups such that the graph IRI string match <strong>RGG_MEMBER_PATTERN</strong> regexp pattern.
</p>
<p>A dictionary of all groups and their members is cached in memory for fast access.
Due to this reason, applications may read these tables and modify <strong>RGG_MEMBER_PATTERN</strong> and <strong>RGG_COMMENT</strong> if needed but not change other fields directly.
The following API procedures makes changes in a safe way:
</p>
<div>
      <pre class="programlisting">
DB.DBA.RDF_GRAPH_GROUP_CREATE (
  in group_iri varchar,
  in quiet integer,
  in member_pattern varchar := null,
  in comment varchar := null)
</pre>
    </div>

<p>That creates a new empty graph group. An error is signaled if the group exists already and quiet
parameter is zero.</p>

<div>
      <pre class="programlisting">
DB.DBA.RDF_GRAPH_GROUP_INS (in group_iri varchar, in memb_iri varchar)
DB.DBA.RDF_GRAPH_GROUP_DEL (in group_iri varchar, in memb_iri varchar)
</pre>
    </div>


<p>These two are to add or remove member to an existing group. Double insert or removal of not a member
will not signal errors, but missing group will.be signaled.</p>

<div>
      <pre class="programlisting">
DB.DBA.RDF_GRAPH_GROUP_DROP (
  in group_iri varchar,
  in quiet integer)
</pre>
    </div>

<p>That removes graph group. An error is signaled if the group did not exist before the call and quiet
parameter is zero.</p>

<p>Graph groups are <strong>&quot;macro-expanded&quot;</strong> only in FROM clauses and have no effect on
FROM NAMED or on GRAPH &lt;IRI&gt; {...} . Technically, it is not prohibited to use an IRI as both plain
graph IRI and graph group IRI in one storage but this is confusing and is not recommended.</p>

<p>Graph groups can not be members of other graph groups, i.e. the IRI of a graph group can appear in the
list of members of some group but it will be treated as plain graph IRI and will not cause recursive
expansion of groups.</p>
<br />
<a name="rdfgraphsecuritynotfrom" />
    <h3>14.4.2. NOT FROM and NOT FROM NAMED Clauses</h3>
<p>In addition to standard FROM and FROM NAMED clauses, Virtuoso extends SPARQL with NOT FROM and NOT
FROM NAMED clauses of &quot;opposite&quot; meaning.</p>

<div>
      <pre class="programlisting">
SELECT ... NOT FROM &lt;x&gt; ... WHERE {...}
</pre>
    </div>

<p>means &quot;SELECT FROM other graphs, but not from the given one&quot;.
This is especially useful because NOT FROM supports graph groups (NOT FROM NAMED supports only plain graphs).
So if</p>

<div>
      <pre class="programlisting">
&lt;http://example.com/users/private&gt;
</pre>
    </div>

<p>is a graph group of all graphs with confidential data about users then</p>

<div>
      <pre class="programlisting">
SELECT * NOT FROM &lt;http://example.com/users/private&gt; WHERE {...}
</pre>
    </div>

<p>will be restricted only to insecure data.</p>

<p>NOT FROM overrides any FROM and NOT FROM NAMED overrides any FROM NAMED, the order of clauses in the
query text is not important.</p>

<p>The SPARQL web service endpoint configuration string may contain pragmas
<strong>input:default-graph-exclude</strong> and <strong>input:named-graph-exclude</strong> that
become equivalent to NOT FROM and NOT FROM NAMED clauses like <strong>input:default-graph-uri</strong>
and <strong>input:named-graph-uri</strong> mimics FROM and FROM NAMED.</p>
<br />
<a name="rdfgraphsecurity" />
    <h3>14.4.3. Graph-Level Security</h3>
<p>Virtuoso supports graph-level security for &quot;physical&quot; RDF storage. That is somewhat similar to table
access permissions in SQL. However, the difference between SPARQL and SQL data models results in totally
different style of security administration. In SQL, when new application is installed it comes with its own
set of tables and every query in its code explicitly specifies tables in use. Security restrictions of two
applications interfere only if applications knows each other and are supposedly designed to cooperate. It
is possible to write an application that will get list of available tables and retrieve data from any given
table but that is a special case and it usually requires DBA privileges.</p>

<p>In SPARQL, data of different applications shares one table and the query language allows to select data
of all applications at once. This feature makes SPARQL convenient for cross-application data integration. At
the same time, that become a giant security hole if any sensitive data are stored.</p>

<p>A blind copying SQL security model to SPARQL domain would result in significant loss of performance or
weak security or even both problems at the same time. That is why SPARQL model is made much more restrictive,
even if it becomes inconvenient for some administration tasks.</p>

<p>Graph-level security does not replace traditional SQL security. A user should become member of
appropriate group (SPARQL_SELECT, SPARQL_SPONGE or SPARQL_UPDATE) in order to start using its graph-level
privileges.</p>
<br />
<a name="rdfgraphsecurityunddefperm" />
    <h3>14.4.4. Understanding Default Permissions</h3>

<p>In relational database, default permissions are trivial. DBA is usually the only account that can
access any table for both read and write. Making some table public or private does not affect applications
that do not refer that table in the code. Tables are always created before making security restrictions on
them.</p>

<p>Chances are very low that an application will unintentionally create some table and fill in with
confidential data. There are no unauthenticated users, any client has some user ID and no one user is
&quot;default user&quot; so permissions of any two users are always independent.</p>

<p>SPARQL access can be anonymous and graphs can be created during routine data manipulation.
For anonymous user, only public resources are available. Thus &quot;default permissions&quot; on some or all graphs are
actually permissions of &quot;nobody&quot; user, (the numeric ID of this user can be obtained by http_nobody_uid()
function call). As a consequence, there&#39;s a strong need in &quot;default permission&quot; for a user, this is the only
way to specify what to do with all graphs that does not exist now it might exist in some future.
</p>

<p>An attempt to make default permissions wider than specific is always potential security hole in SPARQL,
so this is strictly prohibited.</p>

<p>Four sorts of access are specified by four bits of an integer &quot;permission bit-mask&quot;, plain old UNIX
style:</p>

<ul>
  <li>Bit 1 permits read access.</li>
  <li>Bit 2 permits write access via SPARUL and it&#39;s basically useless without bit 1 set.</li>
  <li>Bit 4 permits write access via &quot;RDF sponge&quot; methods and it&#39;s basically useless
without bits 1 and 2 set.</li>
  <li>Bit 8 allows to obtain list of members of graph group; an IRI can be used as graph IRI and as
graph group IRI at the same time so bit 8 can be freely combined with any of bits 1, 2 or 4.</li>
</ul>

<p>Note that obtaining the list of members of a graph group does not grant any access permissions to
triples from member graphs. It is quite safe to mix secure and public graphs in one graph group.</p>

<p>When a SPARQL query should check whether a given user have permission to access a given graph then
the order of checks is as follows:</p>

<ol>
      <li>permissions of the user on the specific graph;</li>
      <li>default permissions of the user on all graphs;</li>
      <li>public permissions on the specific graph;</li>
      <li>public permissions on all graphs</li>
    </ol>

<p>If no one above mentioned permission is set then the access is &quot;read/write/sponge/list&quot;.</p>
<p>For &quot;nobody&quot; user, steps 3 and 4 become exact copies of steps 1 and 2 so they are skipped.</p>
<br />
<a name="rdfgraphsecurityintconfsec" />
    <h3>14.4.5. Initial Configuration of SPARQL Security</h3>
<p>It is convenient to configure the RDF storage security by adding restrictions in the order inverse
to the order of checks:</p>

<ul>
  <li>Step 1: Set public permissions on all graphs to the most restricted level of any application
that will be installed. So if any single graph will be unreadable for public, then public permissions on
all graphs should be set to 0 or 8.</li>
  <li>Step 2: Public permissions on &quot;insecure&quot; graphs should be set. So if the database contains
DBpedia or WordNet or some other data of Linking Open Data project then public permissions for that graphs
may be set to 1.</li>
  <li>Step3: Configure trusted users, such as administrative DBA-like accounts, and to specify their
permissions on all graphs.</li>
  <li>Step 4: Some additional right can be granted to some specific users on some specific graphs.</li>
</ul>

<p>Note that there&#39;s no need to permit something to DBA itself, because DBA&#39;s default permissions are
set automatically.</p>
<a name="rdfgraphsecurityintconfsecuser" />
    <h4>14.4.5.1. Configuring New User</h4>
<ul>
  <li>Step 1: Grant SPARQL_SELECT, SPARQL_SPONGE or SPARQL_UPDATE to the user.</li>
  <li>Step 2: Set user&#39;s permissions on all graphs.</li>
  <li>Step 3: Grant rights on some specific graphs.</li>
</ul>
<br />
<a name="rdfgraphsecurityintex" />
    <h4>14.4.5.2. Example: Blogs and Resource Sharing</h4>
<p>Consider a &quot;groupware&quot; application that let users create personal resources with access policies.</p>

<div>
      <pre class="programlisting">
-- First, create few users, in alphabetical order.
DB.DBA.USER_CREATE (&#39;Anna&#39;, &#39;Anna&#39;);
DB.DBA.USER_CREATE (&#39;Brad&#39;, &#39;Brad&#39;);
DB.DBA.USER_CREATE (&#39;Carl&#39;, &#39;Carl&#39;);
grant SPARQL_UPDATE to &quot;Anna&quot;;
grant SPARQL_UPDATE to &quot;Brad&quot;;
grant SPARQL_UPDATE to &quot;Carl&quot;;

-- At least some data are supposed to be confidential, thus the whole storage becomes confidential.
DB.DBA.RDF_DEFAULT_USER_PERMS_SET (&#39;nobody&#39;, 0);

-- Moreover, no one of created users have access to all graphs (even for reading).
DB.DBA.RDF_DEFAULT_USER_PERMS_SET (&#39;Anna&#39;, 0);
DB.DBA.RDF_DEFAULT_USER_PERMS_SET (&#39;Brad&#39;, 0);
DB.DBA.RDF_DEFAULT_USER_PERMS_SET (&#39;Carl&#39;, 0);

-- Anna can only read her personal system data graph.
DB.DBA.RDF_GRAPH_USER_PERMS_SET (&#39;http://example.com/Anna/system&#39;, &#39;Anna&#39;, 1);

-- Anna can read and write her private data graph.
DB.DBA.RDF_GRAPH_USER_PERMS_SET (&#39;http://example.com/Anna/private&#39;, &#39;Anna&#39;, 3);

-- Anna and Bred are friends and can read each others notes for friends.
DB.DBA.RDF_GRAPH_USER_PERMS_SET (&#39;http://example.com/Anna/friends&#39;, &#39;Anna&#39;, 3);
DB.DBA.RDF_GRAPH_USER_PERMS_SET (&#39;http://example.com/Anna/friends&#39;, &#39;Brad&#39;, 1);
DB.DBA.RDF_GRAPH_USER_PERMS_SET (&#39;http://example.com/Brad/friends&#39;, &#39;Brad&#39;, 3);
DB.DBA.RDF_GRAPH_USER_PERMS_SET (&#39;http://example.com/Brad/friends&#39;, &#39;Anna&#39;, 1);

-- Brad and Carl share write access to graph of his company.
DB.DBA.RDF_GRAPH_USER_PERMS_SET (&#39;http://example.com/BubbleSortingServicesInc&#39;, &#39;Brad&#39;, 3);
DB.DBA.RDF_GRAPH_USER_PERMS_SET (&#39;http://example.com/BubbleSortingServicesInc&#39;, &#39;Carl&#39;, 3);

-- Anna writes a blog for public.
DB.DBA.RDF_GRAPH_USER_PERMS_SET (&#39;http://example.com/Anna/blog&#39;, &#39;Anna&#39;, 3);
DB.DBA.RDF_GRAPH_USER_PERMS_SET (&#39;http://example.com/Anna/blog&#39;, &#39;nobody&#39;, 1);

-- DBpedia is public read and local discussion wiki is readable and writable.
DB.DBA.RDF_GRAPH_USER_PERMS_SET (&#39;http://dbpedia.org/&#39;, &#39;nobody&#39;, 1);
DB.DBA.RDF_GRAPH_USER_PERMS_SET (&#39;http://example.com/wiki&#39;, &#39;nobody&#39;, 3);
DB.DBA.RDF_GRAPH_USER_PERMS_SET (&#39;http://example.com/publicB&#39;, &#39;nobody&#39;, 3);

-- Graph groups have its own security.
DB.DBA.RDF_GRAPH_GROUP_CREATE (&#39;http://example.com/Personal&#39;, 1);
DB.DBA.RDF_GRAPH_GROUP_INS (&#39;http://example.com/Personal&#39;, &#39;http://example.com/Anna/system&#39;);
DB.DBA.RDF_GRAPH_GROUP_INS (&#39;http://example.com/Personal&#39;, &#39;http://example.com/Anna/private&#39;);
DB.DBA.RDF_GRAPH_GROUP_INS (&#39;http://example.com/Personal&#39;, &#39;http://example.com/Brad/system&#39;);
DB.DBA.RDF_GRAPH_GROUP_INS (&#39;http://example.com/Personal&#39;, &#39;http://example.com/Brad/private&#39;);
DB.DBA.RDF_GRAPH_USER_PERMS_SET (&#39;http://example.com/Personal&#39;, &#39;Anna&#39;, 8);
DB.DBA.RDF_GRAPH_USER_PERMS_SET (&#39;http://example.com/Personal&#39;, &#39;Brad&#39;, 8);
</pre>
    </div>

<p>If Anna and Brad execute same</p>

<div>
      <pre class="programlisting">
SELECT *
FROM &lt;http://example.com/Personal&gt;
WHERE { ?s ?p ?o }
</pre>
    </div>

<p>then results will be totally different: users will not get access to each others data.</p>
<br />
<br />
<a name="rdfgraphsecurityappcallb" />
    <h3>14.4.6. Application Callbacks for Graph Level Security</h3>
<p>In some cases, different applications should provide different security for different users. Two
SPARQL pragmas are provided for this purpose:</p>

<ul>
  <li>Pragma sql:gs-app-callback is to specify Virtuoso/PL callback function that return permission bits for given graph.</li>
  <li>Pragma sql:gs-app-uid is to specify application-specific user ID that is some string that is passed to the callback &quot;as is&quot;.</li>
</ul>

<p>The name of callback is always DB.DBA.SPARQL_GS_APP_CALLBACK_nnn, where nnn is value of
sql:gs-app-callback.</p>

<p>The callback is called only if the application has access to the graph in question so it may restrict
the caller&#39;s account but not grant more permissions.</p>
<a name="rdfgraphsecurityappcallbex" />
    <h4>14.4.6.1. Example</h4>
<p>Let user of application get full access to graphs whose IRIs contain user&#39;s name in path.
In addition, let all of them permission to use all graph groups and let the &quot;moderator&quot; user read everything.</p>

<div>
      <pre class="programlisting">
reconnect &quot;dba&quot;;

create function DB.DBA.SPARQL_GS_APP_CALLBACK_TEST (in g_iid IRI_ID, in app_uid varchar) returns integer
{
  declare g_uri varchar;
-- A fake IRI ID #i0 is used to mention account&#39;s default permissions for all graphs.
  if (#i0 = g_iid)
    {
      if (&#39;moderator&#39; = app_uid)
        return 9; -- Moderator can read and list everything.
      return 8; -- Other users can list everything.
    }
  g_uri := id_to_iri (g_iid);
  if (strstr (g_uri, &#39;/&#39; || app_uid || &#39;/&#39;))
    return 15; -- User has full access to &quot;his&quot; graph.
  return 8; -- User can list any given graph group.
}
;

SPARQL
define sql:gs-app-callback &quot;TEST&quot;
define sql:gs-app-uid &quot;Anna&quot;
SELECT ?g ?s WHERE { ?s &lt;p&gt; ?o }
;
</pre>
    </div>
<br />
<br />
<table border="0" width="90%" id="navbarbottom">
    <tr>
        <td align="left" width="33%">
          <a href="sparqlextensions.html" title="Extensions">Previous</a>
          <br />Extensions</td>
     <td align="center" width="34%">
          <a href="rdfandsparql.html">Chapter Contents</a>
     </td>
        <td align="right" width="33%">
          <a href="rdfviews.html" title="Linked Data Views over RDBMS Data Source">Next</a>
          <br />Linked Data Views over RDBMS Data Source</td>
    </tr>
    </table>
  </div>
  <div id="footer">
    <div>Copyright© 1999 - 2009 OpenLink Software All rights reserved.</div>
   <div id="validation">
    <a href="http://validator.w3.org/check/referer">
        <img src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0!" height="31" width="88" />
    </a>
    <a href="http://jigsaw.w3.org/css-validator/">
        <img src="http://jigsaw.w3.org/css-validator/images/vcss" alt="Valid CSS!" height="31" width="88" />
    </a>
   </div>
  </div>
 </body>
</html>