001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2010 Sun Microsystems, Inc.
015 * Portions Copyright 2012-2016 ForgeRock AS.
016 */
017package org.opends.server.tools.dsreplication;
018
019import static org.opends.messages.AdminToolMessages.*;
020
021import java.io.File;
022
023import org.forgerock.i18n.LocalizableMessage;
024import org.forgerock.i18n.slf4j.LocalizedLogger;
025
026import org.opends.quicksetup.util.ProgressMessageFormatter;
027import org.opends.server.replication.plugin.LDAPReplicationDomain;
028import org.forgerock.opendj.ldap.DN;
029import org.opends.server.types.DirectoryEnvironmentConfig;
030import org.opends.server.types.DirectoryException;
031import org.opends.server.types.OpenDsException;
032import org.forgerock.opendj.ldap.ResultCode;
033import org.opends.server.util.EmbeddedUtils;
034import org.opends.server.util.TimeThread;
035import com.forgerock.opendj.cli.ConsoleApplication;
036import org.opends.server.util.cli.PointAdder;
037
038/**
039 * The class that is in charge of taking the different information provided
040 * by the user through the command-line and actually executing the local
041 * purge.
042 *
043 */
044public class LocalPurgeHistorical
045{
046  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
047
048  private final PurgeHistoricalUserData uData;
049  private final ConsoleApplication app;
050  private final ProgressMessageFormatter formatter;
051  private final String configFile;
052
053  /**
054   * The default constructor.
055   * @param uData the object containing the information provided by the user.
056   * @param app the console application that is used to write the progress
057   * and error messages.
058   * @param formatter the formatter to be used to generated the messages.
059   * @param configFile the file that contains the configuration.  This is
060   * required to initialize properly the server.
061   */
062  public LocalPurgeHistorical(PurgeHistoricalUserData uData,
063      ConsoleApplication app,
064      ProgressMessageFormatter formatter, String configFile)
065  {
066    this.uData = uData;
067    this.app = app;
068    this.formatter = formatter;
069    this.configFile = configFile;
070  }
071
072  /**
073   * Executes the purge historical operation locally.
074   * @return the result code.
075   */
076  public ReplicationCliReturnCode execute()
077  {
078    boolean applyTimeout = uData.getMaximumDuration() > 0;
079
080    long startTime = TimeThread.getTime();
081    long purgeMaxTime = getTimeoutInSeconds() * 1000L;
082
083    long endMaxTime = startTime + purgeMaxTime;
084
085    app.print(formatter.getFormattedProgress(
086        INFO_REPLICATION_PURGE_HISTORICAL_LOCAL_ENVIRONMENT.get()));
087
088    PointAdder pointAdder = new PointAdder(app);
089    pointAdder.start();
090
091    try
092    {
093      // Create a configuration for the server.
094      DirectoryEnvironmentConfig environmentConfig =
095        new DirectoryEnvironmentConfig();
096      environmentConfig.setConfigFile(new File(configFile));
097      environmentConfig.setDisableConnectionHandlers(true);
098      EmbeddedUtils.startServer(environmentConfig);
099    }
100    catch (OpenDsException ode)
101    {
102      pointAdder.stop();
103      app.println(ode.getMessageObject());
104      logger.error(LocalizableMessage.raw("Error starting server with file "+configFile+
105          ": "+ode, ode));
106      return ReplicationCliReturnCode.ERROR_LOCAL_PURGE_HISTORICAL_SERVER_START;
107    }
108    pointAdder.stop();
109    app.print(formatter.getFormattedDone());
110    app.println();
111    app.println();
112    app.print(formatter.getFormattedProgress(
113        INFO_REPLICATION_PURGE_HISTORICAL_LOCAL_STARTING.get()));
114    app.println();
115
116    if (applyTimeout && timeoutOccurred(endMaxTime))
117    {
118      return handleTimeout();
119    }
120
121    try
122    {
123      // launch the job
124      for (String baseDN : uData.getBaseDNs())
125      {
126        DN dn = DN.valueOf(baseDN);
127        // We can assume that this is an LDAP replication domain
128        LDAPReplicationDomain domain =
129            LDAPReplicationDomain.retrievesReplicationDomain(dn);
130
131        domain.purgeConflictsHistorical(null, startTime + purgeMaxTime);
132      }
133
134    }
135    catch (DirectoryException de)
136    {
137      if (de.getResultCode() == ResultCode.ADMIN_LIMIT_EXCEEDED)
138      {
139        return handleTimeout();
140      }
141      else
142      {
143        return handleGenericExecuting(de);
144      }
145    }
146    return ReplicationCliReturnCode.SUCCESSFUL;
147  }
148
149  private ReplicationCliReturnCode handleGenericExecuting(OpenDsException ode)
150  {
151    logger.error(LocalizableMessage.raw("Error executing purge historical: "+ode, ode));
152    app.println();
153    app.println(ERR_REPLICATION_PURGE_HISTORICAL_EXECUTING.get(
154        ode.getMessageObject()));
155    return ReplicationCliReturnCode.ERROR_LOCAL_PURGE_HISTORICAL_EXECUTING;
156  }
157
158  private ReplicationCliReturnCode handleTimeout()
159  {
160    app.println();
161    app.println(ERR_REPLICATION_PURGE_HISTORICAL_TIMEOUT.get(
162        getTimeoutInSeconds()));
163    return ReplicationCliReturnCode.ERROR_LOCAL_PURGE_HISTORICAL_TIMEOUT;
164  }
165
166  /**
167   * Returns the time-out provided by the user in seconds.
168   * @return the time-out provided by the user in seconds.
169   */
170  private int getTimeoutInSeconds()
171  {
172    return uData.getMaximumDuration();
173  }
174
175  /**
176   * A method that tells whether the maximum time to execute the operation was
177   * elapsed or not.
178   * @param endMaxTime the latest time in milliseconds when the operation should
179   * be completed.
180   * @return {@code true} if the time-out occurred and {@code false} otherwise.
181   */
182  private boolean timeoutOccurred(long endMaxTime)
183  {
184    return TimeThread.getTime() > endMaxTime;
185  }
186}