DBA Data[Home] [Help]

PACKAGE BODY: APPS.FND_OAM_DSCRAM_TASKS_PKG

Source


1 PACKAGE BODY FND_OAM_DSCRAM_TASKS_PKG as
2 /* $Header: AFOAMDSTASKB.pls 120.4 2006/05/04 15:16 ilawler noship $ */
3 
4    ----------------------------------------
5    -- Private Body Constants
6    ----------------------------------------
7    PKG_NAME                     CONSTANT VARCHAR2(20) := 'DSCRAM_TASKS_PKG.';
8 
9    ----------------------------------------
10    -- Private Body Variables
11    ----------------------------------------
12    -- Includes a non-authoritative check that the task has valid units with worker spots to keep
13    -- from constantly assigning workers to full tasks before open ones.  Unit will verify
14    -- during its assign that the available unit is valid and in phase.  Since work cannot be created
15    -- during execution, this optimizes fetching without skipping work since we override the check when
16    -- no workers are assigned.
17    CURSOR B_TASKS
18    IS
19       SELECT /*+ FIRST_ROWS(1) */ T.task_id, T.task_status
20       FROM fnd_oam_dscram_tasks T
21       WHERE T.bundle_id = FND_OAM_DSCRAM_BUNDLES_PKG.GET_BUNDLE_ID
22       AND T.task_status in (FND_OAM_DSCRAM_UTILS_PKG.G_STATUS_UNPROCESSED,
23                             FND_OAM_DSCRAM_UTILS_PKG.G_STATUS_PROCESSING,
24                             FND_OAM_DSCRAM_UTILS_PKG.G_STATUS_RESTARTABLE)
25       AND (EXISTS (SELECT unit_id
26                    FROM fnd_oam_dscram_units U
27                    WHERE U.task_id = T.task_id
28                    AND U.unit_status IN (FND_OAM_DSCRAM_UTILS_PKG.G_STATUS_UNPROCESSED,
29                                          FND_OAM_DSCRAM_UTILS_PKG.G_STATUS_PROCESSING,
30                                          FND_OAM_DSCRAM_UTILS_PKG.G_STATUS_RESTARTABLE)
31                    AND U.concurrent_group_unit_id IS NULL
32                    AND (U.actual_workers_allowed IS NULL OR U.actual_workers_allowed > U.workers_assigned)) OR
33            T.workers_assigned = 0)
34       ORDER BY priority ASC, weight DESC;
35 
36    --package cache of currently executing task
37    TYPE b_task_cache_type IS RECORD
38       (
39        initialized              BOOLEAN         := FALSE,
40        task_id                  NUMBER          := NULL,
41        last_validated           DATE            := NULL,
42        last_validation_ret_sts  VARCHAR2(6)     := NULL
43        );
44    b_task_info          b_task_cache_type;
45 
46    --not part of state because stored before assign
47    b_last_fetched_task_id       NUMBER(15) := NULL;
48 
49    ----------------------------------------
50    -- Public/Private Procedures/Functions
51    ----------------------------------------
52 
53    -- Public
54    FUNCTION GET_TASK_ID
55       RETURN NUMBER
56    IS
57    BEGIN
58       IF NOT b_task_info.initialized THEN
59          RAISE NO_DATA_FOUND;
60       END IF;
61 
62       RETURN b_task_info.task_id;
63    END;
64 
65    -- Public
66    -- Return Statuses:
67    -- SUCCESS, ERROR, ERROR_UNEXP, EMPTY
68    PROCEDURE FETCH_NEXT_TASK(p_requery          IN              BOOLEAN,
69                              x_task_id          OUT NOCOPY      NUMBER,
70                              x_return_status    OUT NOCOPY      VARCHAR2,
71                              x_return_msg       OUT NOCOPY      VARCHAR2)
72    IS
73       l_ctxt            VARCHAR2(60) := PKG_NAME||'FETCH_NEXT_TASK';
74 
75       l_task_id NUMBER(15);
76       l_status  VARCHAR2(30);
77    BEGIN
78       fnd_oam_debug.log(2, l_ctxt, 'ENTER');
79       x_return_status := FND_API.G_RET_STS_ERROR;
80       x_return_msg := '';
81 
82       --handle closing/opening the cursor as necessary depending on p_requery
83       IF p_requery OR
84          NOT B_TASKS%ISOPEN THEN
85          --reset the last vars when doing a requery
86          b_last_fetched_task_id := NULL;
87 
88          IF p_requery AND
89             B_TASKS%ISOPEN THEN
90             CLOSE B_TASKS;
91          END IF;
92          OPEN B_TASKS;
93       END IF;
94 
95       --FETCH the next row
96       FETCH B_TASKS INTO l_task_id, l_status;
97 
98       -- no rows is an empty
99       IF B_TASKS%NOTFOUND THEN
100          fnd_oam_debug.log(1, l_ctxt, 'B_TASKS empty');
101          fnd_oam_debug.log(2, l_ctxt, 'EXIT');
102          x_return_status := FND_OAM_DSCRAM_UTILS_PKG.G_RET_STS_EMPTY;
103          CLOSE B_TASKS;
104          RETURN;
105       END IF;
106 
107       --cache the last task fetched to allow a quick validation later
108       fnd_oam_debug.log(1, l_ctxt, 'Task ID(Status): '||l_task_id||'('||l_status||')');
109       x_task_id := l_task_id;
110       b_last_fetched_task_id := l_task_id;
111 
112       --success
113       fnd_oam_debug.log(2, l_ctxt, 'EXIT');
114       x_return_status := FND_API.G_RET_STS_SUCCESS;
115    EXCEPTION
116       WHEN OTHERS THEN
117          IF B_TASKS%ISOPEN THEN
118             CLOSE B_TASKS;
119          END IF;
120          x_return_status := FND_API.G_RET_STS_UNEXP_ERROR;
121          x_return_msg := 'Unhandled Exception: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))';
122          fnd_oam_debug.log(6, l_ctxt, x_return_msg);
123          fnd_oam_debug.log(2, l_ctxt, 'EXIT');
124    END;
125 
126    -- Private
127    -- Called by execute_task before assigning the worker to sanity check
128    -- the input args.
129    -- Return Statuses:
130    --  SUCCESS, ERROR, ERROR_UNEXP
131    --  -Converted- : SKIP, PROCESSED, STOPPED, ERROR_FATAL, ERROR_UNKNOWN
132    FUNCTION VALIDATE_START_EXECUTION(p_task_id          IN NUMBER,
133                                      x_return_status    OUT NOCOPY VARCHAR2,
134                                      x_return_msg       OUT NOCOPY VARCHAR2)
135       RETURN BOOLEAN
136    IS
137       l_ctxt            VARCHAR2(60) := PKG_NAME||'VALIDATE_START_EXECUTION';
138 
139       l_status                  VARCHAR2(30);
140 
141       l_return_status           VARCHAR2(6);
142       l_return_msg              VARCHAR2(2048);
143 
144       CURSOR C1
145       IS
146          SELECT task_status
147          FROM fnd_oam_dscram_tasks
148          WHERE task_id = p_task_id;
149    BEGIN
150       fnd_oam_debug.log(2, l_ctxt, 'ENTER');
151       x_return_status := FND_API.G_RET_STS_ERROR;
152       x_return_msg := '';
153 
154       -- automatically valid if task_id same as last fetched, if status has changed
155       -- then assign will catch it.
156       IF p_task_id = b_last_fetched_task_id THEN
157          fnd_oam_debug.log(2, l_ctxt, 'EXIT');
158          x_return_status := FND_API.G_RET_STS_SUCCESS;
159          RETURN TRUE;
160       END IF;
161 
162       --fetch necessary task attributes
163       OPEN C1;
164       FETCH C1 INTO l_status;
165       IF C1%NOTFOUND THEN
166          x_return_msg := 'Invalid task_id: ('||p_task_id||')';
167          fnd_oam_debug.log(6, l_ctxt, x_return_msg);
168          fnd_oam_debug.log(2, l_ctxt, 'EXIT');
169          RETURN FALSE;
170       END IF;
171       CLOSE C1;
172 
173       --make sure the task has been marked as started by the controller
174       IF NOT FND_OAM_DSCRAM_UTILS_PKG.STATUS_IS_EXECUTABLE(l_status) THEN
175          -- report the true status of the task to execute to pass on to execute's caller
176          x_return_status := FND_OAM_DSCRAM_UTILS_PKG.CONV_VALIDATE_START_STS_TO_RET(l_status);
177          IF FND_OAM_DSCRAM_UTILS_PKG.RET_STS_IS_ERROR(x_return_status) THEN
178             x_return_msg := 'Invalid task status('||l_status||')';
179             fnd_oam_debug.log(1, l_ctxt, x_return_msg);
180          END IF;
181          fnd_oam_debug.log(2, l_ctxt, 'EXIT');
182          RETURN FALSE;
183       END IF;
184 
185       --success
186       fnd_oam_debug.log(2, l_ctxt, 'EXIT');
187       x_return_status := FND_API.G_RET_STS_SUCCESS;
188       RETURN TRUE;
189    EXCEPTION
190       WHEN OTHERS THEN
191          x_return_status := FND_API.G_RET_STS_UNEXP_ERROR;
192          x_return_msg := 'Unhandled Exception: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))';
193          fnd_oam_debug.log(6, l_ctxt, x_return_msg);
194          fnd_oam_debug.log(2, l_ctxt, 'EXIT');
195          RETURN FALSE;
196    END;
197 
198    -- Public
199    -- Return Statuses:
200    --  SUCCESS, ERROR, ERROR_UNEXP, STOPPED
201    --  -Converted- : PROCESSED, STOPPED, ERROR_FATAL, ERROR_UNKNOWN
202    FUNCTION VALIDATE_CONTINUED_EXECUTION(p_force_query          IN BOOLEAN,
203                                          p_recurse              IN BOOLEAN,
204                                          x_return_status        OUT NOCOPY VARCHAR2,
205                                          x_return_msg           OUT NOCOPY VARCHAR2)
206       RETURN BOOLEAN
207    IS
208       l_ctxt            VARCHAR2(60) := PKG_NAME||'VALIDATE_CONTINUED_EXECUTION';
209 
210       l_status                  VARCHAR2(30) := NULL;
211       l_return_status           VARCHAR2(6);
212       l_return_msg              VARCHAR2(2048);
213 
214       CURSOR C1
215       IS
216          SELECT task_status
217          FROM fnd_oam_dscram_tasks
218          WHERE task_id = b_task_info.task_id;
219    BEGIN
220       x_return_status := FND_API.G_RET_STS_ERROR;
221       x_return_msg := '';
222 
223       -- make sure the state's initialized
224       IF NOT b_task_info.initialized THEN
225          RAISE NO_DATA_FOUND;
226       END IF;
227 
228       -- check if we should do work or if we can presume the cached status
229       IF (p_force_query OR
230           FND_OAM_DSCRAM_UTILS_PKG.VALIDATION_DUE(b_task_info.last_validated)) THEN
231 
232          fnd_oam_debug.log(1, l_ctxt, '>RE-QUERYING<');
233 
234          -- re-init the cached fields to allow easy exit
235          b_task_info.last_validation_ret_sts := x_return_status;
236          b_task_info.last_validated := SYSDATE;
237 
238          --otherwise, fetch necessary run attributes and evaluate
239          OPEN C1;
240          FETCH C1 INTO l_status;
241          IF C1%NOTFOUND THEN
242             --shouldn't happen since we're using the cache
243             x_return_msg := 'Invalid cached task_id: '||b_task_info.task_id;
244             fnd_oam_debug.log(6, l_ctxt, x_return_msg);
245             RETURN FALSE;
246          END IF;
247          CLOSE C1;
248 
249          --make sure the task has been marked as processing
250          IF NOT FND_OAM_DSCRAM_UTILS_PKG.STATUS_IS_PROCESSING(l_status) THEN
251             x_return_status := FND_OAM_DSCRAM_UTILS_PKG.CONV_VALIDATE_CONT_STS_TO_RET(l_status);
252             b_task_info.last_validation_ret_sts := x_return_status;
253             IF x_return_status <> FND_OAM_DSCRAM_UTILS_PKG.G_RET_STS_PROCESSED THEN
254                x_return_msg := 'Invalid task status('||l_status||')';
255                fnd_oam_debug.log(1, l_ctxt, x_return_msg);
256             END IF;
257             RETURN FALSE;
258          END IF;
259          x_return_status := FND_API.G_RET_STS_SUCCESS;
260       ELSE
261          x_return_status := b_task_info.last_validation_ret_sts;
262       END IF;
263 
264       -- make a recursive call to the bundle if required
265       IF p_recurse THEN
266          IF NOT FND_OAM_DSCRAM_BUNDLES_PKG.VALIDATE_CONTINUED_EXECUTION(p_force_query,
267                                                                         TRUE,
268                                                                         l_return_status,
269                                                                         l_return_msg) THEN
270             -- the run/bundle has an invalid status, tell the execute to stop the task
271             x_return_status := FND_OAM_DSCRAM_UTILS_PKG.G_RET_STS_STOPPED;
272             x_return_msg := '[Continued Validation Parent(s) Failed]:(Status('||l_return_status||'), Msg('||l_return_msg||'))';
273             fnd_oam_debug.log(1, l_ctxt, x_return_msg);
274             RETURN FALSE;
275          END IF;
276       END IF;
277 
278       --success
279       b_task_info.last_validation_ret_sts := x_return_status;
280       b_task_info.last_validated := SYSDATE;
281       RETURN (x_return_status = FND_API.G_RET_STS_SUCCESS);
282    EXCEPTION
283       WHEN OTHERS THEN
284          x_return_msg := 'Unhandled Exception: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))';
285          fnd_oam_debug.log(6, l_ctxt, x_return_msg);
286          x_return_status := FND_API.G_RET_STS_UNEXP_ERROR;
287          b_task_info.last_validation_ret_sts := x_return_status;
288          b_task_info.last_validated := SYSDATE;
289          RETURN FALSE;
290    END;
291 
292    -- Private: Autonomous Txn
293    -- Invariant:
294    --   Validate_statr must preceed this call so we can assume the p_task_id has a valid
295    --   database row.
296    -- Before a call to execute_task can start doing work, it needs to call this procedure
297    -- to make sure the status is set to processing and a stats row is created for it.
298    -- Return Statuses:
299    --  SUCCESS, ERROR, ERROR_UNEXP
300    --  -Conv Validate_start statuses-
301    PROCEDURE ASSIGN_WORKER_TO_TASK(p_task_id            IN NUMBER,
302                                    x_return_status      OUT NOCOPY VARCHAR2,
303                                    x_return_msg         OUT NOCOPY VARCHAR2)
304    IS
305       PRAGMA AUTONOMOUS_TRANSACTION;
306 
307       l_ctxt            VARCHAR2(60) := PKG_NAME||'ASSIGN_WORKER_TO_TASK';
308 
309       l_stat_id                 NUMBER;
310       l_status                  VARCHAR2(30) := NULL;
311       l_workers_assigned        NUMBER(15);
312 
313    BEGIN
314       fnd_oam_debug.log(2, l_ctxt, 'ENTER');
315       x_return_status := FND_API.G_RET_STS_ERROR;
316       x_return_msg := '';
317 
318       -- Do a locking select without a pre-select since we always have to update the
319       -- row to add to the # of workers assigned.  Also updates the status to started if it
320       -- hasn't been set yet.
321       SELECT task_status, workers_assigned
322          INTO l_status, l_workers_assigned
323          FROM fnd_oam_dscram_tasks
324          WHERE task_id = p_task_id
325          FOR UPDATE;
326 
327       fnd_oam_debug.log(1, l_ctxt, 'Task Status(Workers): '||l_status||'('||l_workers_assigned||')');
328 
329       -- make sure the status is runnable after the lock
330       IF NOT FND_OAM_DSCRAM_UTILS_PKG.STATUS_IS_EXECUTABLE(l_status) THEN
331          x_return_status := FND_OAM_DSCRAM_UTILS_PKG.CONV_VALIDATE_START_STS_TO_RET(l_status);
332          IF FND_OAM_DSCRAM_UTILS_PKG.RET_STS_IS_ERROR(x_return_status) THEN
333             x_return_msg := 'Invalid task in assign, status('||l_status||')';
334             fnd_oam_debug.log(1, l_ctxt, x_return_msg);
335          END IF;
336          fnd_oam_debug.log(2, l_ctxt, 'EXIT');
337          ROLLBACK;
338          RETURN;
339       END IF;
340 
341       -- if we're executable but not processing we should start the entry
342       IF l_status <> FND_OAM_DSCRAM_UTILS_PKG.G_STATUS_PROCESSING THEN
343          IF l_workers_assigned = 0 THEN
344             --create a new stats entry for the task
345             FND_OAM_DSCRAM_STATS_PKG.CREATE_ENTRY(p_source_object_type  => FND_OAM_DSCRAM_UTILS_PKG.G_TYPE_TASK,
346                                                   p_source_object_id    => p_task_id,
347                                                   p_start_time          => SYSDATE,
348                                                   p_prestart_status     => l_status,
349                                                   x_stat_id             => l_stat_id);
350             UPDATE fnd_oam_dscram_tasks
351                SET task_status = FND_OAM_DSCRAM_UTILS_PKG.G_STATUS_PROCESSING,
352                STATS_FINISHED = FND_API.G_FALSE
353                WHERE task_id = p_task_id;
354          ELSE
355             --the bundle isn't processing but the worker count's nonzero, this shouldn't happen
356             x_return_msg := 'Task Status ('||l_status||') is not in-progress but the number of workers assigned('||l_workers_assigned||') is nonzero.';
357             fnd_oam_debug.log(6, l_ctxt, x_return_msg);
358             fnd_oam_debug.log(2, l_ctxt, 'EXIT');
359             ROLLBACK;
360             RETURN;
361          END IF;
362       END IF;
363 
364       --update the task's # of workers assigned
365       UPDATE fnd_oam_dscram_tasks
366          SET workers_assigned = workers_assigned + 1,
367          last_updated_by = fnd_global.user_id,
368          last_update_login = fnd_global.user_id,
369          last_update_date = SYSDATE
370          WHERE task_id = p_task_id;
371 
372       --commit the changes and release the lock
373       COMMIT;
374 
375       --populate the task state
376       b_task_info.task_id := p_task_id;
377       b_task_info.last_validated := NULL;
378       b_task_info.initialized := TRUE;
379 
380       -- invalidate the last_fetched vars since we've changed things
381       b_last_fetched_task_id := NULL;
382 
383       x_return_status := FND_API.G_RET_STS_SUCCESS;
384       fnd_oam_debug.log(2, l_ctxt, 'EXIT');
385    EXCEPTION
386       WHEN OTHERS THEN
387          x_return_status := FND_API.G_RET_STS_UNEXP_ERROR;
388          x_return_msg := 'Unhandled Exception: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))';
389          fnd_oam_debug.log(6, l_ctxt, x_return_msg);
390          fnd_oam_debug.log(2, l_ctxt, 'EXIT');
391          ROLLBACK;
392    END;
393 
394    -- Private: Autonomous Txn
395    -- Called when a task is completed in some way, usually when there are no more
396    -- processable units to fetch.  Duties include updating the task's status and completing
397    -- the stats record.
398    PROCEDURE COMPLETE_TASK(p_proposed_status    IN VARCHAR2,
399                            p_proposed_ret_sts   IN VARCHAR2,
400                            x_final_status       OUT NOCOPY VARCHAR2,
401                            x_final_ret_sts      OUT NOCOPY VARCHAR2)
402    IS
403       PRAGMA AUTONOMOUS_TRANSACTION;
404 
405       l_ctxt            VARCHAR2(60) := PKG_NAME||'COMPLETE_TASK';
406 
407       l_final_status    VARCHAR2(30);
408       l_final_ret_sts   VARCHAR2(6);
409 
410       l_status                  VARCHAR2(30);
411       l_workers_assigned        NUMBER(15);
412    BEGIN
413       fnd_oam_debug.log(2, l_ctxt, 'ENTER');
414 
415       -- always lock the task since we have to decrement the worker count
416       SELECT task_status, workers_assigned
417          INTO l_status, l_workers_assigned
418          FROM fnd_oam_dscram_tasks
419          WHERE task_id = b_task_info.task_id
420          FOR UPDATE;
421 
422       -- translate the new_status into a valid final status
423       FND_OAM_DSCRAM_UTILS_PKG.TRANSLATE_COMPLETED_STATUS(l_status,
424                                                           l_workers_assigned,
425                                                           p_proposed_status,
426                                                           p_proposed_ret_sts,
427                                                           l_final_status,
428                                                           l_final_ret_sts);
429       fnd_oam_debug.log(1, l_ctxt, 'Translated status "'||p_proposed_status||'" into "'||l_final_status||'"');
430       fnd_oam_debug.log(1, l_ctxt, 'Translated Execute Ret Sts "'||p_proposed_ret_sts||'" into "'||l_final_ret_sts||'"');
431 
432       --if we discovered that we're full, possibly temporarily, just decrement the worker count and leave as long as we're not the last worker
433       IF l_final_ret_sts = FND_OAM_DSCRAM_UTILS_PKG.G_RET_STS_FULL AND l_workers_assigned > 1 THEN
434          UPDATE fnd_oam_dscram_tasks
435             SET workers_assigned = workers_assigned - 1,
436             last_updated_by = fnd_global.user_id,
437             last_update_login = fnd_global.user_id,
438             last_update_date = SYSDATE
439             WHERE task_id = b_task_info.task_id;
440       ELSE
441          -- otherwise, update the status and workers_assigned
442          UPDATE fnd_oam_dscram_tasks
443             SET task_status = l_final_status,
444             workers_assigned = workers_assigned - 1,
445             last_updated_by = fnd_global.user_id,
446             last_update_login = fnd_global.user_id,
447             last_update_date = SYSDATE
448             WHERE task_id = b_task_info.task_id;
449 
450          --only complete stats if we changed state
451          IF l_final_status <> l_status AND
452             FND_OAM_DSCRAM_UTILS_PKG.STATUS_IS_FINAL(l_final_status) THEN
453 
454             FND_OAM_DSCRAM_STATS_PKG.COMPLETE_ENTRY(p_source_object_type        => FND_OAM_DSCRAM_UTILS_PKG.G_TYPE_TASK,
455                                                     p_source_object_id          => b_task_info.task_id,
456                                                     p_end_time                  => SYSDATE,
457                                                     p_postend_status            => l_final_status);
458          END IF;
459       END IF;
460 
461       -- push the changes and release the lock
462       COMMIT;
463 
464       x_final_status := l_final_status;
465       x_final_ret_sts := l_final_ret_sts;
466 
467       --after completing the task, kill the state
468       b_task_info.initialized := FALSE;
469 
470       fnd_oam_debug.log(2, l_ctxt, 'EXIT');
471    EXCEPTION
472       WHEN OTHERS THEN
473          x_final_status := FND_OAM_DSCRAM_UTILS_PKG.G_STATUS_ERROR_UNKNOWN;
474          x_final_ret_sts := FND_API.G_RET_STS_UNEXP_ERROR;
475          fnd_oam_debug.log(6, l_ctxt, 'Unhandled Exception: (Code('||SQLCODE||'), Message("'||SQLERRM||'"))');
476          fnd_oam_debug.log(2, l_ctxt, 'EXIT');
477          ROLLBACK;
478    END;
479 
480    -- Public
481    PROCEDURE EXECUTE_TASK(p_task_id             IN NUMBER,
482                           x_return_status       OUT NOCOPY VARCHAR2,
483                           x_return_msg          OUT NOCOPY VARCHAR2)
484    IS
485       l_ctxt            VARCHAR2(60) := PKG_NAME||'EXECUTE_TASK';
486 
487       l_unit_id         NUMBER;
488       l_completed_status        VARCHAR2(30);
489 
490       l_return_status   VARCHAR2(6);
491       l_return_msg      VARCHAR2(2048);
492       l_temp            VARCHAR2(30);
493    BEGIN
494       fnd_oam_debug.log(2, l_ctxt, 'ENTER');
495       x_return_status := FND_API.G_RET_STS_ERROR;
496       x_return_msg := '';
497 
498       -- do an initial validation of the task
499       IF NOT VALIDATE_START_EXECUTION(p_task_id,
500                                       l_return_status,
501                                       l_return_msg) THEN
502          x_return_status := l_return_status;
503          x_return_msg := '[Task Validation Failed]:('||l_return_msg||')';
504          fnd_oam_debug.log(1, l_ctxt, x_return_msg);
505          fnd_oam_debug.log(2, l_ctxt, 'EXIT');
506          RETURN;
507       END IF;
508 
509       -- attempt to assign this invocation as a worker for the bundle
510       ASSIGN_WORKER_TO_TASK(p_task_id,
511                             l_return_status,
512                             l_return_msg);
513       IF l_return_status <> FND_API.G_RET_STS_SUCCESS THEN
514          x_return_status := l_return_status;
515          x_return_msg := '[Task Worker Assignment Failed]:('||l_return_msg||')';
516          fnd_oam_debug.log(1, l_ctxt, x_return_msg);
517          fnd_oam_debug.log(2, l_ctxt, 'EXIT');
518          RETURN;
519       END IF;
520 
521       --before proceeding after the assign, check our parent objects to make sure
522       --their state suggests we should continue
523       IF NOT FND_OAM_DSCRAM_BUNDLES_PKG.VALIDATE_CONTINUED_EXECUTION(FALSE,
524                                                                      TRUE,
525                                                                      l_return_status,
526                                                                      l_return_msg) THEN
527          --we don't care why a parent is invalid, just knowing so forces us to
528          --stop our work
529          COMPLETE_TASK(FND_OAM_DSCRAM_UTILS_PKG.G_STATUS_STOPPED,
530                        FND_OAM_DSCRAM_UTILS_PKG.G_RET_STS_STOPPED,
531                        l_completed_status,
532                        x_return_status);
533          x_return_msg := '[Post-Assignment Parent Validation Failed]:('||l_return_msg||')';
534          fnd_oam_debug.log(1, l_ctxt, x_return_msg);
535          fnd_oam_debug.log(2, l_ctxt, 'EXIT');
536          RETURN;
537       END IF;
538 
539       --at this point, we're assigned so we need to issue a complete before returning.
540       --this means no quick returns, so we hit the complete after the loop.
541       l_completed_status := FND_OAM_DSCRAM_UTILS_PKG.G_STATUS_PROCESSED;
542       l_return_status := FND_API.G_RET_STS_SUCCESS;
543 
544       -- we're in, start pulling units and executing them.
545       <<outer>>
546       LOOP
547          --get the next available task
548          FND_OAM_DSCRAM_UNITS_PKG.FETCH_NEXT_UNIT(TRUE,
549                                                   l_unit_id,
550                                                   l_return_status,
551                                                   l_return_msg);
552          IF l_return_status = FND_OAM_DSCRAM_UTILS_PKG.G_RET_STS_EMPTY THEN
553             -- empty means no units left, independent of phase
554             l_return_status := FND_API.G_RET_STS_SUCCESS;
555             EXIT outer;
556          ELSIF l_return_status = FND_OAM_DSCRAM_UTILS_PKG.G_RET_STS_FULL THEN
557             -- full means nothing available right now so return and find another task.
558             EXIT outer;
559          ELSIF l_return_status <> FND_API.G_RET_STS_SUCCESS THEN
560             l_completed_status := FND_OAM_DSCRAM_UTILS_PKG.G_STATUS_ERROR_UNKNOWN;
561             x_return_msg := '[Fetch Next Unit Failed]:('||l_return_msg||')';
562             fnd_oam_debug.log(6, l_ctxt, x_return_msg);
563             EXIT outer;
564          END IF;
565 
566          --execute the unit
567          FND_OAM_DSCRAM_UNITS_PKG.EXECUTE_UNIT(l_unit_id,
568                                                l_return_status,
569                                                l_return_msg);
570          IF l_return_status = FND_OAM_DSCRAM_UTILS_PKG.G_RET_STS_FULL THEN
571             --If we got past the fetch but the execute found it full, continue
572             --fetching.
573             <<inner>>
574             LOOP
575                FND_OAM_DSCRAM_UNITS_PKG.FETCH_NEXT_UNIT(FALSE,
576                                                         l_unit_id,
577                                                         l_return_status,
578                                                         l_return_msg);
579                IF l_return_status IN (FND_OAM_DSCRAM_UTILS_PKG.G_RET_STS_EMPTY,
580                                       FND_OAM_DSCRAM_UTILS_PKG.G_RET_STS_FULL) THEN
581                   -- seeing an empty or full here doesn't mean the task's done, just that it's busy.
582                   -- return full to the bundle_pkg to pick another task.
583                   l_return_status := FND_OAM_DSCRAM_UTILS_PKG.G_RET_STS_FULL;
584                   EXIT outer;
585                ELSIF l_return_status <> FND_API.G_RET_STS_SUCCESS THEN
586                   l_completed_status := FND_OAM_DSCRAM_UTILS_PKG.G_STATUS_ERROR_UNKNOWN;
587                   x_return_msg := '[Inner Fetch Next Unit Failed]:('||l_return_msg||')';
588                   fnd_oam_debug.log(6, l_ctxt, x_return_msg);
589                   EXIT outer;
590                END IF;
591 
592                -- try to execute this unit
593                FND_OAM_DSCRAM_UNITS_PKG.EXECUTE_UNIT(l_unit_id,
594                                                      l_return_status,
595                                                      l_return_msg);
596                IF l_return_status = FND_OAM_DSCRAM_UTILS_PKG.G_RET_STS_FULL THEN
597                   --continue to the next inner loop iteration for the next fetch
598                   null;
599                ELSIF l_return_status = FND_API.G_RET_STS_SUCCESS THEN
600                   --on success break out of the loop so we can requery the units table from scratch
601                   EXIT inner;
602                ELSIF l_return_status <> FND_OAM_DSCRAM_UTILS_PKG.G_RET_STS_PROCESSED AND
603                      l_return_status <> FND_OAM_DSCRAM_UTILS_PKG.G_RET_STS_SKIPPED THEN
604                   -- unexpected execution failure, since units have phases, there may be dependencies between
605                   -- units which will break if we continue with the task. To handle this, we'll stop the task and
606                   -- allow the user to choose whether to ignore the failed unit or retry them when restarting the task.
607                   x_return_msg := '[Inner Execute Unit Failed]:(Status('||l_return_status||'), Msg('||l_return_msg||')). Stopping task.';
608                   fnd_oam_debug.log(6, l_ctxt, x_return_msg);
609                   l_return_status := FND_OAM_DSCRAM_UTILS_PKG.G_RET_STS_STOPPED;
610                   l_completed_status := FND_OAM_DSCRAM_UTILS_PKG.G_STATUS_STOPPED;
611                   EXIT outer;
612                END IF;
613             END LOOP inner;
614          ELSIF l_return_status <> FND_API.G_RET_STS_SUCCESS AND
615                l_return_status <> FND_OAM_DSCRAM_UTILS_PKG.G_RET_STS_PROCESSED AND
616                l_return_status <> FND_OAM_DSCRAM_UTILS_PKG.G_RET_STS_SKIPPED THEN
617             -- take the same actions as when the inner execute fails
618             x_return_msg := '[Outer Execute Unit Failed]:(Status('||l_return_status||'), Msg('||l_return_msg||')). Stopping task.';
619             fnd_oam_debug.log(6, l_ctxt, x_return_msg);
620             l_return_status := FND_OAM_DSCRAM_UTILS_PKG.G_RET_STS_STOPPED;
621             l_completed_status := FND_OAM_DSCRAM_UTILS_PKG.G_STATUS_STOPPED;
622             EXIT outer;
623          END IF;
624 
625          --after every unit evaluation, check on the task and its parents.
626          --tell it to requery if the child's execution came back non-successful since this should
627          --be pretty uncommon and will help detect when a child has seen a stop in a parent.
628          IF NOT VALIDATE_CONTINUED_EXECUTION((l_return_status <> FND_API.G_RET_STS_SUCCESS),
629                                              TRUE,
630                                              l_return_status,
631                                              l_return_msg) THEN
632             --complete the task based on what validate found
633             l_completed_status := FND_OAM_DSCRAM_UTILS_PKG.CONV_RET_STS_TO_COMPL_STATUS(l_return_status);
634             IF FND_OAM_DSCRAM_UTILS_PKG.STATUS_IS_ERROR(l_return_status) THEN
635                x_return_msg := '[End-of-Loop Validate Failed]:('||l_return_msg||')';
636                fnd_oam_debug.log(6, l_ctxt, x_return_msg);
637             END IF;
638             EXIT outer;
639          END IF;
640 
641       END LOOP outer;
642 
643       --finished processing the bundle
644       fnd_oam_debug.log(1, l_ctxt, 'Finished Task with status: '||l_completed_status||'('||l_return_status||')');
645       COMPLETE_TASK(l_completed_status,
646                     l_return_status,
647                     l_temp,
648                     x_return_status);
649 
650       fnd_oam_debug.log(2, l_ctxt, 'EXIT');
651    EXCEPTION
652       WHEN OTHERS THEN
653          COMPLETE_TASK(FND_OAM_DSCRAM_UTILS_PKG.G_STATUS_ERROR_UNKNOWN,
654                          FND_API.G_RET_STS_UNEXP_ERROR,
655                          l_completed_status,
656                          x_return_status);
657          x_return_msg := 'Unhandled Exception: [Code('||SQLCODE||'), Message("'||SQLERRM||'")]';
658          fnd_oam_debug.log(6, l_ctxt, x_return_msg);
659          fnd_oam_debug.log(2, l_ctxt, 'EXIT');
660    END;
661 
662 END FND_OAM_DSCRAM_TASKS_PKG;