0N/A/*
2362N/A * Copyright (c) 1999, 2004, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage com.sun.jndi.ldap;
0N/A
0N/Aimport javax.naming.*;
0N/Aimport javax.naming.directory.*;
0N/Aimport java.util.Hashtable;
0N/Aimport java.util.Vector;
0N/A
0N/A/**
0N/A * Netscape's 3.1 servers have some schema bugs:
0N/A * - It puts quotes around OIDs (such as those for SUP, SYNTAX).
0N/A * - When you try to write out the MUST/MAY list (such as "MUST cn"),
0N/A * it wants ("MUST (cn)") instead
0N/A */
0N/A
0N/Afinal class LdapSchemaParser {
0N/A
0N/A // do debugging
0N/A private static final boolean debug = false;
0N/A
0N/A
0N/A // names of attribute IDs in the LDAP schema entry
0N/A static final String OBJECTCLASSDESC_ATTR_ID = "objectClasses";
0N/A static final String ATTRIBUTEDESC_ATTR_ID = "attributeTypes";
0N/A static final String SYNTAXDESC_ATTR_ID = "ldapSyntaxes";
0N/A static final String MATCHRULEDESC_ATTR_ID = "matchingRules";
0N/A
0N/A // information for creating internal nodes in JNDI schema tree
0N/A static final String OBJECTCLASS_DEFINITION_NAME =
0N/A "ClassDefinition";
0N/A private static final String[] CLASS_DEF_ATTRS = {
0N/A "objectclass", "ClassDefinition"};
0N/A static final String ATTRIBUTE_DEFINITION_NAME =
0N/A "AttributeDefinition";
0N/A private static final String[] ATTR_DEF_ATTRS = {
0N/A "objectclass", "AttributeDefinition" };
0N/A static final String SYNTAX_DEFINITION_NAME =
0N/A "SyntaxDefinition";
0N/A private static final String[] SYNTAX_DEF_ATTRS = {
0N/A "objectclass", "SyntaxDefinition" };
0N/A static final String MATCHRULE_DEFINITION_NAME =
0N/A "MatchingRule";
0N/A private static final String[] MATCHRULE_DEF_ATTRS = {
0N/A "objectclass", "MatchingRule" };
0N/A
0N/A // special tokens used in LDAP schema descriptions
0N/A private static final char SINGLE_QUOTE = '\'';
0N/A private static final char WHSP = ' ';
0N/A private static final char OID_LIST_BEGIN = '(';
0N/A private static final char OID_LIST_END = ')';
0N/A private static final char OID_SEPARATOR = '$';
0N/A
0N/A // common IDs
0N/A private static final String NUMERICOID_ID = "NUMERICOID";
0N/A private static final String NAME_ID = "NAME";
0N/A private static final String DESC_ID = "DESC";
0N/A private static final String OBSOLETE_ID = "OBSOLETE";
0N/A private static final String SUP_ID = "SUP";
0N/A private static final String PRIVATE_ID = "X-";
0N/A
0N/A // Object Class specific IDs
0N/A private static final String ABSTRACT_ID = "ABSTRACT";
0N/A private static final String STRUCTURAL_ID = "STRUCTURAL";
0N/A private static final String AUXILARY_ID = "AUXILIARY";
0N/A private static final String MUST_ID = "MUST";
0N/A private static final String MAY_ID = "MAY";
0N/A
0N/A // Attribute Type specific IDs
0N/A private static final String EQUALITY_ID = "EQUALITY";
0N/A private static final String ORDERING_ID = "ORDERING";
0N/A private static final String SUBSTR_ID = "SUBSTR";
0N/A private static final String SYNTAX_ID = "SYNTAX";
0N/A private static final String SINGLE_VAL_ID = "SINGLE-VALUE";
0N/A private static final String COLLECTIVE_ID = "COLLECTIVE";
0N/A private static final String NO_USER_MOD_ID = "NO-USER-MODIFICATION";
0N/A private static final String USAGE_ID = "USAGE";
0N/A
0N/A // The string value we give to boolean variables
0N/A private static final String SCHEMA_TRUE_VALUE = "true";
0N/A
0N/A // To get around writing schemas that crash Netscape server
0N/A private boolean netscapeBug;
0N/A
0N/A LdapSchemaParser(boolean netscapeBug) {
0N/A this.netscapeBug = netscapeBug;
0N/A }
0N/A
0N/A final static void LDAP2JNDISchema(Attributes schemaAttrs,
0N/A LdapSchemaCtx schemaRoot) throws NamingException {
0N/A Attribute objectClassesAttr = null;
0N/A Attribute attributeDefAttr = null;
0N/A Attribute syntaxDefAttr = null;
0N/A Attribute matchRuleDefAttr = null;
0N/A
0N/A objectClassesAttr = schemaAttrs.get(OBJECTCLASSDESC_ATTR_ID);
0N/A if(objectClassesAttr != null) {
0N/A objectDescs2ClassDefs(objectClassesAttr,schemaRoot);
0N/A }
0N/A
0N/A attributeDefAttr = schemaAttrs.get(ATTRIBUTEDESC_ATTR_ID);
0N/A if(attributeDefAttr != null) {
0N/A attrDescs2AttrDefs(attributeDefAttr, schemaRoot);
0N/A }
0N/A
0N/A syntaxDefAttr = schemaAttrs.get(SYNTAXDESC_ATTR_ID);
0N/A if(syntaxDefAttr != null) {
0N/A syntaxDescs2SyntaxDefs(syntaxDefAttr, schemaRoot);
0N/A }
0N/A
0N/A matchRuleDefAttr = schemaAttrs.get(MATCHRULEDESC_ATTR_ID);
0N/A if(matchRuleDefAttr != null) {
0N/A matchRuleDescs2MatchRuleDefs(matchRuleDefAttr, schemaRoot);
0N/A }
0N/A }
0N/A
0N/A final private static DirContext objectDescs2ClassDefs(Attribute objDescsAttr,
0N/A LdapSchemaCtx schemaRoot)
0N/A throws NamingException {
0N/A
0N/A NamingEnumeration objDescs;
0N/A Attributes objDef;
0N/A LdapSchemaCtx classDefTree;
0N/A
0N/A // create the class def subtree
0N/A Attributes attrs = new BasicAttributes(LdapClient.caseIgnore);
0N/A attrs.put(CLASS_DEF_ATTRS[0], CLASS_DEF_ATTRS[1]);
0N/A classDefTree = schemaRoot.setup(LdapSchemaCtx.OBJECTCLASS_ROOT,
0N/A OBJECTCLASS_DEFINITION_NAME, attrs);
0N/A
0N/A objDescs = objDescsAttr.getAll();
0N/A String currentName;
0N/A while(objDescs.hasMore()) {
0N/A String objDesc = (String)objDescs.next();
0N/A try {
0N/A Object[] def = desc2Def(objDesc);
0N/A currentName = (String) def[0];
0N/A objDef = (Attributes) def[1];
0N/A classDefTree.setup(LdapSchemaCtx.OBJECTCLASS,
0N/A currentName, objDef);
0N/A } catch (NamingException ne) {
0N/A // error occurred while parsing, ignore current entry
0N/A }
0N/A }
0N/A
0N/A return classDefTree;
0N/A }
0N/A
0N/A final private static DirContext attrDescs2AttrDefs(Attribute attributeDescAttr,
0N/A LdapSchemaCtx schemaRoot)
0N/A throws NamingException {
0N/A
0N/A NamingEnumeration attrDescs;
0N/A Attributes attrDef;
0N/A LdapSchemaCtx attrDefTree;
0N/A
0N/A // create the AttributeDef subtree
0N/A Attributes attrs = new BasicAttributes(LdapClient.caseIgnore);
0N/A attrs.put(ATTR_DEF_ATTRS[0], ATTR_DEF_ATTRS[1]);
0N/A attrDefTree = schemaRoot.setup(LdapSchemaCtx.ATTRIBUTE_ROOT,
0N/A ATTRIBUTE_DEFINITION_NAME, attrs);
0N/A
0N/A attrDescs = attributeDescAttr.getAll();
0N/A String currentName;
0N/A while(attrDescs.hasMore()) {
0N/A String attrDesc = (String)attrDescs.next();
0N/A try {
0N/A Object[] def = desc2Def(attrDesc);
0N/A currentName = (String) def[0];
0N/A attrDef = (Attributes) def[1];
0N/A attrDefTree.setup(LdapSchemaCtx.ATTRIBUTE,
0N/A currentName, attrDef);
0N/A } catch (NamingException ne) {
0N/A // error occurred while parsing, ignore current entry
0N/A }
0N/A }
0N/A
0N/A return attrDefTree;
0N/A }
0N/A
0N/A final private static DirContext syntaxDescs2SyntaxDefs(
0N/A Attribute syntaxDescAttr,
0N/A LdapSchemaCtx schemaRoot)
0N/A throws NamingException {
0N/A
0N/A NamingEnumeration syntaxDescs;
0N/A Attributes syntaxDef;
0N/A LdapSchemaCtx syntaxDefTree;
0N/A
0N/A // create the SyntaxDef subtree
0N/A Attributes attrs = new BasicAttributes(LdapClient.caseIgnore);
0N/A attrs.put(SYNTAX_DEF_ATTRS[0], SYNTAX_DEF_ATTRS[1]);
0N/A syntaxDefTree = schemaRoot.setup(LdapSchemaCtx.SYNTAX_ROOT,
0N/A SYNTAX_DEFINITION_NAME, attrs);
0N/A
0N/A syntaxDescs = syntaxDescAttr.getAll();
0N/A String currentName;
0N/A while(syntaxDescs.hasMore()) {
0N/A String syntaxDesc = (String)syntaxDescs.next();
0N/A try {
0N/A Object[] def = desc2Def(syntaxDesc);
0N/A currentName = (String) def[0];
0N/A syntaxDef = (Attributes) def[1];
0N/A syntaxDefTree.setup(LdapSchemaCtx.SYNTAX,
0N/A currentName, syntaxDef);
0N/A } catch (NamingException ne) {
0N/A // error occurred while parsing, ignore current entry
0N/A }
0N/A }
0N/A
0N/A return syntaxDefTree;
0N/A }
0N/A
0N/A final private static DirContext matchRuleDescs2MatchRuleDefs(
0N/A Attribute matchRuleDescAttr,
0N/A LdapSchemaCtx schemaRoot)
0N/A throws NamingException {
0N/A
0N/A NamingEnumeration matchRuleDescs;
0N/A Attributes matchRuleDef;
0N/A LdapSchemaCtx matchRuleDefTree;
0N/A
0N/A // create the MatchRuleDef subtree
0N/A Attributes attrs = new BasicAttributes(LdapClient.caseIgnore);
0N/A attrs.put(MATCHRULE_DEF_ATTRS[0], MATCHRULE_DEF_ATTRS[1]);
0N/A matchRuleDefTree = schemaRoot.setup(LdapSchemaCtx.MATCHRULE_ROOT,
0N/A MATCHRULE_DEFINITION_NAME, attrs);
0N/A
0N/A matchRuleDescs = matchRuleDescAttr.getAll();
0N/A String currentName;
0N/A while(matchRuleDescs.hasMore()) {
0N/A String matchRuleDesc = (String)matchRuleDescs.next();
0N/A try {
0N/A Object[] def = desc2Def(matchRuleDesc);
0N/A currentName = (String) def[0];
0N/A matchRuleDef = (Attributes) def[1];
0N/A matchRuleDefTree.setup(LdapSchemaCtx.MATCHRULE,
0N/A currentName, matchRuleDef);
0N/A } catch (NamingException ne) {
0N/A // error occurred while parsing, ignore current entry
0N/A }
0N/A }
0N/A
0N/A return matchRuleDefTree;
0N/A }
0N/A
0N/A final private static Object[] desc2Def(String desc)
0N/A throws NamingException {
0N/A //System.err.println(desc);
0N/A
0N/A Attributes attrs = new BasicAttributes(LdapClient.caseIgnore);
0N/A Attribute attr = null;
0N/A int[] pos = new int[]{1}; // tolerate missing leading space
0N/A boolean moreTags = true;
0N/A
0N/A // Always begins with <whsp numericoid whsp>
0N/A attr = readNumericOID(desc, pos);
0N/A String currentName = (String) attr.get(0); // name is OID by default
0N/A attrs.put(attr);
0N/A
0N/A skipWhitespace(desc, pos);
0N/A
0N/A while (moreTags) {
0N/A attr = readNextTag(desc, pos);
0N/A attrs.put(attr);
0N/A
0N/A if (attr.getID().equals(NAME_ID)) {
0N/A currentName = (String) attr.get(0); // use NAME attribute as name
0N/A }
0N/A
0N/A skipWhitespace(desc, pos);
0N/A
0N/A if( pos[0] >= desc.length() -1 ) {
0N/A moreTags = false;
0N/A }
0N/A }
0N/A
0N/A return new Object[] {currentName, attrs};
0N/A }
0N/A
0N/A // returns the index of the first whitespace char of a linear whitspace
0N/A // sequince ending at the given position.
0N/A final private static int findTrailingWhitespace(String string, int pos) {
0N/A for(int i = pos; i > 0; i--) {
0N/A if(string.charAt(i) != WHSP) {
0N/A return i + 1;
0N/A }
0N/A }
0N/A return 0;
0N/A }
0N/A
0N/A final private static void skipWhitespace(String string, int[] pos) {
0N/A for(int i=pos[0]; i < string.length(); i++) {
0N/A if(string.charAt(i) != WHSP) {
0N/A pos[0] = i;
0N/A if (debug) {
0N/A System.err.println("skipWhitespace: skipping to "+i);
0N/A }
0N/A return;
0N/A }
0N/A }
0N/A }
0N/A
0N/A final private static Attribute readNumericOID(String string, int[] pos)
0N/A throws NamingException {
0N/A
0N/A if (debug) {
0N/A System.err.println("readNumericoid: pos="+pos[0]);
0N/A }
0N/A
0N/A int begin, end;
0N/A String value = null;
0N/A
0N/A skipWhitespace(string, pos);
0N/A
0N/A begin = pos[0];
0N/A end = string.indexOf(WHSP, begin);
0N/A
0N/A if (end == -1 || end - begin < 1) {
0N/A throw new InvalidAttributeValueException("no numericoid found: "
0N/A + string);
0N/A }
0N/A
0N/A value = string.substring(begin, end);
0N/A
0N/A pos[0] += value.length();
0N/A
0N/A return new BasicAttribute(NUMERICOID_ID, value);
0N/A }
0N/A
0N/A final private static Attribute readNextTag(String string, int[] pos)
0N/A throws NamingException {
0N/A
0N/A Attribute attr = null;
0N/A String tagName = null;
0N/A String[] values = null;
0N/A
0N/A skipWhitespace(string, pos);
0N/A
0N/A if (debug) {
0N/A System.err.println("readNextTag: pos="+pos[0]);
0N/A }
0N/A
0N/A // get the name and values of the attribute to return
0N/A int trailingSpace = string.indexOf( WHSP, pos[0] );
0N/A
0N/A // tolerate a schema that omits the trailing space
0N/A if (trailingSpace < 0) {
0N/A tagName = string.substring( pos[0], string.length() - 1);
0N/A } else {
0N/A tagName = string.substring( pos[0], trailingSpace );
0N/A }
0N/A
0N/A values = readTag(tagName, string, pos);
0N/A
0N/A // make sure at least one value was returned
0N/A if(values.length < 0) {
0N/A throw new InvalidAttributeValueException("no values for " +
0N/A "attribute \"" +
0N/A tagName + "\"");
0N/A }
0N/A
0N/A // create the attribute, using the first value
0N/A attr = new BasicAttribute(tagName, values[0]);
0N/A
0N/A // add other values if there are any
0N/A for(int i = 1; i < values.length; i++) {
0N/A attr.add(values[i]);
0N/A }
0N/A
0N/A return attr;
0N/A }
0N/A
0N/A final private static String[] readTag(String tag, String string, int[] pos)
0N/A throws NamingException {
0N/A
0N/A if (debug) {
0N/A System.err.println("ReadTag: " + tag + " pos="+pos[0]);
0N/A }
0N/A
0N/A // move parser past tag name
0N/A pos[0] += tag.length();
0N/A skipWhitespace(string, pos);
0N/A
0N/A if (tag.equals(NAME_ID)) {
0N/A return readQDescrs(string, pos); // names[0] is NAME
0N/A }
0N/A
0N/A if(tag.equals(DESC_ID)) {
0N/A return readQDString(string, pos);
0N/A }
0N/A
0N/A if (
0N/A tag.equals(EQUALITY_ID) ||
0N/A tag.equals(ORDERING_ID) ||
0N/A tag.equals(SUBSTR_ID) ||
0N/A tag.equals(SYNTAX_ID)) {
0N/A return readWOID(string, pos);
0N/A }
0N/A
0N/A if (tag.equals(OBSOLETE_ID) ||
0N/A tag.equals(ABSTRACT_ID) ||
0N/A tag.equals(STRUCTURAL_ID) ||
0N/A tag.equals(AUXILARY_ID) ||
0N/A tag.equals(SINGLE_VAL_ID) ||
0N/A tag.equals(COLLECTIVE_ID) ||
0N/A tag.equals(NO_USER_MOD_ID)) {
0N/A return new String[] {SCHEMA_TRUE_VALUE};
0N/A }
0N/A
0N/A if (tag.equals(SUP_ID) || // oid list for object class; WOID for attribute
0N/A tag.equals(MUST_ID) ||
0N/A tag.equals(MAY_ID) ||
0N/A tag.equals(USAGE_ID)) {
0N/A return readOIDs(string, pos);
0N/A }
0N/A
0N/A // otherwise it's a schema element with a quoted string value
0N/A return readQDStrings(string, pos);
0N/A }
0N/A
0N/A final private static String[] readQDString(String string, int[] pos)
0N/A throws NamingException {
0N/A
0N/A int begin, end;
0N/A
0N/A begin = string.indexOf(SINGLE_QUOTE, pos[0]) + 1;
0N/A end = string.indexOf(SINGLE_QUOTE, begin);
0N/A
0N/A if (debug) {
0N/A System.err.println("ReadQDString: pos=" + pos[0] +
0N/A " begin=" + begin + " end=" + end);
0N/A }
0N/A
0N/A if(begin == -1 || end == -1 || begin == end) {
0N/A throw new InvalidAttributeIdentifierException("malformed " +
0N/A "QDString: " +
0N/A string);
0N/A }
0N/A
0N/A // make sure the qdstring end symbol is there
0N/A if (string.charAt(begin - 1) != SINGLE_QUOTE) {
0N/A throw new InvalidAttributeIdentifierException("qdstring has " +
0N/A "no end mark: " +
0N/A string);
0N/A }
0N/A
0N/A pos[0] = end+1;
0N/A return new String[] {string.substring(begin, end)};
0N/A }
0N/A
0N/A /**
0N/A * dstring = 1*utf8
0N/A * qdstring = whsp "'" dstring "'" whsp
0N/A * qdstringlist = [ qdstring *( qdstring ) ]
0N/A * qdstrings = qdstring / ( whsp "(" qdstringlist ")" whsp )
0N/A */
0N/A private final static String[] readQDStrings(String string, int[] pos)
0N/A throws NamingException {
0N/A
0N/A return readQDescrs(string, pos);
0N/A }
0N/A
0N/A /**
0N/A * ; object descriptors used as schema element names
0N/A * qdescrs = qdescr / ( whsp "(" qdescrlist ")" whsp )
0N/A * qdescrlist = [ qdescr *( qdescr ) ]
0N/A * qdescr = whsp "'" descr "'" whsp
0N/A * descr = keystring
0N/A */
0N/A final private static String[] readQDescrs(String string, int[] pos)
0N/A throws NamingException {
0N/A
0N/A if (debug) {
0N/A System.err.println("readQDescrs: pos="+pos[0]);
0N/A }
0N/A
0N/A skipWhitespace(string, pos);
0N/A
0N/A switch( string.charAt(pos[0]) ) {
0N/A case OID_LIST_BEGIN:
0N/A return readQDescrList(string, pos);
0N/A case SINGLE_QUOTE:
0N/A return readQDString(string, pos);
0N/A default:
0N/A throw new InvalidAttributeValueException("unexpected oids " +
0N/A "string: " + string);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * qdescrlist = [ qdescr *( qdescr ) ]
0N/A * qdescr = whsp "'" descr "'" whsp
0N/A * descr = keystring
0N/A */
0N/A final private static String[] readQDescrList(String string, int[] pos)
0N/A throws NamingException {
0N/A
0N/A int begin, end;
0N/A Vector values = new Vector(5);
0N/A
0N/A if (debug) {
0N/A System.err.println("ReadQDescrList: pos="+pos[0]);
0N/A }
0N/A
0N/A pos[0]++; // skip '('
0N/A skipWhitespace(string, pos);
0N/A begin = pos[0];
0N/A end = string.indexOf(OID_LIST_END, begin);
0N/A
0N/A if(end == -1) {
0N/A throw new InvalidAttributeValueException ("oidlist has no end "+
0N/A "mark: " + string);
0N/A }
0N/A
0N/A while(begin < end) {
0N/A String[] one = readQDString(string, pos);
0N/A
0N/A if (debug) {
0N/A System.err.println("ReadQDescrList: found '" + one[0] +
0N/A "' at begin=" + begin + " end =" + end);
0N/A }
0N/A
0N/A values.addElement(one[0]);
0N/A skipWhitespace(string, pos);
0N/A begin = pos[0];
0N/A }
0N/A
0N/A pos[0] = end+1; // skip ')'
0N/A
0N/A String[] answer = new String[values.size()];
0N/A for (int i = 0; i < answer.length; i++) {
0N/A answer[i] = (String)values.elementAt(i);
0N/A }
0N/A return answer;
0N/A }
0N/A
0N/A final private static String[] readWOID(String string, int[] pos)
0N/A throws NamingException {
0N/A
0N/A if (debug) {
0N/A System.err.println("readWOIDs: pos="+pos[0]);
0N/A }
0N/A
0N/A skipWhitespace(string, pos);
0N/A
0N/A if (string.charAt(pos[0]) == SINGLE_QUOTE) {
0N/A // %%% workaround for Netscape schema bug
0N/A return readQDString(string, pos);
0N/A }
0N/A
0N/A int begin, end;
0N/A
0N/A begin = pos[0];
0N/A end = string.indexOf(WHSP, begin);
0N/A
0N/A if (debug) {
0N/A System.err.println("ReadWOID: pos=" + pos[0] +
0N/A " begin=" + begin + " end=" + end);
0N/A }
0N/A
0N/A if(end == -1 || begin == end) {
0N/A throw new InvalidAttributeIdentifierException("malformed " +
0N/A "OID: " +
0N/A string);
0N/A }
0N/A pos[0] = end+1;
0N/A
0N/A return new String[] {string.substring(begin, end)};
0N/A }
0N/A
0N/A /*
0N/A * oids = woid / ( "(" oidlist ")" )
0N/A * oidlist = woid *( "$" woid )
0N/A */
0N/A final private static String[] readOIDs(String string, int[] pos)
0N/A throws NamingException {
0N/A
0N/A if (debug) {
0N/A System.err.println("readOIDs: pos="+pos[0]);
0N/A }
0N/A
0N/A skipWhitespace(string, pos);
0N/A
0N/A // Single OID
0N/A if (string.charAt(pos[0]) != OID_LIST_BEGIN) {
0N/A return readWOID(string, pos);
0N/A }
0N/A
0N/A // Multiple OIDs
0N/A
0N/A int begin, cur, end;
0N/A String oidName = null;
0N/A Vector values = new Vector(5);
0N/A
0N/A if (debug) {
0N/A System.err.println("ReadOIDList: pos="+pos[0]);
0N/A }
0N/A
0N/A pos[0]++;
0N/A skipWhitespace(string, pos);
0N/A begin = pos[0];
0N/A end = string.indexOf(OID_LIST_END, begin);
0N/A cur = string.indexOf(OID_SEPARATOR, begin);
0N/A
0N/A if(end == -1) {
0N/A throw new InvalidAttributeValueException ("oidlist has no end "+
0N/A "mark: " + string);
0N/A }
0N/A
0N/A if(cur == -1 || end < cur) {
0N/A cur = end;
0N/A }
0N/A
0N/A while(cur < end && cur > 0) {
0N/A int wsBegin = findTrailingWhitespace(string, cur - 1);
0N/A oidName = string.substring(begin, wsBegin);
0N/A if (debug) {
0N/A System.err.println("ReadOIDList: found '" + oidName +
0N/A "' at begin=" + begin + " end =" + end);
0N/A }
0N/A values.addElement(oidName);
0N/A pos[0] = cur + 1;
0N/A skipWhitespace(string, pos);
0N/A begin = pos[0];
0N/A cur = string.indexOf(OID_SEPARATOR, begin);
0N/A if(debug) {System.err.println("ReadOIDList: begin = " + begin);}
0N/A }
0N/A
0N/A if (debug) {
0N/A System.err.println("ReadOIDList: found '" + oidName +
0N/A "' at begin=" + begin + " end =" + end);
0N/A }
0N/A
0N/A int wsBegin = findTrailingWhitespace(string, end - 1);
0N/A oidName = string.substring(begin, wsBegin);
0N/A values.addElement(oidName);
0N/A
0N/A pos[0] = end+1;
0N/A
0N/A String[] answer = new String[values.size()];
0N/A for (int i = 0; i < answer.length; i++) {
0N/A answer[i] = (String)values.elementAt(i);
0N/A }
0N/A return answer;
0N/A }
0N/A
0N/A// ----------------- "unparser" methods
0N/A// Methods that are used for translating a node in the schema tree
0N/A// into RFC2252 format for storage back into the LDAP directory
0N/A/*
0N/A static Attributes JNDI2LDAPSchema(DirContext schemaRoot)
0N/A throws NamingException {
0N/A
0N/A Attribute objDescAttr = new BasicAttribute(OBJECTCLASSDESC_ATTR_ID);
0N/A Attribute attrDescAttr = new BasicAttribute(ATTRIBUTEDESC_ATTR_ID);
0N/A Attribute syntaxDescAttr = new BasicAttribute(SYNTAXDESC_ATTR_ID);
0N/A Attributes attrs = new BasicAttributes(LdapClient.caseIgnore);
0N/A DirContext classDefs, attributeDefs, syntaxDefs;
0N/A Attributes classDefsAttrs, attributeDefsAttrs, syntaxDefsAttrs;
0N/A NamingEnumeration defs;
0N/A Object obj;
0N/A int i = 0;
0N/A
0N/A try {
0N/A obj = schemaRoot.lookup(OBJECTCLASS_DEFINITION_NAME);
0N/A if(obj != null && obj instanceof DirContext) {
0N/A classDefs = (DirContext)obj;
0N/A defs = classDefs.listBindings("");
0N/A while(defs.hasMoreElements()) {
0N/A i++;
0N/A DirContext classDef = (DirContext)
0N/A ((Binding)(defs.next())).getObject();
0N/A classDefAttrs = classDef.getAttributes("");
0N/A objDescAttr.add(classDef2ObjectDesc(classDefAttrs));
0N/A }
0N/A if (debug)
0N/A System.err.println(i + " total object classes");
0N/A attrs.put(objDescAttr);
0N/A } else {
0N/A throw new NamingException(
0N/A "Problem with Schema tree: the object named " +
0N/A OBJECTCLASS_DEFINITION_NAME + " is not a " +
0N/A "DirContext");
0N/A }
0N/A } catch (NameNotFoundException e) {} // ignore
0N/A
0N/A i=0;
0N/A try {
0N/A obj = schemaRoot.lookup(ATTRIBUTE_DEFINITION_NAME);
0N/A if(obj instanceof DirContext) {
0N/A attributeDefs = (DirContext)obj;
0N/A defs = attributeDefs.listBindings("");
0N/A while(defs.hasMoreElements()) {
0N/A i++;
0N/A DirContext attrDef = (DirContext)
0N/A ((Binding)defs.next()).getObject();
0N/A attrDefAttrs = attrDef.getAttributes("");
0N/A attrDescAttr.add(attrDef2AttrDesc(attrDefAttrs));
0N/A }
0N/A if (debug)
0N/A System.err.println(i + " attribute definitions");
0N/A attrs.put(attrDescAttr);
0N/A } else {
0N/A throw new NamingException(
0N/A "Problem with schema tree: the object named " +
0N/A ATTRIBUTE_DEFINITION_NAME + " is not a " +
0N/A "DirContext");
0N/A }
0N/A } catch (NameNotFoundException e) {} // ignore
0N/A
0N/A i=0;
0N/A try {
0N/A obj = schemaRoot.lookup(SYNTAX_DEFINITION_NAME);
0N/A if(obj instanceof DirContext) {
0N/A syntaxDefs = (DirContext)obj;
0N/A defs =syntaxDefs.listBindings("");
0N/A while(defs.hasMoreElements()) {
0N/A i++;
0N/A DirContext syntaxDef = (DirContext)
0N/A ((Binding)defs.next()).getObject();
0N/A syntaxDefAttrs = syntaxDef.getAttributes("");
0N/A syntaxDescAttr.add(syntaxDef2SyntaxDesc(syntaxDefAttrs));
0N/A }
0N/A if (debug)
0N/A System.err.println(i + " total syntax definitions");
0N/A attrs.put(syntaxDescAttr);
0N/A } else {
0N/A throw new NamingException(
0N/A "Problem with schema tree: the object named " +
0N/A SYNTAX_DEFINITION_NAME + " is not a " +
0N/A "DirContext");
0N/A }
0N/A } catch (NameNotFoundException e) {} // ignore
0N/A
0N/A return attrs;
0N/A }
0N/A
0N/A*/
0N/A
0N/A /**
0N/A * Translate attributes that describe an object class into the
0N/A * string description as defined in RFC 2252.
0N/A */
0N/A final private String classDef2ObjectDesc(Attributes attrs)
0N/A throws NamingException {
0N/A
0N/A StringBuffer objectDesc = new StringBuffer("( ");
0N/A
0N/A Attribute attr = null;
0N/A int count = 0;
0N/A
0N/A // extract attributes by ID to guarantee ordering
0N/A
0N/A attr = attrs.get(NUMERICOID_ID);
0N/A if (attr != null) {
0N/A objectDesc.append(writeNumericOID(attr));
0N/A count++;
0N/A } else {
0N/A throw new ConfigurationException("Class definition doesn't" +
0N/A "have a numeric OID");
0N/A }
0N/A
0N/A attr = attrs.get(NAME_ID);
0N/A if (attr != null) {
0N/A objectDesc.append(writeQDescrs(attr));
0N/A count++;
0N/A }
0N/A
0N/A attr = attrs.get(DESC_ID);
0N/A if (attr != null) {
0N/A objectDesc.append(writeQDString(attr));
0N/A count++;
0N/A }
0N/A
0N/A attr = attrs.get(OBSOLETE_ID);
0N/A if (attr != null) {
0N/A objectDesc.append(writeBoolean(attr));
0N/A count++;
0N/A }
0N/A
0N/A attr = attrs.get(SUP_ID);
0N/A if (attr != null) {
0N/A objectDesc.append(writeOIDs(attr));
0N/A count++;
0N/A }
0N/A
0N/A attr = attrs.get(ABSTRACT_ID);
0N/A if (attr != null) {
0N/A objectDesc.append(writeBoolean(attr));
0N/A count++;
0N/A }
0N/A
0N/A attr = attrs.get(STRUCTURAL_ID);
0N/A if (attr != null) {
0N/A objectDesc.append(writeBoolean(attr));
0N/A count++;
0N/A }
0N/A
0N/A attr = attrs.get(AUXILARY_ID);
0N/A if (attr != null) {
0N/A objectDesc.append(writeBoolean(attr));
0N/A count++;
0N/A }
0N/A
0N/A attr = attrs.get(MUST_ID);
0N/A if (attr != null) {
0N/A objectDesc.append(writeOIDs(attr));
0N/A count++;
0N/A }
0N/A
0N/A attr = attrs.get(MAY_ID);
0N/A if (attr != null) {
0N/A objectDesc.append(writeOIDs(attr));
0N/A count++;
0N/A }
0N/A
0N/A // process any remaining attributes
0N/A if (count < attrs.size()) {
0N/A String attrId = null;
0N/A
0N/A // use enumeration because attribute ID is not known
0N/A for (NamingEnumeration ae = attrs.getAll();
0N/A ae.hasMoreElements(); ) {
0N/A
0N/A attr = (Attribute)ae.next();
0N/A attrId = attr.getID();
0N/A
0N/A // skip those already processed
0N/A if (attrId.equals(NUMERICOID_ID) ||
0N/A attrId.equals(NAME_ID) ||
0N/A attrId.equals(SUP_ID) ||
0N/A attrId.equals(MAY_ID) ||
0N/A attrId.equals(MUST_ID) ||
0N/A attrId.equals(STRUCTURAL_ID) ||
0N/A attrId.equals(DESC_ID) ||
0N/A attrId.equals(AUXILARY_ID) ||
0N/A attrId.equals(ABSTRACT_ID) ||
0N/A attrId.equals(OBSOLETE_ID)) {
0N/A continue;
0N/A
0N/A } else {
0N/A objectDesc.append(writeQDStrings(attr));
0N/A }
0N/A }
0N/A }
0N/A
0N/A objectDesc.append(")");
0N/A
0N/A return objectDesc.toString();
0N/A }
0N/A
0N/A /**
0N/A * Translate attributes that describe an attribute definition into the
0N/A * string description as defined in RFC 2252.
0N/A */
0N/A final private String attrDef2AttrDesc(Attributes attrs)
0N/A throws NamingException {
0N/A
0N/A StringBuffer attrDesc = new StringBuffer("( "); // opening parens
0N/A
0N/A Attribute attr = null;
0N/A int count = 0;
0N/A
0N/A // extract attributes by ID to guarantee ordering
0N/A
0N/A attr = attrs.get(NUMERICOID_ID);
0N/A if (attr != null) {
0N/A attrDesc.append(writeNumericOID(attr));
0N/A count++;
0N/A } else {
0N/A throw new ConfigurationException("Attribute type doesn't" +
0N/A "have a numeric OID");
0N/A }
0N/A
0N/A attr = attrs.get(NAME_ID);
0N/A if (attr != null) {
0N/A attrDesc.append(writeQDescrs(attr));
0N/A count++;
0N/A }
0N/A
0N/A attr = attrs.get(DESC_ID);
0N/A if (attr != null) {
0N/A attrDesc.append(writeQDString(attr));
0N/A count++;
0N/A }
0N/A
0N/A attr = attrs.get(OBSOLETE_ID);
0N/A if (attr != null) {
0N/A attrDesc.append(writeBoolean(attr));
0N/A count++;
0N/A }
0N/A
0N/A attr = attrs.get(SUP_ID);
0N/A if (attr != null) {
0N/A attrDesc.append(writeWOID(attr));
0N/A count++;
0N/A }
0N/A
0N/A attr = attrs.get(EQUALITY_ID);
0N/A if (attr != null) {
0N/A attrDesc.append(writeWOID(attr));
0N/A count++;
0N/A }
0N/A
0N/A attr = attrs.get(ORDERING_ID);
0N/A if (attr != null) {
0N/A attrDesc.append(writeWOID(attr));
0N/A count++;
0N/A }
0N/A
0N/A attr = attrs.get(SUBSTR_ID);
0N/A if (attr != null) {
0N/A attrDesc.append(writeWOID(attr));
0N/A count++;
0N/A }
0N/A
0N/A attr = attrs.get(SYNTAX_ID);
0N/A if (attr != null) {
0N/A attrDesc.append(writeWOID(attr));
0N/A count++;
0N/A }
0N/A
0N/A attr = attrs.get(SINGLE_VAL_ID);
0N/A if (attr != null) {
0N/A attrDesc.append(writeBoolean(attr));
0N/A count++;
0N/A }
0N/A
0N/A attr = attrs.get(COLLECTIVE_ID);
0N/A if (attr != null) {
0N/A attrDesc.append(writeBoolean(attr));
0N/A count++;
0N/A }
0N/A
0N/A attr = attrs.get(NO_USER_MOD_ID);
0N/A if (attr != null) {
0N/A attrDesc.append(writeBoolean(attr));
0N/A count++;
0N/A }
0N/A
0N/A attr = attrs.get(USAGE_ID);
0N/A if (attr != null) {
0N/A attrDesc.append(writeQDString(attr));
0N/A count++;
0N/A }
0N/A
0N/A // process any remaining attributes
0N/A if (count < attrs.size()) {
0N/A String attrId = null;
0N/A
0N/A // use enumeration because attribute ID is not known
0N/A for (NamingEnumeration ae = attrs.getAll();
0N/A ae.hasMoreElements(); ) {
0N/A
0N/A attr = (Attribute)ae.next();
0N/A attrId = attr.getID();
0N/A
0N/A // skip those already processed
0N/A if (attrId.equals(NUMERICOID_ID) ||
0N/A attrId.equals(NAME_ID) ||
0N/A attrId.equals(SYNTAX_ID) ||
0N/A attrId.equals(DESC_ID) ||
0N/A attrId.equals(SINGLE_VAL_ID) ||
0N/A attrId.equals(EQUALITY_ID) ||
0N/A attrId.equals(ORDERING_ID) ||
0N/A attrId.equals(SUBSTR_ID) ||
0N/A attrId.equals(NO_USER_MOD_ID) ||
0N/A attrId.equals(USAGE_ID) ||
0N/A attrId.equals(SUP_ID) ||
0N/A attrId.equals(COLLECTIVE_ID) ||
0N/A attrId.equals(OBSOLETE_ID)) {
0N/A continue;
0N/A
0N/A } else {
0N/A attrDesc.append(writeQDStrings(attr));
0N/A }
0N/A }
0N/A }
0N/A
0N/A attrDesc.append(")"); // add closing parens
0N/A
0N/A return attrDesc.toString();
0N/A }
0N/A
0N/A /**
0N/A * Translate attributes that describe an attribute syntax definition into the
0N/A * string description as defined in RFC 2252.
0N/A */
0N/A final private String syntaxDef2SyntaxDesc(Attributes attrs)
0N/A throws NamingException {
0N/A
0N/A StringBuffer syntaxDesc = new StringBuffer("( "); // opening parens
0N/A
0N/A Attribute attr = null;
0N/A int count = 0;
0N/A
0N/A // extract attributes by ID to guarantee ordering
0N/A
0N/A attr = attrs.get(NUMERICOID_ID);
0N/A if (attr != null) {
0N/A syntaxDesc.append(writeNumericOID(attr));
0N/A count++;
0N/A } else {
0N/A throw new ConfigurationException("Attribute type doesn't" +
0N/A "have a numeric OID");
0N/A }
0N/A
0N/A attr = attrs.get(DESC_ID);
0N/A if (attr != null) {
0N/A syntaxDesc.append(writeQDString(attr));
0N/A count++;
0N/A }
0N/A
0N/A // process any remaining attributes
0N/A if (count < attrs.size()) {
0N/A String attrId = null;
0N/A
0N/A // use enumeration because attribute ID is not known
0N/A for (NamingEnumeration ae = attrs.getAll();
0N/A ae.hasMoreElements(); ) {
0N/A
0N/A attr = (Attribute)ae.next();
0N/A attrId = attr.getID();
0N/A
0N/A // skip those already processed
0N/A if (attrId.equals(NUMERICOID_ID) ||
0N/A attrId.equals(DESC_ID)) {
0N/A continue;
0N/A
0N/A } else {
0N/A syntaxDesc.append(writeQDStrings(attr));
0N/A }
0N/A }
0N/A }
0N/A
0N/A syntaxDesc.append(")");
0N/A
0N/A return syntaxDesc.toString();
0N/A }
0N/A
0N/A /**
0N/A * Translate attributes that describe an attribute matching rule
0N/A * definition into the string description as defined in RFC 2252.
0N/A */
0N/A final private String matchRuleDef2MatchRuleDesc(Attributes attrs)
0N/A throws NamingException {
0N/A
0N/A StringBuffer matchRuleDesc = new StringBuffer("( "); // opening parens
0N/A
0N/A Attribute attr = null;
0N/A int count = 0;
0N/A
0N/A // extract attributes by ID to guarantee ordering
0N/A
0N/A attr = attrs.get(NUMERICOID_ID);
0N/A if (attr != null) {
0N/A matchRuleDesc.append(writeNumericOID(attr));
0N/A count++;
0N/A } else {
0N/A throw new ConfigurationException("Attribute type doesn't" +
0N/A "have a numeric OID");
0N/A }
0N/A
0N/A attr = attrs.get(NAME_ID);
0N/A if (attr != null) {
0N/A matchRuleDesc.append(writeQDescrs(attr));
0N/A count++;
0N/A }
0N/A
0N/A attr = attrs.get(DESC_ID);
0N/A if (attr != null) {
0N/A matchRuleDesc.append(writeQDString(attr));
0N/A count++;
0N/A }
0N/A
0N/A attr = attrs.get(OBSOLETE_ID);
0N/A if (attr != null) {
0N/A matchRuleDesc.append(writeBoolean(attr));
0N/A count++;
0N/A }
0N/A
0N/A attr = attrs.get(SYNTAX_ID);
0N/A if (attr != null) {
0N/A matchRuleDesc.append(writeWOID(attr));
0N/A count++;
0N/A } else {
0N/A throw new ConfigurationException("Attribute type doesn't" +
0N/A "have a syntax OID");
0N/A }
0N/A
0N/A // process any remaining attributes
0N/A if (count < attrs.size()) {
0N/A String attrId = null;
0N/A
0N/A // use enumeration because attribute ID is not known
0N/A for (NamingEnumeration ae = attrs.getAll();
0N/A ae.hasMoreElements(); ) {
0N/A
0N/A attr = (Attribute)ae.next();
0N/A attrId = attr.getID();
0N/A
0N/A // skip those already processed
0N/A if (attrId.equals(NUMERICOID_ID) ||
0N/A attrId.equals(NAME_ID) ||
0N/A attrId.equals(SYNTAX_ID) ||
0N/A attrId.equals(DESC_ID) ||
0N/A attrId.equals(OBSOLETE_ID)) {
0N/A continue;
0N/A
0N/A } else {
0N/A matchRuleDesc.append(writeQDStrings(attr));
0N/A }
0N/A }
0N/A }
0N/A
0N/A matchRuleDesc.append(")");
0N/A
0N/A return matchRuleDesc.toString();
0N/A }
0N/A
0N/A final private String writeNumericOID(Attribute nOIDAttr)
0N/A throws NamingException {
0N/A if(nOIDAttr.size() != 1) {
0N/A throw new InvalidAttributeValueException(
0N/A "A class definition must have exactly one numeric OID");
0N/A }
0N/A return (String)(nOIDAttr.get()) + WHSP;
0N/A }
0N/A
0N/A final private String writeWOID(Attribute attr) throws NamingException {
0N/A if (netscapeBug)
0N/A return writeQDString(attr);
0N/A else
0N/A return attr.getID() + WHSP + attr.get() + WHSP;
0N/A }
0N/A
0N/A /* qdescr = whsp "'" descr "'" whsp */
0N/A final private String writeQDString(Attribute qdStringAttr)
0N/A throws NamingException {
0N/A if(qdStringAttr.size() != 1) {
0N/A throw new InvalidAttributeValueException(
0N/A qdStringAttr.getID() + " must have exactly one value");
0N/A }
0N/A
0N/A return qdStringAttr.getID() + WHSP +
0N/A SINGLE_QUOTE + qdStringAttr.get() + SINGLE_QUOTE + WHSP;
0N/A }
0N/A
0N/A /**
0N/A * dstring = 1*utf8
0N/A * qdstring = whsp "'" dstring "'" whsp
0N/A * qdstringlist = [ qdstring *( qdstring ) ]
0N/A * qdstrings = qdstring / ( whsp "(" qdstringlist ")" whsp )
0N/A */
0N/A private final String writeQDStrings(Attribute attr) throws NamingException {
0N/A return writeQDescrs(attr);
0N/A }
0N/A
0N/A /**
0N/A * qdescrs = qdescr / ( whsp "(" qdescrlist ")" whsp )
0N/A * qdescrlist = [ qdescr *( qdescr ) ]
0N/A * qdescr = whsp "'" descr "'" whsp
0N/A * descr = keystring
0N/A */
0N/A private final String writeQDescrs(Attribute attr) throws NamingException {
0N/A switch(attr.size()) {
0N/A case 0:
0N/A throw new InvalidAttributeValueException(
0N/A attr.getID() + "has no values");
0N/A case 1:
0N/A return writeQDString(attr);
0N/A }
0N/A
0N/A // write QDList
0N/A
0N/A StringBuffer qdList = new StringBuffer(attr.getID());
0N/A qdList.append(WHSP);
0N/A qdList.append(OID_LIST_BEGIN);
0N/A
0N/A NamingEnumeration values = attr.getAll();
0N/A
0N/A while(values.hasMore()) {
0N/A qdList.append(WHSP);
0N/A qdList.append(SINGLE_QUOTE);
0N/A qdList.append((String)values.next());
0N/A qdList.append(SINGLE_QUOTE);
0N/A qdList.append(WHSP);
0N/A }
0N/A
0N/A qdList.append(OID_LIST_END);
0N/A qdList.append(WHSP);
0N/A
0N/A return qdList.toString();
0N/A }
0N/A
0N/A final private String writeOIDs(Attribute oidsAttr)
0N/A throws NamingException {
0N/A
0N/A switch(oidsAttr.size()) {
0N/A case 0:
0N/A throw new InvalidAttributeValueException(
0N/A oidsAttr.getID() + "has no values");
0N/A
0N/A case 1:
0N/A if (netscapeBug) {
0N/A break; // %%% write out as list to avoid crashing server
0N/A }
0N/A return writeWOID(oidsAttr);
0N/A }
0N/A
0N/A // write OID List
0N/A
0N/A StringBuffer oidList = new StringBuffer(oidsAttr.getID());
0N/A oidList.append(WHSP);
0N/A oidList.append(OID_LIST_BEGIN);
0N/A
0N/A NamingEnumeration values = oidsAttr.getAll();
0N/A oidList.append(WHSP);
0N/A oidList.append(values.next());
0N/A
0N/A while(values.hasMore()) {
0N/A oidList.append(WHSP);
0N/A oidList.append(OID_SEPARATOR);
0N/A oidList.append(WHSP);
0N/A oidList.append((String)values.next());
0N/A }
0N/A
0N/A oidList.append(WHSP);
0N/A oidList.append(OID_LIST_END);
0N/A oidList.append(WHSP);
0N/A
0N/A return oidList.toString();
0N/A }
0N/A
0N/A private final String writeBoolean(Attribute booleanAttr)
0N/A throws NamingException {
0N/A return booleanAttr.getID() + WHSP;
0N/A }
0N/A
0N/A /**
0N/A * Returns an attribute for updating the Object Class Definition schema
0N/A * attribute
0N/A */
0N/A final Attribute stringifyObjDesc(Attributes classDefAttrs)
0N/A throws NamingException {
0N/A Attribute objDescAttr = new BasicAttribute(OBJECTCLASSDESC_ATTR_ID);
0N/A objDescAttr.add(classDef2ObjectDesc(classDefAttrs));
0N/A return objDescAttr;
0N/A }
0N/A
0N/A /**
0N/A * Returns an attribute for updating the Attribute Definition schema attribute
0N/A */
0N/A final Attribute stringifyAttrDesc(Attributes attrDefAttrs)
0N/A throws NamingException {
0N/A Attribute attrDescAttr = new BasicAttribute(ATTRIBUTEDESC_ATTR_ID);
0N/A attrDescAttr.add(attrDef2AttrDesc(attrDefAttrs));
0N/A return attrDescAttr;
0N/A }
0N/A
0N/A /**
0N/A * Returns an attribute for updating the Syntax schema attribute
0N/A */
0N/A final Attribute stringifySyntaxDesc(Attributes syntaxDefAttrs)
0N/A throws NamingException {
0N/A Attribute syntaxDescAttr = new BasicAttribute(SYNTAXDESC_ATTR_ID);
0N/A syntaxDescAttr.add(syntaxDef2SyntaxDesc(syntaxDefAttrs));
0N/A return syntaxDescAttr;
0N/A }
0N/A
0N/A /**
0N/A * Returns an attribute for updating the Matching Rule schema attribute
0N/A */
0N/A final Attribute stringifyMatchRuleDesc(Attributes matchRuleDefAttrs)
0N/A throws NamingException {
0N/A Attribute matchRuleDescAttr = new BasicAttribute(MATCHRULEDESC_ATTR_ID);
0N/A matchRuleDescAttr.add(matchRuleDef2MatchRuleDesc(matchRuleDefAttrs));
0N/A return matchRuleDescAttr;
0N/A }
0N/A}