directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache Directory Server v1.5 > Apache DS Registries
Date Mon, 23 Nov 2009 16:17:00 GMT
<html>
<head>
    <base href="http://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/1519/1/1/_/styles/combined.css?spaceKey=DIRxSRVx11&amp;forWysiwyg=true" type="text/css">
    </head>
<body style="background-color: white" bgcolor="white">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
     <h2><a href="http://cwiki.apache.org/confluence/display/DIRxSRVx11/Apache+DS+Registries">Apache DS Registries</a></h2>
     <h4>Page <b>edited</b> by             <a href="http://cwiki.apache.org/confluence/display/~elecharny">Emmanuel Lécharny</a>
    </h4>
     
          <br/>
     <div class="notificationGreySide">
         <div class='panelMacro'><table class='noteMacro'><colgroup><col width='24'><col></colgroup><tr><td valign='top'><img src="/confluence/images/icons/emoticons/warning.gif" width="16" height="16" align="absmiddle" alt="" border="0"></td><td><b>Work in progress</b><br /><p>This site is in the process of being reviewed and updated.</p></td></tr></table></div>

<h1><a name="ApacheDSRegistries-Introduction"></a>Introduction</h1>

<p>Apache DS has to keep a lot of internal structures available from all the parts of the server. This is done through what we call the <b>SchemaManager</b>. It hide all the internal structure from the users.</p>

<h2><a name="ApacheDSRegistries-SchemaManager"></a>SchemaManager</h2>

<p>The <b>SchemaManager</b> stores <b>Registries</b>, which are hives where each <b>SchemaObjects</b> are stored. We also store some dedicated data structures :</p>
<ul>
	<li>factory : The object responsible for the <b>SchemaObject</b> instance creation, given an Entry containing a <b>SchemaObject</b> description</li>
	<li>namingContext : The partition this&#42; SchemaManager&#42; is associated with. In the future, we want to associate a <b>SchemaManager</b> to a Partition, allowing the server to have more than one <b>SchemaManager</b></li>
	<li>registries : The container for all the <b>SchemaObject</b> Registries</li>
	<li>schemaLoader : The loader for this instance. <b>SchemaObjects</b> may be stored on disk, in a database... The loader is responsible for their retrieval</li>
	<li>errors : The list of errors we got when we have updated the schema. It should be empty before we can use this SchemaManager in the server</li>
</ul>


<p>h2 Registries<br/>
This is the internal container for all the <b>SchemaObject</b> registries. When modifying the schema, this object will be cloned, modified, chekced, and if thee is no error, we will apply those modifications to the real registries.</p>

<p>It contains a set of fields used to manage the schema :</p>
<ul>
	<li>globalOidRegistry : It stores the list of all the <b>SchemaObject*s' OIDs. A &#42;SchemaObject</b> has a unique OID in a <b>SchemaManager</b></li>
	<li>&lt;SchemaObject&gt;Registry : A registry per <b>SchemaObject</b> type.</li>
	<li>loadedSchemas : The list of all the loaded schemas</li>
	<li>schemaObjectsBySchemaName : A list of all <b>SchemaObjects</b> per schema</li>
	<li>usedBy : a map containing the list of <b>SchemaObject</b> referencing a given <b>SchemaObject</b></li>
	<li>using : a map containing the list of <b>SchemaObject</b> used by a given <b>SchemaObject</b></li>
</ul>


<h2><a name="ApacheDSRegistries-SchemaObjectRegistries"></a>SchemaObject Registries</h2>

<p>For each different type of <b>SchemaObject</b>, we have a dedicated Registry.</p>

<p>The following diagram shows the class diagram for those registries : <br/>
<div align="center"><a class="confluence-thumbnail-link 1159x828" href='http://cwiki.apache.org/confluence/download/attachments/29461/SchemaObjectRegistryclassdiagram.png'><img src="/confluence/download/thumbnails/29461/SchemaObjectRegistryclassdiagram.png" border="0" /></a></div></p>



<h2><a name="ApacheDSRegistries-SchemaObjects"></a>SchemaObjects</h2>

<p>We have 11 different <b>SchemaObjects</b>, 3 of them are Apache DS specific :</p>
<ul>
	<li>(AT)  AttributeType</li>
	<li>(C)   Comparator (specific)</li>
	<li>(DCR) DITContentRule</li>
	<li>(DSR) DITStructureRule</li>
	<li>(MR)  MatchingRule</li>
	<li>(MRU) MatchingRuleUse</li>
	<li>(NF)  NameForm</li>
	<li>(N)   Normalizer (specific)</li>
	<li>(OC)  ObjectClass</li>
	<li>(S)   Syntax</li>
	<li>(SC)  SyntaxChecker (specific)</li>
</ul>


<p>The specific SchemaObjects are those we can load into the server dynamically : they are compiled Java classes.</p>

<p>All the <b>SchemaObjects</b> are related with each other. The following schema shows all the existing relations  : <div align="center"><img src="/confluence/download/attachments/29461/SchemaObjects.png" border="0" /></div></p>

<p>This class diagram exposes the relations between all those classes : <br/>
<div align="center"><img src="/confluence/download/attachments/29461/SchemaObjectclassdiagram.png" border="0" /></div></p>

<h2><a name="ApacheDSRegistries-AttributeType"></a>AttributeType</h2>

<p>Here are the fields stored in a AttributeType instance :</p>

<table class='confluenceTable'><tbody>
<tr>
<th class='confluenceTh'> Name </th>
<th class='confluenceTh'> default </th>
</tr>
<tr>
<td class='confluenceTd'> description </td>
<td class='confluenceTd'> N/A </td>
</tr>
<tr>
<td class='confluenceTd'> extensions </td>
<td class='confluenceTd'> N/A </td>
</tr>
<tr>
<td class='confluenceTd'> isEnabled </td>
<td class='confluenceTd'> TRUE </td>
</tr>
<tr>
<td class='confluenceTd'> isObsolete </td>
<td class='confluenceTd'> FALSE </td>
</tr>
<tr>
<td class='confluenceTd'> isReadOnly </td>
<td class='confluenceTd'> FALSE </td>
</tr>
<tr>
<td class='confluenceTd'> names </td>
<td class='confluenceTd'> No names </td>
</tr>
<tr>
<td class='confluenceTd'> objectType </td>
<td class='confluenceTd'> ATTRIBUTE_TYPE </td>
</tr>
<tr>
<td class='confluenceTd'> oid </td>
<td class='confluenceTd'> AT OID </td>
</tr>
<tr>
<td class='confluenceTd'> schemaName </td>
<td class='confluenceTd'> N/A </td>
</tr>
<tr>
<td class='confluenceTd'> specification </td>
<td class='confluenceTd'> not modifiable </td>
</tr>
<tr>
<td class='confluenceTd'> canUserModify </td>
<td class='confluenceTd'> TRUE </td>
</tr>
<tr>
<td class='confluenceTd'> equality </td>
<td class='confluenceTd'> MR reference </td>
</tr>
<tr>
<td class='confluenceTd'> equalityOid </td>
<td class='confluenceTd'> MR OID </td>
</tr>
<tr>
<td class='confluenceTd'> isCollective </td>
<td class='confluenceTd'> FALSE </td>
</tr>
<tr>
<td class='confluenceTd'> isSingleValued </td>
<td class='confluenceTd'> FALSE </td>
</tr>
<tr>
<td class='confluenceTd'> ordering </td>
<td class='confluenceTd'> MR reference </td>
</tr>
<tr>
<td class='confluenceTd'> orderingOid </td>
<td class='confluenceTd'> MR OID </td>
</tr>
<tr>
<td class='confluenceTd'> substring </td>
<td class='confluenceTd'> MR reference </td>
</tr>
<tr>
<td class='confluenceTd'> substringOid </td>
<td class='confluenceTd'>  MR OID </td>
</tr>
<tr>
<td class='confluenceTd'> superior </td>
<td class='confluenceTd'> AT reference </td>
</tr>
<tr>
<td class='confluenceTd'> superiorOid </td>
<td class='confluenceTd'> MR OID </td>
</tr>
<tr>
<td class='confluenceTd'> syntax </td>
<td class='confluenceTd'> Syntax reference </td>
</tr>
<tr>
<td class='confluenceTd'> syntaxLength </td>
<td class='confluenceTd'> 0 </td>
</tr>
<tr>
<td class='confluenceTd'> syntaxOid </td>
<td class='confluenceTd'> Syntax OID </td>
</tr>
<tr>
<td class='confluenceTd'> usage </td>
<td class='confluenceTd'> userApplications </td>
</tr>
</tbody></table>

<h3><a name="ApacheDSRegistries-AddinganAttributeType"></a>Adding an AttributeType</h3>

<p>Register the AttributeType into the AttributeTypeRegistry :<br/>
update the AttributeTypeRegistry.byOid : add &lt;oid, AttributeType&gt;<br/>
for all the attributeType names, plus the oid,<br/>
    update the AttributeTypeRegistry.byName : add &lt;name, AttributeType&gt;<br/>
update the AttributeTypeRegistry.byName : add &lt;oid, AttributeType&gt;<br/>
associate the AttributeType with the schema : &lt;schema, set&lt;SchemaObject&gt;&gt; &#43;= AttributeType<br/>
update the Registries.globalOidRegistry : add &lt;oid, AttributeType&gt;</p>

<p>When all the schema modifications will be done, do the additional updates :</p>

<p>update the AttributeType.syntax : SyntaxRegistry.lookup( syntaxOid )<br/>
update the AttributeType.equality : MatchingRuleRegistry.lookup( equalityOid )<br/>
update the AttributeType.ordering : MatchingRuleRegistry.lookup( orderingOid )<br/>
update the AttributeType.substring : MatchingRuleRegistry.lookup( substringOid )<br/>
update the AttributeType.sup : AttributeType.lookup( superiorOid )<br/>
update the Registries.using map : &lt;AttributeType.oid, set&lt;SchemaObject&gt;&gt; += <br/>
    syntax, equality, ordering, substring, superior<br/>
update the Registries.usedBy map : <br/>
    &lt;Syntax.oid, set&lt;SchemaObject&gt;&gt; += AttributeType<br/>
    &lt;equalityOid, set&lt;SchemaObject&gt;&gt; += AttributeType<br/>
    &lt;orderingOid, set&lt;SchemaObject&gt;&gt; += AttributeType<br/>
    &lt;substringOid, set&lt;SchemaObject&gt;&gt; += AttributeType<br/>
    &lt;superiorOid, set&lt;SchemaObject&gt;&gt; += AttributeType</p>

<p>There are special cases to deal with :</p>
<ul>
	<li>if the Syntax is null, then inherit it from the superior, whcih must not be null</li>
	<li>if the equality is null, and if we have a superior, inherit the equality from it</li>
	<li>if there is a superior, the Usage must be the same than its superior's</li>
	<li>if the superior is COLLECTIVE, the it must also be COLLECTIVE</li>
	<li>if it's COLLECTIVE, then the Usage must be operational</li>
</ul>


<h3><a name="ApacheDSRegistries-ModifyinganAttributeType"></a>Modifying an AttributeType</h3>

<p>We won't create a new object, but will update the existing one. The OID can't be changed</p>

<p>If we have changed one of the MRs, or the S, or the superior AT, when all the schema <br/>
modifications will be done, do the additional updates :<br/>
update the AttributeType.&lt;MR/S/sup&gt; : &lt;MR/S/AT&gt;Registry.lookup( oid )<br/>
update the Registries.using map : &lt;AttributeType.oid, set&lt;SchemaObject&gt;&gt; -= old &lt;MR/S/AT&gt;<br/>
update the Registries.using map : &lt;AttributeType.oid, set&lt;SchemzObject&gt;&gt; += new &lt;MR/S/AT&gt;<br/>
update the Registries.usedBy map : &lt;old &lt;MR/S/AT&gt;.oid, set&lt;SchemaObject&gt;&gt; -= AttributeType<br/>
update the Registries.usedBy map : &lt;new &lt;MR/S/AT&gt;.oid, set&lt;SchemaObject&gt;&gt; += AttributeType</p>

<p>We will also have to check that the modified AT is still valid</p>

<h3><a name="ApacheDSRegistries-DeletinganAttributeType"></a>Deleting an AttributeType</h3>

<p>We can't delete an AttributeType if it's refered by an ObjectClass, or another AttributeType.<br/>
This is checked by verifying inthe usedBy table :</p>

<p>if usedBy.get( attributeType.oid ) is not empty, generate an error.</p>

<p>remove the oid from the AttributeTypeRegistry.byOid<br/>
for each AttributeType's name, <br/>
  remove the AttributeType.name from the AttributeTypeRegistry.byName<br/>
 + remove the AttributeType.oid from the AttributeTypeRegistry.byName<br/>
remove all the names and the oid from the AttributeTypeRegistry.byName<br/>
remove the AttributeType from the bySchemaNameSchemaObject map : &lt;schema, set&lt;SchemaObject&gt;&gt; &#45;= AttributeType<br/>
remove the AttributeType.oid from the globalOidRegistry : remove &lt;oid, AttributeType&gt;</p>

<p>When all the schema modifications will be done, do the additional updates :</p>

<p>update the Registries.using map : remove the relation &lt;AttributeType.oid, set&lt;SchemaObject&gt;&gt;<br/>
update the Registries.usedBy map for each AT/MR/S referenced in the AttributeType : <br/>
  &lt;&lt;AT/MR/S&gt;.oid, set&lt;SchemaObject&gt;&gt; -= AttributeType</p>

<h2><a name="ApacheDSRegistries-Comparator"></a>Comparator</h2>

<p>Here are the fields stored in a Comparator instance :</p>

<table class='confluenceTable'><tbody>
<tr>
<th class='confluenceTh'> Name </th>
<th class='confluenceTh'> default </th>
</tr>
<tr>
<td class='confluenceTd'> description </td>
<td class='confluenceTd'> N/A </td>
</tr>
<tr>
<td class='confluenceTd'> extensions </td>
<td class='confluenceTd'> N/A </td>
</tr>
<tr>
<td class='confluenceTd'> isEnabled </td>
<td class='confluenceTd'> TRUE </td>
</tr>
<tr>
<td class='confluenceTd'> isObsolete </td>
<td class='confluenceTd'> FALSE </td>
</tr>
<tr>
<td class='confluenceTd'> isReadOnly </td>
<td class='confluenceTd'> FALSE </td>
</tr>
<tr>
<td class='confluenceTd'> names </td>
<td class='confluenceTd'> No names </td>
</tr>
<tr>
<td class='confluenceTd'> objectType </td>
<td class='confluenceTd'> COMPARATOR </td>
</tr>
<tr>
<td class='confluenceTd'> oid </td>
<td class='confluenceTd'> MR OID </td>
</tr>
<tr>
<td class='confluenceTd'> schemaName </td>
<td class='confluenceTd'> N/A </td>
</tr>
<tr>
<td class='confluenceTd'> specification </td>
<td class='confluenceTd'> not modifiable </td>
</tr>
<tr>
<td class='confluenceTd'> bytecode </td>
<td class='confluenceTd'> not modifiable </td>
</tr>
<tr>
<td class='confluenceTd'> fqcn </td>
<td class='confluenceTd'> not modifiable </td>
</tr>
</tbody></table>

<h3><a name="ApacheDSRegistries-Addingacomparator"></a>Adding a comparator</h3>

<p>Register the comparator into the ComparatorRegistry :<br/>
update the ComparatorRegistry.byOid : add &lt;oid, comparator&gt;<br/>
update the ComparatorRegistry.byName : add &lt;oid, comparator&gt;<br/>
associate the Comparator with the schema : &lt;schema, set&lt;SchemaObject&gt;&gt; &#43;= comparator</p>

<h3><a name="ApacheDSRegistries-Modifyingacomparator"></a>Modifying a comparator</h3>

<p>Nothing to do but update the comparator in place (replacing all the fields of the original comparator).</p>

<p>Note that all the fields are not modifiables.</p>

<h3><a name="ApacheDSRegistries-Deletingacomparator"></a>Deleting a comparator</h3>

<p>We can't delete a comparator if it is used by a MatchingRule. This is checked by verifying in<br/>
the usedBy table :</p>

<p>if usedBy.get( comparator.oid ) is not empty, generate an error.</p>

<p>This is a more complex operation, as we may have some MatchingRules pointing on this object.<br/>
We have to :<br/>
remove the oid from the ComparatorRegistry.byOid<br/>
remove the oid from the ComparatorRegistry.byName<br/>
remove the Comparator from the bySchemaNameSchemaObject map : &lt;schema, set&lt;SchemaObject&gt;&gt; &#45;= comparator</p>

<h2><a name="ApacheDSRegistries-DITContentRule"></a>DITContentRule</h2>
<p>Not Yet Implemented</p>

<h2><a name="ApacheDSRegistries-DITStructureRule"></a>DITStructureRule</h2>
<p>Not Yet Implemented</p>

<h2><a name="ApacheDSRegistries-MatchingRule"></a>MatchingRule</h2>

<p>Here are the fields stored in a MatchingRule instance :</p>

<table class='confluenceTable'><tbody>
<tr>
<th class='confluenceTh'> Name </th>
<th class='confluenceTh'> default </th>
</tr>
<tr>
<td class='confluenceTd'> description </td>
<td class='confluenceTd'> N/A </td>
</tr>
<tr>
<td class='confluenceTd'> extensions </td>
<td class='confluenceTd'> N/A </td>
</tr>
<tr>
<td class='confluenceTd'> isEnabled </td>
<td class='confluenceTd'> TRUE </td>
</tr>
<tr>
<td class='confluenceTd'> isObsolete </td>
<td class='confluenceTd'> FALSE </td>
</tr>
<tr>
<td class='confluenceTd'> isReadOnly </td>
<td class='confluenceTd'> FALSE </td>
</tr>
<tr>
<td class='confluenceTd'> names </td>
<td class='confluenceTd'> No names </td>
</tr>
<tr>
<td class='confluenceTd'> objectType </td>
<td class='confluenceTd'> ATTRIBUTE_TYPE </td>
</tr>
<tr>
<td class='confluenceTd'> oid </td>
<td class='confluenceTd'> AT OID </td>
</tr>
<tr>
<td class='confluenceTd'> schemaName </td>
<td class='confluenceTd'> N/A </td>
</tr>
<tr>
<td class='confluenceTd'> ldapComparator </td>
<td class='confluenceTd'> Comparator reference </td>
</tr>
<tr>
<td class='confluenceTd'> ldapSyntax </td>
<td class='confluenceTd'> Syntax reference </td>
</tr>
<tr>
<td class='confluenceTd'> ldapSyntaxOid </td>
<td class='confluenceTd'> The Syntax OID </td>
</tr>
<tr>
<td class='confluenceTd'> normalizer </td>
<td class='confluenceTd'> Normalizer reference </td>
</tr>
</tbody></table>

<h3><a name="ApacheDSRegistries-AddingaMatchingRule"></a>Adding a MatchingRule</h3>

<p>Register the MatchingRule into the MatchingRuleRegistry :<br/>
update the MatchingRuleRegistry.byOid : add &lt;oid, MatchingRule&gt;<br/>
update the MatchingRuleRegistry.byName : add &lt;oid, MatchingRule&gt;<br/>
associate the MatchingRule with the schema : &lt;schema, set&lt;SchemaObject&gt;&gt; &#43;= MatchingRule<br/>
update the Registries.globalOidRegistry : add &lt;oid, MatchingRule&gt;</p>

<p>When all the schema modifications will be done, do the additional updates :</p>

<p>update the MatchingRule.syntax : SyntaxRegistry.lookup( syntaxoid )<br/>
update the MatchingRule.normalizer : NormalizerRegistry.lookup( matchingRule.oid )<br/>
update the MatchingRule.comparator : ComparatorRegistry.lookup( matchingRule.oid )<br/>
update the Registries.using map : &lt;MatchingRule.oid, set&lt;SchemaObject&gt;&gt; += syntax, normalizer, comparator<br/>
update the Registries.usedBy map : <br/>
    &lt;Syntax.oid, set&lt;SchemaObject&gt;&gt; += MatchingRule<br/>
    &lt;Comparator.oid, set&lt;SchemaObject&gt;&gt; += MatchingRule<br/>
    &lt;Normalizer.oid, set&lt;SchemaObject&gt;&gt; += MatchingRule</p>

<h3><a name="ApacheDSRegistries-ModifyingaMatchingRule"></a>Modifying a MatchingRule</h3>

<p>We won't create a new object, but will update the existing one. The OID can't be changed</p>

<p>If we have changed the (N)ormalizer, the (S)yntax or the (C)omparator, when all the schema <br/>
modifications will be done, do the additional updates :<br/>
update the MatchingRule.&lt;C/N/S&gt; : &lt;C/S/N&gt;Registry.lookup( oid )<br/>
update the Registries.using map : &lt;MatchingRule.oid, set&lt;SchemaObject&gt;&gt; -= old &lt;C/S/N&gt;<br/>
update the Registries.using map : &lt;MatchingRule.oid, set&lt;SchemzObject&gt;&gt; += new &lt;C/S/N&gt;<br/>
update the Registries.usedBy map : &lt;old &lt;C/S/N&gt;.oid, set&lt;SchemaObject&gt;&gt; -= MatchingRule<br/>
update the Registries.usedBy map : &lt;new &lt;C/S/N&gt;.oid, set&lt;SchemaObject&gt;&gt; += MatchingRule</p>


<h3><a name="ApacheDSRegistries-DeletingaMatchingRule"></a>Deleting a MatchingRule</h3>

<p>We can't delete a MatchingRule which is used by an AttributeType. This is checked by verifying in<br/>
the usedBy table :</p>

<p>if usedBy.get( MatchingRule.oid ) is not empty, generate an error.</p>

<p>Otherwise, here are the operations we have to conduct :<br/>
remove the MatchingRule.oid from the MatchingRuleRegistry.byOid<br/>
for each MatchingRule's name, <br/>
  remove the MatchingRule.name from the MatchingRuleRegistry.byName<br/>
 + remove the MatchingRule.oid from the MatchingRuleRegistry.byName<br/>
remove the MatchingRule from the bySchemaNameSchemaObject map : &lt;schema, set&lt;SchemaObject&gt;&gt; &#45;= MatchingRule<br/>
remove the Registries.globalOidRegistry : remove &lt;oid, MatchingRule&gt;</p>

<p>When all the schema modifications will be done, do the additional updates :</p>

<p>update the Registries.using map : remove the relation &lt;MatchingRule.oid, set&lt;SchemaObject&gt;&gt;<br/>
update the Registries.usedBy map for each C/S/N referenced in the MatchingRule : <br/>
  &lt;&lt;C/S/N&gt;.oid, set&lt;SchemaObject&gt;&gt; -= MatchingRule</p>


<h2><a name="ApacheDSRegistries-MatchingRuleUse"></a>MatchingRuleUse</h2>
<p>Not Yet Implemented</p>

<h2><a name="ApacheDSRegistries-NameForm"></a>NameForm</h2>
<p>Not Yet Implemented</p>

<h2><a name="ApacheDSRegistries-Normalizer%28specific%29"></a>Normalizer (specific)</h2>
<p>Here are the fields stored in a Normalizer instance :</p>

<table class='confluenceTable'><tbody>
<tr>
<th class='confluenceTh'> Name </th>
<th class='confluenceTh'> default </th>
</tr>
<tr>
<td class='confluenceTd'> description </td>
<td class='confluenceTd'> N/A </td>
</tr>
<tr>
<td class='confluenceTd'> extensions </td>
<td class='confluenceTd'> N/A </td>
</tr>
<tr>
<td class='confluenceTd'> isEnabled </td>
<td class='confluenceTd'> TRUE </td>
</tr>
<tr>
<td class='confluenceTd'> isObsolete </td>
<td class='confluenceTd'> FALSE </td>
</tr>
<tr>
<td class='confluenceTd'> isReadOnly </td>
<td class='confluenceTd'> FALSE </td>
</tr>
<tr>
<td class='confluenceTd'> names </td>
<td class='confluenceTd'> No names </td>
</tr>
<tr>
<td class='confluenceTd'> objectType </td>
<td class='confluenceTd'> NORMALIZER </td>
</tr>
<tr>
<td class='confluenceTd'> oid </td>
<td class='confluenceTd'> MR OID </td>
</tr>
<tr>
<td class='confluenceTd'> schemaName </td>
<td class='confluenceTd'> N/A </td>
</tr>
<tr>
<td class='confluenceTd'> specification </td>
<td class='confluenceTd'> not modifiable </td>
</tr>
<tr>
<td class='confluenceTd'> bytecode </td>
<td class='confluenceTd'> not modifiable </td>
</tr>
<tr>
<td class='confluenceTd'> fqcn </td>
<td class='confluenceTd'> not modifiable </td>
<td class='confluenceTd'> &#42; </td>
</tr>
</tbody></table>

<h3><a name="ApacheDSRegistries-AddingaNormalizer"></a>Adding a Normalizer</h3>

<p>Register the Normalizer into the NormalizerRegistry :<br/>
update the NormalizerRegistry.byOid : add &lt;oid, Normalizer&gt;<br/>
update the NormalizerRegistry.byName : add &lt;oid, Normalizer&gt;<br/>
associate the Normalizer with the schema : &lt;schema, set&lt;SchemaObject&gt;&gt; &#43;= Normalizer</p>

<h3><a name="ApacheDSRegistries-ModifyingaNormalizer"></a>Modifying a Normalizer</h3>

<p>Nothing to do but update the Normalizer in place (replacing all the fields of the original Normalizer).</p>

<p>Note that all the fields are not modifiables.</p>

<h3><a name="ApacheDSRegistries-DeletingaNormalizer"></a>Deleting a Normalizer</h3>

<p>We can't delete a Normalizer if it is used by a MatchingRule. This is checked by verifying in<br/>
the usedBy table :</p>

<p>if usedBy.get( Normalizer.oid ) is not empty, generate an error.</p>

<p>This is a more complex operation, as we may have some MatchingRules pointing on this object.<br/>
We have to :<br/>
remove the oid from the NormalizerRegistry.byOid<br/>
remove the oid from the NormalizerRegistry.byName<br/>
remove the Normalizer from the bySchemaNameSchemaObject map : &lt;schema, set&lt;SchemaObject&gt;&gt; &#45;= Normalizer</p>


<h2><a name="ApacheDSRegistries-ObjectClass"></a>ObjectClass</h2>
<p>TODO</p>

<h2><a name="ApacheDSRegistries-Syntax"></a>Syntax</h2>

<p>Here are the fields stored in a Syntax instance :</p>

<table class='confluenceTable'><tbody>
<tr>
<th class='confluenceTh'> Name </th>
<th class='confluenceTh'> default </th>
</tr>
<tr>
<td class='confluenceTd'> description </td>
<td class='confluenceTd'> N/A </td>
</tr>
<tr>
<td class='confluenceTd'> extensions </td>
<td class='confluenceTd'> N/A </td>
</tr>
<tr>
<td class='confluenceTd'> isEnabled </td>
<td class='confluenceTd'> TRUE </td>
</tr>
<tr>
<td class='confluenceTd'> isObsolete </td>
<td class='confluenceTd'> FALSE </td>
</tr>
<tr>
<td class='confluenceTd'> isReadOnly </td>
<td class='confluenceTd'> FALSE </td>
</tr>
<tr>
<td class='confluenceTd'> names </td>
<td class='confluenceTd'> No names </td>
</tr>
<tr>
<td class='confluenceTd'> objectType </td>
<td class='confluenceTd'> ATTRIBUTE_TYPE </td>
</tr>
<tr>
<td class='confluenceTd'> oid </td>
<td class='confluenceTd'> AT OID </td>
</tr>
<tr>
<td class='confluenceTd'> schemaName </td>
<td class='confluenceTd'> N/A </td>
</tr>
<tr>
<td class='confluenceTd'> isHumanReadable </td>
<td class='confluenceTd'> FALSE </td>
</tr>
<tr>
<td class='confluenceTd'> syntaxChecker </td>
<td class='confluenceTd'> SC reference </td>
</tr>
</tbody></table>

<h3><a name="ApacheDSRegistries-AddingaSyntax"></a>Adding a Syntax</h3>

<p>Register the Syntax into the SyntaxRegistry :<br/>
update the SyntaxRegistry.byOid : add &lt;oid, Syntax&gt;<br/>
update the SyntaxRegistry.byName : add &lt;oid, Syntax&gt;<br/>
associate the Syntax with the schema : &lt;schema, set&lt;SchemaObject&gt;&gt; &#43;= Syntax<br/>
update the Registries.globalOidRegistry : add &lt;oid, Syntax&gt;</p>

<p>When all the schema modifications will be done, do the additional updates :</p>

<p>update the Syntax.syntaxChecker : SyntaxCheckerRegistry.lookup( oid )<br/>
update the Registries.using map : &lt;Syntax.oid, set&lt;SchemaObject&gt;&gt; += SyntaxChecker<br/>
update the Registries.usedBy map : &lt;SyntaxChecker.oid, set&lt;SchemaObject&gt;&gt; += Syntax</p>

<h3><a name="ApacheDSRegistries-ModifyingaSyntax"></a>Modifying a Syntax</h3>

<p>We won't create a new object, but will update the existing one. The OID can't be changed</p>

<p>If we have changed the SyntaxChecker, when all the schema modifications will be done, do the<br/>
additional updates :<br/>
update the Syntax.syntaxChecker : SyntaxCheckerRegistry.lookup( oid )<br/>
update the Registries.using map : &lt;Syntax.oid, set&lt;SchemaObject&gt;&gt; -= old SyntaxChecker<br/>
update the Registries.using map : &lt;Syntax.oid, set&lt;SchemaObject&gt;&gt; += new SyntaxChecker<br/>
update the Registries.usedBy map : &lt;old SyntaxChecker.oid, set&lt;SchemaObject&gt;&gt; -= Syntax<br/>
update the Registries.usedBy map : &lt;new SyntaxChecker.oid, set&lt;SchemaObject&gt;&gt; += Syntax</p>


<h3><a name="ApacheDSRegistries-DeletingaSyntax"></a>Deleting a Syntax</h3>

<p>We can't delete a Syntax which is used by either a MatchingRule or an AttributeType. This is checked by verifying in<br/>
the usedBy table :</p>

<p>if usedBy.get( Syntax.oid ) is not empty, generate an error.</p>

<p>Otherwise, here are the operations we have to conduct :<br/>
remove the Syntax.oid from the SyntaxRegistry.byOid<br/>
for each Syntax' name, <br/>
  remove the Syntax.name from the SyntaxRegistry.byName<br/>
 + remove the Syntax.oid from the SyntaxRegistry.byName<br/>
remove the Syntax from the bySchemaNameSchemaObject map : &lt;schema, set&lt;SchemaObject&gt;&gt; &#45;= Syntax<br/>
remove the Registries.globalOidRegistry : remove &lt;oid, Syntax&gt;</p>

<p>When all the schema modifications will be done, do the additional updates :</p>

<p>update the Registries.using map : remove the relation &lt;Syntax.oid, set&lt;SchemaObject&gt;&gt;<br/>
update the Registries.usedBy map : &lt;SyntaxChecker.oid, set&lt;SchemaObject&gt;&gt; -= Syntax</p>


<h2><a name="ApacheDSRegistries-SyntaxChecker%28specific%29"></a>SyntaxChecker (specific)</h2>
<p>Here are the fields stored in a SyntaxChecker instance :</p>

<table class='confluenceTable'><tbody>
<tr>
<th class='confluenceTh'> Name </th>
<th class='confluenceTh'> default </th>
</tr>
<tr>
<td class='confluenceTd'> description </td>
<td class='confluenceTd'> N/A </td>
</tr>
<tr>
<td class='confluenceTd'> extensions </td>
<td class='confluenceTd'> N/A </td>
</tr>
<tr>
<td class='confluenceTd'> isEnabled </td>
<td class='confluenceTd'> TRUE </td>
</tr>
<tr>
<td class='confluenceTd'> isObsolete </td>
<td class='confluenceTd'> FALSE </td>
</tr>
<tr>
<td class='confluenceTd'> isReadOnly </td>
<td class='confluenceTd'> FALSE </td>
</tr>
<tr>
<td class='confluenceTd'> names </td>
<td class='confluenceTd'> No names </td>
</tr>
<tr>
<td class='confluenceTd'> objectType </td>
<td class='confluenceTd'> SYNTAX_CHECKER </td>
</tr>
<tr>
<td class='confluenceTd'> oid </td>
<td class='confluenceTd'> SYNTAX OID </td>
</tr>
<tr>
<td class='confluenceTd'> schemaName </td>
<td class='confluenceTd'> N/A </td>
</tr>
<tr>
<td class='confluenceTd'> specification </td>
<td class='confluenceTd'> not modifiable </td>
</tr>
<tr>
<td class='confluenceTd'> bytecode </td>
<td class='confluenceTd'> not modifiable </td>
</tr>
<tr>
<td class='confluenceTd'> fqcn </td>
<td class='confluenceTd'> not modifiable </td>
<td class='confluenceTd'> &#42; </td>
</tr>
</tbody></table>

<h3><a name="ApacheDSRegistries-AddingaSyntaxChecker"></a>Adding a SyntaxChecker</h3>

<p>Register the SyntaxChecker into the SyntaxCheckerRegistry :<br/>
update the SyntaxCheckerRegistry.byOid : add &lt;oid, SyntaxChecker&gt;<br/>
update the SyntaxCheckerRegistry.byName : add &lt;oid, SyntaxChecker&gt;<br/>
associate the SyntaxChecker with the schema : &lt;schema, set&lt;SchemaObject&gt;&gt; &#43;= SyntaxChecker</p>

<h3><a name="ApacheDSRegistries-ModifyingaSyntaxChecker"></a>Modifying a SyntaxChecker</h3>

<p>Nothing to do but update the SyntaxChecker in place (replacing all the fields of the original SyntaxChecker).</p>

<p>Note that all the fields are not modifiables.</p>

<h3><a name="ApacheDSRegistries-DeletingaSyntaxChecker"></a>Deleting a SyntaxChecker</h3>

<p>We can't delete a SyntaxChecker if it is used by a Syntax. This is checked by verifying in<br/>
the usedBy table :</p>

<p>if usedBy.get( SyntaxChecker.oid ) is not empty, generate an error.</p>

<p>This is a more complex operation, as we may have some Syntax pointing on this object.<br/>
We have to :<br/>
remove the oid from the SyntaxCheckerRegistry.byOid<br/>
remove the oid from the SyntaxCheckerRegistry.byName<br/>
remove the SyntaxChecker from the bySchemaNameSchemaObject map : &lt;schema, set&lt;SchemaObject&gt;&gt; &#45;= SyntaxChecker</p>


<h2><a name="ApacheDSRegistries-SyntaxCheckerslist"></a>SyntaxCheckers list</h2>

<p>&nbsp; We can see that we may have many syntax checkers. The list are given in <a href="http://www.rfc-archive.org/getrfc.php?rfc=2252" rel="nofollow">RFC 2252</a>, <a href="http://www.rfc-archive.org/getrfc.php?rfc=4517" rel="nofollow">RFC 4517</a> and <a href="http://www.rfc-archive.org/getrfc.php?rfc=4523" rel="nofollow">RFC 4523</a>:</p>
<table class='confluenceTable'><tbody>
<tr>
<th class='confluenceTh'> RFC 2252/22566 </th>
<th class='confluenceTh'> RFC 4517/4523 </th>
<th class='confluenceTh'> Syntax Checker </th>
<th class='confluenceTh'> OID </th>
<th class='confluenceTh'> H/R </th>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> Attribute Type Description </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.3 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> (removed) </td>
<td class='confluenceTd'> Binary </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.5 </td>
<td class='confluenceTd'> N </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> Bit String </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.6 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> Boolean </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.7 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> (RFC 4523) </td>
<td class='confluenceTd'> Certificate </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.8 </td>
<td class='confluenceTd'> N </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> (RFC 4523) </td>
<td class='confluenceTd'> Certificate List </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.9 </td>
<td class='confluenceTd'> N </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> (RFC 4523) </td>
<td class='confluenceTd'> Certificate Pair </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.10 </td>
<td class='confluenceTd'> N </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> Country String </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.11 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> Delivery Method </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.14 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> Directory String </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.15 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> DIT Content Rule Description </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.16 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> DIT Structure Rule Description </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.17 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> DN </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.12 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> Enhanced Guide </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.21 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> Facsimile Telephone Number </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.22 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> Fax </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.23 </td>
<td class='confluenceTd'> N </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> Generalized Time </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.24 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> Guide </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.25 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> IA5 String </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.26 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> Integer </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.27 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> JPEG </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.28 </td>
<td class='confluenceTd'> N </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> LDAP Syntax Description </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.54 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> Matching Rule Description </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.30 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> Matching Rule Use Description </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.31 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> (removed) </td>
<td class='confluenceTd'> MHS OR Address </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.33 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> Name and Optional UID </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.34 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> Name Form Description </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.35 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> Numeric String </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.36 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> Object Class Description </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.37 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> Octet String </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.40 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> OID </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.38 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> Other Mailbox </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.39 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> Postal Address </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.41 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> (removed) </td>
<td class='confluenceTd'> Presentation Address </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.43 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> Printable String </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.44 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> &#45; </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> Substring Assertion </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.58 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> (RFC 4523) </td>
<td class='confluenceTd'> Supported Algorithm </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.49 </td>
<td class='confluenceTd'> N </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> Telephone Number </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.50 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> Teletex Terminal Identifier </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.51 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> Telex Number </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.52 </td>
<td class='confluenceTd'> Y </td>
</tr>
<tr>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> X </td>
<td class='confluenceTd'> UTC Time </td>
<td class='confluenceTd'> 1.3.6.1.4.1.1466.115.121.1.53 </td>
<td class='confluenceTd'> Y </td>
</tr>
</tbody></table>

<p>As we can see, each syntax should have a specific class associated with a specific <b>check</b> method used to control that the attribute value is correct. This value will be checked for every entry adsded or modified by a user. Each <b>DN</b> submitted will also be checked against those classes.</p>

<p>To be able to extend the server with new syntaxes, thoses checker classes will be dynamically loaded at startup. We can do that in different ways :</p>
<ul>
	<li>defining those classes into ADS code, and load them statically during the compilation of the server : this will not be dynamic, but anyway, we will follow the specification and the server will be LDAP V3 compliant</li>
	<li>compiling the syntaxChecker classes and injecting the <b>.class</b> into the <b>cn=schema,ou=system</b> partition : This is possible by either injecting a LDIF file where the .class is serialized, or using a description containing the SyntaxChecker</li>
</ul>


<p>TO BE CONTIINUED</p>

<p>.</p>
     </div>
     <div id="commentsSection" class="wiki-content pageSection">
       <div style="float: right;">
            <a href="http://cwiki.apache.org/confluence/users/viewnotifications.action" class="grey">Change Notification Preferences</a>
       </div>

       <a href="http://cwiki.apache.org/confluence/display/DIRxSRVx11/Apache+DS+Registries">View Online</a>
       |
       <a href="http://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=29461&revisedVersion=26&originalVersion=25">View Change</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message