opends/src/messages/messages/backend.properties
@@ -1140,3 +1140,13 @@ because its dependency task %s is missing NOTICE_TASK_STARTED_413=%s task %s started execution NOTICE_TASK_FINISHED_414=%s task %s finished execution MILD_ERR_SCHEMA_MODIFY_MULTIPLE_CONFLICTS_FOR_ADD_LDAP_SYNTAX_415=Unable to \ add ldap syntax description with OID %s because it conflicts with an existing ldap syntax description MILD_ERR_SCHEMA_MODIFY_REMOVE_NO_SUCH_LSD_416=Unable to remove ldap syntax \ description %s from the server schema because no such ldap syntax \ description is defined MILD_ERR_ATTR_SYNTAX_INVALID_SUBSTITUTION_SYNTAX_417=The provided value "%s" \ could not be parsed as a substitution syntax because its OID %s corresponds \ to an attribute syntax that is already implemented MILD_ERR_SCHEMA_MODIFY_CANNOT_DECODE_LDAP_SYNTAX_418=An error occurred while \ attempting to decode the ldapsyntax description "%s": %s opends/src/messages/messages/config.properties
@@ -2155,3 +2155,8 @@ SEVERE_ERR_CONFIG_NETWORK_GROUP_POLICY_CANNOT_INITIALIZE_722=An error occurred \ while trying to initialize a network group policy loaded from class %s with \ the information in configuration entry %s: %s SEVERE_WARN_CONFIG_SCHEMA_CANNOT_PARSE_LDAP_SYNTAX_723=An ldapSyntaxes \ attribute read from schema configuration file %s could not be parsed: %s SEVERE_WARN_CONFIG_SCHEMA_CONFLICTING_LDAP_SYNTAX_724=An ldap syntax read \ from schema configuration file %s conflicts with another ldap syntax already \ read into the schema: %s. The later ldap syntax description will be used opends/src/messages/messages/schema.properties
@@ -995,4 +995,10 @@ MILD_WARN_ATTR_CONFLICTING_ASSERTION_FORMAT_304=The provided \ value "%s" could not be parsed as a valid assertion value because more than \ one time units are not allowed MILD_WARN_ATTR_LDAP_SYNTAX_ILLEGAL_CHAR_IN_OID_305=The provided value "%s" \ could not be parsed as an ldap syntax because the OID contained an illegal \ character %s at position %d MILD_WARN_ATTR_SYNTAX_LDAPSYNTAX_UNKNOWN_EXT_306=The provided value "%s" \ could not be parsed as an ldap syntax because it contains an unrecognized \ extension %s at position %d opends/src/server/org/opends/server/backends/SchemaBackend.java
@@ -78,6 +78,7 @@ import org.opends.server.schema.DITContentRuleSyntax; import org.opends.server.schema.DITStructureRuleSyntax; import org.opends.server.schema.GeneralizedTimeSyntax; import org.opends.server.schema.LDAPSyntaxDescriptionSyntax; import org.opends.server.schema.MatchingRuleUseSyntax; import org.opends.server.schema.NameFormSyntax; import org.opends.server.schema.ObjectClassSyntax; @@ -1270,6 +1271,34 @@ addMatchingRuleUse(mru, newSchema, modifiedSchemaFiles); } } else if(at.equals(ldapSyntaxesType)) { for(AttributeValue v : a) { LDAPSyntaxDescription lsd = null; try { lsd = LDAPSyntaxDescriptionSyntax.decodeLDAPSyntax( v.getValue(), newSchema, false); } catch(DirectoryException de) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, de); } Message message = ERR_SCHEMA_MODIFY_CANNOT_DECODE_LDAP_SYNTAX.get( v.getValue().toString(), de.getMessageObject()); throw new DirectoryException( ResultCode.INVALID_ATTRIBUTE_SYNTAX, message, de); } addLdapSyntaxDescription(lsd,newSchema,modifiedSchemaFiles); } } else { Message message = @@ -1456,6 +1485,34 @@ modifiedSchemaFiles); } } else if (at.equals(ldapSyntaxesType)) { for(AttributeValue v : a) { LDAPSyntaxDescription lsd = null; try { lsd = LDAPSyntaxDescriptionSyntax.decodeLDAPSyntax( v.getValue(), newSchema, false); } catch(DirectoryException de) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, de); } Message message = ERR_SCHEMA_MODIFY_CANNOT_DECODE_LDAP_SYNTAX.get( v.getValue().toString(), de.getMessageObject()); throw new DirectoryException( ResultCode.INVALID_ATTRIBUTE_SYNTAX, message, de); } removeLdapSyntaxDescription(lsd,newSchema,modifiedSchemaFiles); } } else { Message message = @@ -3229,6 +3286,125 @@ /** * Handles all processing required for adding the provided ldap syntax * description to the given schema, replacing an existing ldap syntax * description if necessary, and ensuring all other metadata is properly * updated. * * @param ldapSyntaxDesc The ldap syntax description to add or replace in * the server schema. * @param schema The schema to which the name form should be * added. * @param modifiedSchemaFiles The names of the schema files containing * schema elements that have been updated as part * of the schema modification. * * @throws DirectoryException If a problem occurs while attempting to add * the provided ldap syntax description to the * server schema. */ private void addLdapSyntaxDescription(LDAPSyntaxDescription ldapSyntaxDesc, Schema schema, Set<String> modifiedSchemaFiles) throws DirectoryException { //Check if there is an existing syntax with this oid. String oid = ldapSyntaxDesc.getLdapSyntaxDescriptionSyntax().getOID(); // We allow only unimplemented syntaxes to be substituted. if(schema.getSyntax(oid) !=null) { Message message = ERR_ATTR_SYNTAX_INVALID_SUBSTITUTION_SYNTAX.get( ldapSyntaxDesc.getDefinition(),oid); throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); } LDAPSyntaxDescription existingLSD = schema.getLdapSyntaxDescription(oid); // If there is no existing lsd, then we're adding a new ldapsyntax. // Otherwise, we're replacing an existing one. if (existingLSD == null) { schema.registerLdapSyntaxDescription(ldapSyntaxDesc, false); String schemaFile = ldapSyntaxDesc.getSchemaFile(); if ((schemaFile == null) || (schemaFile.length() == 0)) { schemaFile = FILE_USER_SCHEMA_ELEMENTS; ldapSyntaxDesc.setSchemaFile(schemaFile); } modifiedSchemaFiles.add(schemaFile); } else { schema.deregisterLdapSyntaxDescription(existingLSD); schema.registerLdapSyntaxDescription(ldapSyntaxDesc, false); schema.rebuildDependentElements(existingLSD); if ((ldapSyntaxDesc.getSchemaFile() == null) || (ldapSyntaxDesc.getSchemaFile().length() == 0)) { String schemaFile = ldapSyntaxDesc.getSchemaFile(); if ((schemaFile == null) || (schemaFile.length() == 0)) { schemaFile = FILE_USER_SCHEMA_ELEMENTS; } ldapSyntaxDesc.setSchemaFile(schemaFile); modifiedSchemaFiles.add(schemaFile); } else { String newSchemaFile = ldapSyntaxDesc.getSchemaFile(); String oldSchemaFile = existingLSD.getSchemaFile(); if ((oldSchemaFile == null) || oldSchemaFile.equals(newSchemaFile)) { modifiedSchemaFiles.add(newSchemaFile); } else { modifiedSchemaFiles.add(newSchemaFile); modifiedSchemaFiles.add(oldSchemaFile); } } } } //Gets rid of the ldap syntax description. private void removeLdapSyntaxDescription(LDAPSyntaxDescription ldapSyntaxDesc, Schema schema, Set<String> modifiedSchemaFiles) throws DirectoryException { //See if the specified ldap syntax description is actually defined in the //server schema. If not, then fail. Note that we are checking only the //real part of the ldapsyntaxes attribute. A virtual value is not searched // and hence never deleted. String oid = ldapSyntaxDesc.getLdapSyntaxDescriptionSyntax().getOID(); LDAPSyntaxDescription removeLSD = schema.getLdapSyntaxDescription(oid); if ((removeLSD == null) || (! removeLSD.equals(ldapSyntaxDesc))) { Message message = ERR_SCHEMA_MODIFY_REMOVE_NO_SUCH_LSD.get(oid); throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); } schema.deregisterLdapSyntaxDescription(removeLSD); String schemaFile = removeLSD.getSchemaFile(); if (schemaFile != null) { modifiedSchemaFiles.add(schemaFile); } } /** * Creates an empty entry that may be used as the basis for a new schema file. * * @return An empty entry that may be used as the basis for a new schema @@ -3439,6 +3615,33 @@ schemaEntry.putAttribute(matchingRuleUsesType, attrList); } /** * Add all of the ldap syntax descriptions to the schema entry. We do * this only for the real part of the ldapsyntaxes attribute. The real part * is read and write to/from the schema files. */ values = new LinkedHashSet<AttributeValue>(); for (LDAPSyntaxDescription ldapSyntax : schema.getLdapSyntaxDescriptions().values()) { if(schemaFile.equals(ldapSyntax.getSchemaFile())) { values.add(AttributeValues.create(ldapSyntaxesType, ldapSyntax.getDefinition())); } } if (! values.isEmpty()) { ArrayList<Attribute> attrList = new ArrayList<Attribute>(1); AttributeBuilder builder = new AttributeBuilder(ldapSyntaxesType); builder.addAll(values); attrList.add(builder.toAttribute()); schemaEntry.putAttribute(attributeTypesType, attrList); } if (schemaFile.equals(FILE_USER_SCHEMA_ELEMENTS)) { Map<String, Attribute> attributes = schema.getExtraAttributes(); opends/src/server/org/opends/server/core/SchemaConfigManager.java
@@ -22,7 +22,7 @@ * CDDL HEADER END * * * Copyright 2006-2008 Sun Microsystems, Inc. * Copyright 2006-2009 Sun Microsystems, Inc. */ package org.opends.server.core; import org.opends.messages.Message; @@ -64,6 +64,8 @@ import static org.opends.server.loggers.debug.DebugLogger.*; import static org.opends.server.loggers.ErrorLogger.*; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.schema.LDAPSyntaxDescriptionSyntax; import org.opends.server.types.LDAPSyntaxDescription; import static org.opends.messages.ConfigMessages.*; import static org.opends.server.schema.SchemaConstants.*; import static org.opends.server.util.ServerConstants.*; @@ -771,6 +773,47 @@ } } // Get the ldapsyntaxes attribute from the entry. LDAPSyntaxDescriptionSyntax ldapSyntax; try { ldapSyntax = (LDAPSyntaxDescriptionSyntax) schema.getSyntax( SYNTAX_LDAP_SYNTAX_OID); if (ldapSyntax == null) { ldapSyntax = new LDAPSyntaxDescriptionSyntax(); ldapSyntax.initializeSyntax(null); } } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } ldapSyntax = new LDAPSyntaxDescriptionSyntax(); ldapSyntax.initializeSyntax(null); } AttributeType ldapSyntaxAttrType = schema.getAttributeType(ATTR_LDAP_SYNTAXES_LC); if (ldapSyntaxAttrType == null) { ldapSyntaxAttrType = DirectoryServer.getDefaultAttributeType(ATTR_LDAP_SYNTAXES, ldapSyntax); } List<Attribute> ldapSyntaxList = entry.getAttribute(ldapSyntaxAttrType); if ((ldapSyntaxList != null) && (! ldapSyntaxList.isEmpty())) { for (Attribute a : ldapSyntaxList) { mods.add(new Modification(ModificationType.ADD, a)); } } // Loop on all the attribute of the schema entry to // find the extra attribute that shoule be loaded in the Schema. for (Attribute attribute : entry.getAttributes()) @@ -1344,6 +1387,100 @@ } // Parse the ldapsyntaxes definitions if there are any. if (ldapSyntaxList != null) { for (Attribute a : ldapSyntaxList) { for (AttributeValue v : a) { LDAPSyntaxDescription syntaxDescription = null; try { syntaxDescription = LDAPSyntaxDescriptionSyntax.decodeLDAPSyntax( v.getValue(),schema,false); } catch (DirectoryException de) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, de); } Message message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_LDAP_SYNTAX.get( schemaFile, de.getMessageObject()); if (failOnError) { throw new ConfigException(message, de); } else { logError(message); continue; } } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } Message message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_LDAP_SYNTAX.get( schemaFile, v.getValue().toString() + ": " + getExceptionMessage(e)); if (failOnError) { throw new ConfigException(message, e); } else { logError(message); continue; } } // Register it with the schema. We will allow duplicates, with the // later definition overriding any earlier definition, but we want // to trap them and log a warning. try { schema.registerLdapSyntaxDescription( syntaxDescription, failOnError); } catch (DirectoryException de) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, de); } Message message = WARN_CONFIG_SCHEMA_CONFLICTING_LDAP_SYNTAX.get( schemaFile, de.getMessageObject()); logError(message); try { schema.registerLdapSyntaxDescription(syntaxDescription, true); } catch (Exception e) { // This should never happen. if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } } } } } } return mods; } @@ -1369,13 +1506,16 @@ attributeOid.equals("2.5.21.7") || attributeOid.equals("2.5.21.8") || attributeOid.equals("2.5.4.3") || attributeOid.equals("1.3.6.1.4.1.1466.101.120.16") || attributeOid.equals("attributetypes-oid") || attributeOid.equals("objectclasses-oid") || attributeOid.equals("matchingRules-oid") || attributeOid.equals("matchingRuleUse-oid") || attributeOid.equals("NameFormDescription-oid") || attributeOid.equals("dITContentRules-oid") || attributeOid.equals("dITStructureRules") attributeOid.equals("dITStructureRules") || attributeOid.equals("ldapSyntaxes-oid") ) { return true; opends/src/server/org/opends/server/schema/LDAPSyntaxDescriptionSyntax.java
@@ -22,10 +22,10 @@ * CDDL HEADER END * * * Copyright 2006-2008 Sun Microsystems, Inc. * Copyright 2006-2009 Sun Microsystems, Inc. */ package org.opends.server.schema; import org.opends.messages.Message; @@ -37,7 +37,7 @@ import org.opends.server.api.SubstringMatchingRule; import org.opends.server.config.ConfigException; import org.opends.server.core.DirectoryServer; import org.opends.messages.Message; import static org.opends.server.loggers.debug.DebugLogger.*; import org.opends.server.loggers.debug.DebugTracer; @@ -228,31 +228,18 @@ /** * Indicates whether the provided value is acceptable for use in an attribute * with this syntax. If it is not, then the reason may be appended to the * provided buffer. * * @param value The value for which to make the determination. * @param invalidReason The buffer to which the invalid reason should be * appended. * * @return <CODE>true</CODE> if the provided value is acceptable for use with * this syntax, or <CODE>false</CODE> if not. * Parse the OID and Description fields from the ldap syntaxes. */ @Override public boolean valueIsAcceptable(ByteSequence value, MessageBuilder invalidReason) private static int parseOIDAndDescription(String valueStr, StringBuilder descriptionBuffer, StringBuilder oidBuffer) throws DirectoryException { // Get string representations of the provided value using the provided form // and with all lowercase characters. String valueStr = value.toString(); String lowerStr = toLowerCase(valueStr); // We'll do this a character at a time. First, skip over any leading // whitespace. int pos = 0; int length = valueStr.length(); String lowerStr = toLowerCase(valueStr); while ((pos < length) && (valueStr.charAt(pos) == ' ')) { pos++; @@ -263,8 +250,9 @@ // This means that the value was empty or contained only whitespace. That // is illegal. invalidReason.append(ERR_ATTR_SYNTAX_ATTRSYNTAX_EMPTY_VALUE.get()); return false; Message message = ERR_ATTR_SYNTAX_ATTRSYNTAX_EMPTY_VALUE.get(); throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); } @@ -274,10 +262,11 @@ if (c != '(') { invalidReason.append( Message message = ERR_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_OPEN_PARENTHESIS.get( valueStr, (pos-1), String.valueOf(c))); return false; valueStr, (pos-1), String.valueOf(c)); throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); } @@ -291,27 +280,30 @@ { // This means that the end of the value was reached before we could find // the OID. Ths is illegal. invalidReason.append(ERR_ATTR_SYNTAX_ATTRSYNTAX_TRUNCATED_VALUE.get( valueStr)); return false; Message message = ERR_ATTR_SYNTAX_ATTRSYNTAX_TRUNCATED_VALUE.get( valueStr); throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); } int oidStartPos = pos; if (isDigit(c)) { // This must be a numeric OID. In that case, we will accept only digits // and periods, but not consecutive periods. boolean lastWasPeriod = false; while ((pos < length) && ((c = valueStr.charAt(pos++)) != ' ')) while ((pos < length) && ((c = valueStr.charAt(pos)) != ' ') && (c = valueStr.charAt(pos)) != ')') { if (c == '.') { if (lastWasPeriod) { invalidReason.append( ERR_ATTR_SYNTAX_ATTRSYNTAX_DOUBLE_PERIOD_IN_NUMERIC_OID.get( valueStr, (pos-1))); return false; Message message = ERR_ATTR_SYNTAX_ATTRTYPE_DOUBLE_PERIOD_IN_NUMERIC_OID. get(valueStr, (pos-1)); throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); } else { @@ -321,48 +313,56 @@ else if (! isDigit(c)) { // This must have been an illegal character. invalidReason.append( ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_IN_NUMERIC_OID.get( valueStr, String.valueOf(c), (pos-1))); return false; Message message = ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_IN_NUMERIC_OID. get(valueStr, String.valueOf(c), (pos-1)); throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); } else { lastWasPeriod = false; } pos++; } } else { // This must be a "fake" OID. In this case, we will only accept // alphabetic characters, numeric digits, and the hyphen. while ((pos < length) && ((c = valueStr.charAt(pos++)) != ' ')) while ((pos < length) && ((c = valueStr.charAt(pos)) != ' ') && (c=valueStr.charAt(pos))!=')') { if (isAlpha(c) || isDigit(c) || (c == '-') || ((c == '_') && DirectoryServer.allowAttributeNameExceptions())) { // This is fine. It is an acceptable character. pos++; } else { // This must have been an illegal character. invalidReason.append( ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_IN_STRING_OID.get( valueStr, String.valueOf(c), (pos-1))); return false; Message message = ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_IN_STRING_OID. get(valueStr, String.valueOf(c), (pos-1)); throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); } } } // If we're at the end of the value, then it isn't a valid attribute type // description. Otherwise, parse out the OID. if (pos >= length) { invalidReason.append(ERR_ATTR_SYNTAX_ATTRSYNTAX_TRUNCATED_VALUE.get( valueStr)); return false; Message message = ERR_ATTR_SYNTAX_ATTRSYNTAX_TRUNCATED_VALUE.get( valueStr); throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); } else { oidBuffer.append(lowerStr.substring(oidStartPos, pos)); } @@ -376,9 +376,10 @@ { // This means that the end of the value was reached before we could find // the OID. Ths is illegal. invalidReason.append(ERR_ATTR_SYNTAX_ATTRSYNTAX_TRUNCATED_VALUE.get( valueStr)); return false; Message message = ERR_ATTR_SYNTAX_ATTRSYNTAX_TRUNCATED_VALUE.get( valueStr); throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); } @@ -388,16 +389,15 @@ { if (pos < length) { invalidReason.append( Message message = ERR_ATTR_SYNTAX_ATTRSYNTAX_UNEXPECTED_CLOSE_PARENTHESIS.get( valueStr, (pos-1))); return false; valueStr, (pos-1)); throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); } return true; } // The next token must be "DESC" followed by a quoted string. String tokenName; try @@ -413,24 +413,25 @@ TRACER.debugCaught(DebugLogLevel.ERROR, e); } invalidReason.append( Message message = ERR_ATTR_SYNTAX_ATTRSYNTAX_CANNOT_READ_DESC_TOKEN.get( valueStr, pos, getExceptionMessage(e))); return false; valueStr, pos, getExceptionMessage(e)); throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); } if (! tokenName.equals("desc")) { invalidReason.append(ERR_ATTR_SYNTAX_ATTRSYNTAX_TOKEN_NOT_DESC.get( valueStr, tokenName)); return false; Message message = ERR_ATTR_SYNTAX_ATTRSYNTAX_TOKEN_NOT_DESC.get( valueStr, tokenName); throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); } // The next component must be the quoted description. try { StringBuilder descriptionBuffer = new StringBuilder(); pos = readQuotedString(valueStr, descriptionBuffer, pos); } catch (Exception e) @@ -440,13 +441,173 @@ TRACER.debugCaught(DebugLogLevel.ERROR, e); } invalidReason.append( Message message = ERR_ATTR_SYNTAX_ATTRSYNTAX_CANNOT_READ_DESC_VALUE.get( valueStr, pos, getExceptionMessage(e))); valueStr, pos, getExceptionMessage(e)); throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); } return pos; } /** * Decodes the contents of the provided byte sequence as an ldap syntax * definition according to the rules of this syntax. Note that the provided * byte sequence value does not need to be normalized (and in fact, it should * not be in order to allow the desired capitalization to be preserved). * * @param value The byte sequence containing the value * to decode (it does not need to be * normalized). * @param schema The schema to use to resolve references to * other schema elements. * @param allowUnknownElements Indicates whether to allow values that * reference a superior class or required or * optional attribute types which are not * defined in the server schema. This should * only be true when called by * {@code valueIsAcceptable}. * * @return The decoded ldapsyntax definition. * * @throws DirectoryException If the provided value cannot be decoded as an * ldapsyntax definition. */ public static LDAPSyntaxDescription decodeLDAPSyntax(ByteSequence value, Schema schema, boolean allowUnknownElements) throws DirectoryException { // Get string representations of the provided value using the provided form // and with all lowercase characters. String valueStr = value.toString(); String lowerStr = toLowerCase(valueStr); int length = valueStr.length(); StringBuilder descriptionBuffer = new StringBuilder(); StringBuilder oidBuffer = new StringBuilder(); //Retrieve the OID and Description part of the defition. int pos = parseOIDAndDescription(valueStr, descriptionBuffer,oidBuffer); String oid = oidBuffer.toString(); String description = descriptionBuffer.toString(); StringBuilder extBuffer = new StringBuilder(); //Attribute syntax which will sustitute the syntax with oid. AttributeSyntax subSyntax = null; pos = readTokenName(valueStr, extBuffer, pos); String lowerTokenName = toLowerCase(extBuffer.toString()); if(lowerTokenName.equals("x-subst")) { StringBuilder woidBuffer = new StringBuilder(); pos = readQuotedString(lowerStr, woidBuffer, pos); String syntaxOID = woidBuffer.toString(); subSyntax = schema.getSyntax(syntaxOID); if(subSyntax == null) { Message message = WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SYNTAX.get( String.valueOf(oid), syntaxOID); throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); } } else { Message message = WARN_ATTR_SYNTAX_LDAPSYNTAX_UNKNOWN_EXT.get( valueStr,lowerTokenName,pos); throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); } char c = valueStr.charAt(pos); while ((pos < length) && (c == ' ')) { pos++; } // The next character must be the closing parenthesis and there should not // be anything after it (except maybe some spaces). if ((c = valueStr.charAt(pos++)) != ')') { Message message = ERR_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_CLOSE_PARENTHESIS.get( valueStr, pos, String.valueOf(c)); throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); } while (pos < length) { c = valueStr.charAt(pos++); if (c != ' ') { Message message = ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_AFTER_CLOSE.get( valueStr, String.valueOf(c), pos); throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); } } LDAPSyntaxDescription syntaxDesc = null; //Since we reached here it means everything is OK. if(subSyntax !=null) { //A SubstitutionSyntax is requested. syntaxDesc = new LDAPSyntaxDescription(valueStr, new SubstitutionSyntax(subSyntax,description,oid), description,null); } return syntaxDesc; } /** * Indicates whether the provided value is acceptable for use in an attribute * with this syntax. If it is not, then the reason may be appended to the * provided buffer. * * @param value The value for which to make the determination. * @param invalidReason The buffer to which the invalid reason should be * appended. * * @return <CODE>true</CODE> if the provided value is acceptable for use with * this syntax, or <CODE>false</CODE> if not. */ @Override public boolean valueIsAcceptable(ByteSequence value, MessageBuilder invalidReason) { // Get string representations of the provided value using the provided form // and with all lowercase characters. String valueStr = value.toString(); StringBuilder descriptionBuffer = new StringBuilder(); StringBuilder oidBuffer = new StringBuilder(); int length = valueStr.length(); int pos = 0; try { pos = parseOIDAndDescription(valueStr, descriptionBuffer,oidBuffer); } catch(DirectoryException de) { invalidReason.append(de.getMessageObject()); return false; } char c = valueStr.charAt(pos); //Check if we have a RFC 4512 style extension. if ((c = valueStr.charAt(pos)) != ')') if (c != ')') { try { pos=parseExtension(valueStr, pos); @@ -724,5 +885,148 @@ { return false; } /** * This class provides a substitution mechanism where one unimplemented * syntax can be substituted by another defined syntax. A substitution syntax * is an LDAPSyntaxDescriptionSyntax with X-SUBST extension. */ private static class SubstitutionSyntax extends LDAPSyntaxDescriptionSyntax { // The syntax that will subsittute the unimplemented syntax. private AttributeSyntax subSyntax; // The description of this syntax. private String description; //The oid of this syntax. private String oid; //Creates a new instance of this syntax. private SubstitutionSyntax(AttributeSyntax subSyntax, String description, String oid) { super(); this.subSyntax = subSyntax; this.description = description; this.oid = oid; } /** * {@inheritDoc} */ @Override public String getSyntaxName() { // There is no name for a substitution syntax. return null; } /** * {@inheritDoc} */ @Override public String getOID() { return oid; } /** * {@inheritDoc} */ @Override public String getDescription() { return description; } /** * {@inheritDoc} */ @Override public boolean valueIsAcceptable(ByteSequence value, MessageBuilder invalidReason) { return subSyntax.valueIsAcceptable(value, invalidReason); } /** * Retrieves the default equality matching rule that will be used for * attributes with this syntax. * * @return The default equality matching rule that will be used for * attributes with this syntax, or <CODE>null</CODE> if equality * matches will not be allowed for this type by default. */ @Override public EqualityMatchingRule getEqualityMatchingRule() { return subSyntax.getEqualityMatchingRule(); } /** * Retrieves the default ordering matching rule that will be used for * attributes with this syntax. * * @return The default ordering matching rule that will be used for * attributes with this syntax, or <CODE>null</CODE> if ordering * matches will not be allowed for this type by default. */ @Override public OrderingMatchingRule getOrderingMatchingRule() { return subSyntax.getOrderingMatchingRule(); } /** * Retrieves the default substring matching rule that will be used for * attributes with this syntax. * * @return The default substring matching rule that will be used for * attributes with this syntax, or <CODE>null</CODE> if substring * matches will not be allowed for this type by default. */ @Override public SubstringMatchingRule getSubstringMatchingRule() { return subSyntax.getSubstringMatchingRule(); } /** * Retrieves the default approximate matching rule that will be used for * attributes with this syntax. * * @return The default approximate matching rule that will be used for * attributes with this syntax, or <CODE>null</CODE> if approximate * matches will not be allowed for this type by default. */ @Override public ApproximateMatchingRule getApproximateMatchingRule() { return subSyntax.getApproximateMatchingRule(); } } } opends/src/server/org/opends/server/types/Entry.java
@@ -1659,6 +1659,17 @@ return allSuccessful; } AttributeType ldapSyntaxType = DirectoryServer.getAttributeType(ATTR_LDAP_SYNTAXES_LC, true); if (attribute.getAttributeType().equals(ldapSyntaxType)) { // This is tricky as ldapsyntaxes type is part real and part // virtual. Don't do anything here and let the backend take // care of it. return true; } AttributeType attributeType = attribute.getAttributeType(); List<Attribute> attributes; opends/src/server/org/opends/server/types/LDAPSyntaxDescription.java
New file @@ -0,0 +1,467 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2009 Sun Microsystems, Inc. */ package org.opends.server.types; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.opends.server.schema.LDAPSyntaxDescriptionSyntax; import static org.opends.server.util.ServerConstants.*; import static org.opends.server.util.Validator.*; /** * This class defines a data structure for storing and interacting * with an ldap syntax, which defines the custom ldap syntaxes. */ @org.opends.server.types.PublicAPI( stability=org.opends.server.types.StabilityLevel.UNCOMMITTED, mayInstantiate=false, mayExtend=false, mayInvoke=true) public final class LDAPSyntaxDescription implements SchemaFileElement { // The set of additional name-value pairs associated with this ldap // syntax definition. private final Map<String,List<String>> extraProperties; // The definition string used to create this ldap syntax //description. private final String definition; // The description for this ldap syntax description. private final String description; // The OID of the enclosed ldap syntax description. private final String oid; //The LDAPSyntaxDescritpionSyntax associated with this ldap syntax. private LDAPSyntaxDescriptionSyntax descriptionSyntax; /** * Creates a new ldap syntax definition with the provided * information. * * @param definition The definition string used to create * this ldap syntax. It must not be * {@code null}. * @param descriptionSyntax The ldap syntax description syntax * associated with this ldap syntax. * @param description The description for this ldap * syntax. * @param extraProperties A set of extra properties for this * ldap syntax description. */ public LDAPSyntaxDescription(String definition, LDAPSyntaxDescriptionSyntax descriptionSyntax, String description, Map<String,List<String>> extraProperties) { ensureNotNull(definition,descriptionSyntax); this.descriptionSyntax = descriptionSyntax; this.oid = descriptionSyntax.getOID(); this.description = description; int schemaFilePos = definition.indexOf(SCHEMA_PROPERTY_FILENAME); if (schemaFilePos > 0) { String defStr; try { int firstQuotePos = definition.indexOf('\'', schemaFilePos); int secondQuotePos = definition.indexOf('\'', firstQuotePos+1); defStr = definition.substring(0, schemaFilePos).trim() + " " + definition.substring(secondQuotePos+1).trim(); } catch (Exception e) { defStr = definition; } this.definition = defStr; } else { this.definition = definition; } if ((extraProperties == null) || extraProperties.isEmpty()) { this.extraProperties = new LinkedHashMap<String,List<String>>(0); } else { this.extraProperties = new LinkedHashMap<String,List<String>>(extraProperties); } } /** * Retrieves the definition string used to create this ldap syntax * description. * * @return The definition string used to create this ldap syntax * description. */ public String getDefinition() { return definition; } /** * Retrieves the ldap syntax description syntax associated with * this ldap syntax. * * @return The description syntax for this defition. */ public LDAPSyntaxDescriptionSyntax getLdapSyntaxDescriptionSyntax() { return descriptionSyntax; } /** * Creates a new instance of this ldap syntax based on the * definition string. It will also preserve other state * information associated with this ldap syntax that is not * included in the definition string (e.g., the name of the schema * file with which it is associated). * * @return The new instance of this ldap syntax based on the * definition string. * * @throws DirectoryException If a problem occurs while * attempting to create a new ldap * syntax instance from the definition * string. */ public LDAPSyntaxDescription recreateFromDefinition() throws DirectoryException { ByteString value = ByteString.valueOf(definition); Schema schema = DirectoryConfig.getSchema(); LDAPSyntaxDescription ls = LDAPSyntaxDescriptionSyntax.decodeLDAPSyntax(value, schema, false); ls.setSchemaFile(getSchemaFile()); return ls; } /** * Retrieves the path to the schema file that contains the * definition for this ldap syntax description. * * @return The path to the schema file that contains the * definition for this ldap syntax description, or * {@code null} if it is not known or if it is not stored * in any schema file. */ public String getSchemaFile() { List<String> values = extraProperties.get(SCHEMA_PROPERTY_FILENAME); if ((values == null) || values.isEmpty()) { return null; } return values.get(0); } /** * Specifies the path to the schema file that contains the * definition for this ldap syntax description. * * @param schemaFile The path to the schema file that contains * the definition for this ldap syntax description. */ public void setSchemaFile(String schemaFile) { setExtraProperty(SCHEMA_PROPERTY_FILENAME, schemaFile); } /** * Retrieves the description for this ldap syntax description. * * @return The description for this ldap syntax description, or * {@code true} if there is none. */ public String getDescription() { return description; } /** * Retrieves a mapping between the names of any extra non-standard * properties that may be associated with this ldap syntax * description and the value for that property. * * @return A mapping between the names of any extra non-standard * properties that may be associated with this ldap syntax * description and the value for that property. */ public Map<String,List<String>> getExtraProperties() { return extraProperties; } /** * Retrieves the value of the specified "extra" property for this * ldap syntax description. * * @param propertyName The name of the "extra" property for which * to retrieve the value. * * @return The value of the specified "extra" property for this * ldap syntax description, or {@code null} if no such * property is defined. */ public List<String> getExtraProperty(String propertyName) { return extraProperties.get(propertyName); } /** * Specifies the provided "extra" property for this ldap syntax * description. * * @param name The name for the "extra" property. It must not * be {@code null}. * @param value The value for the "extra" property, or * {@code null} if the property is to be removed. */ public void setExtraProperty(String name, String value) { ensureNotNull(name); if (value == null) { extraProperties.remove(name); } else { LinkedList<String> values = new LinkedList<String>(); values.add(value); extraProperties.put(name, values); } } /** * Specifies the provided "extra" property for this ldap syntax * description. * * @param name The name for the "extra" property. It must not * be {@code null}. * @param values The set of value for the "extra" property, or * {@code null} if the property is to be removed. */ public void setExtraProperty(String name, List<String> values) { ensureNotNull(name); if ((values == null) || values.isEmpty()) { extraProperties.remove(name); } else { LinkedList<String> valuesCopy = new LinkedList<String>(values); extraProperties.put(name, valuesCopy); } } /** * Indicates whether the provided object is equal to this ldap * syntax. The object will be considered equal if it is a ldap * syntax with the same OID as the current ldap syntax description. * * @param o The object for which to make the determination. * * @return {@code true} if the provided object is equal to this * ldap syntax description, or {@code true} if not. */ @Override public boolean equals(Object o) { if (this == o) { return true; } if ((o == null) || (! (o instanceof LDAPSyntaxDescription))) { return false; } return oid.equals(((LDAPSyntaxDescription) o).oid); } /** * Retrieves the hash code for this ldap syntax description. It * will be based on the sum of the bytes of the OID. * * @return The hash code for this ldap syntax description. */ @Override public int hashCode() { int oidLength = oid.length(); int hashCode = 0; for (int i=0; i < oidLength; i++) { hashCode += oid.charAt(i); } return hashCode; } /** * Retrieves the string representation of this ldap syntax * description in the form specified in RFC 2252. * * @return The string representation of this ldap syntax in the * form specified in RFC 2252. */ @Override public String toString() { StringBuilder buffer = new StringBuilder(); toString(buffer, true); return buffer.toString(); } /** * Appends a string representation of this ldap syntax in the form * specified in RFC 2252 to the provided buffer. * * @param buffer The buffer to which the information * should be appended. * @param includeFileElement Indicates whether to include an * "extra" property that specifies the * path to the schema file from which * this ldap syntax was loaded. */ public void toString(StringBuilder buffer, boolean includeFileElement) { buffer.append("( "); buffer.append(oid); if ((description != null) && (description.length() > 0)) { buffer.append(" DESC '"); buffer.append(description); buffer.append("'"); } if (! extraProperties.isEmpty()) { for (String property : extraProperties.keySet()) { if ((! includeFileElement) && property.equals(SCHEMA_PROPERTY_FILENAME)) { continue; } List<String> valueList = extraProperties.get(property); buffer.append(" "); buffer.append(property); if (valueList.size() == 1) { buffer.append(" '"); buffer.append(valueList.get(0)); buffer.append("'"); } else { buffer.append(" ( "); for (String value : valueList) { buffer.append("'"); buffer.append(value); buffer.append("' "); } buffer.append(")"); } } } buffer.append(" )"); } } opends/src/server/org/opends/server/types/Schema.java
@@ -190,6 +190,11 @@ // names/OID and the name form itself. private ConcurrentHashMap<String,NameForm> nameFormsByName; // The set of ldap syntax descriptions for this schema, mapped // the OID and the ldap syntax description itself. private ConcurrentHashMap<String,LDAPSyntaxDescription> ldapSyntaxDescriptions; // The set of pre-encoded attribute syntax representations. private LinkedHashSet<AttributeValue> syntaxSet; @@ -263,6 +268,8 @@ nameFormsByOC = new ConcurrentHashMap<ObjectClass,List<NameForm>>(); nameFormsByName = new ConcurrentHashMap<String,NameForm>(); ldapSyntaxDescriptions = new ConcurrentHashMap<String,LDAPSyntaxDescription>(); subordinateTypes = new ConcurrentHashMap<AttributeType,List<AttributeType>>(); @@ -906,6 +913,145 @@ /** * Retrieves the ldap syntax definitions for this schema, as a * mapping between the OID for the syntax and the ldap syntax * defition itself. Each ldap syntax should only be present once, * since its only key is its OID. The contents of the returned * mapping must not be altered. * * @return The ldap syntax definitions for this schema. */ public ConcurrentHashMap<String,LDAPSyntaxDescription> getLdapSyntaxDescriptions() { return ldapSyntaxDescriptions; } /** * Indicates whether this schema definition includes an ldap * syntax description with the provided name or OID. * * @param lowerName The OID for which to make the * determination, formatted in all lowercase * characters. * * @return {@code true} if this schema contains an ldap syntax * with the provided name or OID, or {@code false} if not. */ public boolean hasLdapSyntaxDescription(String lowerName) { return ldapSyntaxDescriptions.containsKey(lowerName); } /** * Retrieves the ldap syntax definition with the OID. * * @param lowerName The OID of the ldap syntax to retrieve, * formatted in all lowercase characters. * * @return The requested ldap syntax, or <CODE>null</CODE> if * no syntax is registered with the provided OID. */ public LDAPSyntaxDescription getLdapSyntaxDescription( String lowerName) { return ldapSyntaxDescriptions.get(lowerName); } /** * Registers the provided ldap syntax description with this * schema. * * @param syntax The ldap syntax description to register * with this schema. * @param overwriteExisting Indicates whether to overwrite an * existing mapping if there are any * conflicts (i.e., another ldap * syntax with the same OID). * * @throws DirectoryException If a conflict is encountered and * <CODE>overwriteExisting</CODE> flag * is set to <CODE>false</CODE> */ public void registerLdapSyntaxDescription( LDAPSyntaxDescription syntax, boolean overwriteExisting) throws DirectoryException { /** * ldapsyntaxes is part real and part virtual. For any * ldapsyntaxes attribute this is real, an LDAPSyntaxDescription * object is created and stored with the schema. Also, the * associated LDAPSyntaxDescriptionSyntax is added into the * virtual syntax set to make this available through virtual * ldapsyntaxes attribute. */ synchronized (ldapSyntaxDescriptions) { String oid = toLowerCase( syntax.getLdapSyntaxDescriptionSyntax().getOID()); if (! overwriteExisting) { if (ldapSyntaxDescriptions.containsKey(oid)) { Message message = ERR_SCHEMA_MODIFY_MULTIPLE_CONFLICTS_FOR_ADD_LDAP_SYNTAX. get(oid); throw new DirectoryException( ResultCode.CONSTRAINT_VIOLATION, message); } } ldapSyntaxDescriptions.put(oid, syntax); //Register the attribute syntax with the schema. It will ensure // syntax is available along with the other virtual values for // ldapsyntaxes. registerSyntax(syntax.getLdapSyntaxDescriptionSyntax(), overwriteExisting); } } /** * Deregisters the provided ldap syntax description with this * schema. * * @param syntax The ldap syntax to deregister with this * schema. */ public void deregisterLdapSyntaxDescription( LDAPSyntaxDescription syntax) { synchronized (ldapSyntaxDescriptions) { //Remove the real value. ldapSyntaxDescriptions.remove( toLowerCase(syntax.getLdapSyntaxDescriptionSyntax().getOID()), syntax); try { //Get rid of this from the virtual ldapsyntaxes. deregisterSyntax(syntax.getLdapSyntaxDescriptionSyntax()); } catch (Exception e) { deregisterSyntax(syntax.getLdapSyntaxDescriptionSyntax()); } } } /** * Retrieves the entire set of matching rule definitions for this * schema, as a mapping between the lowercase names and OIDs for the * matching rule and the matching rule itself. Each matching rule @@ -3173,6 +3319,7 @@ ditStructureRulesByNameForm); dupSchema.nameFormsByOC.putAll(nameFormsByOC); dupSchema.nameFormsByName.putAll(nameFormsByName); dupSchema.ldapSyntaxDescriptions.putAll(ldapSyntaxDescriptions); dupSchema.syntaxSet.addAll(syntaxSet); dupSchema.attributeTypeSet.addAll(attributeTypeSet); dupSchema.ditContentRuleSet.addAll(ditContentRuleSet); opends/tests/unit-tests-testng/src/server/org/opends/server/schema/LDAPSyntaxTest.java
@@ -22,12 +22,30 @@ * CDDL HEADER END * * * Copyright 2006-2008 Sun Microsystems, Inc. * Copyright 2006-2009 Sun Microsystems, Inc. */ package org.opends.server.schema; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import org.opends.server.TestCaseUtils; import org.opends.server.api.AttributeSyntax; import org.opends.server.core.DirectoryServer; import org.opends.server.protocols.internal.InternalClientConnection; import org.opends.server.protocols.internal.InternalSearchOperation; import org.opends.server.protocols.ldap.LDAPFilter; import org.opends.server.types.Attribute; import org.opends.server.types.AttributeValue; import org.opends.server.types.ByteString; import org.opends.server.types.DereferencePolicy; import org.opends.server.types.ResultCode; import org.opends.server.types.SearchResultEntry; import org.opends.server.types.SearchScope; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static org.testng.Assert.*; /** * Test the LDAPSyntaxDescriptionSyntax. @@ -113,4 +131,239 @@ }; } /** * Tests whether an implemented syntax can't be substituted by another. */ @Test() public void testSubstitutionSyntaxForInvalidSubstitution() throws Exception { try { //Test if we can substitute a directory string syntax by itself. int resultCode = TestCaseUtils.applyModifications(true, "dn: cn=schema", "changetype: modify", "add: ldapsyntaxes", "ldapsyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.15 " + "DESC 'Replacing DirectorySyntax' " + " X-SUBST '1.3.6.1.4.1.1466.115.121.1.15' )"); //This is not expected to happen assertFalse(resultCode==0); //Test if we can substitute a directory string syntax by an undefined. resultCode = TestCaseUtils.applyModifications(true, "dn: cn=schema", "changetype: modify", "add: ldapsyntaxes", "ldapsyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.15 " + "DESC 'Replacing DirectorySyntax' " + " X-SUBST '1.1.1' )"); //This is not expected to happen assertFalse(resultCode==0); //Test if we can substitute a core syntax with a user-defined //syntax addSubtitutionSyntax(); //Replace the IA5Stringsyntax with the custom syntax we just created. resultCode = TestCaseUtils.applyModifications(true, "dn: cn=schema", "changetype: modify", "add: ldapsyntaxes", "ldapsyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.26 " + "DESC 'Replacing DirectorySyntax' " + " X-SUBST '9.9.9' )"); //This is not expected to happen assertFalse(resultCode==0); } finally { deleteSubstitutionSyntax(); } } /** * Tests whether both the virtual and the newly added real substitution * sytanx are available when a search is made for ldapsyntaxes attribute. * * @throws java.lang.Exception */ @Test() public void testSubstitutionSyntaxSearch() throws Exception { try { addSubtitutionSyntax(); InternalClientConnection conn = InternalClientConnection.getRootConnection(); LinkedHashSet<String> attrList = new LinkedHashSet<String>(); attrList.add("ldapsyntaxes"); InternalSearchOperation searchOperation = new InternalSearchOperation( conn, InternalClientConnection.nextOperationID(), InternalClientConnection.nextMessageID(), null, ByteString.valueOf("cn=schema"), SearchScope.WHOLE_SUBTREE, DereferencePolicy.NEVER_DEREF_ALIASES, Integer.MAX_VALUE, Integer.MAX_VALUE, false, LDAPFilter.decode("objectclass=ldapsubentry"), attrList, null); searchOperation.run(); assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS); List<SearchResultEntry> entries = searchOperation.getSearchEntries(); SearchResultEntry e = entries.get(0); //An entry must be returned. assertNotNull(e); Attribute attr = e.getAttribute("ldapsyntaxes").get(0); Iterator<AttributeValue> iter = attr.iterator(); //There are other ways of doing it but we will extract the OID //from the attribute values and then check to see if our //OID is found in the result set or not. List<String> syntaxList = new ArrayList<String>(); while(iter.hasNext()) { AttributeValue val = iter.next(); //parse the OIDs. syntaxList.add(getOIDFromLdapSyntax(val.toString())); } assertTrue(syntaxList.size() == DirectoryServer.getAttributeSyntaxSet().size() ) ; //Check if we find our OID. assertTrue(syntaxList.contains("9.9.9")); //DirectoryString. assertTrue(syntaxList.contains("1.3.6.1.4.1.1466.115.121.1.15")); //IA5String. assertTrue(syntaxList.contains("1.3.6.1.4.1.1466.115.121.1.26")); } finally { deleteSubstitutionSyntax(); } } /** * Tests whether it is possible to add values after an umimplemented syntax * has been subsitutited by DirectoryString syntax. * * @throws java.lang.Exception */ public void testSubsitutionSyntaxAddValues() throws Exception { try { addSubtitutionSyntax(); //Add an attribute with undefined syntax. int resultCode = TestCaseUtils.applyModifications(true, "dn: cn=schema", "changetype: modify", "add: attributetypes", "attributetypes: ( test-oid NAME 'test-attr' SYNTAX 9.9.9 )", "-", "add: objectclasses", "objectclasses: ( oc-oid NAME 'testOC' SUP top AUXILIARY MUST test-attr)" ); assertTrue(resultCode == 0); TestCaseUtils.initializeTestBackend(true); TestCaseUtils.addEntry( "dn: cn=syntax-test,o=test", "objectclass: person", "objectclass: testOC", "cn: syntax-test", "sn: xyz", "test-attr: test value for unimplemented syntax"); } finally { deleteSubstitutionSyntax(); } } //Parses the OID from the syntax defitions. private String getOIDFromLdapSyntax(String valueStr) { int pos = 0; int length = valueStr.length(); while ((pos < length) && (valueStr.charAt(pos) == ' ')) { pos++; } // The next character must be an open parenthesis. If it is not, then that // is an error. char c = valueStr.charAt(pos++); // Skip over any spaces immediately following the opening parenthesis. while ((pos < length) && ((c = valueStr.charAt(pos)) == ' ')) { pos++; } int oidStartPos = pos; boolean lastWasPeriod = false; while ((pos < length) && ((c = valueStr.charAt(pos)) != ' ') && (c = valueStr.charAt(pos)) != ')') { if (c == '.') { lastWasPeriod = true; } else { lastWasPeriod = false; } pos++; } return valueStr.substring(oidStartPos, pos); } //Adds a substitutionsyntax to the schema. private void addSubtitutionSyntax() throws Exception { //Add the substitution syntax for an unimplemented syntax. int resultCode = TestCaseUtils.applyModifications(true, "dn: cn=schema", "changetype: modify", "add: ldapsyntaxes", "ldapsyntaxes: ( 9.9.9 DESC 'Unimplemented Syntax' " + " X-SUBST '1.3.6.1.4.1.1466.115.121.1.15' )"); assertTrue(resultCode==0); } //Deletes the substitutionSyntax from the schema. private void deleteSubstitutionSyntax() throws Exception { //delete the substitution syntax. int resultCode = TestCaseUtils.applyModifications(true, "dn: cn=schema", "changetype: modify", "delete: ldapsyntaxes", "ldapsyntaxes: ( 9.9.9 DESC 'Unimplemented Syntax' " + " X-SUBST '1.3.6.1.4.1.1466.115.121.1.15' )"); assertTrue(resultCode==0); } }