/** * Generates an entry for a backup directory based on the provided DN. The DN must contain an RDN * component that specifies the path to the backup directory, and that directory must exist and be * a valid backup directory. * * @param entryDN The DN of the backup directory entry to retrieve. * @return The requested backup directory entry. * @throws DirectoryException If the specified directory does not exist or is not a valid backup * directory, or if the DN does not specify any backup directory. */ private Entry getBackupDirectoryEntry(DN entryDN) throws DirectoryException { // Make sure that the DN specifies a backup directory. AttributeType t = DirectoryServer.getAttributeType(ATTR_BACKUP_DIRECTORY_PATH, true); AttributeValue v = entryDN.getRDN().getAttributeValue(t); if (v == null) { Message message = ERR_BACKUP_DN_DOES_NOT_SPECIFY_DIRECTORY.get(String.valueOf(entryDN)); throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message, backupBaseDN, null); } // Get a handle to the backup directory and the information that it // contains. BackupDirectory backupDirectory; try { backupDirectory = BackupDirectory.readBackupDirectoryDescriptor(v.getValue().toString()); } catch (ConfigException ce) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, ce); } Message message = ERR_BACKUP_INVALID_BACKUP_DIRECTORY.get(String.valueOf(entryDN), ce.getMessage()); throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } Message message = ERR_BACKUP_ERROR_GETTING_BACKUP_DIRECTORY.get(getExceptionMessage(e)); throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message); } // Construct the backup directory entry to return. LinkedHashMap<ObjectClass, String> ocMap = new LinkedHashMap<ObjectClass, String>(2); ocMap.put(DirectoryServer.getTopObjectClass(), OC_TOP); ObjectClass backupDirOC = DirectoryServer.getObjectClass(OC_BACKUP_DIRECTORY, true); ocMap.put(backupDirOC, OC_BACKUP_DIRECTORY); LinkedHashMap<AttributeType, List<Attribute>> opAttrs = new LinkedHashMap<AttributeType, List<Attribute>>(0); LinkedHashMap<AttributeType, List<Attribute>> userAttrs = new LinkedHashMap<AttributeType, List<Attribute>>(3); ArrayList<Attribute> attrList = new ArrayList<Attribute>(1); attrList.add(Attributes.create(t, v)); userAttrs.put(t, attrList); t = DirectoryServer.getAttributeType(ATTR_BACKUP_BACKEND_DN, true); attrList = new ArrayList<Attribute>(1); attrList.add( Attributes.create( t, AttributeValues.create(t, backupDirectory.getConfigEntryDN().toString()))); userAttrs.put(t, attrList); Entry e = new Entry(entryDN, ocMap, userAttrs, opAttrs); e.processVirtualAttributes(); return e; }
/** * Indicates whether to include the entry with the specified DN in the import. * * @param dn The DN of the entry for which to make the determination. * @return <CODE>true</CODE> if the entry with the specified DN should be included in the import, * or <CODE>false</CODE> if not. */ public boolean includeEntry(DN dn) { if (!excludeBranches.isEmpty()) { for (DN excludeBranch : excludeBranches) { if (excludeBranch.isAncestorOf(dn)) { return false; } } } if (!includeBranches.isEmpty()) { for (DN includeBranch : includeBranches) { if (includeBranch.isAncestorOf(dn)) { return true; } } return false; } return true; }
/** {@inheritDoc} */ @Override public Entry getEntry(DN entryDN) throws DirectoryException { // If the requested entry was null, then throw an exception. if (entryDN == null) { throw new DirectoryException( DirectoryServer.getServerErrorResultCode(), ERR_BACKEND_GET_ENTRY_NULL.get(getBackendID())); } // If the requested entry was the backend base entry, then retrieve it. if (entryDN.equals(backupBaseDN)) { return backupBaseEntry.duplicate(true); } // See if the requested entry was one level below the backend base entry. // If so, then it must point to a backup directory. Otherwise, it must be // two levels below the backup base entry and must point to a specific // backup. DN parentDN = entryDN.getParentDNInSuffix(); if (parentDN == null) { Message message = ERR_BACKUP_INVALID_BASE.get(String.valueOf(entryDN)); throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message); } else if (parentDN.equals(backupBaseDN)) { return getBackupDirectoryEntry(entryDN); } else if (backupBaseDN.equals(parentDN.getParentDNInSuffix())) { return getBackupEntry(entryDN); } else { Message message = ERR_BACKUP_INVALID_BASE.get(String.valueOf(entryDN)); throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message, backupBaseDN, null); } }
/** * Create a new child DN from a given parent DN. The child RDN is formed from a given attribute * type and string value. * * @param parentDN The DN of the parent. * @param rdnAttrType The attribute type of the RDN. * @param rdnStringValue The string value of the RDN. * @return A new child DN. */ public static DN makeChildDN(DN parentDN, AttributeType rdnAttrType, String rdnStringValue) { AttributeValue attrValue = AttributeValues.create(rdnAttrType, rdnStringValue); return parentDN.concat(RDN.create(rdnAttrType, attrValue)); }
/** {@inheritDoc} */ @Override public void search(SearchOperation searchOperation) throws DirectoryException { // Get the base entry for the search, if possible. If it doesn't exist, // then this will throw an exception. DN baseDN = searchOperation.getBaseDN(); Entry baseEntry = getEntry(baseDN); // Look at the base DN and see if it's the backup base DN, a backup // directory entry DN, or a backup entry DN. DN parentDN; SearchScope scope = searchOperation.getScope(); SearchFilter filter = searchOperation.getFilter(); if (backupBaseDN.equals(baseDN)) { if ((scope == SearchScope.BASE_OBJECT || scope == SearchScope.WHOLE_SUBTREE) && filter.matchesEntry(baseEntry)) { searchOperation.returnEntry(baseEntry, null); } if (scope != SearchScope.BASE_OBJECT && !backupDirectories.isEmpty()) { AttributeType backupPathType = DirectoryServer.getAttributeType(ATTR_BACKUP_DIRECTORY_PATH, true); for (File f : backupDirectories) { // Check to see if the descriptor file exists. If not, then skip this // backup directory. File descriptorFile = new File(f, BACKUP_DIRECTORY_DESCRIPTOR_FILE); if (!descriptorFile.exists()) { continue; } DN backupDirDN = makeChildDN(backupBaseDN, backupPathType, f.getAbsolutePath()); Entry backupDirEntry; try { backupDirEntry = getBackupDirectoryEntry(backupDirDN); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } continue; } if (filter.matchesEntry(backupDirEntry)) { searchOperation.returnEntry(backupDirEntry, null); } if (scope != SearchScope.SINGLE_LEVEL) { List<Attribute> attrList = backupDirEntry.getAttribute(backupPathType); if (attrList != null && !attrList.isEmpty()) { for (AttributeValue v : attrList.get(0)) { try { BackupDirectory backupDirectory = BackupDirectory.readBackupDirectoryDescriptor(v.getValue().toString()); AttributeType idType = DirectoryServer.getAttributeType(ATTR_BACKUP_ID, true); for (String backupID : backupDirectory.getBackups().keySet()) { DN backupEntryDN = makeChildDN(backupDirDN, idType, backupID); Entry backupEntry = getBackupEntry(backupEntryDN); if (filter.matchesEntry(backupEntry)) { searchOperation.returnEntry(backupEntry, null); } } } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } continue; } } } } } } } else if (backupBaseDN.equals(parentDN = baseDN.getParentDNInSuffix())) { Entry backupDirEntry = getBackupDirectoryEntry(baseDN); if ((scope == SearchScope.BASE_OBJECT || scope == SearchScope.WHOLE_SUBTREE) && filter.matchesEntry(backupDirEntry)) { searchOperation.returnEntry(backupDirEntry, null); } if (scope != SearchScope.BASE_OBJECT) { AttributeType t = DirectoryServer.getAttributeType(ATTR_BACKUP_DIRECTORY_PATH, true); List<Attribute> attrList = backupDirEntry.getAttribute(t); if (attrList != null && !attrList.isEmpty()) { for (AttributeValue v : attrList.get(0)) { try { BackupDirectory backupDirectory = BackupDirectory.readBackupDirectoryDescriptor(v.getValue().toString()); AttributeType idType = DirectoryServer.getAttributeType(ATTR_BACKUP_ID, true); for (String backupID : backupDirectory.getBackups().keySet()) { DN backupEntryDN = makeChildDN(baseDN, idType, backupID); Entry backupEntry = getBackupEntry(backupEntryDN); if (filter.matchesEntry(backupEntry)) { searchOperation.returnEntry(backupEntry, null); } } } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } continue; } } } } } else { if (parentDN == null || !backupBaseDN.equals(parentDN.getParentDNInSuffix())) { Message message = ERR_BACKUP_NO_SUCH_ENTRY.get(String.valueOf(backupBaseDN)); throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message); } if (scope == SearchScope.BASE_OBJECT || scope == SearchScope.WHOLE_SUBTREE) { Entry backupEntry = getBackupEntry(baseDN); if (backupEntry == null) { Message message = ERR_BACKUP_NO_SUCH_ENTRY.get(String.valueOf(backupBaseDN)); throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message); } if (filter.matchesEntry(backupEntry)) { searchOperation.returnEntry(backupEntry, null); } } } }
/** * Generates an entry for a backup based on the provided DN. The DN must have an RDN component * that specifies the backup ID, and the parent DN must have an RDN component that specifies the * backup directory. * * @param entryDN The DN of the backup entry to retrieve. * @return The requested backup entry. * @throws DirectoryException If the specified backup does not exist or is invalid. */ private Entry getBackupEntry(DN entryDN) throws DirectoryException { // First, get the backup ID from the entry DN. AttributeType idType = DirectoryServer.getAttributeType(ATTR_BACKUP_ID, true); AttributeValue idValue = entryDN.getRDN().getAttributeValue(idType); if (idValue == null) { Message message = ERR_BACKUP_NO_BACKUP_ID_IN_DN.get(String.valueOf(entryDN)); throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); } String backupID = idValue.getValue().toString(); // Next, get the backup directory from the parent DN. DN parentDN = entryDN.getParentDNInSuffix(); if (parentDN == null) { Message message = ERR_BACKUP_NO_BACKUP_PARENT_DN.get(String.valueOf(entryDN)); throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); } AttributeType t = DirectoryServer.getAttributeType(ATTR_BACKUP_DIRECTORY_PATH, true); AttributeValue v = parentDN.getRDN().getAttributeValue(t); if (v == null) { Message message = ERR_BACKUP_NO_BACKUP_DIR_IN_DN.get(String.valueOf(entryDN)); throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); } BackupDirectory backupDirectory; try { backupDirectory = BackupDirectory.readBackupDirectoryDescriptor(v.getValue().toString()); } catch (ConfigException ce) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, ce); } Message message = ERR_BACKUP_INVALID_BACKUP_DIRECTORY.get(String.valueOf(entryDN), ce.getMessageObject()); throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } Message message = ERR_BACKUP_ERROR_GETTING_BACKUP_DIRECTORY.get(getExceptionMessage(e)); throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message); } BackupInfo backupInfo = backupDirectory.getBackupInfo(backupID); if (backupInfo == null) { Message message = ERR_BACKUP_NO_SUCH_BACKUP.get(backupID, backupDirectory.getPath()); throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message, parentDN, null); } // Construct the backup entry to return. LinkedHashMap<ObjectClass, String> ocMap = new LinkedHashMap<ObjectClass, String>(3); ocMap.put(DirectoryServer.getTopObjectClass(), OC_TOP); ObjectClass oc = DirectoryServer.getObjectClass(OC_BACKUP_INFO, true); ocMap.put(oc, OC_BACKUP_INFO); oc = DirectoryServer.getObjectClass(OC_EXTENSIBLE_OBJECT_LC, true); ocMap.put(oc, OC_EXTENSIBLE_OBJECT); LinkedHashMap<AttributeType, List<Attribute>> opAttrs = new LinkedHashMap<AttributeType, List<Attribute>>(0); LinkedHashMap<AttributeType, List<Attribute>> userAttrs = new LinkedHashMap<AttributeType, List<Attribute>>(); ArrayList<Attribute> attrList = new ArrayList<Attribute>(1); attrList.add(Attributes.create(idType, idValue)); userAttrs.put(idType, attrList); backupInfo.getBackupDirectory(); attrList = new ArrayList<Attribute>(1); attrList.add(Attributes.create(t, v)); userAttrs.put(t, attrList); Date backupDate = backupInfo.getBackupDate(); if (backupDate != null) { t = DirectoryServer.getAttributeType(ATTR_BACKUP_DATE, true); attrList = new ArrayList<Attribute>(1); attrList.add( Attributes.create( t, AttributeValues.create(t, GeneralizedTimeSyntax.format(backupDate)))); userAttrs.put(t, attrList); } t = DirectoryServer.getAttributeType(ATTR_BACKUP_COMPRESSED, true); attrList = new ArrayList<Attribute>(1); attrList.add(Attributes.create(t, BooleanSyntax.createBooleanValue(backupInfo.isCompressed()))); userAttrs.put(t, attrList); t = DirectoryServer.getAttributeType(ATTR_BACKUP_ENCRYPTED, true); attrList = new ArrayList<Attribute>(1); attrList.add(Attributes.create(t, BooleanSyntax.createBooleanValue(backupInfo.isEncrypted()))); userAttrs.put(t, attrList); t = DirectoryServer.getAttributeType(ATTR_BACKUP_INCREMENTAL, true); attrList = new ArrayList<Attribute>(1); attrList.add( Attributes.create(t, BooleanSyntax.createBooleanValue(backupInfo.isIncremental()))); userAttrs.put(t, attrList); HashSet<String> dependencies = backupInfo.getDependencies(); if (dependencies != null && !dependencies.isEmpty()) { t = DirectoryServer.getAttributeType(ATTR_BACKUP_DEPENDENCY, true); AttributeBuilder builder = new AttributeBuilder(t); for (String s : dependencies) { builder.add(AttributeValues.create(t, s)); } attrList = new ArrayList<Attribute>(1); attrList.add(builder.toAttribute()); userAttrs.put(t, attrList); } byte[] signedHash = backupInfo.getSignedHash(); if (signedHash != null) { t = DirectoryServer.getAttributeType(ATTR_BACKUP_SIGNED_HASH, true); attrList = new ArrayList<Attribute>(1); attrList.add(Attributes.create(t, AttributeValues.create(t, ByteString.wrap(signedHash)))); userAttrs.put(t, attrList); } byte[] unsignedHash = backupInfo.getUnsignedHash(); if (unsignedHash != null) { t = DirectoryServer.getAttributeType(ATTR_BACKUP_UNSIGNED_HASH, true); attrList = new ArrayList<Attribute>(1); attrList.add(Attributes.create(t, AttributeValues.create(t, ByteString.wrap(unsignedHash)))); userAttrs.put(t, attrList); } HashMap<String, String> properties = backupInfo.getBackupProperties(); if (properties != null && !properties.isEmpty()) { for (Map.Entry<String, String> e : properties.entrySet()) { t = DirectoryServer.getAttributeType(toLowerCase(e.getKey()), true); attrList = new ArrayList<Attribute>(1); attrList.add(Attributes.create(t, AttributeValues.create(t, e.getValue()))); userAttrs.put(t, attrList); } } Entry e = new Entry(entryDN, ocMap, userAttrs, opAttrs); e.processVirtualAttributes(); return e; }
/** {@inheritDoc} */ @Override public long numSubordinates(DN entryDN, boolean subtree) throws DirectoryException { // If the requested entry was null, then return undefined. if (entryDN == null) { return -1; } // If the requested entry was the backend base entry, then return // the number of backup directories. if (backupBaseDN.equals(entryDN)) { long count = 0; for (File f : backupDirectories) { // Check to see if the descriptor file exists. If not, then skip this // backup directory. File descriptorFile = new File(f, BACKUP_DIRECTORY_DESCRIPTOR_FILE); if (!descriptorFile.exists()) { continue; } // If subtree is included, count the number of entries for each // backup directory. if (subtree) { try { BackupDirectory backupDirectory = BackupDirectory.readBackupDirectoryDescriptor(f.getPath()); count += backupDirectory.getBackups().keySet().size(); } catch (Exception e) { return -1; } } count++; } return count; } // See if the requested entry was one level below the backend base entry. // If so, then it must point to a backup directory. Otherwise, it must be // two levels below the backup base entry and must point to a specific // backup. DN parentDN = entryDN.getParentDNInSuffix(); if (parentDN == null) { return -1; } else if (backupBaseDN.equals(parentDN)) { long count = 0; Entry backupDirEntry = getBackupDirectoryEntry(entryDN); AttributeType t = DirectoryServer.getAttributeType(ATTR_BACKUP_DIRECTORY_PATH, true); List<Attribute> attrList = backupDirEntry.getAttribute(t); if (attrList != null && !attrList.isEmpty()) { for (AttributeValue v : attrList.get(0)) { try { BackupDirectory backupDirectory = BackupDirectory.readBackupDirectoryDescriptor(v.getValue().toString()); count += backupDirectory.getBackups().keySet().size(); } catch (Exception e) { return -1; } } } return count; } else if (backupBaseDN.equals(parentDN.getParentDNInSuffix())) { return 0; } else { return -1; } }
/** {@inheritDoc} */ @Override public void initializeBackend() throws ConfigException, InitializationException { // Create the set of base DNs that we will handle. In this case, it's just // the DN of the base backup entry. try { backupBaseDN = DN.decode(DN_BACKUP_ROOT); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } Message message = ERR_BACKEND_CANNOT_DECODE_BACKEND_ROOT_DN.get(getExceptionMessage(e), getBackendID()); throw new InitializationException(message, e); } // FIXME -- Deal with this more correctly. this.baseDNs = new DN[] {backupBaseDN}; // Determine the set of backup directories that we will use by default. Set<String> values = currentConfig.getBackupDirectory(); backupDirectories = new LinkedHashSet<File>(values.size()); for (String s : values) { backupDirectories.add(getFileForPath(s)); } // Construct the backup base entry. LinkedHashMap<ObjectClass, String> objectClasses = new LinkedHashMap<ObjectClass, String>(2); objectClasses.put(DirectoryServer.getTopObjectClass(), OC_TOP); ObjectClass untypedOC = DirectoryServer.getObjectClass(OC_UNTYPED_OBJECT_LC, true); objectClasses.put(untypedOC, OC_UNTYPED_OBJECT); LinkedHashMap<AttributeType, List<Attribute>> opAttrs = new LinkedHashMap<AttributeType, List<Attribute>>(0); LinkedHashMap<AttributeType, List<Attribute>> userAttrs = new LinkedHashMap<AttributeType, List<Attribute>>(1); RDN rdn = backupBaseDN.getRDN(); int numAVAs = rdn.getNumValues(); for (int i = 0; i < numAVAs; i++) { AttributeType attrType = rdn.getAttributeType(i); ArrayList<Attribute> attrList = new ArrayList<Attribute>(1); attrList.add(Attributes.create(attrType, rdn.getAttributeValue(i))); userAttrs.put(attrType, attrList); } backupBaseEntry = new Entry(backupBaseDN, objectClasses, userAttrs, opAttrs); currentConfig.addBackupChangeListener(this); // Register the backup base as a private suffix. try { DirectoryServer.registerBaseDN(backupBaseDN, this, true); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } Message message = ERR_BACKEND_CANNOT_REGISTER_BASEDN.get(backupBaseDN.toString(), getExceptionMessage(e)); throw new InitializationException(message, e); } }
/** Tests the maximum persistent search limit imposed by the server. */ @Test public void testMaxPSearch() throws Exception { TestCaseUtils.initializeTestBackend(true); // Modify the configuration to allow only 1 concurrent persistent search. InternalClientConnection conn = getRootConnection(); LDAPAttribute attr = new LDAPAttribute("ds-cfg-max-psearches", "1"); ArrayList<RawModification> mods = new ArrayList<>(); mods.add(new LDAPModification(ModificationType.REPLACE, attr)); ModifyOperation modifyOperation = conn.processModify(ByteString.valueOf("cn=config"), mods); assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS); // Create a persistent search request. Set<PersistentSearchChangeType> changeTypes = EnumSet.of(ADD, DELETE, MODIFY, MODIFY_DN); SearchRequest request = newSearchRequest(DN.valueOf("o=test"), SearchScope.BASE_OBJECT) .setTypesOnly(true) .addAttribute("cn") .addControl(new PersistentSearchControl(changeTypes, true, true)); final InternalSearchOperation search = conn.processSearch(request); Thread t = new Thread( new Runnable() { @Override public void run() { try { search.run(); } catch (Exception ex) { } } }, "Persistent Search Test"); t.start(); t.join(2000); // Create a persistent search request. final String[] args = { "-D", "cn=Directory Manager", "-w", "password", "-h", "127.0.0.1", "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), "-b", "o=test", "-s", "sub", "-C", "ps:add:true:true", "--noPropertiesFile", "(objectClass=*)" }; assertEquals(LDAPSearch.mainSearch(args, false, true, null, System.err), 11); // cancel the persisting persistent search. search.cancel(new CancelRequest(true, LocalizableMessage.EMPTY)); }
/** Test EntryChangeNotificationControl. */ @Test(dataProvider = "entryChangeNotificationControl") public void checkEntryChangeNotificationControlTest( boolean isCritical, long changeNumber, String dnString) throws Exception { // Test constructor EntryChangeNotificationControl // (PersistentSearchChangeType changeType,long changeNumber) PersistentSearchChangeType[] types = PersistentSearchChangeType.values(); EntryChangeNotificationControl ecnc = null; EntryChangeNotificationControl newEcnc; ByteStringBuilder bsb = new ByteStringBuilder(); ASN1Writer writer = ASN1.getWriter(bsb); for (PersistentSearchChangeType type : types) { ecnc = new EntryChangeNotificationControl(type, changeNumber); assertNotNull(ecnc); assertEquals(OID_ENTRY_CHANGE_NOTIFICATION, ecnc.getOID()); assertEquals(changeNumber, ecnc.getChangeNumber()); assertEquals(type, ecnc.getChangeType()); assertNull(ecnc.getPreviousDN()); assertEquals(false, ecnc.isCritical()); checkEntryChangeNotificationControlToString(ecnc); // also check encode/decode try { bsb.clear(); ecnc.write(writer); LDAPControl control = LDAPReader.readControl(ASN1.getReader(bsb)); newEcnc = EntryChangeNotificationControl.DECODER.decode(control.isCritical(), control.getValue()); assertNotNull(newEcnc); assertEquals(ecnc.getOID(), newEcnc.getOID()); assertEquals(ecnc.getChangeNumber(), newEcnc.getChangeNumber()); assertEquals(ecnc.getChangeType(), newEcnc.getChangeType()); assertNull(newEcnc.getPreviousDN()); assertEquals(ecnc.isCritical(), newEcnc.isCritical()); } catch (DirectoryException e) { fail(); } } // Test constructor EntryChangeNotificationControl // (PersistentSearchChangeType changeType, DN previousDN, long // changeNumber) DN dn = DN.valueOf(dnString); for (PersistentSearchChangeType type : types) { ecnc = new EntryChangeNotificationControl(type, dn, changeNumber); assertNotNull(ecnc); assertEquals(OID_ENTRY_CHANGE_NOTIFICATION, ecnc.getOID()); assertEquals(changeNumber, ecnc.getChangeNumber()); assertEquals(type, ecnc.getChangeType()); assertEquals(dn, ecnc.getPreviousDN()); assertEquals(false, ecnc.isCritical()); checkEntryChangeNotificationControlToString(ecnc); // also check encode/decode try { bsb.clear(); ecnc.write(writer); LDAPControl control = LDAPReader.readControl(ASN1.getReader(bsb)); newEcnc = EntryChangeNotificationControl.DECODER.decode(control.isCritical(), control.getValue()); assertNotNull(newEcnc); assertEquals(ecnc.getOID(), newEcnc.getOID()); assertEquals(ecnc.getChangeNumber(), newEcnc.getChangeNumber()); assertEquals(ecnc.getChangeType(), newEcnc.getChangeType()); assertEquals(ecnc.getPreviousDN(), newEcnc.getPreviousDN()); assertEquals(ecnc.isCritical(), newEcnc.isCritical()); } catch (DirectoryException e) { assertNotEquals( type.compareTo(MODIFY_DN), 0, "couldn't decode a control with previousDN not null and type=modDN"); } } // Test constructor EntryChangeNotificationControl(boolean // isCritical, PersistentSearchChangeType changeType, // DN previousDN, long changeNumber) for (PersistentSearchChangeType type : types) { ecnc = new EntryChangeNotificationControl(isCritical, type, dn, changeNumber); assertNotNull(ecnc); assertEquals(OID_ENTRY_CHANGE_NOTIFICATION, ecnc.getOID()); assertEquals(changeNumber, ecnc.getChangeNumber()); assertEquals(type, ecnc.getChangeType()); assertEquals(dn, ecnc.getPreviousDN()); assertEquals(isCritical, ecnc.isCritical()); checkEntryChangeNotificationControlToString(ecnc); // also check encode/decode try { bsb.clear(); ecnc.write(writer); LDAPControl control = LDAPReader.readControl(ASN1.getReader(bsb)); newEcnc = EntryChangeNotificationControl.DECODER.decode(control.isCritical(), control.getValue()); assertNotNull(newEcnc); assertEquals(ecnc.getOID(), newEcnc.getOID()); assertEquals(ecnc.getChangeNumber(), newEcnc.getChangeNumber()); assertEquals(ecnc.getChangeType(), newEcnc.getChangeType()); assertEquals(ecnc.getPreviousDN(), newEcnc.getPreviousDN()); assertEquals(ecnc.isCritical(), newEcnc.isCritical()); } catch (DirectoryException e) { assertNotEquals( type.compareTo(PersistentSearchChangeType.MODIFY_DN), 0, "couldn't decode a control with previousDN not null and type=modDN"); } } // Check error on decode try { LDAPControl control = new LDAPControl(OID_ENTRY_CHANGE_NOTIFICATION, isCritical); newEcnc = EntryChangeNotificationControl.DECODER.decode(control.isCritical(), control.getValue()); fail(); } catch (DirectoryException expected) { assertEquals(expected.getMessage(), CANNOT_DECODE_CHANGE_NOTIF_CONTROL_NO_VALUE); } }