| | |
| | | * |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014 ForgeRock AS |
| | | */ |
| | | 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.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.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 |
| | |
| | | * unknown backup directory is included in the base DN. |
| | | */ |
| | | public class BackupBackend |
| | | extends Backend |
| | | extends Backend<BackupBackendCfg> |
| | | implements ConfigurationChangeListener<BackupBackendCfg> |
| | | { |
| | | /** |
| | |
| | | |
| | | |
| | | |
| | | // The current configuration state. |
| | | /** The current configuration state. */ |
| | | private BackupBackendCfg currentConfig; |
| | | |
| | | // The DN for the base backup entry. |
| | | /** The DN for the base backup entry. */ |
| | | private DN backupBaseDN; |
| | | |
| | | // The set of base DNs for this backend. |
| | | /** The set of base DNs for this backend. */ |
| | | private DN[] baseDNs; |
| | | |
| | | // The backup base entry. |
| | | /** 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. |
| | | /** The set of predefined backup directories that we will use. */ |
| | | private LinkedHashSet<File> backupDirectories; |
| | | |
| | | |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | public void configureBackend(Configuration config) throws ConfigException |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void configureBackend(BackupBackendCfg 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); |
| | | throw new ConfigException(ERR_BACKEND_CONFIG_ENTRY_NULL.get(getBackendID())); |
| | | } |
| | | |
| | | |
| | | Validator.ensureTrue(config instanceof BackupBackendCfg); |
| | | |
| | | currentConfig = (BackupBackendCfg)config; |
| | | currentConfig = config; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void initializeBackend() |
| | | throws ConfigException, InitializationException |
| | | { |
| | |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, e); |
| | | } |
| | | |
| | | Message message = |
| | | ERR_BACKUP_CANNOT_DECODE_BACKUP_ROOT_DN.get(getExceptionMessage(e)); |
| | | Message message = ERR_BACKEND_CANNOT_DECODE_BACKEND_ROOT_DN.get( |
| | | getExceptionMessage(e), getBackendID()); |
| | | throw new InitializationException(message, e); |
| | | } |
| | | |
| | |
| | | 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 |
| | | { |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void finalizeBackend() |
| | | { |
| | | currentConfig.removeBackupChangeListener(this); |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public DN[] getBaseDNs() |
| | | { |
| | | return baseDNs; |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public long getEntryCount() |
| | | { |
| | | int numEntries = 1; |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean isLocal() |
| | | { |
| | | // For the purposes of this method, this is a local backend. |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean isIndexed(AttributeType attributeType, IndexType indexType) |
| | | { |
| | | // All searches in this backend will always be considered indexed. |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public ConditionResult hasSubordinates(DN entryDN) throws DirectoryException |
| | | { |
| | | long ret = numSubordinates(entryDN, false); |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public long numSubordinates(DN entryDN, boolean subtree) |
| | | throws DirectoryException |
| | | { |
| | |
| | | AttributeType t = |
| | | DirectoryServer.getAttributeType(ATTR_BACKUP_DIRECTORY_PATH, true); |
| | | List<Attribute> attrList = backupDirEntry.getAttribute(t); |
| | | if ((attrList != null) && (! attrList.isEmpty())) |
| | | if (attrList != null && !attrList.isEmpty()) |
| | | { |
| | | for (AttributeValue v : attrList.get(0)) |
| | | { |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | /** {@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); |
| | | ERR_BACKEND_GET_ENTRY_NULL.get(getBackendID())); |
| | | } |
| | | |
| | | |
| | |
| | | userAttrs.put(t, attrList); |
| | | |
| | | HashSet<String> dependencies = backupInfo.getDependencies(); |
| | | if ((dependencies != null) && (!dependencies.isEmpty())) { |
| | | if (dependencies != null && !dependencies.isEmpty()) { |
| | | t = DirectoryServer.getAttributeType(ATTR_BACKUP_DEPENDENCY, true); |
| | | AttributeBuilder builder = new AttributeBuilder(t); |
| | | for (String s : dependencies) { |
| | |
| | | } |
| | | |
| | | HashMap<String, String> properties = backupInfo.getBackupProperties(); |
| | | if ((properties != null) && (!properties.isEmpty())) { |
| | | 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); |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | /** {@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); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, |
| | | ERR_BACKEND_ADD_NOT_SUPPORTED.get(String.valueOf(entry.getDN()), getBackendID())); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | /** {@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); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, |
| | | ERR_BACKEND_DELETE_NOT_SUPPORTED.get(String.valueOf(entryDN), getBackendID())); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | /** {@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); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, |
| | | ERR_BACKEND_MODIFY_NOT_SUPPORTED.get(String.valueOf(oldEntry.getDN()), getBackendID())); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | /** {@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); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, |
| | | ERR_BACKEND_MODIFY_DN_NOT_SUPPORTED.get(String.valueOf(currentDN), getBackendID())); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void search(SearchOperation searchOperation) |
| | | throws DirectoryException |
| | | { |
| | |
| | | SearchFilter filter = searchOperation.getFilter(); |
| | | if (backupBaseDN.equals(baseDN)) |
| | | { |
| | | if ((scope == SearchScope.BASE_OBJECT) || |
| | | (scope == SearchScope.WHOLE_SUBTREE)) |
| | | if ((scope == SearchScope.BASE_OBJECT || scope == SearchScope.WHOLE_SUBTREE) |
| | | && filter.matchesEntry(baseEntry)) |
| | | { |
| | | if (filter.matchesEntry(baseEntry)) |
| | | { |
| | | searchOperation.returnEntry(baseEntry, null); |
| | | } |
| | | searchOperation.returnEntry(baseEntry, null); |
| | | } |
| | | |
| | | if ((scope != SearchScope.BASE_OBJECT) && (! backupDirectories.isEmpty())) |
| | | if (scope != SearchScope.BASE_OBJECT && !backupDirectories.isEmpty()) |
| | | { |
| | | AttributeType backupPathType = |
| | | DirectoryServer.getAttributeType(ATTR_BACKUP_DIRECTORY_PATH, true); |
| | |
| | | { |
| | | List<Attribute> attrList = |
| | | backupDirEntry.getAttribute(backupPathType); |
| | | if ((attrList != null) && (! attrList.isEmpty())) |
| | | if (attrList != null && !attrList.isEmpty()) |
| | | { |
| | | for (AttributeValue v : attrList.get(0)) |
| | | { |
| | |
| | | { |
| | | Entry backupDirEntry = getBackupDirectoryEntry(baseDN); |
| | | |
| | | if ((scope == SearchScope.BASE_OBJECT) || |
| | | (scope == SearchScope.WHOLE_SUBTREE)) |
| | | if ((scope == SearchScope.BASE_OBJECT || scope == SearchScope.WHOLE_SUBTREE) |
| | | && filter.matchesEntry(backupDirEntry)) |
| | | { |
| | | if (filter.matchesEntry(backupDirEntry)) |
| | | { |
| | | searchOperation.returnEntry(backupDirEntry, null); |
| | | } |
| | | searchOperation.returnEntry(backupDirEntry, null); |
| | | } |
| | | |
| | | |
| | |
| | | AttributeType t = |
| | | DirectoryServer.getAttributeType(ATTR_BACKUP_DIRECTORY_PATH, true); |
| | | List<Attribute> attrList = backupDirEntry.getAttribute(t); |
| | | if ((attrList != null) && (! attrList.isEmpty())) |
| | | if (attrList != null && !attrList.isEmpty()) |
| | | { |
| | | for (AttributeValue v : attrList.get(0)) |
| | | { |
| | |
| | | } |
| | | else |
| | | { |
| | | if ((parentDN == null) |
| | | || (! backupBaseDN.equals(parentDN.getParentDNInSuffix()))) |
| | | 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)) |
| | | if (scope == SearchScope.BASE_OBJECT || |
| | | scope == SearchScope.WHOLE_SUBTREE) |
| | | { |
| | | Entry backupEntry = getBackupEntry(baseDN); |
| | | if (backupEntry == null) |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | public HashSet<String> getSupportedControls() |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Set<String> getSupportedControls() |
| | | { |
| | | return supportedControls; |
| | | return Collections.emptySet(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | public HashSet<String> getSupportedFeatures() |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Set<String> getSupportedFeatures() |
| | | { |
| | | return supportedFeatures; |
| | | return Collections.emptySet(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean supportsLDIFExport() |
| | | { |
| | | // We do not support LDIF exports. |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | /** {@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); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, |
| | | ERR_BACKEND_IMPORT_AND_EXPORT_NOT_SUPPORTED.get(getBackendID())); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean supportsLDIFImport() |
| | | { |
| | | // This backend does not support LDIF imports. |
| | | return false; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | /** {@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); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, |
| | | ERR_BACKEND_IMPORT_AND_EXPORT_NOT_SUPPORTED.get(getBackendID())); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean supportsBackup() |
| | | { |
| | | // This backend does not provide a backup/restore mechanism. |
| | | return false; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean supportsBackup(BackupConfig backupConfig, |
| | | StringBuilder unsupportedReason) |
| | | { |
| | | // This backend does not provide a backup/restore mechanism. |
| | | return false; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | /** {@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); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, |
| | | ERR_BACKEND_BACKUP_AND_RESTORE_NOT_SUPPORTED.get(getBackendID())); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | /** {@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); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, |
| | | ERR_BACKEND_BACKUP_AND_RESTORE_NOT_SUPPORTED.get(getBackendID())); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean supportsRestore() |
| | | { |
| | | // This backend does not provide a backup/restore mechanism. |
| | | return false; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | /** {@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); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, |
| | | ERR_BACKEND_BACKUP_AND_RESTORE_NOT_SUPPORTED.get(getBackendID())); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean isConfigurationChangeAcceptable( |
| | | BackupBackendCfg cfg, List<Message> unacceptableReasons) |
| | | { |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public ConfigChangeResult applyConfigurationChange(BackupBackendCfg cfg) |
| | | { |
| | | ResultCode resultCode = ResultCode.SUCCESS; |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void preloadEntryCache() throws UnsupportedOperationException { |
| | | throw new UnsupportedOperationException("Operation not supported."); |
| | | } |