/* * 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-2009 Sun Microsystems, Inc. */ package org.opends.server.tasks; import org.opends.messages.Message; import org.opends.messages.TaskMessages; import static org.opends.server.core.DirectoryServer.getAttributeType; import static org.opends.server.config.ConfigConstants.*; import static org.opends.messages.TaskMessages.*; import static org.opends.messages.ToolMessages.*; import static org.opends.server.util.StaticUtils.*; import org.opends.server.backends.task.Task; import org.opends.server.backends.task.TaskState; import org.opends.server.core.DirectoryServer; import org.opends.server.core.LockFileManager; import org.opends.server.api.Backend; import org.opends.server.api.ClientConnection; import org.opends.server.types.Attribute; import org.opends.server.types.AttributeType; import org.opends.server.types.DirectoryException; import org.opends.server.types.DN; import org.opends.server.types.Entry; import org.opends.server.types.ExistingFileBehavior; import org.opends.server.types.LDIFExportConfig; import org.opends.server.types.Operation; import org.opends.server.types.Privilege; import org.opends.server.types.ResultCode; import org.opends.server.types.SearchFilter; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.HashMap; import java.io.File; /** * This class provides an implementation of a Directory Server task that can * be used to export the contents of a Directory Server backend to an LDIF file. */ public class ExportTask extends Task { /** * Stores mapping between configuration attribute name and its label. */ static private Map<String,Message> argDisplayMap = new HashMap<String,Message>(); static { argDisplayMap.put( ATTR_TASK_EXPORT_LDIF_FILE, INFO_EXPORT_ARG_LDIF_FILE.get()); argDisplayMap.put( ATTR_TASK_EXPORT_BACKEND_ID, INFO_EXPORT_ARG_BACKEND_ID.get()); argDisplayMap.put( ATTR_TASK_EXPORT_APPEND_TO_LDIF, INFO_EXPORT_ARG_APPEND_TO_LDIF.get()); argDisplayMap.put( ATTR_TASK_EXPORT_COMPRESS_LDIF, INFO_EXPORT_ARG_COMPRESS_LDIF.get()); argDisplayMap.put( ATTR_TASK_EXPORT_ENCRYPT_LDIF, INFO_EXPORT_ARG_ENCRYPT_LDIF.get()); argDisplayMap.put( ATTR_TASK_EXPORT_SIGN_HASH, INFO_EXPORT_ARG_SIGN_HASH.get()); argDisplayMap.put( ATTR_TASK_EXPORT_INCLUDE_ATTRIBUTE, INFO_EXPORT_ARG_INCL_ATTR.get()); argDisplayMap.put( ATTR_TASK_EXPORT_EXCLUDE_ATTRIBUTE, INFO_EXPORT_ARG_EXCL_ATTR.get()); argDisplayMap.put( ATTR_TASK_EXPORT_INCLUDE_FILTER, INFO_EXPORT_ARG_INCL_FILTER.get()); argDisplayMap.put( ATTR_TASK_EXPORT_EXCLUDE_FILTER, INFO_EXPORT_ARG_EXCL_FILTER.get()); argDisplayMap.put( ATTR_TASK_EXPORT_INCLUDE_BRANCH, INFO_EXPORT_ARG_INCL_BRANCH.get()); argDisplayMap.put( ATTR_TASK_EXPORT_EXCLUDE_BRANCH, INFO_EXPORT_ARG_EXCL_BRANCH.get()); argDisplayMap.put( ATTR_TASK_EXPORT_WRAP_COLUMN, INFO_EXPORT_ARG_WRAP_COLUMN.get()); } private String ldifFile; private String backendID; private int wrapColumn; private boolean appendToLDIF; private boolean compressLDIF; private boolean encryptLDIF; private boolean signHash; private boolean includeOperationalAttributes; private ArrayList<String> includeAttributeStrings; private ArrayList<String> excludeAttributeStrings; private ArrayList<String> includeFilterStrings; private ArrayList<String> excludeFilterStrings; private ArrayList<String> includeBranchStrings; private ArrayList<String> excludeBranchStrings; private LDIFExportConfig exportConfig; /** * {@inheritDoc} */ public Message getDisplayName() { return INFO_TASK_EXPORT_NAME.get(); } /** * {@inheritDoc} */ public Message getAttributeDisplayName(String name) { return argDisplayMap.get(name); } /** * {@inheritDoc} */ @Override public void initializeTask() throws DirectoryException { // If the client connection is available, then make sure the associated // client has the LDIF_EXPORT privilege. Operation operation = getOperation(); if (operation != null) { ClientConnection clientConnection = operation.getClientConnection(); if (! clientConnection.hasPrivilege(Privilege.LDIF_EXPORT, operation)) { Message message = ERR_TASK_LDIFEXPORT_INSUFFICIENT_PRIVILEGES.get(); throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS, message); } } Entry taskEntry = getTaskEntry(); AttributeType typeLdifFile; AttributeType typeBackendID; AttributeType typeAppendToLDIF; AttributeType typeCompressLDIF; AttributeType typeEncryptLDIF; AttributeType typeSignHash; AttributeType typeIncludeAttribute; AttributeType typeExcludeAttribute; AttributeType typeIncludeFilter; AttributeType typeExcludeFilter; AttributeType typeIncludeBranch; AttributeType typeExcludeBranch; AttributeType typeWrapColumn; AttributeType typeIncludeOperationalAttributes; typeLdifFile = getAttributeType(ATTR_TASK_EXPORT_LDIF_FILE, true); typeBackendID = getAttributeType(ATTR_TASK_EXPORT_BACKEND_ID, true); typeAppendToLDIF = getAttributeType(ATTR_TASK_EXPORT_APPEND_TO_LDIF, true); typeCompressLDIF = getAttributeType(ATTR_TASK_EXPORT_COMPRESS_LDIF, true); typeEncryptLDIF = getAttributeType(ATTR_TASK_EXPORT_ENCRYPT_LDIF, true); typeSignHash = getAttributeType(ATTR_TASK_EXPORT_SIGN_HASH, true); typeIncludeAttribute = getAttributeType(ATTR_TASK_EXPORT_INCLUDE_ATTRIBUTE, true); typeExcludeAttribute = getAttributeType(ATTR_TASK_EXPORT_EXCLUDE_ATTRIBUTE, true); typeIncludeFilter = getAttributeType(ATTR_TASK_EXPORT_INCLUDE_FILTER, true); typeExcludeFilter = getAttributeType(ATTR_TASK_EXPORT_EXCLUDE_FILTER, true); typeIncludeBranch = getAttributeType(ATTR_TASK_EXPORT_INCLUDE_BRANCH, true); typeExcludeBranch = getAttributeType(ATTR_TASK_EXPORT_EXCLUDE_BRANCH, true); typeWrapColumn = getAttributeType(ATTR_TASK_EXPORT_WRAP_COLUMN, true); typeIncludeOperationalAttributes = getAttributeType(ATTR_TASK_EXPORT_INCLUDE_OPERATIONAL_ATTRIBUTES, true); List<Attribute> attrList; attrList = taskEntry.getAttribute(typeLdifFile); ldifFile = TaskUtils.getSingleValueString(attrList); File f = new File (ldifFile); if (! f.isAbsolute()) { f = new File(DirectoryServer.getInstanceRoot(), ldifFile); try { ldifFile = f.getCanonicalPath(); } catch (Exception ex) { ldifFile = f.getAbsolutePath(); } } attrList = taskEntry.getAttribute(typeBackendID); backendID = TaskUtils.getSingleValueString(attrList); attrList = taskEntry.getAttribute(typeAppendToLDIF); appendToLDIF = TaskUtils.getBoolean(attrList, false); attrList = taskEntry.getAttribute(typeCompressLDIF); compressLDIF = TaskUtils.getBoolean(attrList, false); attrList = taskEntry.getAttribute(typeEncryptLDIF); encryptLDIF = TaskUtils.getBoolean(attrList, false); attrList = taskEntry.getAttribute(typeSignHash); signHash = TaskUtils.getBoolean(attrList, false); attrList = taskEntry.getAttribute(typeIncludeAttribute); includeAttributeStrings = TaskUtils.getMultiValueString(attrList); attrList = taskEntry.getAttribute(typeExcludeAttribute); excludeAttributeStrings = TaskUtils.getMultiValueString(attrList); attrList = taskEntry.getAttribute(typeIncludeFilter); includeFilterStrings = TaskUtils.getMultiValueString(attrList); attrList = taskEntry.getAttribute(typeExcludeFilter); excludeFilterStrings = TaskUtils.getMultiValueString(attrList); attrList = taskEntry.getAttribute(typeIncludeBranch); includeBranchStrings = TaskUtils.getMultiValueString(attrList); attrList = taskEntry.getAttribute(typeExcludeBranch); excludeBranchStrings = TaskUtils.getMultiValueString(attrList); attrList = taskEntry.getAttribute(typeWrapColumn); wrapColumn = TaskUtils.getSingleValueInteger(attrList, 0); attrList = taskEntry.getAttribute(typeIncludeOperationalAttributes); includeOperationalAttributes = TaskUtils.getBoolean(attrList, true); } /** * {@inheritDoc} */ public void interruptTask(TaskState interruptState, Message interruptReason) { if (TaskState.STOPPED_BY_ADMINISTRATOR.equals(interruptState) && exportConfig != null) { addLogMessage(TaskMessages.INFO_TASK_STOPPED_BY_ADMIN.get( interruptReason)); setTaskInterruptState(interruptState); exportConfig.cancel(); } } /** * {@inheritDoc} */ public boolean isInterruptable() { return true; } /** * {@inheritDoc} */ protected TaskState runTask() { // See if there were any user-defined sets of include/exclude attributes or // filters. If so, then process them. HashSet<AttributeType> excludeAttributes; if (excludeAttributeStrings == null) { excludeAttributes = null; } else { excludeAttributes = new HashSet<AttributeType>(); for (String attrName : excludeAttributeStrings) { String lowerName = attrName.toLowerCase(); AttributeType attrType = DirectoryServer.getAttributeType(lowerName); if (attrType == null) { attrType = DirectoryServer.getDefaultAttributeType(attrName); } excludeAttributes.add(attrType); } } HashSet<AttributeType> includeAttributes; if (includeAttributeStrings == null) { includeAttributes = null; } else { includeAttributes = new HashSet<AttributeType>(); for (String attrName : includeAttributeStrings) { String lowerName = attrName.toLowerCase(); AttributeType attrType = DirectoryServer.getAttributeType(lowerName); if (attrType == null) { attrType = DirectoryServer.getDefaultAttributeType(attrName); } includeAttributes.add(attrType); } } ArrayList<SearchFilter> excludeFilters; if (excludeFilterStrings == null) { excludeFilters = null; } else { excludeFilters = new ArrayList<SearchFilter>(); for (String filterString : excludeFilterStrings) { try { excludeFilters.add(SearchFilter.createFilterFromString(filterString)); } catch (DirectoryException de) { Message message = ERR_LDIFEXPORT_CANNOT_PARSE_EXCLUDE_FILTER.get( filterString, de.getMessageObject()); logError(message); return TaskState.STOPPED_BY_ERROR; } catch (Exception e) { Message message = ERR_LDIFEXPORT_CANNOT_PARSE_EXCLUDE_FILTER.get( filterString, getExceptionMessage(e)); logError(message); return TaskState.STOPPED_BY_ERROR; } } } ArrayList<SearchFilter> includeFilters; if (includeFilterStrings == null) { includeFilters = null; } else { includeFilters = new ArrayList<SearchFilter>(); for (String filterString : includeFilterStrings) { try { includeFilters.add(SearchFilter.createFilterFromString(filterString)); } catch (DirectoryException de) { Message message = ERR_LDIFEXPORT_CANNOT_PARSE_INCLUDE_FILTER.get( filterString, de.getMessageObject()); logError(message); return TaskState.STOPPED_BY_ERROR; } catch (Exception e) { Message message = ERR_LDIFEXPORT_CANNOT_PARSE_INCLUDE_FILTER.get( filterString, getExceptionMessage(e)); logError(message); return TaskState.STOPPED_BY_ERROR; } } } // Get the backend into which the LDIF should be imported. Backend backend; ArrayList<DN> defaultIncludeBranches; backend = DirectoryServer.getBackend(backendID); if (backend == null) { Message message = ERR_LDIFEXPORT_NO_BACKENDS_FOR_ID.get(backendID); logError(message); return TaskState.STOPPED_BY_ERROR; } else if (! backend.supportsLDIFExport()) { Message message = ERR_LDIFEXPORT_CANNOT_EXPORT_BACKEND.get(backendID); logError(message); return TaskState.STOPPED_BY_ERROR; } defaultIncludeBranches = new ArrayList<DN>(backend.getBaseDNs().length); for (DN dn : backend.getBaseDNs()) { defaultIncludeBranches.add(dn); } ArrayList<DN> excludeBranches = new ArrayList<DN>(); if (excludeBranchStrings != null) { for (String s : excludeBranchStrings) { DN excludeBranch; try { excludeBranch = DN.decode(s); } catch (DirectoryException de) { Message message = ERR_LDIFEXPORT_CANNOT_DECODE_EXCLUDE_BASE.get( s, de.getMessageObject()); logError(message); return TaskState.STOPPED_BY_ERROR; } catch (Exception e) { Message message = ERR_LDIFEXPORT_CANNOT_DECODE_EXCLUDE_BASE.get( s, getExceptionMessage(e)); logError(message); return TaskState.STOPPED_BY_ERROR; } if (! excludeBranches.contains(excludeBranch)) { excludeBranches.add(excludeBranch); } } } ArrayList<DN> includeBranches; if (!includeBranchStrings.isEmpty()) { includeBranches = new ArrayList<DN>(); for (String s : includeBranchStrings) { DN includeBranch; try { includeBranch = DN.decode(s); } catch (DirectoryException de) { Message message = ERR_LDIFIMPORT_CANNOT_DECODE_INCLUDE_BASE.get( s, de.getMessageObject()); logError(message); return TaskState.STOPPED_BY_ERROR; } catch (Exception e) { Message message = ERR_LDIFIMPORT_CANNOT_DECODE_INCLUDE_BASE.get( s, getExceptionMessage(e)); logError(message); return TaskState.STOPPED_BY_ERROR; } if (! Backend.handlesEntry(includeBranch, defaultIncludeBranches, excludeBranches)) { Message message = ERR_LDIFEXPORT_INVALID_INCLUDE_BASE.get(s, backendID); logError(message); return TaskState.STOPPED_BY_ERROR; } includeBranches.add(includeBranch); } } else { includeBranches = defaultIncludeBranches; } // Create the LDIF export configuration to use when reading the LDIF. ExistingFileBehavior existingBehavior; if (appendToLDIF) { existingBehavior = ExistingFileBehavior.APPEND; } else { existingBehavior = ExistingFileBehavior.OVERWRITE; } exportConfig = new LDIFExportConfig(ldifFile, existingBehavior); exportConfig.setCompressData(compressLDIF); exportConfig.setEncryptData(encryptLDIF); exportConfig.setExcludeAttributes(excludeAttributes); exportConfig.setExcludeBranches(excludeBranches); exportConfig.setExcludeFilters(excludeFilters); exportConfig.setIncludeAttributes(includeAttributes); exportConfig.setIncludeBranches(includeBranches); exportConfig.setIncludeFilters(includeFilters); exportConfig.setSignHash(signHash); exportConfig.setWrapColumn(wrapColumn); exportConfig.setIncludeOperationalAttributes(includeOperationalAttributes); // FIXME -- Should this be conditional? exportConfig.setInvokeExportPlugins(true); // Get the set of base DNs for the backend as an array. DN[] baseDNs = new DN[defaultIncludeBranches.size()]; defaultIncludeBranches.toArray(baseDNs); // From here we must make sure we close the export config. try { // Acquire a shared lock for the backend. try { String lockFile = LockFileManager.getBackendLockFileName(backend); StringBuilder failureReason = new StringBuilder(); if (! LockFileManager.acquireSharedLock(lockFile, failureReason)) { Message message = ERR_LDIFEXPORT_CANNOT_LOCK_BACKEND.get( backend.getBackendID(), String.valueOf(failureReason)); logError(message); return TaskState.STOPPED_BY_ERROR; } } catch (Exception e) { Message message = ERR_LDIFEXPORT_CANNOT_LOCK_BACKEND.get( backend.getBackendID(), getExceptionMessage(e)); logError(message); return TaskState.STOPPED_BY_ERROR; } // From here we must make sure we release the shared backend lock. try { // Launch the export. try { DirectoryServer.notifyExportBeginning(backend, exportConfig); addLogMessage(INFO_LDIFEXPORT_PATH_TO_LDIF_FILE.get(ldifFile)); backend.exportLDIF(exportConfig); DirectoryServer.notifyExportEnded(backend, exportConfig, true); } catch (DirectoryException de) { DirectoryServer.notifyExportEnded(backend, exportConfig, false); Message message = ERR_LDIFEXPORT_ERROR_DURING_EXPORT.get(de.getMessageObject()); logError(message); return TaskState.STOPPED_BY_ERROR; } catch (Exception e) { DirectoryServer.notifyExportEnded(backend, exportConfig, false); Message message = ERR_LDIFEXPORT_ERROR_DURING_EXPORT.get(getExceptionMessage(e)); logError(message); return TaskState.STOPPED_BY_ERROR; } } finally { // Release the shared lock on the backend. try { String lockFile = LockFileManager.getBackendLockFileName(backend); StringBuilder failureReason = new StringBuilder(); if (! LockFileManager.releaseLock(lockFile, failureReason)) { Message message = WARN_LDIFEXPORT_CANNOT_UNLOCK_BACKEND.get( backend.getBackendID(), String.valueOf(failureReason)); logError(message); return TaskState.COMPLETED_WITH_ERRORS; } } catch (Exception e) { Message message = WARN_LDIFEXPORT_CANNOT_UNLOCK_BACKEND.get( backend.getBackendID(), getExceptionMessage(e)); logError(message); return TaskState.COMPLETED_WITH_ERRORS; } } } finally { // Clean up after the export by closing the export config. exportConfig.close(); } // If the operation was cancelled delete the export file since // if will be incomplete. if (exportConfig.isCancelled()) { File f = new File(ldifFile); if (f.exists()) { f.delete(); } } // If we got here the task either completed successfully or // was interrupted return getFinalTaskState(); } }