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 java.util.Iterator;
033    import java.util.LinkedHashSet;
034    import java.util.List;
035    
036    import org.opends.server.core.DirectoryServer;
037    import org.opends.server.types.Attribute;
038    import org.opends.server.types.AttributeType;
039    import org.opends.server.types.AttributeValue;
040    import org.opends.server.types.DirectoryException;
041    import org.opends.server.types.DN;
042    import org.opends.server.types.Entry;
043    import org.opends.server.types.InitializationException;
044    import org.opends.server.types.ResultCode;
045    
046    import static org.opends.server.config.ConfigConstants.*;
047    import static org.opends.server.loggers.debug.DebugLogger.*;
048    import org.opends.server.loggers.debug.DebugTracer;
049    import org.opends.server.types.DebugLogLevel;
050    import static org.opends.messages.BackendMessages.*;
051    import static org.opends.server.util.StaticUtils.*;
052    
053    
054    
055    /**
056     * This class defines a information about a recurring task, which will be used
057     * to repeatedly schedule tasks for processing.
058     */
059    public class RecurringTask
060    {
061      /**
062       * The tracer object for the debug logger.
063       */
064      private static final DebugTracer TRACER = getTracer();
065    
066    
067    
068    
069      // The DN of the entry that actually defines this task.
070      private DN recurringTaskEntryDN;
071    
072      // The entry that actually defines this task.
073      private Entry recurringTaskEntry;
074    
075      // The unique ID for this recurring task.
076      private String recurringTaskID;
077    
078      // The fully-qualified name of the class that will be used to implement the
079      // class.
080      private String taskClassName;
081    
082      // The reference to the task scheduler that will be used to schedule new
083      // iterations of this recurring task.
084      private TaskScheduler taskScheduler;
085    
086    
087    
088      /**
089       * Creates a new recurring task based on the information in the provided
090       * entry.
091       *
092       * @param  taskScheduler       A reference to the task scheduler that may be
093       *                             used to schedule new tasks.
094       * @param  recurringTaskEntry  The entry containing the information to use to
095       *                             define the task to process.
096       *
097       * @throws  DirectoryException  If the provided entry does not contain a valid
098       *                              recurring task definition.
099       */
100      public RecurringTask(TaskScheduler taskScheduler, Entry recurringTaskEntry)
101             throws DirectoryException
102      {
103        this.taskScheduler        = taskScheduler;
104        this.recurringTaskEntry   = recurringTaskEntry;
105        this.recurringTaskEntryDN = recurringTaskEntry.getDN();
106    
107    
108        // Get the recurring task ID from the entry.  If there isn't one, then fail.
109        AttributeType attrType = DirectoryServer.getAttributeType(
110                                      ATTR_RECURRING_TASK_ID.toLowerCase());
111        if (attrType == null)
112        {
113          attrType = DirectoryServer.getDefaultAttributeType(
114                                          ATTR_RECURRING_TASK_ID);
115        }
116    
117        List<Attribute> attrList = recurringTaskEntry.getAttribute(attrType);
118        if ((attrList == null) || attrList.isEmpty())
119        {
120          Message message =
121              ERR_RECURRINGTASK_NO_ID_ATTRIBUTE.get(ATTR_RECURRING_TASK_ID);
122          throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message);
123        }
124    
125        if (attrList.size() > 1)
126        {
127          Message message =
128              ERR_RECURRINGTASK_MULTIPLE_ID_TYPES.get(ATTR_RECURRING_TASK_ID);
129          throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message);
130        }
131    
132        Attribute attr = attrList.get(0);
133        LinkedHashSet<AttributeValue> values = attr.getValues();
134        if ((values == null) || values.isEmpty())
135        {
136          Message message = ERR_RECURRINGTASK_NO_ID.get(ATTR_RECURRING_TASK_ID);
137          throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message);
138        }
139    
140        Iterator<AttributeValue> iterator = values.iterator();
141        AttributeValue value = iterator.next();
142        if (iterator.hasNext())
143        {
144          Message message =
145              ERR_RECURRINGTASK_MULTIPLE_ID_VALUES.get(ATTR_RECURRING_TASK_ID);
146          throw new DirectoryException(ResultCode.OBJECTCLASS_VIOLATION, message);
147        }
148    
149        recurringTaskID = value.getStringValue();
150    
151    
152        // FIXME -- Need to have some method of getting the scheduling information
153        //          from the recurring task entry.
154    
155    
156        // Get the class name from the entry.  If there isn't one, then fail.
157        attrType = DirectoryServer.getAttributeType(
158                        ATTR_RECURRING_TASK_CLASS_NAME.toLowerCase());
159        if (attrType == null)
160        {
161          attrType = DirectoryServer.getDefaultAttributeType(
162                                          ATTR_RECURRING_TASK_CLASS_NAME);
163        }
164    
165        attrList = recurringTaskEntry.getAttribute(attrType);
166        if ((attrList == null) || attrList.isEmpty())
167        {
168          Message message = ERR_RECURRINGTASK_NO_CLASS_ATTRIBUTE.get(
169              ATTR_RECURRING_TASK_CLASS_NAME);
170          throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message);
171        }
172    
173        if (attrList.size() > 0)
174        {
175          Message message = ERR_RECURRINGTASK_MULTIPLE_CLASS_TYPES.get(
176              ATTR_RECURRING_TASK_CLASS_NAME);
177          throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message);
178        }
179    
180        attr = attrList.get(0);
181        values = attr.getValues();
182        if ((values == null) || values.isEmpty())
183        {
184          Message message =
185              ERR_RECURRINGTASK_NO_CLASS_VALUES.get(ATTR_RECURRING_TASK_CLASS_NAME);
186          throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message);
187        }
188    
189        iterator = values.iterator();
190        value = iterator.next();
191        if (iterator.hasNext())
192        {
193          Message message = ERR_RECURRINGTASK_MULTIPLE_CLASS_VALUES.get(
194              ATTR_RECURRING_TASK_CLASS_NAME);
195          throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message);
196        }
197    
198        taskClassName = value.getStringValue();
199    
200    
201        // Make sure that the specified class can be loaded.
202        Class taskClass;
203        try
204        {
205          taskClass = DirectoryServer.loadClass(taskClassName);
206        }
207        catch (Exception e)
208        {
209          if (debugEnabled())
210          {
211            TRACER.debugCaught(DebugLogLevel.ERROR, e);
212          }
213    
214          Message message = ERR_RECURRINGTASK_CANNOT_LOAD_CLASS.
215              get(String.valueOf(taskClassName), ATTR_RECURRING_TASK_CLASS_NAME,
216                  getExceptionMessage(e));
217          throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message,
218                                       e);
219        }
220    
221    
222        // Make sure that the specified class can be instantiated as a task.
223        Task task;
224        try
225        {
226          task = (Task) taskClass.newInstance();
227        }
228        catch (Exception e)
229        {
230          if (debugEnabled())
231          {
232            TRACER.debugCaught(DebugLogLevel.ERROR, e);
233          }
234    
235          Message message = ERR_RECURRINGTASK_CANNOT_INSTANTIATE_CLASS_AS_TASK.get(
236              String.valueOf(taskClassName), Task.class.getName());
237          throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message,
238                                       e);
239        }
240    
241    
242        // Make sure that we can initialize the task with the information in the
243        // provided entry.
244        try
245        {
246          task.initializeTaskInternal(taskScheduler, recurringTaskEntry);
247        }
248        catch (InitializationException ie)
249        {
250          if (debugEnabled())
251          {
252            TRACER.debugCaught(DebugLogLevel.ERROR, ie);
253          }
254    
255          Message message = ERR_RECURRINGTASK_CANNOT_INITIALIZE_INTERNAL.get(
256              String.valueOf(taskClassName), ie.getMessage());
257          throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
258                                       message, ie);
259        }
260    
261        task.initializeTask();
262      }
263    
264    
265    
266      /**
267       * Retrieves the unique ID assigned to this recurring task.
268       *
269       * @return  The unique ID assigned to this recurring task.
270       */
271      public String getRecurringTaskID()
272      {
273        return recurringTaskID;
274      }
275    
276    
277    
278      /**
279       * Retrieves the DN of the entry containing the data for this recurring task.
280       *
281       * @return  The DN of the entry containing the data for this recurring task.
282       */
283      public DN getRecurringTaskEntryDN()
284      {
285        return recurringTaskEntryDN;
286      }
287    
288    
289    
290      /**
291       * Retrieves the entry containing the data for this recurring task.
292       *
293       * @return  The entry containing the data for this recurring task.
294       */
295      public Entry getRecurringTaskEntry()
296      {
297        return recurringTaskEntry;
298      }
299    
300    
301    
302      /**
303       * Retrieves the fully-qualified name of the Java class that provides the
304       * implementation logic for this recurring task.
305       *
306       * @return  The fully-qualified name of the Java class that provides the
307       *          implementation logic for this recurring task.
308       */
309      public String getTaskClassName()
310      {
311        return taskClassName;
312      }
313    
314    
315    
316      /**
317       * Schedules the next iteration of this recurring task for processing.
318       *
319       * @return  The task that has been scheduled for processing.
320       */
321      public Task scheduleNextIteration()
322      {
323        // NYI
324        return null;
325      }
326    }
327