/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2006-2008 Sun Microsystems, Inc. */ package org.opends.server.backends; import java.io.File; import java.util.*; import org.opends.messages.Message; import org.opends.server.admin.Configuration; import org.opends.server.admin.server.ConfigurationChangeListener; import org.opends.server.admin.std.server.BackupBackendCfg; import org.opends.server.api.Backend; import org.opends.server.config.ConfigException; import org.opends.server.core.AddOperation; import org.opends.server.core.DeleteOperation; import org.opends.server.core.DirectoryServer; import org.opends.server.core.ModifyOperation; import org.opends.server.core.ModifyDNOperation; import org.opends.server.core.SearchOperation; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.types.*; import org.opends.server.schema.BooleanSyntax; import org.opends.server.schema.GeneralizedTimeSyntax; import org.opends.server.util.Validator; import static org.opends.messages.BackendMessages.*; import static org.opends.server.config.ConfigConstants.*; import static org.opends.server.loggers.debug.DebugLogger.*; import static org.opends.server.util.ServerConstants.*; import static org.opends.server.util.StaticUtils.*; /** * This class defines a backend used to present information about Directory * Server backups. It will not actually store anything, but upon request will * retrieve information about the backups that it knows about. The backups will * be arranged in a hierarchy based on the directory that contains them, and * it may be possible to dynamically discover new backups if a previously * unknown backup directory is included in the base DN. */ public class BackupBackend extends Backend implements ConfigurationChangeListener<BackupBackendCfg> { /** * The tracer object for the debug logger. */ private static final DebugTracer TRACER = getTracer(); // The current configuration state. private BackupBackendCfg currentConfig; // The DN for the base backup entry. private DN backupBaseDN; // The set of base DNs for this backend. private DN[] baseDNs; // The backup base entry. private Entry backupBaseEntry; // The set of supported controls for this backend. private HashSet<String> supportedControls; // The set of supported features for this backend. private HashSet<String> supportedFeatures; // The set of predefined backup directories that we will use. private LinkedHashSet<File> backupDirectories; /** * Creates a new backend with the provided information. All backend * implementations must implement a default constructor that use * <CODE>super()</CODE> to invoke this constructor. */ public BackupBackend() { super(); // Perform all initialization in initializeBackend. } /** * {@inheritDoc} */ @Override() public void configureBackend(Configuration config) throws ConfigException { // Make sure that a configuration entry was provided. If not, then we will // not be able to complete initialization. if (config == null) { Message message = ERR_BACKUP_CONFIG_ENTRY_NULL.get(); throw new ConfigException(message); } Validator.ensureTrue(config instanceof BackupBackendCfg); currentConfig = (BackupBackendCfg)config; } /** * {@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_BACKUP_CANNOT_DECODE_BACKUP_ROOT_DN.get(getExceptionMessage(e)); 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); // Define an empty sets for the supported controls and features. supportedControls = new HashSet<String>(0); supportedFeatures = new HashSet<String>(0); // Register this as a change listener. 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); } } /** * {@inheritDoc} */ @Override() public void finalizeBackend() { currentConfig.removeBackupChangeListener(this); try { DirectoryServer.deregisterBaseDN(backupBaseDN); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } } } /** * {@inheritDoc} */ @Override() public DN[] getBaseDNs() { return baseDNs; } /** * {@inheritDoc} */ @Override() public long getEntryCount() { int numEntries = 1; AttributeType backupPathType = DirectoryServer.getAttributeType(ATTR_BACKUP_DIRECTORY_PATH, true); for (File f : backupDirectories) { try { // 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()); getBackupDirectoryEntry(backupDirDN); numEntries++; } catch (Exception e) {} } return numEntries; } /** * {@inheritDoc} */ @Override() public boolean isLocal() { // For the purposes of this method, this is a local backend. return true; } /** * {@inheritDoc} */ @Override() public boolean isIndexed(AttributeType attributeType, IndexType indexType) { // All searches in this backend will always be considered indexed. return true; } /** * {@inheritDoc} */ @Override() public ConditionResult hasSubordinates(DN entryDN) throws DirectoryException { long ret = numSubordinates(entryDN, false); if(ret < 0) { return ConditionResult.UNDEFINED; } else if(ret == 0) { return ConditionResult.FALSE; } else { return ConditionResult.TRUE; } } /** * {@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 Entry getEntry(DN entryDN) throws DirectoryException { // If the requested entry was null, then throw an exception. if (entryDN == null) { Message message = ERR_BACKUP_GET_ENTRY_NULL.get(); throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message); } // 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); } } /** * 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; } /** * 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 void addEntry(Entry entry, AddOperation addOperation) throws DirectoryException { Message message = ERR_BACKUP_ADD_NOT_SUPPORTED.get(); throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); } /** * {@inheritDoc} */ @Override() public void deleteEntry(DN entryDN, DeleteOperation deleteOperation) throws DirectoryException { Message message = ERR_BACKUP_DELETE_NOT_SUPPORTED.get(); throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); } /** * {@inheritDoc} */ @Override() public void replaceEntry(Entry oldEntry, Entry newEntry, ModifyOperation modifyOperation) throws DirectoryException { Message message = ERR_BACKUP_MODIFY_NOT_SUPPORTED.get(); throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); } /** * {@inheritDoc} */ @Override() public void renameEntry(DN currentDN, Entry entry, ModifyDNOperation modifyDNOperation) throws DirectoryException { Message message = ERR_BACKUP_MODIFY_DN_NOT_SUPPORTED.get(); throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); } /** * {@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)) { if (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)) { if (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); } } } } /** * {@inheritDoc} */ @Override() public HashSet<String> getSupportedControls() { return supportedControls; } /** * {@inheritDoc} */ @Override() public HashSet<String> getSupportedFeatures() { return supportedFeatures; } /** * {@inheritDoc} */ @Override() public boolean supportsLDIFExport() { // We do not support LDIF exports. return false; } /** * {@inheritDoc} */ @Override() public void exportLDIF(LDIFExportConfig exportConfig) throws DirectoryException { Message message = ERR_BACKUP_EXPORT_NOT_SUPPORTED.get(); throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); } /** * {@inheritDoc} */ @Override() public boolean supportsLDIFImport() { // This backend does not support LDIF imports. return false; } /** * {@inheritDoc} */ @Override() public LDIFImportResult importLDIF(LDIFImportConfig importConfig) throws DirectoryException { // This backend does not support LDIF imports. Message message = ERR_BACKUP_IMPORT_NOT_SUPPORTED.get(); throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); } /** * {@inheritDoc} */ @Override() public boolean supportsBackup() { // This backend does not provide a backup/restore mechanism. return false; } /** * {@inheritDoc} */ @Override() public boolean supportsBackup(BackupConfig backupConfig, StringBuilder unsupportedReason) { // This backend does not provide a backup/restore mechanism. return false; } /** * {@inheritDoc} */ @Override() public void createBackup(BackupConfig backupConfig) throws DirectoryException { // This backend does not provide a backup/restore mechanism. Message message = ERR_BACKUP_BACKUP_AND_RESTORE_NOT_SUPPORTED.get(); throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); } /** * {@inheritDoc} */ @Override() public void removeBackup(BackupDirectory backupDirectory, String backupID) throws DirectoryException { // This backend does not provide a backup/restore mechanism. Message message = ERR_BACKUP_BACKUP_AND_RESTORE_NOT_SUPPORTED.get(); throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); } /** * {@inheritDoc} */ @Override() public boolean supportsRestore() { // This backend does not provide a backup/restore mechanism. return false; } /** * {@inheritDoc} */ @Override() public void restoreBackup(RestoreConfig restoreConfig) throws DirectoryException { // This backend does not provide a backup/restore mechanism. Message message = ERR_BACKUP_BACKUP_AND_RESTORE_NOT_SUPPORTED.get(); throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); } /** * {@inheritDoc} */ public boolean isConfigurationChangeAcceptable( BackupBackendCfg cfg, List<Message> unacceptableReasons) { // We'll accept anything here. The only configurable attribute is the // default set of backup directories, but that doesn't require any // validation at this point. return true; } /** * {@inheritDoc} */ public ConfigChangeResult applyConfigurationChange(BackupBackendCfg cfg) { ResultCode resultCode = ResultCode.SUCCESS; boolean adminActionRequired = false; ArrayList<Message> messages = new ArrayList<Message>(); Set<String> values = cfg.getBackupDirectory(); backupDirectories = new LinkedHashSet<File>(values.size()); for (String s : values) { backupDirectories.add(getFileForPath(s)); } currentConfig = cfg; return new ConfigChangeResult(resultCode, adminActionRequired, messages); } /** * 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} */ public void preloadEntryCache() throws UnsupportedOperationException { throw new UnsupportedOperationException("Operation not supported."); } }