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 2006-2010 Sun Microsystems, Inc.
025 *      Portions Copyright 2013-2015 ForgeRock AS
026 */
027package org.opends.server.tasks;
028
029import static org.opends.server.config.ConfigConstants.*;
030import static org.opends.server.core.DirectoryServer.*;
031
032import java.util.List;
033
034import org.forgerock.i18n.LocalizableMessage;
035import org.forgerock.i18n.LocalizableMessageBuilder;
036import org.forgerock.i18n.slf4j.LocalizedLogger;
037import org.forgerock.opendj.ldap.ResultCode;
038import org.opends.messages.TaskMessages;
039import org.opends.server.backends.task.Task;
040import org.opends.server.backends.task.TaskState;
041import org.opends.server.replication.plugin.LDAPReplicationDomain;
042import org.opends.server.types.Attribute;
043import org.opends.server.types.AttributeType;
044import org.opends.server.types.DN;
045import org.opends.server.types.DirectoryException;
046import org.opends.server.types.Entry;
047
048/**
049 * This class provides an implementation of a Directory Server task that can
050 * be used to import data over the replication protocol from another
051 * server hosting the same replication domain.
052 */
053public class InitializeTask extends Task
054{
055  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
056
057  private String domainString;
058  private int  source;
059  private LDAPReplicationDomain domain;
060  private TaskState initState;
061
062  /** The total number of entries expected to be processed when this import will end successfully. */
063  private long total;
064  /** The number of entries still to be processed for this import to be completed. */
065  private long left;
066  private LocalizableMessage taskCompletionError;
067
068  /** {@inheritDoc} */
069  @Override
070  public LocalizableMessage getDisplayName() {
071    return TaskMessages.INFO_TASK_INITIALIZE_NAME.get();
072  }
073
074  /** {@inheritDoc} */
075  @Override public void initializeTask() throws DirectoryException
076  {
077    if (TaskState.isDone(getTaskState()))
078    {
079      return;
080    }
081
082    // FIXME -- Do we need any special authorization here?
083    Entry taskEntry = getTaskEntry();
084
085    AttributeType typeDomainBase = getAttributeTypeOrDefault(ATTR_TASK_INITIALIZE_DOMAIN_DN);
086    AttributeType typeSourceScope = getAttributeTypeOrDefault(ATTR_TASK_INITIALIZE_SOURCE);
087
088    List<Attribute> attrList;
089    attrList = taskEntry.getAttribute(typeDomainBase);
090    domainString = TaskUtils.getSingleValueString(attrList);
091
092    try
093    {
094      DN dn = DN.valueOf(domainString);
095      // We can assume that this is an LDAP replication domain
096      domain = LDAPReplicationDomain.retrievesReplicationDomain(dn);
097    }
098    catch(DirectoryException e)
099    {
100      LocalizableMessageBuilder mb = new LocalizableMessageBuilder();
101      mb.append(TaskMessages.ERR_TASK_INITIALIZE_INVALID_DN.get());
102      mb.append(e.getMessage());
103      throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, e);
104    }
105
106    attrList = taskEntry.getAttribute(typeSourceScope);
107    String sourceString = TaskUtils.getSingleValueString(attrList);
108    source = domain.decodeSource(sourceString);
109
110    replaceAttributeValue(ATTR_TASK_INITIALIZE_LEFT, String.valueOf(0));
111    replaceAttributeValue(ATTR_TASK_INITIALIZE_DONE, String.valueOf(0));
112  }
113
114  /** {@inheritDoc} */
115  @Override
116  protected TaskState runTask()
117  {
118    if (logger.isTraceEnabled())
119    {
120      logger.trace("[IE] InitializeTask is starting on domain: %s from source:%d", domain.getBaseDN(), source);
121    }
122    initState = getTaskState();
123    try
124    {
125      // launch the import
126      domain.initializeFromRemote(source, this);
127
128      synchronized(initState)
129      {
130        // Waiting for the end of the job
131        while (initState == TaskState.RUNNING)
132        {
133          initState.wait(1000);
134          replaceAttributeValue(ATTR_TASK_INITIALIZE_LEFT, String.valueOf(left));
135          replaceAttributeValue(ATTR_TASK_INITIALIZE_DONE, String.valueOf(total-left));
136        }
137      }
138      replaceAttributeValue(ATTR_TASK_INITIALIZE_LEFT, String.valueOf(left));
139      replaceAttributeValue(ATTR_TASK_INITIALIZE_DONE, String.valueOf(total-left));
140
141      // Error raised at completion time
142      if (taskCompletionError != null)
143      {
144        logger.error(taskCompletionError);
145      }
146
147    }
148    catch(InterruptedException ie) {}
149    catch(DirectoryException de)
150    {
151      // Error raised at submission time
152      logger.error(de.getMessageObject());
153      initState = TaskState.STOPPED_BY_ERROR;
154    }
155
156    logger.trace("[IE] InitializeTask is ending with state: %s", initState);
157    return initState;
158  }
159
160  /**
161   * Set the state for the current task.
162   *
163   * @param de  When the new state is different from COMPLETED_SUCCESSFULLY
164   * this is the exception that contains the cause of the failure.
165   */
166  public void updateTaskCompletionState(DirectoryException de)
167  {
168    initState =  TaskState.STOPPED_BY_ERROR;
169    try
170    {
171      if (de == null)
172      {
173        initState =  TaskState.COMPLETED_SUCCESSFULLY;
174      }
175      else
176      {
177        taskCompletionError = de.getMessageObject();
178      }
179    }
180    finally
181    {
182      // Wake up runTask method waiting for completion
183      synchronized (initState)
184      {
185        initState.notify();
186      }
187    }
188  }
189
190
191  /**
192   * Set the total number of entries expected to be imported.
193   * @param total The total number of entries.
194   */
195  public void setTotal(long total)
196  {
197    this.total = total;
198  }
199
200  /**
201   * Set the total number of entries still to be imported.
202   * @param left The total number of entries to be imported.
203   */
204  public void setLeft(long left)
205  {
206    this.left = left;
207  }
208}