| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Portions Copyright 2006 Sun Microsystems, Inc. |
| | | * Portions Copyright 2006-2007 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.backends; |
| | | |
| | |
| | | import java.io.FileInputStream; |
| | | import java.io.FileOutputStream; |
| | | import java.io.InputStream; |
| | | import java.io.IOException; |
| | | import java.io.OutputStream; |
| | | import java.security.MessageDigest; |
| | | import java.util.ArrayList; |
| | |
| | | import java.util.LinkedHashSet; |
| | | import java.util.LinkedList; |
| | | import java.util.List; |
| | | import java.util.Set; |
| | | import java.util.TreeSet; |
| | | import java.util.zip.Deflater; |
| | | import java.util.zip.ZipEntry; |
| | | import java.util.zip.ZipInputStream; |
| | |
| | | import javax.crypto.CipherOutputStream; |
| | | import javax.crypto.Mac; |
| | | |
| | | import org.opends.server.api.AlertGenerator; |
| | | import org.opends.server.api.Backend; |
| | | import org.opends.server.api.ConfigurableComponent; |
| | | import org.opends.server.api.MatchingRule; |
| | | import org.opends.server.config.BooleanConfigAttribute; |
| | | import org.opends.server.config.ConfigAttribute; |
| | | import org.opends.server.config.ConfigEntry; |
| | |
| | | import org.opends.server.core.SchemaConfigManager; |
| | | import org.opends.server.core.SearchOperation; |
| | | import org.opends.server.schema.AttributeTypeSyntax; |
| | | import org.opends.server.schema.DITContentRuleSyntax; |
| | | import org.opends.server.schema.DITStructureRuleSyntax; |
| | | import org.opends.server.schema.MatchingRuleUseSyntax; |
| | | import org.opends.server.schema.NameFormSyntax; |
| | | import org.opends.server.schema.ObjectClassSyntax; |
| | | import org.opends.server.types.Attribute; |
| | | import org.opends.server.types.AttributeType; |
| | |
| | | import org.opends.server.types.ConfigChangeResult; |
| | | import org.opends.server.types.CryptoManager; |
| | | import org.opends.server.types.DirectoryException; |
| | | import org.opends.server.types.DITContentRule; |
| | | import org.opends.server.types.DITStructureRule; |
| | | import org.opends.server.types.DN; |
| | | import org.opends.server.types.Entry; |
| | | import org.opends.server.types.ErrorLogCategory; |
| | |
| | | import org.opends.server.types.InitializationException; |
| | | import org.opends.server.types.LDIFImportConfig; |
| | | import org.opends.server.types.LDIFExportConfig; |
| | | import org.opends.server.types.MatchingRuleUse; |
| | | import org.opends.server.types.Modification; |
| | | import org.opends.server.types.ModificationType; |
| | | import org.opends.server.types.NameForm; |
| | | import org.opends.server.types.ObjectClass; |
| | | import org.opends.server.types.ObjectClassType; |
| | | import org.opends.server.types.RDN; |
| | | import org.opends.server.types.RestoreConfig; |
| | | import org.opends.server.types.ResultCode; |
| | | import org.opends.server.types.Schema; |
| | | import org.opends.server.types.SchemaFileElement; |
| | | import org.opends.server.types.SearchFilter; |
| | | import org.opends.server.types.SearchScope; |
| | | import org.opends.server.util.DynamicConstants; |
| | | import org.opends.server.util.LDIFReader; |
| | | import org.opends.server.util.LDIFException; |
| | | import org.opends.server.util.LDIFWriter; |
| | | |
| | | import static org.opends.server.config.ConfigConstants.*; |
| | |
| | | */ |
| | | public class SchemaBackend |
| | | extends Backend |
| | | implements ConfigurableComponent |
| | | implements ConfigurableComponent, AlertGenerator |
| | | { |
| | | /** |
| | | * The fully-qualified name of this class for debugging purposes. |
| | |
| | | // elements, nor will we allow modification of any other attributes. Make |
| | | // sure that the included modify operation is acceptable within these |
| | | // constraints. |
| | | List<Modification> mods = modifyOperation.getModifications(); |
| | | ArrayList<Modification> mods = |
| | | new ArrayList<Modification>(modifyOperation.getModifications()); |
| | | if (mods.isEmpty()) |
| | | { |
| | | // There aren't any modifications, so we don't need to do anything. |
| | |
| | | } |
| | | |
| | | Schema newSchema = DirectoryServer.getSchema().duplicate(); |
| | | LinkedList<AttributeType> newAttrTypes = new LinkedList<AttributeType>(); |
| | | LinkedList<ObjectClass> newObjectClasses = new LinkedList<ObjectClass>(); |
| | | TreeSet<String> modifiedSchemaFiles = new TreeSet<String>(); |
| | | LinkedHashSet<SchemaFileElement> dependentElements = |
| | | new LinkedHashSet<SchemaFileElement>(); |
| | | |
| | | int pos = -1; |
| | | for (Modification m : mods) |
| | | { |
| | | pos++; |
| | | |
| | | if (m.isInternal()) |
| | | { |
| | | // We don't need to do anything for internal modifications (e.g., like |
| | |
| | | continue; |
| | | } |
| | | |
| | | |
| | | // Determine the type of modification to perform. We will support add and |
| | | // delete operations in the schema, and we will also support the ability |
| | | // to add a schema element that already exists and treat it as a |
| | | // replacement of that existing element. |
| | | Attribute a = m.getAttribute(); |
| | | AttributeType at = a.getAttributeType(); |
| | | switch (m.getModificationType()) |
| | | { |
| | | case ADD: |
| | | // This is fine, as long as there aren't any conflicts later. |
| | | LinkedHashSet<AttributeValue> values = a.getValues(); |
| | | if (values.isEmpty()) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | if (at.equals(attributeTypesType)) |
| | | { |
| | | for (AttributeValue v : values) |
| | | { |
| | | AttributeType type; |
| | | try |
| | | { |
| | | type = AttributeTypeSyntax.decodeAttributeType(v.getValue(), |
| | | newSchema); |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | | assert debugException(CLASS_NAME, "replaceEntry", de); |
| | | |
| | | int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_ATTRTYPE; |
| | | String message = getMessage(msgID, v.getStringValue(), |
| | | de.getErrorMessage()); |
| | | throw new DirectoryException( |
| | | ResultCode.INVALID_ATTRIBUTE_SYNTAX, message, |
| | | msgID, de); |
| | | } |
| | | |
| | | addAttributeType(type, newSchema, modifiedSchemaFiles); |
| | | } |
| | | } |
| | | else if (at.equals(objectClassesType)) |
| | | { |
| | | for (AttributeValue v : values) |
| | | { |
| | | ObjectClass oc; |
| | | try |
| | | { |
| | | oc = ObjectClassSyntax.decodeObjectClass(v.getValue(), |
| | | newSchema); |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | | assert debugException(CLASS_NAME, "replaceEntry", de); |
| | | |
| | | int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_OBJECTCLASS; |
| | | String message = getMessage(msgID, v.getStringValue(), |
| | | de.getErrorMessage()); |
| | | throw new DirectoryException( |
| | | ResultCode.INVALID_ATTRIBUTE_SYNTAX, message, |
| | | msgID, de); |
| | | } |
| | | |
| | | addObjectClass(oc, newSchema, modifiedSchemaFiles); |
| | | } |
| | | } |
| | | else if (at.equals(nameFormsType)) |
| | | { |
| | | for (AttributeValue v : values) |
| | | { |
| | | NameForm nf; |
| | | try |
| | | { |
| | | nf = NameFormSyntax.decodeNameForm(v.getValue(), newSchema); |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | | assert debugException(CLASS_NAME, "replaceEntry", de); |
| | | |
| | | int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_NAME_FORM; |
| | | String message = getMessage(msgID, v.getStringValue(), |
| | | de.getErrorMessage()); |
| | | throw new DirectoryException( |
| | | ResultCode.INVALID_ATTRIBUTE_SYNTAX, message, |
| | | msgID, de); |
| | | } |
| | | |
| | | addNameForm(nf, newSchema, modifiedSchemaFiles); |
| | | } |
| | | } |
| | | else if (at.equals(ditContentRulesType)) |
| | | { |
| | | for (AttributeValue v : values) |
| | | { |
| | | DITContentRule dcr; |
| | | try |
| | | { |
| | | dcr = DITContentRuleSyntax.decodeDITContentRule(v.getValue(), |
| | | newSchema); |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | | assert debugException(CLASS_NAME, "replaceEntry", de); |
| | | |
| | | int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_DCR; |
| | | String message = getMessage(msgID, v.getStringValue(), |
| | | de.getErrorMessage()); |
| | | throw new DirectoryException( |
| | | ResultCode.INVALID_ATTRIBUTE_SYNTAX, message, |
| | | msgID, de); |
| | | } |
| | | |
| | | addDITContentRule(dcr, newSchema, modifiedSchemaFiles); |
| | | } |
| | | } |
| | | else if (at.equals(ditStructureRulesType)) |
| | | { |
| | | for (AttributeValue v : values) |
| | | { |
| | | DITStructureRule dsr; |
| | | try |
| | | { |
| | | dsr = DITStructureRuleSyntax.decodeDITStructureRule( |
| | | v.getValue(), newSchema, false); |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | | assert debugException(CLASS_NAME, "replaceEntry", de); |
| | | |
| | | int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_DSR; |
| | | String message = getMessage(msgID, v.getStringValue(), |
| | | de.getErrorMessage()); |
| | | throw new DirectoryException( |
| | | ResultCode.INVALID_ATTRIBUTE_SYNTAX, message, |
| | | msgID, de); |
| | | } |
| | | |
| | | addDITStructureRule(dsr, newSchema, modifiedSchemaFiles); |
| | | } |
| | | } |
| | | else if (at.equals(matchingRuleUsesType)) |
| | | { |
| | | for (AttributeValue v : values) |
| | | { |
| | | MatchingRuleUse mru; |
| | | try |
| | | { |
| | | mru = MatchingRuleUseSyntax.decodeMatchingRuleUse(v.getValue(), |
| | | newSchema); |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | | assert debugException(CLASS_NAME, "replaceEntry", de); |
| | | |
| | | int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_MR_USE; |
| | | String message = getMessage(msgID, v.getStringValue(), |
| | | de.getErrorMessage()); |
| | | throw new DirectoryException( |
| | | ResultCode.INVALID_ATTRIBUTE_SYNTAX, message, |
| | | msgID, de); |
| | | } |
| | | |
| | | addMatchingRuleUse(mru, newSchema, modifiedSchemaFiles); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_UNSUPPORTED_ATTRIBUTE_TYPE; |
| | | String message = getMessage(msgID, a.getName()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, |
| | | message, msgID); |
| | | } |
| | | |
| | | break; |
| | | |
| | | |
| | | case DELETE: |
| | | // FIXME -- We need to support this. |
| | | int msgID = MSGID_SCHEMA_DELETE_MODTYPE_NOT_SUPPORTED; |
| | | String message = getMessage(msgID); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | values = a.getValues(); |
| | | if (values.isEmpty()) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_DELETE_NO_VALUES; |
| | | String message = getMessage(msgID, a.getName()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, |
| | | message, msgID); |
| | | } |
| | | |
| | | case REPLACE: |
| | | // FIXME -- Should we support this? |
| | | case INCREMENT: |
| | | if (at.equals(attributeTypesType)) |
| | | { |
| | | for (AttributeValue v : values) |
| | | { |
| | | AttributeType type; |
| | | try |
| | | { |
| | | type = AttributeTypeSyntax.decodeAttributeType(v.getValue(), |
| | | newSchema); |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | | assert debugException(CLASS_NAME, "replaceEntry", de); |
| | | |
| | | int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_ATTRTYPE; |
| | | String message = getMessage(msgID, v.getStringValue(), |
| | | de.getErrorMessage()); |
| | | throw new DirectoryException( |
| | | ResultCode.INVALID_ATTRIBUTE_SYNTAX, message, |
| | | msgID, de); |
| | | } |
| | | |
| | | removeAttributeType(type, newSchema, mods, pos, |
| | | modifiedSchemaFiles); |
| | | } |
| | | } |
| | | else if (at.equals(objectClassesType)) |
| | | { |
| | | for (AttributeValue v : values) |
| | | { |
| | | ObjectClass oc; |
| | | try |
| | | { |
| | | oc = ObjectClassSyntax.decodeObjectClass(v.getValue(), |
| | | newSchema); |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | | assert debugException(CLASS_NAME, "replaceEntry", de); |
| | | |
| | | int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_OBJECTCLASS; |
| | | String message = getMessage(msgID, v.getStringValue(), |
| | | de.getErrorMessage()); |
| | | throw new DirectoryException( |
| | | ResultCode.INVALID_ATTRIBUTE_SYNTAX, message, |
| | | msgID, de); |
| | | } |
| | | |
| | | removeObjectClass(oc, newSchema, mods, pos, modifiedSchemaFiles); |
| | | } |
| | | } |
| | | else if (at.equals(nameFormsType)) |
| | | { |
| | | for (AttributeValue v : values) |
| | | { |
| | | NameForm nf; |
| | | try |
| | | { |
| | | nf = NameFormSyntax.decodeNameForm(v.getValue(), newSchema); |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | | assert debugException(CLASS_NAME, "replaceEntry", de); |
| | | |
| | | int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_NAME_FORM; |
| | | String message = getMessage(msgID, v.getStringValue(), |
| | | de.getErrorMessage()); |
| | | throw new DirectoryException( |
| | | ResultCode.INVALID_ATTRIBUTE_SYNTAX, message, |
| | | msgID, de); |
| | | } |
| | | |
| | | removeNameForm(nf, newSchema, mods, pos, modifiedSchemaFiles); |
| | | } |
| | | } |
| | | else if (at.equals(ditContentRulesType)) |
| | | { |
| | | for (AttributeValue v : values) |
| | | { |
| | | DITContentRule dcr; |
| | | try |
| | | { |
| | | dcr = DITContentRuleSyntax.decodeDITContentRule(v.getValue(), |
| | | newSchema); |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | | assert debugException(CLASS_NAME, "replaceEntry", de); |
| | | |
| | | int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_DCR; |
| | | String message = getMessage(msgID, v.getStringValue(), |
| | | de.getErrorMessage()); |
| | | throw new DirectoryException( |
| | | ResultCode.INVALID_ATTRIBUTE_SYNTAX, message, |
| | | msgID, de); |
| | | } |
| | | |
| | | removeDITContentRule(dcr, newSchema, mods, pos, |
| | | modifiedSchemaFiles); |
| | | } |
| | | } |
| | | else if (at.equals(ditStructureRulesType)) |
| | | { |
| | | for (AttributeValue v : values) |
| | | { |
| | | DITStructureRule dsr; |
| | | try |
| | | { |
| | | dsr = DITStructureRuleSyntax.decodeDITStructureRule( |
| | | v.getValue(), newSchema, false); |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | | assert debugException(CLASS_NAME, "replaceEntry", de); |
| | | |
| | | int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_DSR; |
| | | String message = getMessage(msgID, v.getStringValue(), |
| | | de.getErrorMessage()); |
| | | throw new DirectoryException( |
| | | ResultCode.INVALID_ATTRIBUTE_SYNTAX, message, |
| | | msgID, de); |
| | | } |
| | | |
| | | removeDITStructureRule(dsr, newSchema, mods, pos, |
| | | modifiedSchemaFiles); |
| | | } |
| | | } |
| | | else if (at.equals(matchingRuleUsesType)) |
| | | { |
| | | for (AttributeValue v : values) |
| | | { |
| | | MatchingRuleUse mru; |
| | | try |
| | | { |
| | | mru = MatchingRuleUseSyntax.decodeMatchingRuleUse(v.getValue(), |
| | | newSchema); |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | | assert debugException(CLASS_NAME, "replaceEntry", de); |
| | | |
| | | int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_MR_USE; |
| | | String message = getMessage(msgID, v.getStringValue(), |
| | | de.getErrorMessage()); |
| | | throw new DirectoryException( |
| | | ResultCode.INVALID_ATTRIBUTE_SYNTAX, message, |
| | | msgID, de); |
| | | } |
| | | |
| | | removeMatchingRuleUse(mru, newSchema, mods, pos, |
| | | modifiedSchemaFiles); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_UNSUPPORTED_ATTRIBUTE_TYPE; |
| | | String message = getMessage(msgID, a.getName()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, |
| | | message, msgID); |
| | | } |
| | | |
| | | break; |
| | | |
| | | |
| | | default: |
| | | // FIXME -- Make sure to update this message once we support |
| | | // schema deletes and possibly replace. |
| | | msgID = MSGID_SCHEMA_INVALID_MODIFICATION_TYPE; |
| | | message = getMessage(msgID, m.getModificationType()); |
| | | int msgID = MSGID_SCHEMA_INVALID_MODIFICATION_TYPE; |
| | | String message = getMessage(msgID, m.getModificationType()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | |
| | | |
| | | // At the present time, we will only allow modification of the |
| | | // attributeTypes and objectClasses attributes. |
| | | Attribute a = m.getAttribute(); |
| | | AttributeType t = a.getAttributeType(); |
| | | if (t.equals(attributeTypesType)) |
| | | { |
| | | for (AttributeValue v : a.getValues()) |
| | | { |
| | | AttributeType newType; |
| | | try |
| | | { |
| | | newType = AttributeTypeSyntax.decodeAttributeType(v.getValue(), |
| | | newSchema); |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | | assert debugException(CLASS_NAME, "replaceEntry", de); |
| | | |
| | | int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_ATTRTYPE; |
| | | String message = getMessage(msgID, v.getStringValue(), |
| | | de.getErrorMessage()); |
| | | throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, |
| | | message, msgID, de); |
| | | } |
| | | |
| | | try |
| | | { |
| | | newSchema.registerAttributeType(newType, false); |
| | | newAttrTypes.add(newType); |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | | assert debugException(CLASS_NAME, "replaceEntry", de); |
| | | |
| | | int msgID = MSGID_SCHEMA_MODIFY_ATTRTYPE_ALREADY_EXISTS; |
| | | String message = getMessage(msgID, newType.getNameOrOID(), |
| | | de.getErrorMessage()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, |
| | | message, msgID, de); |
| | | } |
| | | } |
| | | } |
| | | else if (t.equals(objectClassesType)) |
| | | { |
| | | for (AttributeValue v : a.getValues()) |
| | | { |
| | | ObjectClass newClass; |
| | | try |
| | | { |
| | | newClass = ObjectClassSyntax.decodeObjectClass(v.getValue(), |
| | | newSchema); |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | | assert debugException(CLASS_NAME, "replaceEntry", de); |
| | | |
| | | int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_OBJECTCLASS; |
| | | String message = getMessage(msgID, v.getStringValue(), |
| | | de.getErrorMessage()); |
| | | throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, |
| | | message, msgID, de); |
| | | } |
| | | |
| | | // If there is a superior class, then make sure it is defined. |
| | | ObjectClass superiorClass = newClass.getSuperiorClass(); |
| | | if (superiorClass != null) |
| | | { |
| | | String lowerName = toLowerCase(superiorClass.getNameOrOID()); |
| | | if (! newSchema.hasObjectClass(lowerName)) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_UNDEFINED_SUPERIOR_OBJECTCLASS; |
| | | String message = getMessage(msgID, newClass.getNameOrOID(), |
| | | superiorClass.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, |
| | | message, msgID); |
| | | } |
| | | } |
| | | |
| | | // Make sure that all the associated attribute types are defined. |
| | | for (AttributeType at : newClass.getRequiredAttributes()) |
| | | { |
| | | String lowerName = toLowerCase(at.getNameOrOID()); |
| | | if (! newSchema.hasAttributeType(lowerName)) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_OC_UNDEFINED_REQUIRED_ATTR; |
| | | String message = getMessage(msgID, newClass.getNameOrOID(), |
| | | at.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, |
| | | message, msgID); |
| | | } |
| | | } |
| | | |
| | | for (AttributeType at : newClass.getOptionalAttributes()) |
| | | { |
| | | String lowerName = toLowerCase(at.getNameOrOID()); |
| | | if (! newSchema.hasAttributeType(lowerName)) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_OC_UNDEFINED_OPTIONAL_ATTR; |
| | | String message = getMessage(msgID, newClass.getNameOrOID(), |
| | | at.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, |
| | | message, msgID); |
| | | } |
| | | } |
| | | |
| | | try |
| | | { |
| | | newSchema.registerObjectClass(newClass, false); |
| | | newObjectClasses.add(newClass); |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | | assert debugException(CLASS_NAME, "replaceEntry", de); |
| | | |
| | | int msgID = MSGID_SCHEMA_MODIFY_OBJECTCLASS_ALREADY_EXISTS; |
| | | String message = getMessage(msgID, newClass.getNameOrOID(), |
| | | de.getErrorMessage()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, |
| | | message, msgID, de); |
| | | } |
| | | } |
| | | } |
| | | else |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_UNSUPPORTED_ATTRIBUTE_TYPE; |
| | | String message = getMessage(msgID, a.getName()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | } |
| | | |
| | | |
| | | // If we've gotten here, then everything looks OK. Add the new schema |
| | | // elements to the 99-user.ldif file and swing the new schema into place. |
| | | String schemaDirPath = SchemaConfigManager.getSchemaDirectoryPath(); |
| | | File userSchemaFile = new File(schemaDirPath, FILE_USER_SCHEMA_ELEMENTS); |
| | | Entry userSchemaEntry = null; |
| | | |
| | | if (userSchemaFile.exists()) |
| | | { |
| | | // There's already a set of user-defined schema elements, so we'll need to |
| | | // add these new elements to that set. |
| | | LDIFReader ldifReader = null; |
| | | try |
| | | { |
| | | LDIFImportConfig importConfig = |
| | | new LDIFImportConfig(userSchemaFile.getAbsolutePath()); |
| | | ldifReader = new LDIFReader(importConfig); |
| | | |
| | | userSchemaEntry = ldifReader.readEntry(true); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | assert debugException(CLASS_NAME, "replaceEntry", e); |
| | | |
| | | int msgID = MSGID_SCHEMA_MODIFY_CANNOT_READ_EXISTING_USER_SCHEMA; |
| | | String message = getMessage(msgID, userSchemaFile.getAbsolutePath(), |
| | | stackTraceToSingleLineString(e)); |
| | | throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), |
| | | message, msgID, e); |
| | | } |
| | | finally |
| | | { |
| | | if (ldifReader != null) |
| | | { |
| | | ldifReader.close(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (userSchemaEntry == null) |
| | | { |
| | | // This could happen if there was no user schema file or if it was there |
| | | // but didn't have any entries. At any rate, create a new, empty entry. |
| | | userSchemaEntry = createEmptySchemaEntry(); |
| | | } |
| | | |
| | | |
| | | // Add all of the new schema elements to the entry. |
| | | if (! newAttrTypes.isEmpty()) |
| | | { |
| | | LinkedHashSet<AttributeValue> values = |
| | | new LinkedHashSet<AttributeValue>(); |
| | | for (AttributeType t : newAttrTypes) |
| | | { |
| | | StringBuilder buffer = new StringBuilder(); |
| | | t.toString(buffer, false); |
| | | values.add(new AttributeValue(attributeTypesType, buffer.toString())); |
| | | } |
| | | |
| | | Attribute attrTypeAttribute = new Attribute(attributeTypesType, |
| | | ATTR_ATTRIBUTE_TYPES, values); |
| | | LinkedList<AttributeValue> duplicateValues = |
| | | new LinkedList<AttributeValue>(); |
| | | userSchemaEntry.addAttribute(attrTypeAttribute, duplicateValues); |
| | | } |
| | | |
| | | if (! newObjectClasses.isEmpty()) |
| | | { |
| | | LinkedHashSet<AttributeValue> values = |
| | | new LinkedHashSet<AttributeValue>(); |
| | | for (ObjectClass oc : newObjectClasses) |
| | | { |
| | | StringBuilder buffer = new StringBuilder(); |
| | | oc.toString(buffer, false); |
| | | values.add(new AttributeValue(attributeTypesType, buffer.toString())); |
| | | } |
| | | |
| | | Attribute ocAttribute = new Attribute(objectClassesType, |
| | | ATTR_OBJECTCLASSES, values); |
| | | LinkedList<AttributeValue> duplicateValues = |
| | | new LinkedList<AttributeValue>(); |
| | | userSchemaEntry.addAttribute(ocAttribute, duplicateValues); |
| | | } |
| | | |
| | | |
| | | // Swing the new schema into place. |
| | | // If we've gotten here, then everything looks OK. We'll re-write all |
| | | // impacted schema files by first creating them in a temporary location |
| | | // and then replacing the existing schema files with the new versions. |
| | | // If all that goes successfully, then activate the new schema. |
| | | HashMap<String,File> tempSchemaFiles = new HashMap<String,File>(); |
| | | try |
| | | { |
| | | File tempSchemaFile = new File(userSchemaFile.getAbsolutePath() + ".tmp"); |
| | | LDIFExportConfig exportConfig = |
| | | new LDIFExportConfig(tempSchemaFile.getAbsolutePath(), |
| | | ExistingFileBehavior.OVERWRITE); |
| | | |
| | | LDIFWriter writer = null; |
| | | try |
| | | for (String schemaFile : modifiedSchemaFiles) |
| | | { |
| | | writer = new LDIFWriter(exportConfig); |
| | | writer.writeEntry(userSchemaEntry); |
| | | } |
| | | finally |
| | | { |
| | | if (writer != null) |
| | | { |
| | | writer.close(); |
| | | } |
| | | File tempSchemaFile = writeTempSchemaFile(newSchema, schemaFile); |
| | | tempSchemaFiles.put(schemaFile, tempSchemaFile); |
| | | } |
| | | |
| | | File oldSchemaFile = null; |
| | | if (userSchemaFile.exists()) |
| | | { |
| | | oldSchemaFile = new File(userSchemaFile.getAbsolutePath() + ".old"); |
| | | if (oldSchemaFile.exists()) |
| | | { |
| | | oldSchemaFile.delete(); |
| | | } |
| | | |
| | | userSchemaFile.renameTo(oldSchemaFile); |
| | | } |
| | | |
| | | tempSchemaFile.renameTo(userSchemaFile); |
| | | |
| | | if (oldSchemaFile != null) |
| | | { |
| | | oldSchemaFile.delete(); |
| | | } |
| | | |
| | | installSchemaFiles(tempSchemaFiles); |
| | | DirectoryServer.setSchema(newSchema); |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | | assert debugException(CLASS_NAME, "replaceEntry", de); |
| | | |
| | | throw de; |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | assert debugException(CLASS_NAME, "replaceEntry", e); |
| | | |
| | | int msgID = MSGID_SCHEMA_MODIFY_CANNOT_WRITE_NEW_SCHEMA; |
| | | String message = getMessage(msgID, userSchemaFile.getAbsolutePath(), |
| | | stackTraceToSingleLineString(e)); |
| | | String message = getMessage(msgID, stackTraceToSingleLineString(e)); |
| | | throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), |
| | | message, msgID, e); |
| | | } |
| | | finally |
| | | { |
| | | cleanUpTempSchemaFiles(tempSchemaFiles); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Handles all processing required for adding the provided attribute type to |
| | | * the given schema, replacing an existing type if necessary, and ensuring all |
| | | * other metadata is properly updated. |
| | | * |
| | | * @param attributeType The attribute type to add or replace in the |
| | | * server schema. |
| | | * @param schema The schema to which the attribute type 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 attribute type to the server |
| | | * schema. |
| | | */ |
| | | private void addAttributeType(AttributeType attributeType, Schema schema, |
| | | Set<String> modifiedSchemaFiles) |
| | | throws DirectoryException |
| | | { |
| | | assert debugEnter(CLASS_NAME, "addAttributeType", |
| | | String.valueOf(attributeType), String.valueOf(schema), |
| | | String.valueOf(modifiedSchemaFiles)); |
| | | |
| | | |
| | | // First, see if the specified attribute type already exists. We'll check |
| | | // the OID and all of the names, which means that it's possible there could |
| | | // be more than one match (although if there is, then we'll refuse the |
| | | // operation). |
| | | AttributeType existingType = |
| | | schema.getAttributeType(attributeType.getOID()); |
| | | for (String name : attributeType.getNormalizedNames()) |
| | | { |
| | | AttributeType t = schema.getAttributeType(name); |
| | | if (t == null) |
| | | { |
| | | continue; |
| | | } |
| | | else if (existingType == null) |
| | | { |
| | | existingType = t; |
| | | } |
| | | else if (existingType != t) |
| | | { |
| | | // NOTE: We really do want to use "!=" instead of "! t.equals()" |
| | | // because we want to check whether it's the same object instance, not |
| | | // just a logical equivalent. |
| | | int msgID = MSGID_SCHEMA_MODIFY_MULTIPLE_CONFLICTS_FOR_ADD_ATTRTYPE; |
| | | String message = getMessage(msgID, attributeType.getNameOrOID(), |
| | | existingType.getNameOrOID(), |
| | | t.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | } |
| | | |
| | | |
| | | // Make sure that the new attribute type doesn't reference an undefined |
| | | // superior attribute type. |
| | | AttributeType superiorType = attributeType.getSuperiorType(); |
| | | if (superiorType != null) |
| | | { |
| | | if (! schema.hasAttributeType(superiorType.getOID())) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_UNDEFINED_SUPERIOR_ATTRIBUTE_TYPE; |
| | | String message = getMessage(msgID, attributeType.getNameOrOID(), |
| | | superiorType.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | } |
| | | |
| | | |
| | | // If there is no existing type, then we're adding a new attribute. |
| | | // Otherwise, we're replacing an existing one. |
| | | if (existingType == null) |
| | | { |
| | | schema.registerAttributeType(attributeType, false); |
| | | String schemaFile = attributeType.getSchemaFile(); |
| | | if ((schemaFile == null) || (schemaFile.length() == 0)) |
| | | { |
| | | schemaFile = FILE_USER_SCHEMA_ELEMENTS; |
| | | attributeType.setSchemaFile(schemaFile); |
| | | } |
| | | |
| | | modifiedSchemaFiles.add(schemaFile); |
| | | } |
| | | else |
| | | { |
| | | schema.deregisterAttributeType(existingType); |
| | | schema.registerAttributeType(attributeType, false); |
| | | schema.rebuildDependentElements(existingType); |
| | | |
| | | if ((attributeType.getSchemaFile() == null) || |
| | | (attributeType.getSchemaFile().length() == 0)) |
| | | { |
| | | String schemaFile = existingType.getSchemaFile(); |
| | | if ((schemaFile == null) || (schemaFile.length() == 0)) |
| | | { |
| | | schemaFile = FILE_USER_SCHEMA_ELEMENTS; |
| | | } |
| | | |
| | | attributeType.setSchemaFile(schemaFile); |
| | | modifiedSchemaFiles.add(schemaFile); |
| | | } |
| | | else |
| | | { |
| | | String newSchemaFile = attributeType.getSchemaFile(); |
| | | String oldSchemaFile = existingType.getSchemaFile(); |
| | | if ((oldSchemaFile == null) || oldSchemaFile.equals(newSchemaFile)) |
| | | { |
| | | modifiedSchemaFiles.add(newSchemaFile); |
| | | } |
| | | else |
| | | { |
| | | modifiedSchemaFiles.add(newSchemaFile); |
| | | modifiedSchemaFiles.add(oldSchemaFile); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Handles all processing required to remove the provided attribute type from |
| | | * the server schema, ensuring all other metadata is properly updated. Note |
| | | * that this method will first check to see whether the same attribute type |
| | | * will be later added to the server schema with an updated definition, and if |
| | | * so then the removal will be ignored because the later add will be handled |
| | | * as a replace. If the attribute type will not be replaced with a new |
| | | * definition, then this method will ensure that there are no other schema |
| | | * elements that depend on the attribute type before allowing it to be |
| | | * removed. |
| | | * |
| | | * @param attributeType The attribute type to remove from the server |
| | | * schema. |
| | | * @param schema The schema from which the attribute type |
| | | * should be removed. |
| | | * @param modifications The full set of modifications to be processed |
| | | * against the server schema. |
| | | * @param currentPosition The position of the modification currently |
| | | * being performed. |
| | | * @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 remove |
| | | * the provided attribute type from the server |
| | | * schema. |
| | | */ |
| | | private void removeAttributeType(AttributeType attributeType, Schema schema, |
| | | ArrayList<Modification> modifications, |
| | | int currentPosition, |
| | | Set<String> modifiedSchemaFiles) |
| | | throws DirectoryException |
| | | { |
| | | assert debugEnter(CLASS_NAME, "removeAttributeType", |
| | | String.valueOf(attributeType), String.valueOf(schema), |
| | | String.valueOf(modifications), |
| | | String.valueOf(currentPosition), |
| | | String.valueOf(modifiedSchemaFiles)); |
| | | |
| | | |
| | | // See if the specified attribute type is actually defined in the server |
| | | // schema. If not, then fail. |
| | | AttributeType removeType = schema.getAttributeType(attributeType.getOID()); |
| | | if ((removeType == null) || (! removeType.equals(attributeType))) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_REMOVE_NO_SUCH_ATTRIBUTE_TYPE; |
| | | String message = getMessage(msgID, attributeType.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | |
| | | |
| | | // See if there is another modification later to add the attribute type back |
| | | // into the schema. If so, then it's a replace and we should ignore the |
| | | // remove because adding it back will handle the replace. |
| | | for (int i=currentPosition+1; i < modifications.size(); i++) |
| | | { |
| | | Modification m = modifications.get(i); |
| | | Attribute a = m.getAttribute(); |
| | | |
| | | if ((m.getModificationType() != ModificationType.ADD) || |
| | | (! a.getAttributeType().equals(attributeTypesType))) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | for (AttributeValue v : a.getValues()) |
| | | { |
| | | AttributeType at; |
| | | try |
| | | { |
| | | at = AttributeTypeSyntax.decodeAttributeType(v.getValue(), schema); |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | | assert debugException(CLASS_NAME, "removeAttributeType", de); |
| | | |
| | | int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_ATTRTYPE; |
| | | String message = getMessage(msgID, v.getStringValue(), |
| | | de.getErrorMessage()); |
| | | throw new DirectoryException( |
| | | ResultCode.INVALID_ATTRIBUTE_SYNTAX, message, |
| | | msgID, de); |
| | | } |
| | | |
| | | if (attributeType.getOID().equals(at.getOID())) |
| | | { |
| | | // We found a match where the attribute type is added back later, so |
| | | // we don't need to do anything else here. |
| | | return; |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | // Make sure that the attribute type isn't used as the superior type for |
| | | // any other attributes. |
| | | for (AttributeType at : schema.getAttributeTypes().values()) |
| | | { |
| | | AttributeType superiorType = at.getSuperiorType(); |
| | | if ((superiorType != null) && superiorType.equals(removeType)) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_REMOVE_AT_SUPERIOR_TYPE; |
| | | String message = getMessage(msgID, removeType.getNameOrOID(), |
| | | superiorType.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | } |
| | | |
| | | |
| | | // Make sure that the attribute type isn't used as a required or optional |
| | | // attribute type in any objectclass. |
| | | for (ObjectClass oc : schema.getObjectClasses().values()) |
| | | { |
| | | if (oc.getRequiredAttributes().contains(removeType) || |
| | | oc.getOptionalAttributes().contains(removeType)) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_REMOVE_AT_IN_OC; |
| | | String message = getMessage(msgID, removeType.getNameOrOID(), |
| | | oc.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | } |
| | | |
| | | |
| | | // Make sure that the attribute type isn't used as a required or optional |
| | | // attribute type in any name form. |
| | | for (NameForm nf : schema.getNameFormsByObjectClass().values()) |
| | | { |
| | | if (nf.getRequiredAttributes().contains(removeType) || |
| | | nf.getOptionalAttributes().contains(removeType)) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_REMOVE_AT_IN_NF; |
| | | String message = getMessage(msgID, removeType.getNameOrOID(), |
| | | nf.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | } |
| | | |
| | | |
| | | // Make sure that the attribute type isn't used as a required, optional, or |
| | | // prohibited attribute type in any DIT content rule. |
| | | for (DITContentRule dcr : schema.getDITContentRules().values()) |
| | | { |
| | | if (dcr.getRequiredAttributes().contains(removeType) || |
| | | dcr.getOptionalAttributes().contains(removeType) || |
| | | dcr.getProhibitedAttributes().contains(removeType)) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_REMOVE_AT_IN_DCR; |
| | | String message = getMessage(msgID, removeType.getNameOrOID(), |
| | | dcr.getName()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | } |
| | | |
| | | |
| | | // Make sure that the attribute type isn't referenced by any matching rule |
| | | // use. |
| | | for (MatchingRuleUse mru : schema.getMatchingRuleUses().values()) |
| | | { |
| | | if (mru.getAttributes().contains(removeType)) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_REMOVE_AT_IN_MR_USE; |
| | | String message = getMessage(msgID, removeType.getNameOrOID(), |
| | | mru.getName()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | } |
| | | |
| | | |
| | | // If we've gotten here, then it's OK to remove the attribute type from |
| | | // the schema. |
| | | schema.deregisterAttributeType(removeType); |
| | | String schemaFile = removeType.getSchemaFile(); |
| | | if (schemaFile != null) |
| | | { |
| | | modifiedSchemaFiles.add(schemaFile); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Handles all processing required for adding the provided objectclass to the |
| | | * given schema, replacing an existing class if necessary, and ensuring |
| | | * all other metadata is properly updated. |
| | | * |
| | | * @param objectClass The objectclass to add or replace in the |
| | | * server schema. |
| | | * @param schema The schema to which the objectclass 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 objectclass to the server schema. |
| | | */ |
| | | private void addObjectClass(ObjectClass objectClass, Schema schema, |
| | | Set<String> modifiedSchemaFiles) |
| | | throws DirectoryException |
| | | { |
| | | assert debugEnter(CLASS_NAME, "addObjectClass", String.valueOf(objectClass), |
| | | String.valueOf(schema), |
| | | String.valueOf(modifiedSchemaFiles)); |
| | | |
| | | |
| | | // First, see if the specified objectclass already exists. We'll check the |
| | | // OID and all of the names, which means that it's possible there could be |
| | | // more than one match (although if there is, then we'll refuse the |
| | | // operation). |
| | | ObjectClass existingClass = |
| | | schema.getObjectClass(objectClass.getOID()); |
| | | for (String name : objectClass.getNormalizedNames()) |
| | | { |
| | | ObjectClass oc = schema.getObjectClass(name); |
| | | if (oc == null) |
| | | { |
| | | continue; |
| | | } |
| | | else if (existingClass == null) |
| | | { |
| | | existingClass = oc; |
| | | } |
| | | else if (existingClass != oc) |
| | | { |
| | | // NOTE: We really do want to use "!=" instead of "! t.equals()" |
| | | // because we want to check whether it's the same object instance, not |
| | | // just a logical equivalent. |
| | | int msgID = MSGID_SCHEMA_MODIFY_MULTIPLE_CONFLICTS_FOR_ADD_OBJECTCLASS; |
| | | String message = getMessage(msgID, objectClass.getNameOrOID(), |
| | | existingClass.getNameOrOID(), |
| | | oc.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | } |
| | | |
| | | |
| | | // Make sure that the new objectclass doesn't reference an undefined |
| | | // superior class, or an undefined required or optional attribute type. |
| | | ObjectClass superiorClass = objectClass.getSuperiorClass(); |
| | | if (superiorClass != null) |
| | | { |
| | | if (! schema.hasObjectClass(superiorClass.getOID())) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_UNDEFINED_SUPERIOR_OBJECTCLASS; |
| | | String message = getMessage(msgID, objectClass.getNameOrOID(), |
| | | superiorClass.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | } |
| | | |
| | | for (AttributeType at : objectClass.getRequiredAttributes()) |
| | | { |
| | | if (! schema.hasAttributeType(at.getOID())) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_OC_UNDEFINED_REQUIRED_ATTR; |
| | | String message = getMessage(msgID, objectClass.getNameOrOID(), |
| | | at.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | } |
| | | |
| | | for (AttributeType at : objectClass.getOptionalAttributes()) |
| | | { |
| | | if (! schema.hasAttributeType(at.getOID())) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_OC_UNDEFINED_OPTIONAL_ATTR; |
| | | String message = getMessage(msgID, objectClass.getNameOrOID(), |
| | | at.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | } |
| | | |
| | | |
| | | // If there is no existing class, then we're adding a new objectclass. |
| | | // Otherwise, we're replacing an existing one. |
| | | if (existingClass == null) |
| | | { |
| | | schema.registerObjectClass(objectClass, false); |
| | | String schemaFile = objectClass.getSchemaFile(); |
| | | if ((schemaFile == null) || (schemaFile.length() == 0)) |
| | | { |
| | | schemaFile = FILE_USER_SCHEMA_ELEMENTS; |
| | | objectClass.setSchemaFile(schemaFile); |
| | | } |
| | | |
| | | modifiedSchemaFiles.add(schemaFile); |
| | | } |
| | | else |
| | | { |
| | | schema.deregisterObjectClass(existingClass); |
| | | schema.registerObjectClass(objectClass, false); |
| | | schema.rebuildDependentElements(existingClass); |
| | | |
| | | if ((objectClass.getSchemaFile() == null) || |
| | | (objectClass.getSchemaFile().length() == 0)) |
| | | { |
| | | String schemaFile = existingClass.getSchemaFile(); |
| | | if ((schemaFile == null) || (schemaFile.length() == 0)) |
| | | { |
| | | schemaFile = FILE_USER_SCHEMA_ELEMENTS; |
| | | } |
| | | |
| | | objectClass.setSchemaFile(schemaFile); |
| | | modifiedSchemaFiles.add(schemaFile); |
| | | } |
| | | else |
| | | { |
| | | String newSchemaFile = objectClass.getSchemaFile(); |
| | | String oldSchemaFile = existingClass.getSchemaFile(); |
| | | if ((oldSchemaFile == null) || oldSchemaFile.equals(newSchemaFile)) |
| | | { |
| | | modifiedSchemaFiles.add(newSchemaFile); |
| | | } |
| | | else |
| | | { |
| | | modifiedSchemaFiles.add(newSchemaFile); |
| | | modifiedSchemaFiles.add(oldSchemaFile); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Handles all processing required to remove the provided objectclass from the |
| | | * server schema, ensuring all other metadata is properly updated. Note that |
| | | * this method will first check to see whether the same objectclass will be |
| | | * later added to the server schema with an updated definition, and if so then |
| | | * the removal will be ignored because the later add will be handled as a |
| | | * replace. If the objectclass will not be replaced with a new definition, |
| | | * then this method will ensure that there are no other schema elements that |
| | | * depend on the objectclass before allowing it to be removed. |
| | | * |
| | | * @param objectClass The objectclass to remove from the server |
| | | * schema. |
| | | * @param schema The schema from which the objectclass should |
| | | * be removed. |
| | | * @param modifications The full set of modifications to be processed |
| | | * against the server schema. |
| | | * @param currentPosition The position of the modification currently |
| | | * being performed. |
| | | * @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 remove |
| | | * the provided objectclass from the server |
| | | * schema. |
| | | */ |
| | | private void removeObjectClass(ObjectClass objectClass, Schema schema, |
| | | ArrayList<Modification> modifications, |
| | | int currentPosition, |
| | | Set<String> modifiedSchemaFiles) |
| | | throws DirectoryException |
| | | { |
| | | assert debugEnter(CLASS_NAME, "removeObjectClass", |
| | | String.valueOf(objectClass), String.valueOf(schema), |
| | | String.valueOf(modifications), |
| | | String.valueOf(currentPosition), |
| | | String.valueOf(modifiedSchemaFiles)); |
| | | |
| | | |
| | | // See if the specified objectclass is actually defined in the server |
| | | // schema. If not, then fail. |
| | | ObjectClass removeClass = schema.getObjectClass(objectClass.getOID()); |
| | | if ((removeClass == null) || (! removeClass.equals(objectClass))) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_REMOVE_NO_SUCH_OBJECTCLASS; |
| | | String message = getMessage(msgID, objectClass.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | |
| | | |
| | | // See if there is another modification later to add the objectclass back |
| | | // into the schema. If so, then it's a replace and we should ignore the |
| | | // remove because adding it back will handle the replace. |
| | | for (int i=currentPosition+1; i < modifications.size(); i++) |
| | | { |
| | | Modification m = modifications.get(i); |
| | | Attribute a = m.getAttribute(); |
| | | |
| | | if ((m.getModificationType() != ModificationType.ADD) || |
| | | (! a.getAttributeType().equals(objectClassesType))) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | for (AttributeValue v : a.getValues()) |
| | | { |
| | | ObjectClass oc; |
| | | try |
| | | { |
| | | oc = ObjectClassSyntax.decodeObjectClass(v.getValue(), schema); |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | | assert debugException(CLASS_NAME, "removeObjectClass", de); |
| | | |
| | | int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_OBJECTCLASS; |
| | | String message = getMessage(msgID, v.getStringValue(), |
| | | de.getErrorMessage()); |
| | | throw new DirectoryException( |
| | | ResultCode.INVALID_ATTRIBUTE_SYNTAX, message, |
| | | msgID, de); |
| | | } |
| | | |
| | | if (objectClass.getOID().equals(oc.getOID())) |
| | | { |
| | | // We found a match where the objectClass is added back later, so we |
| | | // don't need to do anything else here. |
| | | return; |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | // Make sure that the objectclass isn't used as the superior class for any |
| | | // other objectclass. |
| | | for (ObjectClass oc : schema.getObjectClasses().values()) |
| | | { |
| | | ObjectClass superiorClass = oc.getSuperiorClass(); |
| | | if ((superiorClass != null) && superiorClass.equals(removeClass)) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_REMOVE_OC_SUPERIOR_CLASS; |
| | | String message = getMessage(msgID, removeClass.getNameOrOID(), |
| | | superiorClass.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | } |
| | | |
| | | |
| | | // Make sure that the objectclass isn't used as the structural class for |
| | | // any name form. |
| | | NameForm nf = schema.getNameForm(removeClass); |
| | | if (nf != null) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_REMOVE_OC_IN_NF; |
| | | String message = getMessage(msgID, removeClass.getNameOrOID(), |
| | | nf.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | |
| | | |
| | | // Make sure that the objectclass isn't used as a structural or auxiliary |
| | | // class for any DIT content rule. |
| | | for (DITContentRule dcr : schema.getDITContentRules().values()) |
| | | { |
| | | if (dcr.getStructuralClass().equals(removeClass) || |
| | | dcr.getAuxiliaryClasses().contains(removeClass)) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_REMOVE_OC_IN_DCR; |
| | | String message = getMessage(msgID, removeClass.getNameOrOID(), |
| | | dcr.getName()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | } |
| | | |
| | | |
| | | // If we've gotten here, then it's OK to remove the objectclass from the |
| | | // schema. |
| | | schema.deregisterObjectClass(removeClass); |
| | | String schemaFile = removeClass.getSchemaFile(); |
| | | if (schemaFile != null) |
| | | { |
| | | modifiedSchemaFiles.add(schemaFile); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Handles all processing required for adding the provided name form to the |
| | | * the given schema, replacing an existing name form if necessary, and |
| | | * ensuring all other metadata is properly updated. |
| | | * |
| | | * @param nameForm The name form 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 name form to the server schema. |
| | | */ |
| | | private void addNameForm(NameForm nameForm, Schema schema, |
| | | Set<String> modifiedSchemaFiles) |
| | | throws DirectoryException |
| | | { |
| | | assert debugEnter(CLASS_NAME, "addNameForm", String.valueOf(nameForm), |
| | | String.valueOf(schema), |
| | | String.valueOf(modifiedSchemaFiles)); |
| | | |
| | | |
| | | // First, see if the specified name form already exists. We'll check the |
| | | // OID and all of the names, which means that it's possible there could be |
| | | // more than one match (although if there is, then we'll refuse the |
| | | // operation). |
| | | NameForm existingNF = |
| | | schema.getNameForm(nameForm.getOID()); |
| | | for (String name : nameForm.getNames().keySet()) |
| | | { |
| | | NameForm nf = schema.getNameForm(name); |
| | | if (nf == null) |
| | | { |
| | | continue; |
| | | } |
| | | else if (existingNF == null) |
| | | { |
| | | existingNF = nf; |
| | | } |
| | | else if (existingNF != nf) |
| | | { |
| | | // NOTE: We really do want to use "!=" instead of "! t.equals()" |
| | | // because we want to check whether it's the same object instance, not |
| | | // just a logical equivalent. |
| | | int msgID = MSGID_SCHEMA_MODIFY_MULTIPLE_CONFLICTS_FOR_ADD_NAME_FORM; |
| | | String message = getMessage(msgID, nameForm.getNameOrOID(), |
| | | existingNF.getNameOrOID(), |
| | | nf.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | } |
| | | |
| | | |
| | | // Make sure that the new name form doesn't reference an undefined |
| | | // structural class, or an undefined required or optional attribute type. |
| | | ObjectClass structuralClass = nameForm.getStructuralClass(); |
| | | if (! schema.hasObjectClass(structuralClass.getOID())) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_NF_UNDEFINED_STRUCTURAL_OC; |
| | | String message = getMessage(msgID, nameForm.getNameOrOID(), |
| | | structuralClass.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | if (structuralClass.getObjectClassType() != ObjectClassType.STRUCTURAL) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_NF_OC_NOT_STRUCTURAL; |
| | | String message = getMessage(msgID, nameForm.getNameOrOID(), |
| | | structuralClass.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | |
| | | NameForm existingNFForClass = schema.getNameForm(structuralClass); |
| | | if ((existingNFForClass != null) && (existingNFForClass != existingNF)) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_STRUCTURAL_OC_CONFLICT_FOR_ADD_NF; |
| | | String message = getMessage(msgID, nameForm.getNameOrOID(), |
| | | structuralClass.getNameOrOID(), |
| | | existingNFForClass.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | |
| | | for (AttributeType at : nameForm.getRequiredAttributes()) |
| | | { |
| | | if (! schema.hasAttributeType(at.getOID())) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_NF_UNDEFINED_REQUIRED_ATTR; |
| | | String message = getMessage(msgID, nameForm.getNameOrOID(), |
| | | at.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | } |
| | | |
| | | for (AttributeType at : nameForm.getOptionalAttributes()) |
| | | { |
| | | if (! schema.hasAttributeType(at.getOID())) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_NF_UNDEFINED_OPTIONAL_ATTR; |
| | | String message = getMessage(msgID, nameForm.getNameOrOID(), |
| | | at.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | } |
| | | |
| | | |
| | | // If there is no existing class, then we're adding a new name form. |
| | | // Otherwise, we're replacing an existing one. |
| | | if (existingNF == null) |
| | | { |
| | | schema.registerNameForm(nameForm, false); |
| | | String schemaFile = nameForm.getSchemaFile(); |
| | | if ((schemaFile == null) || (schemaFile.length() == 0)) |
| | | { |
| | | schemaFile = FILE_USER_SCHEMA_ELEMENTS; |
| | | nameForm.setSchemaFile(schemaFile); |
| | | } |
| | | |
| | | modifiedSchemaFiles.add(schemaFile); |
| | | } |
| | | else |
| | | { |
| | | schema.deregisterNameForm(existingNF); |
| | | schema.registerNameForm(nameForm, false); |
| | | schema.rebuildDependentElements(existingNF); |
| | | |
| | | if ((nameForm.getSchemaFile() == null) || |
| | | (nameForm.getSchemaFile().length() == 0)) |
| | | { |
| | | String schemaFile = existingNF.getSchemaFile(); |
| | | if ((schemaFile == null) || (schemaFile.length() == 0)) |
| | | { |
| | | schemaFile = FILE_USER_SCHEMA_ELEMENTS; |
| | | } |
| | | |
| | | nameForm.setSchemaFile(schemaFile); |
| | | modifiedSchemaFiles.add(schemaFile); |
| | | } |
| | | else |
| | | { |
| | | String newSchemaFile = nameForm.getSchemaFile(); |
| | | String oldSchemaFile = existingNF.getSchemaFile(); |
| | | if ((oldSchemaFile == null) || oldSchemaFile.equals(newSchemaFile)) |
| | | { |
| | | modifiedSchemaFiles.add(newSchemaFile); |
| | | } |
| | | else |
| | | { |
| | | modifiedSchemaFiles.add(newSchemaFile); |
| | | modifiedSchemaFiles.add(oldSchemaFile); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Handles all processing required to remove the provided name form from the |
| | | * server schema, ensuring all other metadata is properly updated. Note that |
| | | * this method will first check to see whether the same name form will be |
| | | * later added to the server schema with an updated definition, and if so then |
| | | * the removal will be ignored because the later add will be handled as a |
| | | * replace. If the name form will not be replaced with a new definition, then |
| | | * this method will ensure that there are no other schema elements that depend |
| | | * on the name form before allowing it to be removed. |
| | | * |
| | | * @param nameForm The name form to remove from the server |
| | | * schema. |
| | | * @param schema The schema from which the name form should be |
| | | * be removed. |
| | | * @param modifications The full set of modifications to be processed |
| | | * against the server schema. |
| | | * @param currentPosition The position of the modification currently |
| | | * being performed. |
| | | * @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 remove |
| | | * the provided name form from the server schema. |
| | | */ |
| | | private void removeNameForm(NameForm nameForm, Schema schema, |
| | | ArrayList<Modification> modifications, |
| | | int currentPosition, |
| | | Set<String> modifiedSchemaFiles) |
| | | throws DirectoryException |
| | | { |
| | | assert debugEnter(CLASS_NAME, "removeNameForm", |
| | | String.valueOf(nameForm), String.valueOf(schema), |
| | | String.valueOf(modifications), |
| | | String.valueOf(currentPosition), |
| | | String.valueOf(modifiedSchemaFiles)); |
| | | |
| | | |
| | | // See if the specified name form is actually defined in the server schema. |
| | | // If not, then fail. |
| | | NameForm removeNF = schema.getNameForm(nameForm.getOID()); |
| | | if ((removeNF == null) || (! removeNF.equals(nameForm))) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_REMOVE_NO_SUCH_NAME_FORM; |
| | | String message = getMessage(msgID, nameForm.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | |
| | | |
| | | // See if there is another modification later to add the name form back |
| | | // into the schema. If so, then it's a replace and we should ignore the |
| | | // remove because adding it back will handle the replace. |
| | | for (int i=currentPosition+1; i < modifications.size(); i++) |
| | | { |
| | | Modification m = modifications.get(i); |
| | | Attribute a = m.getAttribute(); |
| | | |
| | | if ((m.getModificationType() != ModificationType.ADD) || |
| | | (! a.getAttributeType().equals(nameFormsType))) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | for (AttributeValue v : a.getValues()) |
| | | { |
| | | NameForm nf; |
| | | try |
| | | { |
| | | nf = NameFormSyntax.decodeNameForm(v.getValue(), schema); |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | | assert debugException(CLASS_NAME, "removeNameForm", de); |
| | | |
| | | int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_NAME_FORM; |
| | | String message = getMessage(msgID, v.getStringValue(), |
| | | de.getErrorMessage()); |
| | | throw new DirectoryException( |
| | | ResultCode.INVALID_ATTRIBUTE_SYNTAX, message, |
| | | msgID, de); |
| | | } |
| | | |
| | | if (nameForm.getOID().equals(nf.getOID())) |
| | | { |
| | | // We found a match where the name form is added back later, so we |
| | | // don't need to do anything else here. |
| | | return; |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | // Make sure that the name form isn't referenced by any DIT structure |
| | | // rule. |
| | | DITStructureRule dsr = schema.getDITStructureRule(removeNF); |
| | | if (dsr != null) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_REMOVE_NF_IN_DSR; |
| | | String message = getMessage(msgID, removeNF.getNameOrOID(), |
| | | dsr.getNameOrRuleID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | |
| | | |
| | | // If we've gotten here, then it's OK to remove the name form from the |
| | | // schema. |
| | | schema.deregisterNameForm(removeNF); |
| | | String schemaFile = removeNF.getSchemaFile(); |
| | | if (schemaFile != null) |
| | | { |
| | | modifiedSchemaFiles.add(schemaFile); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Handles all processing required for adding the provided DIT content rule to |
| | | * the given schema, replacing an existing rule if necessary, and ensuring |
| | | * all other metadata is properly updated. |
| | | * |
| | | * @param ditContentRule The DIT content rule to add or replace in the |
| | | * server schema. |
| | | * @param schema The schema to which the DIT content rule |
| | | * should be 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 DIT content rule to the server |
| | | * schema. |
| | | */ |
| | | private void addDITContentRule(DITContentRule ditContentRule, Schema schema, |
| | | Set<String> modifiedSchemaFiles) |
| | | throws DirectoryException |
| | | { |
| | | assert debugEnter(CLASS_NAME, "addDITContentRule", |
| | | String.valueOf(ditContentRule), String.valueOf(schema), |
| | | String.valueOf(modifiedSchemaFiles)); |
| | | |
| | | |
| | | // First, see if the specified DIT content rule already exists. We'll check |
| | | // all of the names, which means that it's possible there could be more than |
| | | // one match (although if there is, then we'll refuse the operation). |
| | | DITContentRule existingDCR = null; |
| | | for (DITContentRule dcr : schema.getDITContentRules().values()) |
| | | { |
| | | for (String name : ditContentRule.getNames().keySet()) |
| | | { |
| | | if (dcr.hasName(name)) |
| | | { |
| | | if (existingDCR == null) |
| | | { |
| | | existingDCR = dcr; |
| | | break; |
| | | } |
| | | else |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_MULTIPLE_CONFLICTS_FOR_ADD_DCR; |
| | | String message = getMessage(msgID, ditContentRule.getName(), |
| | | existingDCR.getName(), |
| | | dcr.getName()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, |
| | | message, msgID); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | // Get the structural class for the new DIT content rule and see if there's |
| | | // already an existing rule that is associated with that class. If there |
| | | // is, then it will only be acceptable if it's the DIT content rule that we |
| | | // are replacing (in which case we really do want to use the "!=" operator). |
| | | ObjectClass structuralClass = ditContentRule.getStructuralClass(); |
| | | DITContentRule existingRuleForClass = |
| | | schema.getDITContentRule(structuralClass); |
| | | if ((existingRuleForClass != null) && (existingRuleForClass != existingDCR)) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_STRUCTURAL_OC_CONFLICT_FOR_ADD_DCR; |
| | | String message = getMessage(msgID, ditContentRule.getName(), |
| | | structuralClass.getNameOrOID(), |
| | | existingRuleForClass.getName()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | |
| | | |
| | | // Make sure that the new DIT content rule doesn't reference an undefined |
| | | // structural or auxiliaryclass, or an undefined required, optional, or |
| | | // prohibited attribute type. |
| | | if (! schema.hasObjectClass(structuralClass.getOID())) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_DCR_UNDEFINED_STRUCTURAL_OC; |
| | | String message = getMessage(msgID, ditContentRule.getName(), |
| | | structuralClass.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | |
| | | if (structuralClass.getObjectClassType() != ObjectClassType.STRUCTURAL) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_DCR_OC_NOT_STRUCTURAL; |
| | | String message = getMessage(msgID, ditContentRule.getName(), |
| | | structuralClass.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | |
| | | for (ObjectClass oc : ditContentRule.getAuxiliaryClasses()) |
| | | { |
| | | if (! schema.hasObjectClass(oc.getOID())) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_DCR_UNDEFINED_AUXILIARY_OC; |
| | | String message = getMessage(msgID, ditContentRule.getName(), |
| | | oc.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | } |
| | | |
| | | for (AttributeType at : ditContentRule.getRequiredAttributes()) |
| | | { |
| | | if (! schema.hasAttributeType(at.getOID())) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_DCR_UNDEFINED_REQUIRED_ATTR; |
| | | String message = getMessage(msgID, ditContentRule.getName(), |
| | | at.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | } |
| | | |
| | | for (AttributeType at : ditContentRule.getOptionalAttributes()) |
| | | { |
| | | if (! schema.hasAttributeType(at.getOID())) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_DCR_UNDEFINED_OPTIONAL_ATTR; |
| | | String message = getMessage(msgID, ditContentRule.getName(), |
| | | at.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | } |
| | | |
| | | for (AttributeType at : ditContentRule.getProhibitedAttributes()) |
| | | { |
| | | if (! schema.hasAttributeType(at.getOID())) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_DCR_UNDEFINED_PROHIBITED_ATTR; |
| | | String message = getMessage(msgID, ditContentRule.getName(), |
| | | at.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | } |
| | | |
| | | |
| | | // If there is no existing rule, then we're adding a new DIT content rule. |
| | | // Otherwise, we're replacing an existing one. |
| | | if (existingDCR == null) |
| | | { |
| | | schema.registerDITContentRule(ditContentRule, false); |
| | | String schemaFile = ditContentRule.getSchemaFile(); |
| | | if ((schemaFile == null) || (schemaFile.length() == 0)) |
| | | { |
| | | schemaFile = FILE_USER_SCHEMA_ELEMENTS; |
| | | ditContentRule.setSchemaFile(schemaFile); |
| | | } |
| | | |
| | | modifiedSchemaFiles.add(schemaFile); |
| | | } |
| | | else |
| | | { |
| | | schema.deregisterDITContentRule(existingDCR); |
| | | schema.registerDITContentRule(ditContentRule, false); |
| | | schema.rebuildDependentElements(existingDCR); |
| | | |
| | | if ((ditContentRule.getSchemaFile() == null) || |
| | | (ditContentRule.getSchemaFile().length() == 0)) |
| | | { |
| | | String schemaFile = existingDCR.getSchemaFile(); |
| | | if ((schemaFile == null) || (schemaFile.length() == 0)) |
| | | { |
| | | schemaFile = FILE_USER_SCHEMA_ELEMENTS; |
| | | } |
| | | |
| | | ditContentRule.setSchemaFile(schemaFile); |
| | | modifiedSchemaFiles.add(schemaFile); |
| | | } |
| | | else |
| | | { |
| | | String newSchemaFile = ditContentRule.getSchemaFile(); |
| | | String oldSchemaFile = existingDCR.getSchemaFile(); |
| | | if ((oldSchemaFile == null) || oldSchemaFile.equals(newSchemaFile)) |
| | | { |
| | | modifiedSchemaFiles.add(newSchemaFile); |
| | | } |
| | | else |
| | | { |
| | | modifiedSchemaFiles.add(newSchemaFile); |
| | | modifiedSchemaFiles.add(oldSchemaFile); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Handles all processing required to remove the provided DIT content rule |
| | | * from the server schema, ensuring all other metadata is properly updated. |
| | | * Note that this method will first check to see whether the same rule will be |
| | | * later added to the server schema with an updated definition, and if so then |
| | | * the removal will be ignored because the later add will be handled as a |
| | | * replace. If the DIT content rule will not be replaced with a new |
| | | * definition, then this method will ensure that there are no other schema |
| | | * elements that depend on the rule before allowing it to be removed. |
| | | * |
| | | * @param ditContentRule The DIT content rule to remove from the server |
| | | * schema. |
| | | * @param schema The schema from which the DIT content rule |
| | | * should be removed. |
| | | * @param modifications The full set of modifications to be processed |
| | | * against the server schema. |
| | | * @param currentPosition The position of the modification currently |
| | | * being performed. |
| | | * @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 remove |
| | | * the provided DIT content rule from the server |
| | | * schema. |
| | | */ |
| | | private void removeDITContentRule(DITContentRule ditContentRule, |
| | | Schema schema, |
| | | ArrayList<Modification> modifications, |
| | | int currentPosition, |
| | | Set<String> modifiedSchemaFiles) |
| | | throws DirectoryException |
| | | { |
| | | assert debugEnter(CLASS_NAME, "removeDITContentRule", |
| | | String.valueOf(ditContentRule), String.valueOf(schema), |
| | | String.valueOf(modifications), |
| | | String.valueOf(currentPosition), |
| | | String.valueOf(modifiedSchemaFiles)); |
| | | |
| | | |
| | | // See if the specified DIT content rule is actually defined in the server |
| | | // schema. If not, then fail. |
| | | DITContentRule removeDCR = |
| | | schema.getDITContentRule(ditContentRule.getStructuralClass()); |
| | | if ((removeDCR == null) || (! removeDCR.equals(ditContentRule))) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_REMOVE_NO_SUCH_DCR; |
| | | String message = getMessage(msgID, ditContentRule.getName()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | |
| | | |
| | | // Since DIT content rules don't have any dependencies, then we don't need |
| | | // to worry about the difference between a remove or a replace. We can |
| | | // just remove the DIT content rule now, and if it is added back later then |
| | | // there still won't be any conflict. |
| | | schema.deregisterDITContentRule(removeDCR); |
| | | String schemaFile = removeDCR.getSchemaFile(); |
| | | if (schemaFile != null) |
| | | { |
| | | modifiedSchemaFiles.add(schemaFile); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Handles all processing required for adding the provided DIT structure rule |
| | | * to the given schema, replacing an existing rule if necessary, and ensuring |
| | | * all other metadata is properly updated. |
| | | * |
| | | * @param ditStructureRule The DIT structure rule to add or replace in |
| | | * the server schema. |
| | | * @param schema The schema to which the DIT structure rule |
| | | * should be 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 DIT structure rule to the server |
| | | * schema. |
| | | */ |
| | | private void addDITStructureRule(DITStructureRule ditStructureRule, |
| | | Schema schema, |
| | | Set<String> modifiedSchemaFiles) |
| | | throws DirectoryException |
| | | { |
| | | assert debugEnter(CLASS_NAME, "addDITStructureRule", |
| | | String.valueOf(ditStructureRule), String.valueOf(schema), |
| | | String.valueOf(modifiedSchemaFiles)); |
| | | |
| | | |
| | | // First, see if the specified DIT structure rule already exists. We'll |
| | | // check the rule ID and all of the names, which means that it's possible |
| | | // there could be more than one match (although if there is, then we'll |
| | | // refuse the operation). |
| | | DITStructureRule existingDSR = |
| | | schema.getDITStructureRule(ditStructureRule.getRuleID()); |
| | | for (DITStructureRule dsr : schema.getDITStructureRulesByID().values()) |
| | | { |
| | | for (String name : ditStructureRule.getNames().keySet()) |
| | | { |
| | | if (dsr.hasName(name)) |
| | | { |
| | | // We really do want to use the "!=" operator here because it's |
| | | // acceptable if we find match for the same object instance. |
| | | if ((existingDSR != null) && (existingDSR != dsr)) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_MULTIPLE_CONFLICTS_FOR_ADD_DSR; |
| | | String message = getMessage(msgID, |
| | | ditStructureRule.getNameOrRuleID(), |
| | | existingDSR.getNameOrRuleID(), |
| | | dsr.getNameOrRuleID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, |
| | | message, msgID); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | // Get the name form for the new DIT structure rule and see if there's |
| | | // already an existing rule that is associated with that name form. If |
| | | // there is, then it will only be acceptable if it's the DIT structure rule |
| | | // that we are replacing (in which case we really do want to use the "!=" |
| | | // operator). |
| | | NameForm nameForm = ditStructureRule.getNameForm(); |
| | | DITStructureRule existingRuleForNameForm = |
| | | schema.getDITStructureRule(nameForm); |
| | | if ((existingRuleForNameForm != null) && |
| | | (existingRuleForNameForm != existingDSR)) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_NAME_FORM_CONFLICT_FOR_ADD_DSR; |
| | | String message = getMessage(msgID, ditStructureRule.getNameOrRuleID(), |
| | | nameForm.getNameOrOID(), |
| | | existingRuleForNameForm.getNameOrRuleID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | |
| | | |
| | | // Make sure that the new DIT structure rule doesn't reference an undefined |
| | | // name form or superior DIT structure rule. |
| | | if (! schema.hasNameForm(nameForm.getOID())) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_DSR_UNDEFINED_NAME_FORM; |
| | | String message = getMessage(msgID, ditStructureRule.getNameOrRuleID(), |
| | | nameForm.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | |
| | | |
| | | // If there is no existing rule, then we're adding a new DIT structure rule. |
| | | // Otherwise, we're replacing an existing one. |
| | | if (existingDSR == null) |
| | | { |
| | | schema.registerDITStructureRule(ditStructureRule, false); |
| | | String schemaFile = ditStructureRule.getSchemaFile(); |
| | | if ((schemaFile == null) || (schemaFile.length() == 0)) |
| | | { |
| | | schemaFile = FILE_USER_SCHEMA_ELEMENTS; |
| | | ditStructureRule.setSchemaFile(schemaFile); |
| | | } |
| | | |
| | | modifiedSchemaFiles.add(schemaFile); |
| | | } |
| | | else |
| | | { |
| | | schema.deregisterDITStructureRule(existingDSR); |
| | | schema.registerDITStructureRule(ditStructureRule, false); |
| | | schema.rebuildDependentElements(existingDSR); |
| | | |
| | | if ((ditStructureRule.getSchemaFile() == null) || |
| | | (ditStructureRule.getSchemaFile().length() == 0)) |
| | | { |
| | | String schemaFile = existingDSR.getSchemaFile(); |
| | | if ((schemaFile == null) || (schemaFile.length() == 0)) |
| | | { |
| | | schemaFile = FILE_USER_SCHEMA_ELEMENTS; |
| | | } |
| | | |
| | | ditStructureRule.setSchemaFile(schemaFile); |
| | | modifiedSchemaFiles.add(schemaFile); |
| | | } |
| | | else |
| | | { |
| | | String newSchemaFile = ditStructureRule.getSchemaFile(); |
| | | String oldSchemaFile = existingDSR.getSchemaFile(); |
| | | if ((oldSchemaFile == null) || oldSchemaFile.equals(newSchemaFile)) |
| | | { |
| | | modifiedSchemaFiles.add(newSchemaFile); |
| | | } |
| | | else |
| | | { |
| | | modifiedSchemaFiles.add(newSchemaFile); |
| | | modifiedSchemaFiles.add(oldSchemaFile); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Handles all processing required to remove the provided DIT structure rule |
| | | * from the server schema, ensuring all other metadata is properly updated. |
| | | * Note that this method will first check to see whether the same rule will be |
| | | * later added to the server schema with an updated definition, and if so then |
| | | * the removal will be ignored because the later add will be handled as a |
| | | * replace. If the DIT structure rule will not be replaced with a new |
| | | * definition, then this method will ensure that there are no other schema |
| | | * elements that depend on the rule before allowing it to be removed. |
| | | * |
| | | * @param ditStructureRule The DIT structure rule to remove from the |
| | | * server schema. |
| | | * @param schema The schema from which the DIT structure rule |
| | | * should be removed. |
| | | * @param modifications The full set of modifications to be processed |
| | | * against the server schema. |
| | | * @param currentPosition The position of the modification currently |
| | | * being performed. |
| | | * @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 remove |
| | | * the provided DIT structure rule from the |
| | | * server schema. |
| | | */ |
| | | private void removeDITStructureRule(DITStructureRule ditStructureRule, |
| | | Schema schema, |
| | | ArrayList<Modification> modifications, |
| | | int currentPosition, |
| | | Set<String> modifiedSchemaFiles) |
| | | throws DirectoryException |
| | | { |
| | | assert debugEnter(CLASS_NAME, "removeDITStructureRule", |
| | | String.valueOf(ditStructureRule), String.valueOf(schema), |
| | | String.valueOf(modifications), |
| | | String.valueOf(currentPosition), |
| | | String.valueOf(modifiedSchemaFiles)); |
| | | |
| | | |
| | | // See if the specified DIT structure rule is actually defined in the server |
| | | // schema. If not, then fail. |
| | | DITStructureRule removeDSR = |
| | | schema.getDITStructureRule(ditStructureRule.getRuleID()); |
| | | if ((removeDSR == null) || (! removeDSR.equals(ditStructureRule))) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_REMOVE_NO_SUCH_DSR; |
| | | String message = getMessage(msgID, ditStructureRule.getNameOrRuleID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | |
| | | |
| | | // See if there is another modification later to add the DIT structure rule |
| | | // back into the schema. If so, then it's a replace and we should ignore |
| | | // the remove because adding it back will handle the replace. |
| | | for (int i=currentPosition+1; i < modifications.size(); i++) |
| | | { |
| | | Modification m = modifications.get(i); |
| | | Attribute a = m.getAttribute(); |
| | | |
| | | if ((m.getModificationType() != ModificationType.ADD) || |
| | | (! a.getAttributeType().equals(ditStructureRulesType))) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | for (AttributeValue v : a.getValues()) |
| | | { |
| | | DITStructureRule dsr; |
| | | try |
| | | { |
| | | dsr = DITStructureRuleSyntax.decodeDITStructureRule( |
| | | v.getValue(), schema, false); |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | | assert debugException(CLASS_NAME, "removeDITStructureRule", de); |
| | | |
| | | int msgID = MSGID_SCHEMA_MODIFY_CANNOT_DECODE_DSR; |
| | | String message = getMessage(msgID, v.getStringValue(), |
| | | de.getErrorMessage()); |
| | | throw new DirectoryException( |
| | | ResultCode.INVALID_ATTRIBUTE_SYNTAX, message, |
| | | msgID, de); |
| | | } |
| | | |
| | | if (ditStructureRule.getRuleID() == dsr.getRuleID()) |
| | | { |
| | | // We found a match where the DIT structure rule is added back later, |
| | | // so we don't need to do anything else here. |
| | | return; |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | // Make sure that the DIT structure rule isn't the superior for any other |
| | | // DIT structure rule. |
| | | for (DITStructureRule dsr : schema.getDITStructureRulesByID().values()) |
| | | { |
| | | if (dsr.getSuperiorRules().contains(removeDSR)) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_REMOVE_DSR_SUPERIOR_RULE; |
| | | String message = getMessage(msgID, removeDSR.getNameOrRuleID(), |
| | | dsr.getNameOrRuleID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | } |
| | | |
| | | |
| | | // If we've gotten here, then it's OK to remove the DIT structure rule from |
| | | // the schema. |
| | | schema.deregisterDITStructureRule(removeDSR); |
| | | String schemaFile = removeDSR.getSchemaFile(); |
| | | if (schemaFile != null) |
| | | { |
| | | modifiedSchemaFiles.add(schemaFile); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Handles all processing required for adding the provided matching rule use |
| | | * to the given schema, replacing an existing use if necessary, and ensuring |
| | | * all other metadata is properly updated. |
| | | * |
| | | * @param matchingRuleUse The matching rule use to add or replace in the |
| | | * server schema. |
| | | * @param schema The schema to which the matching rule use |
| | | * 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 matching rule use to the server |
| | | * schema. |
| | | */ |
| | | private void addMatchingRuleUse(MatchingRuleUse matchingRuleUse, |
| | | Schema schema, |
| | | Set<String> modifiedSchemaFiles) |
| | | throws DirectoryException |
| | | { |
| | | assert debugEnter(CLASS_NAME, "addMatchingRuleUse", |
| | | String.valueOf(matchingRuleUse), String.valueOf(schema), |
| | | String.valueOf(modifiedSchemaFiles)); |
| | | |
| | | |
| | | // First, see if the specified matching rule use already exists. We'll |
| | | // check all of the names, which means that it's possible that there could |
| | | // be more than one match (although if there is, then we'll refuse the |
| | | // operation). |
| | | MatchingRuleUse existingMRU = null; |
| | | for (MatchingRuleUse mru : schema.getMatchingRuleUses().values()) |
| | | { |
| | | for (String name : matchingRuleUse.getNames().keySet()) |
| | | { |
| | | if (mru.hasName(name)) |
| | | { |
| | | if (existingMRU == null) |
| | | { |
| | | existingMRU = mru; |
| | | break; |
| | | } |
| | | else |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_MULTIPLE_CONFLICTS_FOR_ADD_MR_USE; |
| | | String message = getMessage(msgID, matchingRuleUse.getName(), |
| | | existingMRU.getName(), mru.getName()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, |
| | | message, msgID); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | // Get the matching rule for the new matching rule use and see if there's |
| | | // already an existing matching rule use that is associated with that |
| | | // matching rule. If there is, then it will only be acceptable if it's the |
| | | // matching rule use that we are replacing (in which case we really do want |
| | | // to use the "!=" operator). |
| | | MatchingRule matchingRule = matchingRuleUse.getMatchingRule(); |
| | | MatchingRuleUse existingMRUForRule = |
| | | schema.getMatchingRuleUse(matchingRule); |
| | | if ((existingMRUForRule != null) && (existingMRUForRule != existingMRU)) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_MR_CONFLICT_FOR_ADD_MR_USE; |
| | | String message = getMessage(msgID, matchingRuleUse.getName(), |
| | | matchingRule.getNameOrOID(), |
| | | existingMRUForRule.getName()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | |
| | | |
| | | // Make sure that the new matching rule use doesn't reference an undefined |
| | | // attribute type. |
| | | for (AttributeType at : matchingRuleUse.getAttributes()) |
| | | { |
| | | if (! schema.hasAttributeType(at.getOID())) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_MRU_UNDEFINED_ATTR; |
| | | String message = getMessage(msgID, matchingRuleUse.getName(), |
| | | at.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | } |
| | | |
| | | |
| | | // If there is no existing matching rule use, then we're adding a new one. |
| | | // Otherwise, we're replacing an existing matching rule use. |
| | | if (existingMRU == null) |
| | | { |
| | | schema.registerMatchingRuleUse(matchingRuleUse, false); |
| | | String schemaFile = matchingRuleUse.getSchemaFile(); |
| | | if ((schemaFile == null) || (schemaFile.length() == 0)) |
| | | { |
| | | schemaFile = FILE_USER_SCHEMA_ELEMENTS; |
| | | matchingRuleUse.setSchemaFile(schemaFile); |
| | | } |
| | | |
| | | modifiedSchemaFiles.add(schemaFile); |
| | | } |
| | | else |
| | | { |
| | | schema.deregisterMatchingRuleUse(existingMRU); |
| | | schema.registerMatchingRuleUse(matchingRuleUse, false); |
| | | schema.rebuildDependentElements(existingMRU); |
| | | |
| | | if ((matchingRuleUse.getSchemaFile() == null) || |
| | | (matchingRuleUse.getSchemaFile().length() == 0)) |
| | | { |
| | | String schemaFile = existingMRU.getSchemaFile(); |
| | | if ((schemaFile == null) || (schemaFile.length() == 0)) |
| | | { |
| | | schemaFile = FILE_USER_SCHEMA_ELEMENTS; |
| | | } |
| | | |
| | | matchingRuleUse.setSchemaFile(schemaFile); |
| | | modifiedSchemaFiles.add(schemaFile); |
| | | } |
| | | else |
| | | { |
| | | String newSchemaFile = matchingRuleUse.getSchemaFile(); |
| | | String oldSchemaFile = existingMRU.getSchemaFile(); |
| | | if ((oldSchemaFile == null) || oldSchemaFile.equals(newSchemaFile)) |
| | | { |
| | | modifiedSchemaFiles.add(newSchemaFile); |
| | | } |
| | | else |
| | | { |
| | | modifiedSchemaFiles.add(newSchemaFile); |
| | | modifiedSchemaFiles.add(oldSchemaFile); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Handles all processing required to remove the provided matching rule use |
| | | * from the server schema, ensuring all other metadata is properly updated. |
| | | * Note that this method will first check to see whether the same matching |
| | | * rule use will be later added to the server schema with an updated |
| | | * definition, and if so then the removal will be ignored because the later |
| | | * add will be handled as a replace. If the matching rule use will not be |
| | | * replaced with a new definition, then this method will ensure that there are |
| | | * no other schema elements that depend on the matching rule use before |
| | | * allowing it to be removed. |
| | | * |
| | | * @param matchingRuleUse The matching rule use to remove from the |
| | | * server schema. |
| | | * @param schema The schema from which the matching rule use |
| | | * should be removed. |
| | | * @param modifications The full set of modifications to be processed |
| | | * against the server schema. |
| | | * @param currentPosition The position of the modification currently |
| | | * being performed. |
| | | * @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 remove |
| | | * the provided matching rule use from the server |
| | | * schema. |
| | | */ |
| | | private void removeMatchingRuleUse(MatchingRuleUse matchingRuleUse, |
| | | Schema schema, |
| | | ArrayList<Modification> modifications, |
| | | int currentPosition, |
| | | Set<String> modifiedSchemaFiles) |
| | | throws DirectoryException |
| | | { |
| | | assert debugEnter(CLASS_NAME, "removeMatchingRuleUse", |
| | | String.valueOf(matchingRuleUse), String.valueOf(schema), |
| | | String.valueOf(modifications), |
| | | String.valueOf(currentPosition), |
| | | String.valueOf(modifiedSchemaFiles)); |
| | | |
| | | |
| | | // See if the specified DIT content rule is actually defined in the server |
| | | // schema. If not, then fail. |
| | | MatchingRuleUse removeMRU = |
| | | schema.getMatchingRuleUse(matchingRuleUse.getMatchingRule()); |
| | | if ((removeMRU == null) || (! removeMRU.equals(matchingRuleUse))) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_REMOVE_NO_SUCH_MR_USE; |
| | | String message = getMessage(msgID, matchingRuleUse.getName()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | |
| | | |
| | | // Since matching rule uses don't have any dependencies, then we don't need |
| | | // to worry about the difference between a remove or a replace. We can |
| | | // just remove the DIT content rule now, and if it is added back later then |
| | | // there still won't be any conflict. |
| | | schema.deregisterMatchingRuleUse(removeMRU); |
| | | String schemaFile = removeMRU.getSchemaFile(); |
| | | if (schemaFile != null) |
| | | { |
| | | modifiedSchemaFiles.add(schemaFile); |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * Writes a temporary version of the specified schema file. |
| | | * |
| | | * @param schema The schema from which to take the definitions to be |
| | | * written. |
| | | * @param schemaFile The name of the schema file to be written. |
| | | * |
| | | * @throws DirectoryException If an unexpected problem occurs while |
| | | * identifying the schema definitions to include |
| | | * in the schema file. |
| | | * |
| | | * @throws IOException If an unexpected error occurs while attempting to |
| | | * write the temporary schema file. |
| | | * |
| | | * @throws LDIFException If an unexpected problem occurs while generating |
| | | * the LDIF representation of the schema entry. |
| | | */ |
| | | private File writeTempSchemaFile(Schema schema, String schemaFile) |
| | | throws DirectoryException, IOException, LDIFException |
| | | { |
| | | assert debugEnter(CLASS_NAME, "writeTempSchemaFile", String.valueOf(schema), |
| | | String.valueOf(schemaFile)); |
| | | |
| | | |
| | | // Start with an empty schema entry. |
| | | Entry schemaEntry = createEmptySchemaEntry(); |
| | | |
| | | |
| | | // Add all of the appropriate attribute types to the schema entry. We need |
| | | // to be careful of the ordering to ensure that any superior types in the |
| | | // same file are written before the subordinate types. |
| | | HashSet<AttributeType> addedTypes = new HashSet<AttributeType>(); |
| | | LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(); |
| | | for (AttributeType at : schema.getAttributeTypes().values()) |
| | | { |
| | | if (schemaFile.equals(at.getSchemaFile())) |
| | | { |
| | | addAttrTypeToSchemaFile(schema, schemaFile, at, values, addedTypes, 0); |
| | | } |
| | | } |
| | | |
| | | if (! values.isEmpty()) |
| | | { |
| | | ArrayList<Attribute> attrList = new ArrayList<Attribute>(1); |
| | | attrList.add(new Attribute(attributeTypesType, |
| | | attributeTypesType.getPrimaryName(), values)); |
| | | schemaEntry.putAttribute(attributeTypesType, attrList); |
| | | } |
| | | |
| | | |
| | | // Add all of the appropriate objectclasses to the schema entry. We need |
| | | // to be careful of the ordering to ensure that any superior classes in the |
| | | // same file are written before the subordinate classes. |
| | | HashSet<ObjectClass> addedClasses = new HashSet<ObjectClass>(); |
| | | values = new LinkedHashSet<AttributeValue>(); |
| | | for (ObjectClass oc : schema.getObjectClasses().values()) |
| | | { |
| | | if (schemaFile.equals(oc.getSchemaFile())) |
| | | { |
| | | addObjectClassToSchemaFile(schema, schemaFile, oc, values, addedClasses, |
| | | 0); |
| | | } |
| | | } |
| | | |
| | | if (! values.isEmpty()) |
| | | { |
| | | ArrayList<Attribute> attrList = new ArrayList<Attribute>(1); |
| | | attrList.add(new Attribute(objectClassesType, |
| | | objectClassesType.getPrimaryName(), values)); |
| | | schemaEntry.putAttribute(objectClassesType, attrList); |
| | | } |
| | | |
| | | |
| | | // Add all of the appropriate name forms to the schema entry. Since there |
| | | // is no hierarchical relationship between name forms, we don't need to |
| | | // worry about ordering. |
| | | values = new LinkedHashSet<AttributeValue>(); |
| | | for (NameForm nf : schema.getNameFormsByObjectClass().values()) |
| | | { |
| | | if (schemaFile.equals(nf.getSchemaFile())) |
| | | { |
| | | values.add(new AttributeValue(nameFormsType, nf.getDefinition())); |
| | | } |
| | | } |
| | | |
| | | if (! values.isEmpty()) |
| | | { |
| | | ArrayList<Attribute> attrList = new ArrayList<Attribute>(1); |
| | | attrList.add(new Attribute(nameFormsType, |
| | | nameFormsType.getPrimaryName(), values)); |
| | | schemaEntry.putAttribute(nameFormsType, attrList); |
| | | } |
| | | |
| | | |
| | | // Add all of the appropriate DIT content rules to the schema entry. Since |
| | | // there is no hierarchical relationship between DIT content rules, we don't |
| | | // need to worry about ordering. |
| | | values = new LinkedHashSet<AttributeValue>(); |
| | | for (DITContentRule dcr : schema.getDITContentRules().values()) |
| | | { |
| | | if (schemaFile.equals(dcr.getSchemaFile())) |
| | | { |
| | | values.add(new AttributeValue(ditContentRulesType, |
| | | dcr.getDefinition())); |
| | | } |
| | | } |
| | | |
| | | if (! values.isEmpty()) |
| | | { |
| | | ArrayList<Attribute> attrList = new ArrayList<Attribute>(1); |
| | | attrList.add(new Attribute(ditContentRulesType, |
| | | ditContentRulesType.getPrimaryName(), values)); |
| | | schemaEntry.putAttribute(ditContentRulesType, attrList); |
| | | } |
| | | |
| | | |
| | | // Add all of the appropriate DIT structure rules to the schema entry. We |
| | | // need to be careful of the ordering to ensure that any superior rules in |
| | | // the same file are written before the subordinate rules. |
| | | HashSet<DITStructureRule> addedDSRs = new HashSet<DITStructureRule>(); |
| | | values = new LinkedHashSet<AttributeValue>(); |
| | | for (DITStructureRule dsr : schema.getDITStructureRulesByID().values()) |
| | | { |
| | | if (schemaFile.equals(dsr.getSchemaFile())) |
| | | { |
| | | addDITStructureRuleToSchemaFile(schema, schemaFile, dsr, values, |
| | | addedDSRs, 0); |
| | | } |
| | | } |
| | | |
| | | if (! values.isEmpty()) |
| | | { |
| | | ArrayList<Attribute> attrList = new ArrayList<Attribute>(1); |
| | | attrList.add(new Attribute(ditStructureRulesType, |
| | | ditStructureRulesType.getPrimaryName(), |
| | | values)); |
| | | schemaEntry.putAttribute(ditStructureRulesType, attrList); |
| | | } |
| | | |
| | | |
| | | // Add all of the appropriate matching rule uses to the schema entry. Since |
| | | // there is no hierarchical relationship between matching rule uses, we |
| | | // don't need to worry about ordering. |
| | | values = new LinkedHashSet<AttributeValue>(); |
| | | for (MatchingRuleUse mru : schema.getMatchingRuleUses().values()) |
| | | { |
| | | if (schemaFile.equals(mru.getSchemaFile())) |
| | | { |
| | | values.add(new AttributeValue(matchingRuleUsesType, |
| | | mru.getDefinition())); |
| | | } |
| | | } |
| | | |
| | | if (! values.isEmpty()) |
| | | { |
| | | ArrayList<Attribute> attrList = new ArrayList<Attribute>(1); |
| | | attrList.add(new Attribute(matchingRuleUsesType, |
| | | matchingRuleUsesType.getPrimaryName(), |
| | | values)); |
| | | schemaEntry.putAttribute(matchingRuleUsesType, attrList); |
| | | } |
| | | |
| | | |
| | | // Create a temporary file to which we can write the schema entry. |
| | | File tempFile = File.createTempFile(schemaFile, "temp"); |
| | | LDIFExportConfig exportConfig = |
| | | new LDIFExportConfig(tempFile.getAbsolutePath(), |
| | | ExistingFileBehavior.OVERWRITE); |
| | | LDIFWriter ldifWriter = new LDIFWriter(exportConfig); |
| | | ldifWriter.writeEntry(schemaEntry); |
| | | ldifWriter.close(); |
| | | |
| | | return tempFile; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Adds the definition for the specified attribute type to the provided set of |
| | | * attribute values, recursively adding superior types as appropriate. |
| | | * |
| | | * @param schema The schema containing the attribute type. |
| | | * @param schemaFile The schema file with which the attribute type is |
| | | * associated. |
| | | * @param attributeType The attribute type whose definition should be added |
| | | * to the value set. |
| | | * @param values The set of values for attribute type definitions |
| | | * already added. |
| | | * @param addedTypes The set of attribute types whose definitions have |
| | | * already been added to the set of values. |
| | | * @param depth A depth counter to use in an attempt to detect |
| | | * circular references. |
| | | */ |
| | | private void addAttrTypeToSchemaFile(Schema schema, String schemaFile, |
| | | AttributeType attributeType, |
| | | LinkedHashSet<AttributeValue> values, |
| | | HashSet<AttributeType> addedTypes, |
| | | int depth) |
| | | throws DirectoryException |
| | | { |
| | | assert debugEnter(CLASS_NAME, "addAttrTypeToSchemaFile", |
| | | String.valueOf(schema), String.valueOf(schemaFile), |
| | | String.valueOf(attributeType), String.valueOf(values), |
| | | String.valueOf(addedTypes), String.valueOf(depth)); |
| | | |
| | | if (depth > 20) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_CIRCULAR_REFERENCE_AT; |
| | | String message = getMessage(msgID, attributeType.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | |
| | | if (addedTypes.contains(attributeType)) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | AttributeType superiorType = attributeType.getSuperiorType(); |
| | | if ((superiorType != null) && |
| | | schemaFile.equals(superiorType.getSchemaFile()) && |
| | | (! addedTypes.contains(superiorType))) |
| | | { |
| | | addAttrTypeToSchemaFile(schema, schemaFile, superiorType, values, |
| | | addedTypes, depth+1); |
| | | } |
| | | |
| | | values.add(new AttributeValue(attributeTypesType, |
| | | attributeType.getDefinition())); |
| | | addedTypes.add(attributeType); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Adds the definition for the specified objectclass to the provided set of |
| | | * attribute values, recursively adding superior classes as appropriate. |
| | | * |
| | | * @param schema The schema containing the objectclass. |
| | | * @param schemaFile The schema file with which the objectclass is |
| | | * associated. |
| | | * @param objectClass The objectclass whose definition should be added to |
| | | * the value set. |
| | | * @param values The set of values for objectclass definitions |
| | | * already added. |
| | | * @param addedClasses The set of objectclasses whose definitions have |
| | | * already been added to the set of values. |
| | | * @param depth A depth counter to use in an attempt to detect |
| | | * circular references. |
| | | */ |
| | | private void addObjectClassToSchemaFile(Schema schema, String schemaFile, |
| | | ObjectClass objectClass, |
| | | LinkedHashSet<AttributeValue> values, |
| | | HashSet<ObjectClass> addedClasses, |
| | | int depth) |
| | | throws DirectoryException |
| | | { |
| | | assert debugEnter(CLASS_NAME, "addObjectClassToSchemaFile", |
| | | String.valueOf(schema), String.valueOf(schemaFile), |
| | | String.valueOf(objectClass), String.valueOf(values), |
| | | String.valueOf(addedClasses), String.valueOf(depth)); |
| | | |
| | | if (depth > 20) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_CIRCULAR_REFERENCE_OC; |
| | | String message = getMessage(msgID, objectClass.getNameOrOID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | |
| | | if (addedClasses.contains(objectClass)) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | ObjectClass superiorClass = objectClass.getSuperiorClass(); |
| | | if ((superiorClass != null) && |
| | | schemaFile.equals(superiorClass.getSchemaFile()) && |
| | | (! addedClasses.contains(superiorClass))) |
| | | { |
| | | addObjectClassToSchemaFile(schema, schemaFile, superiorClass, values, |
| | | addedClasses, depth+1); |
| | | } |
| | | |
| | | values.add(new AttributeValue(objectClassesType, |
| | | objectClass.getDefinition())); |
| | | addedClasses.add(objectClass); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Adds the definition for the specified DIT structure rule to the provided |
| | | * set of attribute values, recursively adding superior rules as appropriate. |
| | | * |
| | | * @param schema The schema containing the DIT structure rule. |
| | | * @param schemaFile The schema file with which the DIT structure rule |
| | | * is associated. |
| | | * @param ditStructureRule The DIT structure rule whose definition should be |
| | | * added to the value set. |
| | | * @param values The set of values for DIT structure rule |
| | | * definitions already added. |
| | | * @param addedDSRs The set of DIT structure rules whose definitions |
| | | * have already been added added to the set of |
| | | * values. |
| | | * @param depth A depth counter to use in an attempt to detect |
| | | * circular references. |
| | | */ |
| | | private void addDITStructureRuleToSchemaFile(Schema schema, String schemaFile, |
| | | DITStructureRule ditStructureRule, |
| | | LinkedHashSet<AttributeValue> values, |
| | | HashSet<DITStructureRule> addedDSRs, int depth) |
| | | throws DirectoryException |
| | | { |
| | | assert debugEnter(CLASS_NAME, "addDITStructureRuleToSchemaFile", |
| | | String.valueOf(schema), String.valueOf(schemaFile), |
| | | String.valueOf(ditStructureRule), String.valueOf(values), |
| | | String.valueOf(addedDSRs), String.valueOf(depth)); |
| | | |
| | | if (depth > 20) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_CIRCULAR_REFERENCE_DSR; |
| | | String message = getMessage(msgID, ditStructureRule.getNameOrRuleID()); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message, |
| | | msgID); |
| | | } |
| | | |
| | | if (addedDSRs.contains(ditStructureRule)) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | for (DITStructureRule dsr : ditStructureRule.getSuperiorRules()) |
| | | { |
| | | if (schemaFile.equals(dsr.getSchemaFile()) && (! addedDSRs.contains(dsr))) |
| | | { |
| | | addDITStructureRuleToSchemaFile(schema, schemaFile, dsr, values, |
| | | addedDSRs, depth+1); |
| | | } |
| | | } |
| | | |
| | | values.add(new AttributeValue(ditStructureRulesType, |
| | | ditStructureRule.getDefinition())); |
| | | addedDSRs.add(ditStructureRule); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Moves the specified temporary schema files in place of the active versions. |
| | | * If an error occurs in the process, then this method will attempt to restore |
| | | * the original schema files if possible. |
| | | * |
| | | * @param tempSchemaFiles The set of temporary schema files to be activated. |
| | | * |
| | | * @throws DirectoryException If a problem occurs while attempting to |
| | | * install the temporary schema files. |
| | | */ |
| | | private void installSchemaFiles(HashMap<String,File> tempSchemaFiles) |
| | | throws DirectoryException |
| | | { |
| | | assert debugEnter(CLASS_NAME, "installSchemaFiles", |
| | | String.valueOf(tempSchemaFiles)); |
| | | |
| | | |
| | | // Create lists that will hold the three types of files we'll be dealing |
| | | // with (the temporary files that will be installed, the installed schema |
| | | // files, and the previously-installed schema files). |
| | | ArrayList<File> installedFileList = new ArrayList<File>(); |
| | | ArrayList<File> tempFileList = new ArrayList<File>(); |
| | | ArrayList<File> origFileList = new ArrayList<File>(); |
| | | |
| | | File schemaDir = new File(SchemaConfigManager.getSchemaDirectoryPath()); |
| | | |
| | | for (String name : tempSchemaFiles.keySet()) |
| | | { |
| | | installedFileList.add(new File(schemaDir, name)); |
| | | tempFileList.add(tempSchemaFiles.get(name)); |
| | | origFileList.add(new File(schemaDir, name + ".orig")); |
| | | } |
| | | |
| | | |
| | | // If there are any old ".orig" files laying around from a previous |
| | | // attempt, then try to clean them up. |
| | | for (File f : origFileList) |
| | | { |
| | | if (f.exists()) |
| | | { |
| | | f.delete(); |
| | | } |
| | | } |
| | | |
| | | |
| | | // Copy all of the currently-installed files with a ".orig" extension. If |
| | | // this fails, then try to clean up the copies. |
| | | try |
| | | { |
| | | for (int i=0; i < installedFileList.size(); i++) |
| | | { |
| | | File installedFile = installedFileList.get(i); |
| | | File origFile = origFileList.get(i); |
| | | |
| | | if (installedFile.exists()) |
| | | { |
| | | copyFile(installedFile, origFile); |
| | | } |
| | | } |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | assert debugException(CLASS_NAME, "installSchemaFiles", e); |
| | | |
| | | boolean allCleaned = true; |
| | | for (File f : origFileList) |
| | | { |
| | | try |
| | | { |
| | | if (f.exists()) |
| | | { |
| | | if (! f.delete()) |
| | | { |
| | | allCleaned = false; |
| | | } |
| | | } |
| | | } |
| | | catch (Exception e2) |
| | | { |
| | | assert debugException(CLASS_NAME, "installSchemaFiles", e2); |
| | | |
| | | allCleaned = false; |
| | | } |
| | | } |
| | | |
| | | if (allCleaned) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_CANNOT_WRITE_ORIG_FILES_CLEANED; |
| | | String message = getMessage(msgID, stackTraceToSingleLineString(e)); |
| | | throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), |
| | | message, msgID, e); |
| | | } |
| | | else |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_CANNOT_WRITE_ORIG_FILES_NOT_CLEANED; |
| | | String message = getMessage(msgID, stackTraceToSingleLineString(e)); |
| | | |
| | | DirectoryServer.sendAlertNotification(this, |
| | | ALERT_TYPE_CANNOT_COPY_SCHEMA_FILES, msgID, |
| | | message); |
| | | |
| | | throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), |
| | | message, msgID, e); |
| | | } |
| | | } |
| | | |
| | | |
| | | // Try to copy all of the temporary files into place over the installed |
| | | // files. If this fails, then try to restore the originals. |
| | | try |
| | | { |
| | | for (int i=0; i < installedFileList.size(); i++) |
| | | { |
| | | File installedFile = installedFileList.get(i); |
| | | File tempFile = tempFileList.get(i); |
| | | copyFile(tempFile, installedFile); |
| | | } |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | assert debugException(CLASS_NAME, "installSchemaFiles", e); |
| | | |
| | | for (File f : installedFileList) |
| | | { |
| | | try |
| | | { |
| | | if (f.exists()) |
| | | { |
| | | f.delete(); |
| | | } |
| | | } |
| | | catch (Exception e2) |
| | | { |
| | | assert debugException(CLASS_NAME, "installSchemaFiles", e2); |
| | | } |
| | | } |
| | | |
| | | boolean allRestored = true; |
| | | for (int i=0; i < installedFileList.size(); i++) |
| | | { |
| | | File installedFile = installedFileList.get(i); |
| | | File origFile = origFileList.get(i); |
| | | |
| | | try |
| | | { |
| | | if (origFile.exists()) |
| | | { |
| | | if (! origFile.renameTo(installedFile)) |
| | | { |
| | | allRestored = false; |
| | | } |
| | | } |
| | | } |
| | | catch (Exception e2) |
| | | { |
| | | assert debugException(CLASS_NAME, "installSchemaFiles", e2); |
| | | |
| | | allRestored = false; |
| | | } |
| | | } |
| | | |
| | | if (allRestored) |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_CANNOT_WRITE_NEW_FILES_RESTORED; |
| | | String message = getMessage(msgID, stackTraceToSingleLineString(e)); |
| | | throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), |
| | | message, msgID, e); |
| | | } |
| | | else |
| | | { |
| | | int msgID = MSGID_SCHEMA_MODIFY_CANNOT_WRITE_NEW_FILES_NOT_RESTORED; |
| | | String message = getMessage(msgID, stackTraceToSingleLineString(e)); |
| | | |
| | | DirectoryServer.sendAlertNotification(this, |
| | | ALERT_TYPE_CANNOT_WRITE_NEW_SCHEMA_FILES, msgID, |
| | | message); |
| | | |
| | | throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), |
| | | message, msgID, e); |
| | | } |
| | | } |
| | | |
| | | |
| | | // At this point, we're committed to the schema change, so we can't throw |
| | | // any more exceptions, but all we have left is to clean up the original and |
| | | // temporary files. |
| | | for (File f : origFileList) |
| | | { |
| | | try |
| | | { |
| | | if (f.exists()) |
| | | { |
| | | f.delete(); |
| | | } |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | assert debugException(CLASS_NAME, "installSchemaFiles", e); |
| | | } |
| | | } |
| | | |
| | | for (File f : tempFileList) |
| | | { |
| | | try |
| | | { |
| | | if (f.exists()) |
| | | { |
| | | f.delete(); |
| | | } |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | assert debugException(CLASS_NAME, "installSchemaFiles", e); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a copy of the specified file. |
| | | * |
| | | * @param from The source file to be copied. |
| | | * @param to The destination file to be created. |
| | | * |
| | | * @throws IOException If a problem occurs. |
| | | */ |
| | | private void copyFile(File from, File to) |
| | | throws IOException |
| | | { |
| | | assert debugEnter(CLASS_NAME, "copyFile", String.valueOf(from), |
| | | String.valueOf(to)); |
| | | |
| | | byte[] buffer = new byte[4096]; |
| | | FileInputStream inputStream = null; |
| | | FileOutputStream outputStream = null; |
| | | try |
| | | { |
| | | inputStream = new FileInputStream(from); |
| | | outputStream = new FileOutputStream(to, false); |
| | | |
| | | int bytesRead = inputStream.read(buffer); |
| | | while (bytesRead > 0) |
| | | { |
| | | outputStream.write(buffer, 0, bytesRead); |
| | | bytesRead = inputStream.read(buffer); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | if (inputStream != null) |
| | | { |
| | | try |
| | | { |
| | | inputStream.close(); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | assert debugException(CLASS_NAME, "copyFile", e); |
| | | } |
| | | } |
| | | |
| | | if (outputStream != null) |
| | | { |
| | | outputStream.close(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Performs any necessary cleanup in an attempt to delete any temporary schema |
| | | * files that may have been left over after trying to install the new schema. |
| | | * |
| | | * @param tempSchemaFiles The set of temporary schema files that have been |
| | | * created and are candidates for cleanup. |
| | | */ |
| | | private void cleanUpTempSchemaFiles(HashMap<String,File> tempSchemaFiles) |
| | | { |
| | | assert debugEnter(CLASS_NAME, "cleanUpTempSchemaFiles", |
| | | String.valueOf(tempSchemaFiles)); |
| | | |
| | | if ((tempSchemaFiles == null) || tempSchemaFiles.isEmpty()) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | for (File f : tempSchemaFiles.values()) |
| | | { |
| | | try |
| | | { |
| | | if (f.exists()) |
| | | { |
| | | f.delete(); |
| | | } |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | assert debugException(CLASS_NAME, "cleanUpTempSchemaFiles", e); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Moves and/or renames the provided entry in this backend, altering any |
| | | * subordinate entries as necessary. This must ensure that an entry already |
| | |
| | | |
| | | this.showAllAttributes = showAllAttributes; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves the DN of the configuration entry with which this alert generator |
| | | * is associated. |
| | | * |
| | | * @return The DN of the configuration entry with which this alert generator |
| | | * is associated. |
| | | */ |
| | | public DN getComponentEntryDN() |
| | | { |
| | | assert debugEnter(CLASS_NAME, "getComponentEntryDN"); |
| | | |
| | | return configEntryDN; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves the fully-qualified name of the Java class for this alert |
| | | * generator implementation. |
| | | * |
| | | * @return The fully-qualified name of the Java class for this alert |
| | | * generator implementation. |
| | | */ |
| | | public String getClassName() |
| | | { |
| | | assert debugEnter(CLASS_NAME, "getClassName"); |
| | | |
| | | return CLASS_NAME; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves information about the set of alerts that this generator may |
| | | * produce. The map returned should be between the notification type for a |
| | | * particular notification and the human-readable description for that |
| | | * notification. This alert generator must not generate any alerts with types |
| | | * that are not contained in this list. |
| | | * |
| | | * @return Information about the set of alerts that this generator may |
| | | * produce. |
| | | */ |
| | | public LinkedHashMap<String,String> getAlerts() |
| | | { |
| | | assert debugEnter(CLASS_NAME, "getAlerts"); |
| | | |
| | | LinkedHashMap<String,String> alerts = new LinkedHashMap<String,String>(); |
| | | |
| | | alerts.put(ALERT_TYPE_CANNOT_COPY_SCHEMA_FILES, |
| | | ALERT_DESCRIPTION_CANNOT_COPY_SCHEMA_FILES); |
| | | alerts.put(ALERT_TYPE_CANNOT_WRITE_NEW_SCHEMA_FILES, |
| | | ALERT_DESCRIPTION_CANNOT_WRITE_NEW_SCHEMA_FILES); |
| | | |
| | | return alerts; |
| | | } |
| | | } |
| | | |