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