You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by ak...@apache.org on 2004/01/17 21:13:00 UTC
svn commit: rev 6186 - incubator/directory/ldap/trunk/eve/backend/schema/common/api/src/java/org/apache/eve/schema
Author: akarasulu
Date: Sat Jan 17 12:12:59 2004
New Revision: 6186
Added:
incubator/directory/ldap/trunk/eve/backend/schema/common/api/src/java/org/apache/eve/schema/DITStructureRule.java (contents, props changed)
- copied, changed from rev 6184, incubator/directory/ldap/trunk/eve/backend/schema/common/api/src/java/org/apache/eve/schema/StructureRule.java
Removed:
incubator/directory/ldap/trunk/eve/backend/schema/common/api/src/java/org/apache/eve/schema/StructureRule.java
Modified:
incubator/directory/ldap/trunk/eve/backend/schema/common/api/src/java/org/apache/eve/schema/DescriptionUtils.java
incubator/directory/ldap/trunk/eve/backend/schema/common/api/src/java/org/apache/eve/schema/MatchingRuleUse.java
Log:
Added to the MatchingRuleUse interface and desc generation.
Copied: incubator/directory/ldap/trunk/eve/backend/schema/common/api/src/java/org/apache/eve/schema/DITStructureRule.java (from rev 6184, incubator/directory/ldap/trunk/eve/backend/schema/common/api/src/java/org/apache/eve/schema/StructureRule.java)
==============================================================================
--- incubator/directory/ldap/trunk/eve/backend/schema/common/api/src/java/org/apache/eve/schema/StructureRule.java (original)
+++ incubator/directory/ldap/trunk/eve/backend/schema/common/api/src/java/org/apache/eve/schema/DITStructureRule.java Sat Jan 17 12:12:59 2004
@@ -100,36 +100,36 @@
* @see <a href=
* "http://www.ietf.org/internet-drafts/draft-ietf-ldapbis-models-09.txt">
* ldapbis [MODELS]</a>
- * @see DescriptionUtils#getDescription(StructureRule)
+ * @see DescriptionUtils#getDescription(DITStructureRule)
* @author <a href="mailto:akarasulu@apache.org">Alex Karasulu</a>
* @author $Author$
* @version $Rev$
*/
-public interface StructureRule
+public interface DITStructureRule
{
/**
- * Gets a description of this StructureRule.
+ * Gets a description of this DITStructureRule.
*
* @return a description
*/
String getDescription() ;
/**
- * Gets a short descriptive name for the StructureRule.
+ * Gets a short descriptive name for the DITStructureRule.
*
* @return a short name.
*/
String getName() ;
/**
- * Gets the oid for this StructureRule.
+ * Gets the oid for this DITStructureRule.
*
* @return the object identifier
*/
String getOid() ;
/**
- * Gets whether or not this StructureRule is obsolete.
+ * Gets whether or not this DITStructureRule is obsolete.
*
* @return true if obsolete, false if not.
*/
@@ -150,5 +150,5 @@
*
* @return the chain of StructureRules
*/
- StructureRule [] getSuperClasses() ;
+ DITStructureRule [] getSuperClasses() ;
}
Modified: incubator/directory/ldap/trunk/eve/backend/schema/common/api/src/java/org/apache/eve/schema/DescriptionUtils.java
==============================================================================
--- incubator/directory/ldap/trunk/eve/backend/schema/common/api/src/java/org/apache/eve/schema/DescriptionUtils.java (original)
+++ incubator/directory/ldap/trunk/eve/backend/schema/common/api/src/java/org/apache/eve/schema/DescriptionUtils.java Sat Jan 17 12:12:59 2004
@@ -51,8 +51,11 @@
/**
- * Utility class used to generate schema object specifications. Descriptions
- * can be generated for the following objects:
+ * Utility class used to generate schema object specifications. Some of the
+ * latest work coming out of the LDAPBIS working body adds optional extensions
+ * to these syntaxes. We have not yet added extension support to these
+ * functions or the schema interfaces in this package. Descriptions can be
+ * generated for the following objects:
* <ul>
* <li><a href="./AttributeType.html">AttributeType</a></li>
* <li><a href="./DITContentRule.html">DITContentRule</a></li>
@@ -60,9 +63,10 @@
* <li><a href="./MatchingRuleUse.html">MatchingRuleUse</a></li>
* <li><a href="./NameForm.html">NameForm</a></li>
* <li><a href="./ObjectClass.html">ObjectClass</a></li>
- * <li><a href="./StructureRule.html">StructureRule</a></li>
+ * <li><a href="./DITStructureRule.html">DITStructureRule</a></li>
* <li><a href="./Syntax.html">Syntax</a></li>
* </ul>
+ * @todo add xml descriptor generation as well as the LDAP Schema descriptors
* @author <a href="mailto:akarasulu@apache.org">Alex Karasulu</a>
* @author $Author$
* @version $Rev$
@@ -172,8 +176,8 @@
/**
- * Generates the DITContentRuleDescription for a DITContentRule as defined by
- * the syntax: 1.3.6.1.4.1.1466.115.121.1.16. Only the right hand side
+ * Generates the DITContentRuleDescription for a DITContentRule as defined
+ * by the syntax: 1.3.6.1.4.1.1466.115.121.1.16. Only the right hand side
* of the description starting at the openning parenthesis is generated:
* that is 'DITContentRuleDescription = ' is not generated.
* <pre>
@@ -192,67 +196,75 @@
* @return the specification according to the DITContentRuleDescription
* syntax
*/
- public static String getDescription( DITContentRule a_crule )
+ public static String getDescription( DITContentRule a_dITContentRule )
{
StringBuffer l_buf = new StringBuffer( "( " ) ;
- l_buf.append( a_crule.getOid() ).append( '\n' ) ;
+ l_buf.append( a_dITContentRule.getOid() ) ;
+ l_buf.append( '\n' ) ;
l_buf.append( "NAME " ) ;
- l_buf.append( a_crule.getName() ).append( '\n' ) ;
+ l_buf.append( a_dITContentRule.getName() ) ;
+ l_buf.append( '\n' ) ;
- if ( a_crule.getDescription() != null )
+ if ( a_dITContentRule.getDescription() != null )
{
l_buf.append( "DESC " ) ;
- l_buf.append( a_crule.getDescription() ).append( '\n' ) ;
+ l_buf.append( a_dITContentRule.getDescription() ) ;
+ l_buf.append( '\n' ) ;
}
- if ( a_crule.isObsolete() )
+ if ( a_dITContentRule.isObsolete() )
{
- l_buf.append( "OBSOLETE" ).append( '\n' ) ;
+ l_buf.append( "OBSOLETE" ) ;
+ l_buf.append( '\n' ) ;
}
// print out all the auxillary object class oids
- ObjectClass [] l_aux = a_crule.getAuxObjectClasses() ;
+ ObjectClass [] l_aux = a_dITContentRule.getAuxObjectClasses() ;
if ( l_aux != null && l_aux.length > 0 )
{
l_buf.append( "AUX\n" ) ;
for ( int ii = 0; ii < l_aux.length; ii++ )
{
l_buf.append( '\t' ) ;
- l_buf.append( l_aux[ii].getOid() ).append( '\n' ) ;
+ l_buf.append( l_aux[ii].getOid() ) ;
+ l_buf.append( '\n' ) ;
}
}
- AttributeType [] l_must = a_crule.getMustNames() ;
+ AttributeType [] l_must = a_dITContentRule.getMustNames() ;
if ( l_must != null && l_must.length > 0 )
{
l_buf.append( "MUST\n" ) ;
for ( int ii = 0; ii < l_must.length; ii++ )
{
l_buf.append( '\t' ) ;
- l_buf.append( l_must[ii].getOid() ).append( '\n' ) ;
+ l_buf.append( l_must[ii].getOid() ) ;
+ l_buf.append( '\n' ) ;
}
}
- AttributeType [] l_may = a_crule.getMayNames() ;
+ AttributeType [] l_may = a_dITContentRule.getMayNames() ;
if ( l_may != null && l_may.length > 0 )
{
l_buf.append( "MAY\n" ) ;
for ( int ii = 0; ii < l_may.length; ii++ )
{
l_buf.append( '\t' ) ;
- l_buf.append( l_may[ii].getOid() ).append( '\n' ) ;
+ l_buf.append( l_may[ii].getOid() ) ;
+ l_buf.append( '\n' ) ;
}
}
- AttributeType [] l_not = a_crule.getNotNames() ;
+ AttributeType [] l_not = a_dITContentRule.getNotNames() ;
if ( l_not != null && l_not.length > 0 )
{
l_buf.append( "NOT\n" ) ;
for ( int ii = 0; ii < l_not.length; ii++ )
{
l_buf.append( '\t' ) ;
- l_buf.append( l_not[ii].getOid() ).append( '\n' ) ;
+ l_buf.append( l_not[ii].getOid() ) ;
+ l_buf.append( '\n' ) ;
}
}
@@ -263,7 +275,9 @@
/**
* Generates the MatchingRuleDescription for a MatchingRule as defined by
- * the syntax: 1.3.6.1.4.1.1466.115.121.1.30.
+ * the syntax: 1.3.6.1.4.1.1466.115.121.1.30. Only the right hand side
+ * of the description starting at the openning parenthesis is generated:
+ * that is 'MatchingRuleDescription = ' is not generated.
* <pre>
* MatchingRuleDescription = "(" whsp
* numericoid whsp ; MatchingRule object identifier
@@ -273,53 +287,118 @@
* "SYNTAX" numericoid
* whsp ")"
* </pre>
- * @param a_mrule the MatchingRule to generate the description for
+ * @param a_matchingEule the MatchingRule to generate the description for
* @return the MatchingRuleDescription string
*/
- public static String getDescription( MatchingRule a_mrule )
+ public static String getDescription( MatchingRule a_matchingRule )
{
StringBuffer l_buf = new StringBuffer( "( " ) ;
- l_buf.append( a_mrule.getOid() ).append( '\n' ) ;
+ l_buf.append( a_matchingRule.getOid() ) ;
+ l_buf.append( '\n' ) ;
l_buf.append( "NAME " ) ;
- l_buf.append( a_mrule.getName() ).append( '\n' ) ;
+ l_buf.append( a_matchingRule.getName() ) ;
+ l_buf.append( '\n' ) ;
- if ( a_mrule.getDescription() != null )
+ if ( a_matchingRule.getDescription() != null )
{
l_buf.append( "DESC " ) ;
- l_buf.append( a_mrule.getDescription() ).append( '\n' ) ;
+ l_buf.append( a_matchingRule.getDescription() ) ;
+ l_buf.append( '\n' ) ;
}
- if ( a_mrule.isObsolete() )
+ if ( a_matchingRule.isObsolete() )
{
- l_buf.append( "OBSOLETE" ).append( '\n' ) ;
+ l_buf.append( "OBSOLETE" ) ;
+ l_buf.append( '\n' ) ;
}
- l_buf.append( "SYNTAX " ).append( a_mrule.getSyntax().getOid() ) ;
+ l_buf.append( "SYNTAX " ) ;
+ l_buf.append( a_matchingRule.getSyntax().getOid() ) ;
l_buf.append( " ) " ) ;
return l_buf.toString() ;
}
/**
- * @todo implement and document me
+ * @todo implement and document me. Only the right hand side
+ * of the description starting at the openning parenthesis is generated:
+ * that is 'MatchingRuleUseDescription = ' is not generated.
+ * <pre>
+ * MatchingRuleUseDescription = LPAREN WSP
+ * numericoid ; object identifier
+ * [ SP "NAME" SP qdescrs ] ; short names (descriptors)
+ * [ SP "DESC" SP qdstring ] ; description
+ * [ SP "OBSOLETE" ] ; not active
+ * SP "APPLIES" SP oids ; attribute types
+ * extensions WSP RPAREN ; extensions
*
- * @param a_mruleUse
+ * where:
+ * [numericoid] is the object identifier of the matching rule
+ * associated with this matching rule use description;
+ * NAME [qdescrs] are short names (descriptors) identifying this
+ * matching rule use;
+ * DESC [qdstring] is a short descriptive string;
+ * OBSOLETE indicates this matching rule use is not active;
+ * APPLIES provides a list of attribute types the matching rule applies
+ * to; and
+ * [extensions] describe extensions.
+ * </pre>
+ * @param a_matchingRuleUse
* @return
*/
- public static String getDescription( MatchingRuleUse a_mruleUse )
+ public static String getDescription( MatchingRuleUse a_matchingRuleUse )
{
StringBuffer l_buf = new StringBuffer( "( " ) ;
+ l_buf.append( a_matchingRuleUse.getMatchingRule().getOid() ) ;
+ l_buf.append( '\n' ) ;
+
+ l_buf.append( "NAME " ) ;
+ l_buf.append( a_matchingRuleUse.getName() ) ;
+ l_buf.append( '\n' ) ;
+
+ if ( a_matchingRuleUse.getDescription() != null )
+ {
+ l_buf.append( "DESC " ) ;
+ l_buf.append( a_matchingRuleUse.getDescription() ) ;
+ l_buf.append( '\n' ) ;
+ }
+
+ if ( a_matchingRuleUse.isObsolete() )
+ {
+ l_buf.append( "OBSOLETE" ) ;
+ l_buf.append( '\n' ) ;
+ }
- throw new UnsupportedOperationException() ;
+ l_buf.append( "APPLIES " ) ;
+ AttributeType[] l_attributeTypes =
+ a_matchingRuleUse.getApplicableAttributes() ;
+ if ( l_attributeTypes.length == 1 )
+ {
+ l_buf.append( l_attributeTypes[0].getOid() ) ;
+ }
+ else // for list of oids we need a parenthesis
+ {
+ l_buf.append( "( " ) ;
+ l_buf.append( l_attributeTypes[0] ) ;
+ for ( int ii = 1; ii < l_attributeTypes.length; ii++ )
+ {
+ l_buf.append( " $ " ) ;
+ l_buf.append( l_attributeTypes[ii] ) ;
+ }
+ l_buf.append( " ) " ) ;
+ }
- //return l_buf.toString() ;
+ l_buf.append( '\n' ) ;
+ return l_buf.toString() ;
}
/**
* Generates the NameFormDescription for a NameForm as defined by the
- * syntax: 1.3.6.1.4.1.1466.115.121.1.35.
+ * syntax: 1.3.6.1.4.1.1466.115.121.1.35. Only the right hand side
+ * of the description starting at the openning parenthesis is generated:
+ * that is 'NameFormDescription = ' is not generated.
* <pre>
* NameFormDescription = "(" whsp
* numericoid whsp ; NameForm identifier
@@ -337,31 +416,37 @@
public static String getDescription( NameForm a_nameForm )
{
StringBuffer l_buf = new StringBuffer( "( " ) ;
- l_buf.append( a_nameForm.getOid() ).append( '\n' ) ;
+ l_buf.append( a_nameForm.getOid() ) ;
+ l_buf.append( '\n' ) ;
l_buf.append( "NAME " ) ;
- l_buf.append( a_nameForm.getName() ).append( '\n' ) ;
+ l_buf.append( a_nameForm.getName() ) ;
+ l_buf.append( '\n' ) ;
if ( a_nameForm.getDescription() != null )
{
l_buf.append( "DESC " ) ;
- l_buf.append( a_nameForm.getDescription() ).append( '\n' ) ;
+ l_buf.append( a_nameForm.getDescription() ) ;
+ l_buf.append( '\n' ) ;
}
if ( a_nameForm.isObsolete() )
{
- l_buf.append( "OBSOLETE" ).append( '\n' ) ;
+ l_buf.append( "OBSOLETE" ) ;
+ l_buf.append( '\n' ) ;
}
l_buf.append( "OC " ) ;
- l_buf.append( a_nameForm.getObjectClass().getOid() ).append( '\n' ) ;
+ l_buf.append( a_nameForm.getObjectClass().getOid() ) ;
+ l_buf.append( '\n' ) ;
l_buf.append( "MUST\n" ) ;
AttributeType[] l_must = a_nameForm.getMustUse() ;
for ( int ii = 0; ii < l_must.length; ii++ )
{
l_buf.append( '\t' ) ;
- l_buf.append( l_must[ii].getOid() ).append( '\n' ) ;
+ l_buf.append( l_must[ii].getOid() ) ;
+ l_buf.append( '\n' ) ;
}
AttributeType[] l_may = a_nameForm.getMaytUse() ;
@@ -371,7 +456,8 @@
for ( int ii = 0; ii < l_must.length; ii++ )
{
l_buf.append( '\t' ) ;
- l_buf.append( l_may[ii].getOid() ).append( '\n' ) ;
+ l_buf.append( l_may[ii].getOid() ) ;
+ l_buf.append( '\n' ) ;
}
}
@@ -382,7 +468,9 @@
/**
* Generates the ObjectClassDescription for an ObjectClass as defined by the
- * syntax: 1.3.6.1.4.1.1466.115.121.1.37.
+ * syntax: 1.3.6.1.4.1.1466.115.121.1.37. Only the right hand side
+ * of the description starting at the openning parenthesis is generated:
+ * that is 'ObjectClassDescription = ' is not generated.
* <pre>
* ObjectClassDescription = "(" whsp
* numericoid whsp ; ObjectClass identifier
@@ -402,20 +490,24 @@
public static String getDescription( ObjectClass a_objectClass )
{
StringBuffer l_buf = new StringBuffer( "( " ) ;
- l_buf.append( a_objectClass.getOid() ).append( '\n' ) ;
+ l_buf.append( a_objectClass.getOid() ) ;
+ l_buf.append( '\n' ) ;
l_buf.append( "NAME " ) ;
- l_buf.append( a_objectClass.getName() ).append( '\n' ) ;
+ l_buf.append( a_objectClass.getName() ) ;
+ l_buf.append( '\n' ) ;
if ( a_objectClass.getDescription() != null )
{
l_buf.append( "DESC " ) ;
- l_buf.append( a_objectClass.getDescription() ).append( '\n' ) ;
+ l_buf.append( a_objectClass.getDescription() ) ;
+ l_buf.append( '\n' ) ;
}
if ( a_objectClass.isObsolete() )
{
- l_buf.append( "OBSOLETE" ).append( '\n' ) ;
+ l_buf.append( "OBSOLETE" ) ;
+ l_buf.append( '\n' ) ;
}
ObjectClass [] l_sups = a_objectClass.getSuperClasses() ;
@@ -425,13 +517,15 @@
for ( int ii = 0; ii < l_sups.length; ii++ )
{
l_buf.append( '\t' ) ;
- l_buf.append( l_sups[ii].getOid() ).append( '\n' ) ;
+ l_buf.append( l_sups[ii].getOid() ) ;
+ l_buf.append( '\n' ) ;
}
}
if ( a_objectClass.getType() != null )
{
- l_buf.append( a_objectClass.getType().getName() ).append( '\n' ) ;
+ l_buf.append( a_objectClass.getType().getName() ) ;
+ l_buf.append( '\n' ) ;
}
AttributeType [] l_must = a_objectClass.getMustList() ;
@@ -441,7 +535,8 @@
for ( int ii = 0; ii < l_must.length; ii++ )
{
l_buf.append( '\t' ) ;
- l_buf.append( l_must[ii].getOid() ).append( '\n' ) ;
+ l_buf.append( l_must[ii].getOid() ) ;
+ l_buf.append( '\n' ) ;
}
}
@@ -452,7 +547,8 @@
for ( int ii = 0; ii < l_may.length; ii++ )
{
l_buf.append( '\t' ) ;
- l_buf.append( l_may[ii].getOid() ).append( '\n' ) ;
+ l_buf.append( l_may[ii].getOid() ) ;
+ l_buf.append( '\n' ) ;
}
}
@@ -462,8 +558,10 @@
/**
- * Generates the DITStructureRuleDescription for a StructureRule as defined
- * by the syntax: 1.3.6.1.4.1.1466.115.121.1.17.
+ * Generates the DITStructureRuleDescription for a DITStructureRule as
+ * defined by the syntax: 1.3.6.1.4.1.1466.115.121.1.17. Only the right
+ * hand side of the description starting at the openning parenthesis is
+ * generated: that is 'DITStructureRuleDescription = ' is not generated.
* <pre>
* DITStructureRuleDescription = "(" whsp
* ruleidentifier whsp ; DITStructureRule identifier
@@ -474,39 +572,46 @@
* [ "SUP" ruleidentifiers whsp ] ; superior DITStructureRules
* ")"
* </pre>
- * @param a_srule the StructureRule to generate a description for
+ * @param a_dITStructureRule the DITStructureRule to generate the
+ * description for
* @return the description in the DITStructureRuleDescription syntax
*/
- public static String getDescription( StructureRule a_srule )
+ public static String getDescription( DITStructureRule a_dITStructureRule )
{
StringBuffer l_buf = new StringBuffer( "( " ) ;
- l_buf.append( a_srule.getOid() ).append( '\n' ) ;
+ l_buf.append( a_dITStructureRule.getOid() ) ;
+ l_buf.append( '\n' ) ;
l_buf.append( "NAME " ) ;
- l_buf.append( a_srule.getName() ).append( '\n' ) ;
+ l_buf.append( a_dITStructureRule.getName() ) ;
+ l_buf.append( '\n' ) ;
- if ( a_srule.getDescription() != null )
+ if ( a_dITStructureRule.getDescription() != null )
{
l_buf.append( "DESC " ) ;
- l_buf.append( a_srule.getDescription() ).append( '\n' ) ;
+ l_buf.append( a_dITStructureRule.getDescription() ) ;
+ l_buf.append( '\n' ) ;
}
- if ( a_srule.isObsolete() )
+ if ( a_dITStructureRule.isObsolete() )
{
- l_buf.append( "OBSOLETE" ).append( '\n' ) ;
+ l_buf.append( "OBSOLETE" ) ;
+ l_buf.append( '\n' ) ;
}
l_buf.append( "FORM " ) ;
- l_buf.append( a_srule.getNameForm().getOid() ).append( '\n' ) ;
+ l_buf.append( a_dITStructureRule.getNameForm().getOid() ) ;
+ l_buf.append( '\n' ) ;
- StructureRule [] l_sups = a_srule.getSuperClasses() ;
+ DITStructureRule [] l_sups = a_dITStructureRule.getSuperClasses() ;
if ( l_sups != null && l_sups.length > 0 )
{
l_buf.append( "SUP\n" ) ;
for ( int ii = 0; ii < l_sups.length; ii++ )
{
l_buf.append( '\t' ) ;
- l_buf.append( l_sups[ii].getOid() ).append( '\n' ) ;
+ l_buf.append( l_sups[ii].getOid() ) ;
+ l_buf.append( '\n' ) ;
}
}
@@ -517,7 +622,9 @@
/**
* Generates the SyntaxDescription for a Syntax as defined by the syntax:
- * 1.3.6.1.4.1.1466.115.121.1.54.
+ * 1.3.6.1.4.1.1466.115.121.1.54. Only the right hand side
+ * of the description starting at the openning parenthesis is generated:
+ * that is 'SyntaxDescription = ' is not generated.
* <pre>
* SyntaxDescription = "(" whsp
* numericoid whsp
@@ -530,12 +637,14 @@
public static String getDescription( Syntax a_syntax )
{
StringBuffer l_buf = new StringBuffer( "( " ) ;
- l_buf.append( a_syntax.getOid() ).append( '\n' ) ;
+ l_buf.append( a_syntax.getOid() ) ;
+ l_buf.append( '\n' ) ;
if ( a_syntax.getDescription() != null )
{
l_buf.append( "DESC " ) ;
- l_buf.append( a_syntax.getDescription() ).append( '\n' ) ;
+ l_buf.append( a_syntax.getDescription() ) ;
+ l_buf.append( '\n' ) ;
}
l_buf.append( " )" ) ;
Modified: incubator/directory/ldap/trunk/eve/backend/schema/common/api/src/java/org/apache/eve/schema/MatchingRuleUse.java
==============================================================================
--- incubator/directory/ldap/trunk/eve/backend/schema/common/api/src/java/org/apache/eve/schema/MatchingRuleUse.java (original)
+++ incubator/directory/ldap/trunk/eve/backend/schema/common/api/src/java/org/apache/eve/schema/MatchingRuleUse.java Sat Jan 17 12:12:59 2004
@@ -109,6 +109,27 @@
public interface MatchingRuleUse
{
/**
+ * Gets a long description for the MatchingRuleUse.
+ *
+ * @return a long description
+ */
+ String getDescription() ;
+
+ /**
+ * Gets a short descriptive name for the MatchingRuleUse.
+ *
+ * @return a short name
+ */
+ String getName() ;
+
+ /**
+ * Gets whether or not this MatchingRuleUse has been obsoleted for another.
+ *
+ * @return true if it is obsolete false otherwise
+ */
+ boolean isObsolete() ;
+
+ /**
* Gets the matchingRule this MatchingRuleUse definition applies to.
*
* @return the matchingRule