001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2015 ForgeRock AS
025 */
026package org.opends.server.tasks;
027
028import org.forgerock.i18n.LocalizableMessage;
029import org.forgerock.i18n.slf4j.LocalizedLogger;
030import org.opends.server.backends.task.Task;
031import org.opends.server.backends.task.TaskState;
032import org.opends.server.replication.common.CSN;
033import org.opends.server.replication.server.ReplicationServer;
034import org.opends.server.replication.server.changelog.api.ChangelogException;
035import org.opends.server.types.Attribute;
036import org.opends.server.types.AttributeType;
037import org.opends.server.types.DN;
038import org.opends.server.types.DirectoryException;
039import org.opends.server.types.Entry;
040
041import java.util.List;
042
043import static org.forgerock.opendj.ldap.ResultCode.*;
044import static org.opends.server.config.ConfigConstants.ATTR_TASK_RESET_CHANGE_NUMBER_BASE_DN;
045import static org.opends.server.config.ConfigConstants.ATTR_TASK_RESET_CHANGE_NUMBER_CSN;
046import static org.opends.server.config.ConfigConstants.ATTR_TASK_RESET_CHANGE_NUMBER_TO;
047import static org.opends.server.core.DirectoryServer.getAttributeTypeOrDefault;
048import static org.opends.messages.TaskMessages.*;
049
050/**
051 * This class provides an implementation of a Directory Server task that can
052 * be used to rebuild the change number index with a given change number and a
053 * change represented by its CSN.
054 */
055public class ResetChangeNumberTask extends Task
056{
057  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
058
059  private int newFirstChangeNumber;
060  private DN baseDN;
061  private CSN newFirstCSN;
062  private ReplicationServer targetRS;
063
064  @Override
065  public LocalizableMessage getDisplayName() {
066    return INFO_TASK_RESET_CHANGE_NUMBER.get();
067  }
068
069  @Override public void initializeTask() throws DirectoryException
070  {
071    if (TaskState.isDone(getTaskState()))
072    {
073      return;
074    }
075
076    final Entry taskEntry = getTaskEntry();
077    newFirstChangeNumber = TaskUtils.getSingleValueInteger(
078        getTaskParameter(taskEntry, ATTR_TASK_RESET_CHANGE_NUMBER_TO), 1);
079    newFirstCSN = CSN.valueOf(TaskUtils.getSingleValueString(
080        getTaskParameter(taskEntry, ATTR_TASK_RESET_CHANGE_NUMBER_CSN)));
081    baseDN = DN.valueOf(TaskUtils.getSingleValueString(
082        getTaskParameter(taskEntry, ATTR_TASK_RESET_CHANGE_NUMBER_BASE_DN)));
083
084    if (newFirstChangeNumber < 1)
085    {
086      throw new DirectoryException(UNWILLING_TO_PERFORM,
087          ERR_TASK_RESET_CHANGE_NUMBER_INVALID.get(newFirstChangeNumber));
088    }
089
090    List<ReplicationServer> allRSes = ReplicationServer.getAllInstances();
091    if (allRSes.isEmpty())
092    {
093      throw new DirectoryException(NO_SUCH_OBJECT, ERR_TASK_RESET_CHANGE_NUMBER_NO_RSES.get());
094    }
095
096    for (ReplicationServer rs : allRSes)
097    {
098      if (rs.getReplicationServerDomain(baseDN) != null)
099      {
100        targetRS = rs;
101        return;
102      }
103    }
104    throw new DirectoryException(NO_SUCH_OBJECT, ERR_TASK_RESET_CHANGE_NUMBER_CHANGELOG_NOT_FOUND.get(baseDN));
105  }
106
107  private List<Attribute> getTaskParameter(Entry taskEntry, String attrTaskResetChangeNumberTo)
108  {
109    AttributeType taskAttr = getAttributeTypeOrDefault(attrTaskResetChangeNumberTo);
110    return taskEntry.getAttribute(taskAttr);
111  }
112
113  @Override
114  protected TaskState runTask()
115  {
116    logger.trace("Reset change number task is starting with new changeNumber %d having CSN %s",
117        newFirstChangeNumber, newFirstCSN);
118
119    try
120    {
121      targetRS.getChangelogDB().getChangeNumberIndexDB().resetChangeNumberTo(newFirstChangeNumber, baseDN, newFirstCSN);
122      return returnWithDebug(TaskState.COMPLETED_SUCCESSFULLY);
123    }
124    catch (ChangelogException ce)
125    {
126      logger.error(ERR_TASK_RESET_CHANGE_NUMBER_FAILED, ce.getMessageObject());
127      return returnWithDebug(TaskState.STOPPED_BY_ERROR);
128    }
129  }
130
131  private TaskState returnWithDebug(TaskState state)
132  {
133    logger.trace("state: %s", state);
134    return state;
135  }
136}