/* * 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 legal-notices/CDDLv1_0.txt * or http://forgerock.org/license/CDDLv1.0.html. * 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 legal-notices/CDDLv1_0.txt. * 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 2010 Sun Microsystems, Inc. * Portions Copyright 2012-2014 ForgeRock AS */ package org.opends.server.tools.dsreplication; import static org.opends.messages.AdminToolMessages.*; import static org.opends.messages.CoreMessages.*; import java.io.File; import org.forgerock.i18n.LocalizableMessage; import org.forgerock.i18n.slf4j.LocalizedLogger; import org.opends.quicksetup.util.ProgressMessageFormatter; import org.opends.server.replication.plugin.LDAPReplicationDomain; import org.opends.server.types.DN; import org.opends.server.types.DirectoryEnvironmentConfig; import org.opends.server.types.DirectoryException; import org.opends.server.types.OpenDsException; import org.forgerock.opendj.ldap.ResultCode; import org.opends.server.util.EmbeddedUtils; import org.opends.server.util.StaticUtils; import org.opends.server.util.TimeThread; import com.forgerock.opendj.cli.ConsoleApplication; import org.opends.server.util.cli.PointAdder; /** * The class that is in charge of taking the different information provided * by the user through the command-line and actually executing the local * purge. * */ public class LocalPurgeHistorical { private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); private final PurgeHistoricalUserData uData; private final ConsoleApplication app; private final ProgressMessageFormatter formatter; private final String configFile; private final String configClass; /** * The default constructor. * @param uData the object containing the information provided by the user. * @param app the console application that is used to write the progress * and error messages. * @param formatter the formatter to be used to generated the messages. * @param configFile the file that contains the configuration. This is * required to initialize properly the server. * @param configClass the class to be used to read the configuration. This is * required to initialize properly the server. */ public LocalPurgeHistorical(PurgeHistoricalUserData uData, ConsoleApplication app, ProgressMessageFormatter formatter, String configFile, String configClass) { this.uData = uData; this.app = app; this.formatter = formatter; this.configFile = configFile; this.configClass = configClass; } /** * Executes the purge historical operation locally. * @return the result code. */ public ReplicationCliReturnCode execute() { boolean applyTimeout = uData.getMaximumDuration() > 0; long startTime = TimeThread.getTime(); long purgeMaxTime = getTimeoutInSeconds() * 1000L; long endMaxTime = startTime + purgeMaxTime; app.print(formatter.getFormattedProgress( INFO_REPLICATION_PURGE_HISTORICAL_LOCAL_ENVIRONMENT.get())); PointAdder pointAdder = new PointAdder(app); pointAdder.start(); Class<?> cfgClass; try { cfgClass = Class.forName(configClass); } catch (Exception e) { pointAdder.stop(); LocalizableMessage message = ERR_CANNOT_LOAD_CONFIG_HANDLER_CLASS.get( configClass, StaticUtils.stackTraceToSingleLineString(e)); app.println(message); logger.error(LocalizableMessage.raw("Error loading configuration class "+configClass+ ": "+e, e)); return ReplicationCliReturnCode.ERROR_LOCAL_PURGE_HISTORICAL_CLASS_LOAD; } try { // Create a configuration for the server. DirectoryEnvironmentConfig environmentConfig = new DirectoryEnvironmentConfig(); environmentConfig.setConfigClass(cfgClass); environmentConfig.setConfigFile(new File(configFile)); environmentConfig.setDisableConnectionHandlers(true); EmbeddedUtils.startServer(environmentConfig); } catch (OpenDsException ode) { pointAdder.stop(); LocalizableMessage message = ode.getMessageObject(); ERR_CANNOT_LOAD_CONFIG_HANDLER_CLASS.get( configClass, StaticUtils.stackTraceToSingleLineString(ode)); app.println(message); logger.error(LocalizableMessage.raw("Error starting server with file "+configFile+ ": "+ode, ode)); return ReplicationCliReturnCode.ERROR_LOCAL_PURGE_HISTORICAL_SERVER_START; } pointAdder.stop(); app.print(formatter.getFormattedDone()); app.println(); app.println(); app.print(formatter.getFormattedProgress( INFO_REPLICATION_PURGE_HISTORICAL_LOCAL_STARTING.get())); app.println(); if (applyTimeout && timeoutOccurred(endMaxTime)) { return handleTimeout(); } try { // launch the job for (String baseDN : uData.getBaseDNs()) { DN dn = DN.valueOf(baseDN); // We can assume that this is an LDAP replication domain LDAPReplicationDomain domain = LDAPReplicationDomain.retrievesReplicationDomain(dn); domain.purgeConflictsHistorical(null, startTime + purgeMaxTime); } } catch (DirectoryException de) { if (de.getResultCode() == ResultCode.ADMIN_LIMIT_EXCEEDED) { return handleTimeout(); } else { return handleGenericExecuting(de); } } return ReplicationCliReturnCode.SUCCESSFUL; } private ReplicationCliReturnCode handleGenericExecuting(OpenDsException ode) { logger.error(LocalizableMessage.raw("Error executing purge historical: "+ode, ode)); app.println(); app.println(ERR_REPLICATION_PURGE_HISTORICAL_EXECUTING.get( ode.getMessageObject())); return ReplicationCliReturnCode.ERROR_LOCAL_PURGE_HISTORICAL_EXECUTING; } private ReplicationCliReturnCode handleTimeout() { app.println(); app.println(ERR_REPLICATION_PURGE_HISTORICAL_TIMEOUT.get( getTimeoutInSeconds())); return ReplicationCliReturnCode.ERROR_LOCAL_PURGE_HISTORICAL_TIMEOUT; } /** * Returns the time-out provided by the user in seconds. * @return the time-out provided by the user in seconds. */ private int getTimeoutInSeconds() { return uData.getMaximumDuration(); } /** * A method that tells whether the maximum time to execute the operation was * elapsed or not. * @param endMaxTime the latest time in milliseconds when the operation should * be completed. * @return {@code true} if the time-out occurred and {@code false} otherwise. */ private boolean timeoutOccurred(long endMaxTime) { return TimeThread.getTime() > endMaxTime; } }