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.api;
028
029import java.util.LinkedHashMap;
030import java.util.Map;
031import java.util.concurrent.ThreadFactory;
032import java.util.concurrent.atomic.AtomicInteger;
033import java.util.concurrent.atomic.AtomicReference;
034
035import org.forgerock.i18n.LocalizableMessage;
036import org.forgerock.i18n.slf4j.LocalizedLogger;
037import org.opends.server.backends.task.Task;
038import org.opends.server.core.DirectoryServer;
039import org.opends.server.types.DN;
040
041import static org.opends.messages.CoreMessages.*;
042import static org.opends.server.util.ServerConstants.*;
043import static org.opends.server.util.StaticUtils.*;
044
045/**
046 * This class defines a generic thread that should be the superclass
047 * for all threads created by the Directory Server.  That is, instead
048 * of having a class that "extends Thread", you should make it
049 * "extends DirectoryThread".  This provides various value-added
050 * capabilities, including:
051 * <BR>
052 * <UL>
053 *   <LI>It helps make sure that all threads have a human-readable
054 *       name so they are easier to identify in stack traces.</LI>
055 *   <LI>It can capture a stack trace from the time that this thread
056 *       was created that could be useful for debugging purposes.</LI>
057 *   <LI>It plays an important role in ensuring that log messages
058 *       generated as part of the processing for Directory Server
059 *       tasks are properly captured and made available as part of
060 *       that task.</LI>
061 * </UL>
062 */
063@org.opends.server.types.PublicAPI(
064     stability=org.opends.server.types.StabilityLevel.VOLATILE,
065     mayInstantiate=true,
066     mayExtend=true,
067     mayInvoke=true)
068public class DirectoryThread extends Thread
069{
070
071  /**
072   * Enumeration holding the "logical" (application) thread states, as opposed
073   * to the operating system-level java.lang.Thread.State.
074   */
075  private static enum ThreadState
076  {
077    /** The current thread is currently not doing any useful work. */
078    IDLE(false),
079    /** The current thread is currently processing a task, doing useful work. */
080    PROCESSING(false),
081    /** The current thread is in the process of shutting down. */
082    SHUTTING_DOWN(true),
083    /**
084     * The current thread has stopped running. Equivalent to
085     * java.lang.Thread.State.TERMINATED.
086     */
087    STOPPED(true);
088
089    /**
090     * Whether this state implies a shutdown has been initiated or completed.
091     */
092    private final boolean shutdownInitiated;
093
094    /**
095     * Constructs an instance of this enum.
096     *
097     * @param shutdownInitiated
098     *          whether this state implies a shutdown was initiated.
099     */
100    private ThreadState(boolean shutdownInitiated)
101    {
102      this.shutdownInitiated = shutdownInitiated;
103    }
104
105    /**
106     * Returns whether the current thread started the shutdown process.
107     *
108     * @return true if the current thread started the shutdown process, false
109     *         otherwise.
110     */
111    public boolean isShutdownInitiated()
112    {
113      return shutdownInitiated;
114    }
115  }
116
117  /**
118   * A factory which can be used by thread pool based services such as
119   * {@code Executor}s to dynamically create new
120   * {@code DirectoryThread} instances.
121   */
122  public static final class Factory implements ThreadFactory
123  {
124    /** The name prefix used for all threads created using this factory. */
125    private final String threadNamePrefix;
126
127    /** The ID to use for the next thread created using this factory. */
128    private final AtomicInteger nextID = new AtomicInteger();
129
130
131    /**
132     * Creates a new directory thread factory using the provided
133     * thread name prefix.
134     *
135     * @param threadNamePrefix
136     *          The name prefix used for all threads created using this factory.
137     */
138    public Factory(String threadNamePrefix)
139    {
140      if (threadNamePrefix == null) {
141        throw new NullPointerException("Null thread name prefix");
142      }
143
144      this.threadNamePrefix = threadNamePrefix;
145    }
146
147
148
149    /** {@inheritDoc} */
150    @Override
151    public Thread newThread(Runnable r)
152    {
153      return new DirectoryThread(r, threadNamePrefix + " "
154          + nextID.getAndIncrement());
155    }
156
157  }
158  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
159
160  /**
161   * The directory thread group that all directory threads will be a
162   * member of.
163   */
164  public static final DirectoryThreadGroup DIRECTORY_THREAD_GROUP =
165      new DirectoryThreadGroup();
166
167  /** The stack trace taken at the time that this thread was created. */
168  private StackTraceElement[] creationStackTrace;
169
170  /** The task with which this thread is associated, if any. */
171  private Task task;
172
173  /** A reference to the thread that was used to create this thread. */
174  private Thread parentThread;
175
176  /** The current logical thread's state. */
177  private volatile AtomicReference<ThreadState> threadState =
178      new AtomicReference<>(ThreadState.IDLE);
179
180  /**
181   * A thread group for all directory threads. This implements a
182   * custom unhandledException handler that logs the error.
183   */
184  private static class DirectoryThreadGroup extends ThreadGroup
185      implements AlertGenerator
186  {
187    private final LinkedHashMap<String,String> alerts = new LinkedHashMap<>();
188
189    /** Private constructor for DirectoryThreadGroup. */
190    private DirectoryThreadGroup()
191    {
192      super("Directory Server Thread Group");
193      alerts.put(ALERT_TYPE_UNCAUGHT_EXCEPTION,
194          ALERT_DESCRIPTION_UNCAUGHT_EXCEPTION);
195    }
196
197    /** {@inheritDoc} */
198    @Override
199    public DN getComponentEntryDN() {
200      return DN.NULL_DN;
201    }
202
203    /** {@inheritDoc} */
204    @Override
205    public String getClassName() {
206      return DirectoryThread.class.getName();
207    }
208
209    /** {@inheritDoc} */
210    @Override
211    public Map<String, String> getAlerts() {
212      return alerts;
213    }
214
215    /**
216     * Provides a means of handling a case in which a thread is about
217     * to die because of an unhandled exception.  This method does
218     * nothing to try to prevent the death of that thread, but will
219     * at least log it so that it can be available for debugging
220     * purposes.
221     *
222     * @param  t  The thread that threw the exception.
223     * @param  e  The exception that was thrown but not properly
224     *            handled.
225     */
226    @Override
227    public void uncaughtException(Thread t, Throwable e)
228    {
229      if (e instanceof ThreadDeath)
230      {
231        // Ignore ThreadDeath errors that can happen when everything is being
232        // shutdown.
233        return;
234      }
235      logger.traceException(e);
236
237      LocalizableMessage message = ERR_UNCAUGHT_THREAD_EXCEPTION.get(t.getName(), stackTraceToSingleLineString(e));
238      logger.error(message);
239      DirectoryServer.sendAlertNotification(this,
240          ALERT_TYPE_UNCAUGHT_EXCEPTION, message);
241    }
242  }
243
244  /**
245   * Creates a new instance of this directory thread with the
246   * specified name and with the specified target as its run object.
247   *
248   * @param  target      The target runnable object.
249   * @param  threadName  The human-readable name to use for this
250   *                     thread for debugging purposes.
251   */
252  public DirectoryThread(Runnable target, String threadName)
253  {
254    super(DIRECTORY_THREAD_GROUP, target, threadName);
255    init();
256  }
257
258  /**
259   * Creates a new instance of this directory thread with the
260   * specified name.
261   *
262   * @param  threadName  The human-readable name to use for this
263   *                     thread for debugging purposes.
264   */
265  protected DirectoryThread(String threadName)
266  {
267    super(DIRECTORY_THREAD_GROUP, threadName);
268    init();
269  }
270
271
272
273  /**
274   * Private method used to factorize constructor initialization.
275   */
276  private void init()
277  {
278    parentThread       = currentThread();
279    creationStackTrace = parentThread.getStackTrace();
280
281    if (parentThread instanceof DirectoryThread)
282    {
283      task = ((DirectoryThread) parentThread).task;
284    }
285    else
286    {
287      task = null;
288    }
289
290    if (DirectoryServer.getEnvironmentConfig().forceDaemonThreads())
291    {
292      setDaemon(true);
293    }
294  }
295
296
297
298  /**
299   * Retrieves the stack trace that was captured at the time that this
300   * thread was created.
301   *
302   * @return  The stack trace that was captured at the time that this
303   *          thread was created.
304   */
305  public StackTraceElement[] getCreationStackTrace()
306  {
307    return creationStackTrace;
308  }
309
310
311
312  /**
313   * Retrieves a reference to the parent thread that created this
314   * directory thread.  That parent thread may or may not be a
315   * directory thread.
316   *
317   * @return  A reference to the parent thread that created this
318   *          directory thread.
319   */
320  public Thread getParentThread()
321  {
322    return parentThread;
323  }
324
325
326
327  /**
328   * Retrieves the task with which this thread is associated.  This
329   * will only be available for threads that are used in the process
330   * of running a task.
331   *
332   * @return  The task with which this thread is associated, or
333   *          {@code null} if there is none.
334   */
335  public Task getAssociatedTask()
336  {
337    return task;
338  }
339
340
341
342  /**
343   * Sets the task with which this thread is associated.  It may be
344   * {@code null} to indicate that it is not associated with any task.
345   *
346   * @param  task  The task with which this thread is associated.
347   */
348  public void setAssociatedTask(Task task)
349  {
350    this.task = task;
351  }
352
353
354  /**
355   * Retrieves any relevant debug information with which this tread is
356   * associated so they can be included in debug messages.
357   *
358   * @return debug information about this thread as a string.
359   */
360  public Map<String, String> getDebugProperties()
361  {
362    Map<String, String> properties = new LinkedHashMap<>();
363
364    properties.put("parentThread", parentThread.getName() +
365        "(" + parentThread.getId() + ")");
366    properties.put("isDaemon", String.valueOf(isDaemon()));
367
368    return properties;
369  }
370
371  /**
372   * Returns whether the shutdown process has been initiated on the current
373   * thread. It also returns true when the thread is actually terminated.
374   * <p>
375   * Waiting for the thread to terminate should be done by invoking one of the
376   * {@link Thread#join()} methods.
377   *
378   * @return true if the shutdown process has been initiated on the current
379   *         thread, false otherwise.
380   */
381  public boolean isShutdownInitiated()
382  {
383    return getThreadState().get().isShutdownInitiated();
384  }
385
386  /**
387   * Instructs the current thread to initiate the shutdown process. The actual
388   * shutdown of the thread is a best effort and is dependent on the
389   * implementation of the {@link Thread#run()} method.
390   */
391  public void initiateShutdown()
392  {
393    setThreadStateIfNotShuttingDown(ThreadState.SHUTTING_DOWN);
394  }
395
396  /**
397   * Sets the current thread state to "processing" if the shutdown process was
398   * not initiated.
399   */
400  public void startWork()
401  {
402    setThreadStateIfNotShuttingDown(ThreadState.PROCESSING);
403  }
404
405  /**
406   * Sets the current thread state to "idle" if the shutdown process was not
407   * initiated.
408   */
409  public void stopWork()
410  {
411    setThreadStateIfNotShuttingDown(ThreadState.IDLE);
412  }
413
414  /**
415   * Sets this thread's current state to the passed in newState if the thread is
416   * not already in a shutting down state.
417   *
418   * @param newState
419   *          the new state to set
420   */
421  private void setThreadStateIfNotShuttingDown(ThreadState newState)
422  {
423    ThreadState currentState = this.threadState.get();
424    while (!currentState.isShutdownInitiated())
425    {
426      if (this.threadState.compareAndSet(currentState, newState))
427      {
428        return;
429      }
430      currentState = this.threadState.get();
431    }
432  }
433
434  /**
435   * Returns the current thread state, possibly returning
436   * {@link ThreadState#STOPPED} if the thread is not alive.
437   *
438   * @return an {@link AtomicReference} to a ThreadState. It can be passed down
439   *         as a method call parameter.
440   */
441  private AtomicReference<ThreadState> getThreadState()
442  {
443    if (!isAlive())
444    {
445      this.threadState.set(ThreadState.STOPPED);
446    }
447    return this.threadState;
448  }
449
450}
451