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 2015-2016 ForgeRock AS.
015 */
016package org.opends.server.tasks;
017
018import org.forgerock.i18n.LocalizableMessage;
019import org.forgerock.i18n.slf4j.LocalizedLogger;
020import org.forgerock.opendj.ldap.schema.AttributeType;
021import org.opends.server.backends.task.Task;
022import org.opends.server.backends.task.TaskState;
023import org.opends.server.replication.common.CSN;
024import org.opends.server.replication.server.ReplicationServer;
025import org.opends.server.replication.server.changelog.api.ChangelogException;
026import org.opends.server.types.Attribute;
027import org.forgerock.opendj.ldap.DN;
028import org.opends.server.types.DirectoryException;
029import org.opends.server.types.Entry;
030
031import java.util.List;
032
033import static org.forgerock.opendj.ldap.ResultCode.*;
034import static org.opends.server.config.ConfigConstants.ATTR_TASK_RESET_CHANGE_NUMBER_BASE_DN;
035import static org.opends.server.config.ConfigConstants.ATTR_TASK_RESET_CHANGE_NUMBER_CSN;
036import static org.opends.server.config.ConfigConstants.ATTR_TASK_RESET_CHANGE_NUMBER_TO;
037import static org.opends.server.core.DirectoryServer.getSchema;
038import static org.opends.messages.TaskMessages.*;
039
040/**
041 * This class provides an implementation of a Directory Server task that can
042 * be used to rebuild the change number index with a given change number and a
043 * change represented by its CSN.
044 */
045public class ResetChangeNumberTask extends Task
046{
047  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
048
049  private int newFirstChangeNumber;
050  private DN baseDN;
051  private CSN newFirstCSN;
052  private ReplicationServer targetRS;
053
054  @Override
055  public LocalizableMessage getDisplayName() {
056    return INFO_TASK_RESET_CHANGE_NUMBER.get();
057  }
058
059  @Override public void initializeTask() throws DirectoryException
060  {
061    if (TaskState.isDone(getTaskState()))
062    {
063      return;
064    }
065
066    final Entry taskEntry = getTaskEntry();
067    newFirstChangeNumber = TaskUtils.getSingleValueInteger(
068        getTaskParameter(taskEntry, ATTR_TASK_RESET_CHANGE_NUMBER_TO), 1);
069    newFirstCSN = CSN.valueOf(TaskUtils.getSingleValueString(
070        getTaskParameter(taskEntry, ATTR_TASK_RESET_CHANGE_NUMBER_CSN)));
071    baseDN = DN.valueOf(TaskUtils.getSingleValueString(
072        getTaskParameter(taskEntry, ATTR_TASK_RESET_CHANGE_NUMBER_BASE_DN)));
073
074    if (newFirstChangeNumber < 1)
075    {
076      throw new DirectoryException(UNWILLING_TO_PERFORM,
077          ERR_TASK_RESET_CHANGE_NUMBER_INVALID.get(newFirstChangeNumber));
078    }
079
080    List<ReplicationServer> allRSes = ReplicationServer.getAllInstances();
081    if (allRSes.isEmpty())
082    {
083      throw new DirectoryException(NO_SUCH_OBJECT, ERR_TASK_RESET_CHANGE_NUMBER_NO_RSES.get());
084    }
085
086    for (ReplicationServer rs : allRSes)
087    {
088      if (rs.getReplicationServerDomain(baseDN) != null)
089      {
090        targetRS = rs;
091        return;
092      }
093    }
094    throw new DirectoryException(NO_SUCH_OBJECT, ERR_TASK_RESET_CHANGE_NUMBER_CHANGELOG_NOT_FOUND.get(baseDN));
095  }
096
097  private List<Attribute> getTaskParameter(Entry taskEntry, String attrTaskResetChangeNumberTo)
098  {
099    AttributeType taskAttr = getSchema().getAttributeType(attrTaskResetChangeNumberTo);
100    return taskEntry.getAttribute(taskAttr);
101  }
102
103  @Override
104  protected TaskState runTask()
105  {
106    logger.trace("Reset change number task is starting with new changeNumber %d having CSN %s",
107        newFirstChangeNumber, newFirstCSN);
108
109    try
110    {
111      targetRS.getChangelogDB().getChangeNumberIndexDB().resetChangeNumberTo(newFirstChangeNumber, baseDN, newFirstCSN);
112      return returnWithDebug(TaskState.COMPLETED_SUCCESSFULLY);
113    }
114    catch (ChangelogException ce)
115    {
116      logger.error(ERR_TASK_RESET_CHANGE_NUMBER_FAILED, ce.getMessageObject());
117      return returnWithDebug(TaskState.STOPPED_BY_ERROR);
118    }
119  }
120
121  private TaskState returnWithDebug(TaskState state)
122  {
123    logger.trace("state: %s", state);
124    return state;
125  }
126}