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
010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2006-2008 Sun Microsystems, Inc.
026 */
027 package org.opends.server.backends.task;
028 import org.opends.messages.Message;
029
030
031
032 import org.opends.server.api.DirectoryThread;
033 import org.opends.server.loggers.debug.DebugTracer;
034 import org.opends.server.types.DebugLogLevel;
035
036 import static org.opends.server.loggers.debug.DebugLogger.*;
037 import static org.opends.server.loggers.ErrorLogger.*;
038 import static org.opends.messages.BackendMessages.*;
039
040 import static org.opends.server.util.StaticUtils.*;
041
042 import java.util.Map;
043
044
045
046 /**
047 * This class defines a thread that will be used to execute a scheduled task
048 * within the server and provide appropriate notification that the task is
049 * complete.
050 */
051 public class TaskThread
052 extends DirectoryThread
053 {
054 /**
055 * The tracer object for the debug logger.
056 */
057 private static final DebugTracer TRACER = getTracer();
058
059
060
061 // Indicates whether a request has been made for this thread to exit.
062 private boolean exitRequested;
063
064 // The thread ID for this task thread.
065 private int threadID;
066
067 // The reference to the scheduler with which this thread is associated.
068 private TaskScheduler taskScheduler;
069
070 // The object that will be used for signaling the thread when there is new
071 // work to perform.
072 private Object notifyLock;
073
074
075
076 /**
077 * Creates a new task thread with the provided information.
078 *
079 * @param taskScheduler The reference to the task scheduler with which this
080 * thread is associated.
081 * @param threadID The ID assigned to this task thread.
082 */
083 public TaskThread(TaskScheduler taskScheduler, int threadID)
084 {
085 super("Task Thread " + threadID);
086
087
088 this.taskScheduler = taskScheduler;
089 this.threadID = threadID;
090
091 notifyLock = new Object();
092 exitRequested = false;
093
094 setAssociatedTask(null);
095 }
096
097
098
099 /**
100 * Retrieves the task currently being processed by this thread, if it is
101 * active.
102 *
103 * @return The task currently being processed by this thread, or
104 * <CODE>null</CODE> if it is not processing any task.
105 */
106 public Task getTask()
107 {
108 return getAssociatedTask();
109 }
110
111
112
113 /**
114 * Provides a new task for processing by this thread. This does not do any
115 * check to ensure that no task is already in process.
116 *
117 * @param task The task to be processed.
118 */
119 public void setTask(Task task)
120 {
121 setAssociatedTask(task);
122
123 synchronized (notifyLock)
124 {
125 notifyLock.notify();
126 }
127 }
128
129
130
131 /**
132 * Attempts to interrupt processing on the task in progress.
133 *
134 * @param interruptState The state to use for the task if it is
135 * successfully interrupted.
136 * @param interruptReason The human-readable reason that the task is to be
137 * interrupted.
138 * @param exitThread Indicates whether this thread should exit when
139 * processing on the active task has completed.
140 */
141 public void interruptTask(TaskState interruptState, Message interruptReason,
142 boolean exitThread)
143 {
144 if (getAssociatedTask() != null)
145 {
146 try
147 {
148 getAssociatedTask().interruptTask(interruptState, interruptReason);
149 }
150 catch (Exception e)
151 {
152 if (debugEnabled())
153 {
154 TRACER.debugCaught(DebugLogLevel.ERROR, e);
155 }
156 }
157 }
158
159 if (exitThread)
160 {
161 exitRequested = true;
162 }
163 }
164
165
166
167 /**
168 * Operates in a loop, sleeping until there is no work to do, then
169 * processing the task and returning to the scheduler for more work.
170 */
171 public void run()
172 {
173 while (! exitRequested)
174 {
175 if (getAssociatedTask() == null)
176 {
177 try
178 {
179 synchronized (notifyLock)
180 {
181 notifyLock.wait(5000);
182 }
183 }
184 catch (InterruptedException ie)
185 {
186 if (debugEnabled())
187 {
188 TRACER.debugCaught(DebugLogLevel.ERROR, ie);
189 }
190 }
191
192 continue;
193 }
194
195 try
196 {
197 TaskState returnState = getAssociatedTask().execute();
198 getAssociatedTask().setTaskState(returnState);
199 }
200 catch (Exception e)
201 {
202 if (debugEnabled())
203 {
204 TRACER.debugCaught(DebugLogLevel.ERROR, e);
205 }
206
207 Task task = getAssociatedTask();
208
209 Message message = ERR_TASK_EXECUTE_FAILED.
210 get(String.valueOf(task.getTaskEntry().getDN()),
211 stackTraceToSingleLineString(e));
212 logError(message);
213 task.setTaskState(TaskState.STOPPED_BY_ERROR);
214 }
215
216 Task completedTask = getAssociatedTask();
217 setAssociatedTask(null);
218 if (! taskScheduler.threadDone(this, completedTask))
219 {
220 exitRequested = true;
221 break;
222 }
223 }
224
225 if (getAssociatedTask() != null)
226 {
227 Task task = getAssociatedTask();
228 task.setTaskState(TaskState.STOPPED_BY_SHUTDOWN);
229 taskScheduler.threadDone(this, task);
230 }
231 }
232
233
234
235 /**
236 * Retrieves any relevent debug information with which this tread is
237 * associated so they can be included in debug messages.
238 *
239 * @return debug information about this thread as a string.
240 */
241 public Map<String, String> getDebugProperties()
242 {
243 Map<String, String> properties = super.getDebugProperties();
244
245 if (getAssociatedTask() != null)
246 {
247 properties.put("task", getAssociatedTask().toString());
248 }
249
250 return properties;
251 }
252 }
253