1 package body WF_XML as
2 /* $Header: wfmxmlb.pls 120.57.12020000.2 2012/07/16 11:28:28 skandepu ship $ */
3 --
4 -- Exceptions
5 --
6 dequeue_timeout exception;
7 pragma EXCEPTION_INIT(dequeue_timeout, -25228);
8
9 dequeue_disabled exception;
10 pragma EXCEPTION_INIT(dequeue_disabled, -25226);
11
12 dequeue_outofseq exception;
13 pragma EXCEPTION_INIT(dequeue_outofseq, -25237);
14
15 no_queue exception;
16 pragma EXCEPTION_INIT(no_queue, -24010);
17
18 -- g_fist_message
19 -- Flag to control the dequeuing of the SMTP queue
20 g_first_message boolean := TRUE;
21
22 g_LOBTable wf_temp_lob.wf_temp_lob_table_type;
23
24 TYPE wf_resourceList_rec_t IS RECORD
25 (
26 contentId VARCHAR2(1000),
27 fileName VARCHAR2(1000),
28 contentType VARCHAR2(1000),
29 value VARCHAR2(4000)
30
31 );
32
33 TYPE resourceList_t IS TABLE OF
34 wf_resourceList_rec_t INDEX BY BINARY_INTEGER;
35
36
37 cursor g_urls(p_nid varchar2) is
38 select WMA.TYPE, WMA.DISPLAY_NAME, WNA.TEXT_VALUE, WNA.NAME
39 from WF_NOTIFICATION_ATTRIBUTES WNA, WF_NOTIFICATIONS WN,
40 WF_MESSAGE_ATTRIBUTES_VL WMA
41 where WNA.NOTIFICATION_ID = p_nid
42 and WN.NOTIFICATION_ID = WNA.NOTIFICATION_ID
43 and WN.MESSAGE_TYPE = WMA.MESSAGE_TYPE
44 and WN.MESSAGE_NAME = WMA.MESSAGE_NAME
45 and WMA.TYPE = 'URL'
46 and WMA.ATTACH = 'N'
47 and WMA.NAME = WNA.NAME;
48
49 -- Set these constants as session level varaibles to minumise the
50 -- calls to wf_core.
51 g_newLine varchar2(1) := wf_core.newLine;
52 g_install varchar2(100) := wf_core.Translate('WF_INSTALL');
53 g_htmlmessage varchar2(200);
54 g_urlNotification varchar2(200);
55 g_urlListAttachment varchar2(200);
56 -- These are only used in legacy procedures.
57 g_webAgent varchar2(200) := wf_core.translate('WF_WEB_AGENT');
58 g_wfSchema varchar2(200) := wf_core.translate('WF_SCHEMA');
59 g_fndapi_misschr varchar2(1) := FND_API.G_MISS_CHAR;
60
61 g_ntfDocText varchar2(30) := wf_notification.doc_text;
62 g_ntfDocHtml varchar2(30) := wf_notification.doc_html;
63
64 -- <<sstomar> : nls changes
65 g_base_language v$nls_parameters.value%TYPE ;
66 g_base_territory v$nls_parameters.value%TYPE ;
67 g_base_codeset v$nls_parameters.value%TYPE ;
68
69 -- << sstomar>> : Initialization can be done by using
70 -- variables from wf_core.nls_date_format,
71 -- wf_core.nls_date_language etc. but since
72 -- when calling WF_NOTIFICATION_UTIL.set/getNLSContext to retrieve
73 -- defaul NLS Language etc. we can define vars. here also.
74 g_base_nlsDateFormat v$nls_parameters.value%TYPE := wf_core.nls_date_format;
75 g_base_nlsDateLanguage v$nls_parameters.value%TYPE := wf_core.nls_date_language;
76 g_base_nlsCalendar v$nls_parameters.value%TYPE := wf_core.nls_calendar;
77 g_base_nlsSort v$nls_parameters.value%TYPE := wf_core.nls_sort ;
78 g_base_nlsNumericCharacters v$nls_parameters.value%TYPE := wf_core.nls_numeric_characters;
79
80 g_WebMail_PostScript_Msg varchar2(1024);
81
82 -- Bug 10202313: global variables to store status, mail_status of WF_NOTIFICATIONS table
83 -- which will be passed as parameters to WF_MAIL.GetLOBMessage4() API
84 g_status wf_notifications.status%TYPE;
85 g_mstatus wf_notifications.mail_status%TYPE;
86
87
88 -- Return TRUE if the URL points to a image file.
89 -- The URL is pretested to ensure that it does NOT contain
90 -- any URL parameters.
91 function isImageReference(url in varchar2, renderType in varchar2)
92 return boolean
93 is
94 extPos pls_integer;
95 extStr varchar2(1000);
96 params pls_integer;
97
98 l_renderType varchar2(10);
99
100 begin
101 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
102 wf_log_pkg.string(WF_LOG_PKG.level_statement,
103 'wf.plsql.WF_XML.isImageReference',
104 'BEGIN {'||url||'} {'||renderType||'}');
105 end if;
106 l_renderType := renderType;
107
108 params := instr(url, '?');
109 if (params = 0) then
110 extPos := instrb(url, '.', -1, 1) + 1;
111 extStr := lower(substrb(url, extPos));
112
113 if (( l_renderType is null or l_renderType = 'IMG:') and
114 extStr in ('gif','jpg','png','tif','bmp','jpeg')) then
115 return true;
116 else
117 l_renderType := 'LNK:';
118 end if;
119
120 if l_renderType = 'LNK:' then
121 return false;
122 end if;
123 else
124 return false;
125 end if;
126 end isImageReference;
127
128 -- GetRecipients
129 -- IN
130 -- Role
131 -- OUT
132 -- List of recipients with their details contained in a PL/SQL Table.
133 -- NOTE
134 -- A role will only be resolved to one level. If a role contains has a
135 -- role associated to it, then that's as far as we go.
136 procedure GetRecipients(p_role in varchar2,
137 p_recipient_list in out NOCOPY WF_DIRECTORY.wf_local_roles_tbl_type)
138 is
139
140 l_display_name wf_roles.display_name%TYPE;
141 l_description wf_roles.description%TYPE;
142 l_email_address wf_roles.email_address%TYPE;
143 l_notification_preference wf_roles.notification_preference%TYPE;
144 l_language wf_roles.language%TYPE;
145 l_territory wf_roles.territory%TYPE;
146
147 cursor urc1(role varchar2, colon binary_integer) is
148 select name
149 from wf_users
150 where (name, orig_system, orig_system_id) in
151 (select user_name, user_orig_system, user_orig_system_id
152 from wf_user_roles
153 where role_name = urc1.role
154 and role_orig_system = substr(urc1.role, 1, urc1.colon-1)
155 and role_orig_system_id = substr(urc1.role, urc1.colon+1)
156 and user_name <> role_name
157 and user_orig_system <> role_orig_system
158 and user_orig_system_id <> role_orig_system_id)
159 and notification_preference not in ('SUMMARY','QUERY')
160 order by notification_preference, language;
161
162
163 cursor urc2(role varchar2) is
164 select name
165 from wf_users
166 where (name, orig_system, orig_system_id) in
167 (select user_name, user_orig_system, user_orig_system_id
168 from wf_user_roles
169 where role_name = urc2.role
170 and user_name <> role_name)
171 and notification_preference not in ('SUMMARY','QUERY')
172 order by notification_preference, language;
173
174 i binary_integer := 0;
175 colon binary_integer;
176
177
178 begin
179
180 -- Get role details.
181 wf_directory.GetRoleInfo(p_role, l_display_name, l_email_address,
182 l_notification_preference, l_language,
183 l_territory);
184
185 -- If the email address is NULL, then look for the members attached to
186 -- the role. Only attach those roles that 'want' a notification.
187 if l_email_address is not NULL
188 and l_notification_preference not in ('SUMMARY','QUERY') then
189 i := p_recipient_list.COUNT + 1;
190 p_recipient_list(i).name := p_role;
191 p_recipient_list(i).display_name := l_display_name;
192 p_recipient_list(i).description := l_description;
193 p_recipient_list(i).notification_preference :=
194 l_notification_preference;
195 p_recipient_list(i).language := l_language;
196 p_recipient_list(i).territory := l_territory;
197 p_recipient_list(i).email_address := l_email_address;
198 else
199 -- The the ROLE has a blank email address, then we
200 -- are interested only in resolving it one level.
201 -- If this is a user with a blank email address, then no one
202 -- will get a notification.
203 colon := instr(p_role, ':');
204 if colon > 0 then
205 for urrec in urc1(p_role, colon) loop
206 wf_directory.GetRoleInfo(urrec.name, l_display_name,
207 l_email_address,
208 l_notification_preference, l_language,
209 l_territory);
210 i := p_recipient_list.COUNT + 1;
211 p_recipient_list(i).name := p_role;
212 p_recipient_list(i).display_name := l_display_name;
213 p_recipient_list(i).description := l_description;
214 p_recipient_list(i).notification_preference :=
215 l_notification_preference;
216 p_recipient_list(i).language := l_language;
217 p_recipient_list(i).territory := l_territory;
218 p_recipient_list(i).email_address := l_email_address;
219 end loop;
220 else
221 for urrec in urc2(p_role) loop
222 wf_directory.GetRoleInfo(urrec.name, l_display_name,
223 l_email_address,
224 l_notification_preference, l_language,
225 l_territory);
226 i := p_recipient_list.COUNT + 1;
227 p_recipient_list(i).name := p_role;
228 p_recipient_list(i).display_name := l_display_name;
229 p_recipient_list(i).description := l_description;
230 p_recipient_list(i).notification_preference :=
231 l_notification_preference;
232 p_recipient_list(i).language := l_language;
233 p_recipient_list(i).territory := l_territory;
234 p_recipient_list(i).email_address := l_email_address;
235 end loop;
236 end if;
237 end if;
238 exception
239 when others then
240 wf_core.context('Wf_XML','GetRecipients',p_role);
241 raise;
242 end GetRecipients;
243
244 -- EncodeEntityReference
245 -- IN
246 -- Data to be encoded
247 -- RETURN
248 -- Encoded data.
249 -- NOTE
250 -- This is needed to encode the HTML data before placing it into
251 -- the XML structure. If it is placed in neat, then the XML parser
252 -- will not be able to cope.
253 function EncodeEntityReference(p_str in varchar2) return varchar2
254 is
255 l_str varchar2(32000);
256 begin
257 l_str := p_str;
258 l_str := replace(l_str,'&','&'||'amp;');
259 l_str := replace(l_str,'<','&'||'lt;');
260 l_str := replace(l_str,'>','&'||'gt;');
261 l_str := replace(l_str,'"','&'||'quot;');
262 l_str := replace(l_str,'''','&'||'apos;');
263 return l_str;
264 end EncodeEntityReference;
265
266
267 -- DecodeEntityReference (PRIVATE)
268 -- IN
269 -- Data to be decoded
270 -- RETURN
271 -- Decoded data.
272 -- NOTE
273 -- This is needed to decode the HTML data after extracting it from
274 -- the XML structure.
275 function DecodeEntityReference(some_text in varchar2)
276 return varchar2 is
277 l_amp varchar2(1) := '&';
278 buf varchar2(32000);
279 begin
280 buf := some_text;
281 buf := replace(buf, l_amp||'#38;', l_amp);
282 buf := replace(buf, l_amp||'lt;', '<');
283 buf := replace(buf, l_amp||'#60;', '<');
284 buf := replace(buf, l_amp||'gt;', '>');
285 buf := replace(buf, l_amp||'#92;', '\');
286 buf := replace(buf, l_amp||'#39;', '''');
287 buf := replace(buf, l_amp||'apos;', '''');
288 buf := replace(buf, l_amp||'quot;', '"');
289 buf := replace(buf, l_amp||'amp;', l_amp);
290 return buf;
291 exception
292 when others then
293 wf_core.context('Wf_Notification', 'DecodeEntityReference');
294 raise;
295 end DecodeEntityReference;
296
297 -- EnqueueLOBMessage
298 -- IN
299 -- Queue Name
300 -- Priority of the message
301 -- Correlation for the message - the NID of the notification
302 -- for this implementation.
303 -- Message - XML encoded.
304 procedure EnqueueLOBMessage(p_queue in varchar2,
305 p_priority number,
306 p_correlation in varchar2,
307 p_message in CLOB) is
308
309 l_enqueue_options dbms_aq.enqueue_options_t;
310 l_message_properties dbms_aq.message_properties_t;
311 l_correlation varchar2(255) := NULL;
312 l_msgid raw(16);
313
314 l_queueu VARCHAR2(200);
315 l_queueName VARCHAR2(30);
316 l_queueTable VARCHAR2(200);
317 l_schemaName VARCHAR2(320);
318 l_msgLength NUMBER;
319 l_sqlbuf VARCHAR2(2000);
320
321 l_amount binary_integer;
322 l_pos pls_integer;
323
324 l_dequeue_options dbms_aq.dequeue_options_t;
325 begin
326
327
328 /** wf_message_payload_t is obsolete in 2.6.4 onwards **/
329 null;
330
331 exception
332 when others then
333 wf_core.context('WF_XML','EnqueueLOBMessage',p_queue,
334 to_char(p_priority),
335 p_correlation);
336 raise;
337 end EnqueueLOBMessage;
338
339
340 -- EnqueueMessage
341 -- IN
342 -- Queue Name
343 -- Priority of the message
344 -- Correlation for the message - the NID of the notification
345 -- for this implementation.
346 -- Message - XML encoded.
347 procedure EnqueueMessage(p_queue in varchar2,
348 p_priority number,
349 p_correlation in varchar2,
350 p_message in VARCHAR2) is
351
352 l_enqueue_options dbms_aq.enqueue_options_t;
353 l_message_properties dbms_aq.message_properties_t;
354 l_correlation varchar2(255) := NULL;
355 l_msgid raw(16);
356
357 -- l_msgLob CLOB;
358 l_msgLobIdx pls_integer;
359 l_queueu VARCHAR2(200);
360 l_queueName VARCHAR2(30);
361 l_queueTable VARCHAR2(200);
362 l_schemaName VARCHAR2(320);
363 l_msgLength NUMBER;
364 l_sqlbuf VARCHAR2(2000);
365
366 l_amount binary_integer;
367 l_pos pls_integer;
368
369 l_dequeue_options dbms_aq.dequeue_options_t;
370 begin
371
372 /** wf_message_payload_t is obsolete in 2.6.4 onwards **/
373 null;
374
375 exception
376 when others then
377 -- just in case, check and free it any way.
378 wf_temp_lob.ReleaseLob(g_LOBTable, l_msgLobIdx);
379 wf_core.context('WF_XML','EnqueueMessage',p_queue, to_char(p_priority),
380 p_correlation);
381 raise;
382 end EnqueueMessage;
383
384
385 -- NewLOBTag - Create a new TAG node and insert it into the
386 -- Document Tree
387 -- IN
388 -- document as a CLOB
389 -- Position to take the new Tag Node
390 -- New Tag to be created
391 -- Data to be added between the start and end TAGs
392 -- Attribute list to be included in the opening TAG
393 -- OUT
394 -- The document containing the new TAG.
395 function NewLOBTag (p_doc in out NOCOPY CLOB,
396 p_pos in integer,
397 p_tag in varchar2,
398 p_data in varchar2,
399 p_attribute_list IN OUT NOCOPY wf_xml_attr_table_type)
400 return integer
401 is
402
403 -- l_temp CLOB;
404 l_tempStr varchar2(32000);
405 l_tempIdx pls_integer;
406 l_node varchar2(32000);
407 l_start varchar2(32000);
408 l_end varchar2(250);
409 l_pos integer;
410 l_nodesize number;
411
412 l_size number;
413 l_amount number;
414
415 begin
416
417 -- Create an instance of the node
418 -- A Node is deemed to be <TAG>Data</TAG>
419 -- dbms_lob.createTemporary(l_temp, TRUE, dbms_lob.CALL);
420 l_tempIdx := -1;
421
422 l_start := '<' || upper(p_tag);
423
424 -- If there are any attributes to add to the tag, then
425 -- add them now, otherwise, close off the TAG.
426 if p_attribute_list.COUNT = 0 then
427 l_start := l_start || '>';
428 else
429 for i in 1..p_attribute_list.COUNT loop
430 l_start := l_start || ' ' ||
431 p_attribute_list(i).attribute || '="' ||
432 p_attribute_list(i).value || '"';
433 end loop;
434 l_start := l_start || '>';
435 end if;
436
437 -- Create the end TAG.
438 l_end := '</' || upper(p_tag) || '>'||g_newLine;
439
440
441 l_size := dbms_lob.getlength(p_doc);
442
443 -- Create the full node to be inserted.
444 l_node := l_start || p_data || l_end;
445 l_nodesize := length(l_node);
446
447 l_amount := 0;
448 if l_size > 1 and l_size <> p_pos then
449 -- Copy the tail end of the LOB to a holder.
450 l_amount := l_size - p_pos;
451 if l_amount < 32000 then
452 dbms_lob.read(lob_loc => p_doc,
453 amount => l_amount,
454 offset => p_pos + 1,
455 buffer => l_tempStr);
456 else
457 l_tempIdx := wf_temp_lob.GetLob(g_LOBTable);
458 dbms_lob.copy(dest_lob => g_LOBTable(l_tempIdx).temp_lob,
459 src_lob => p_doc,
460 amount => l_amount,
461 dest_offset => 1,
462 src_offset => p_pos +1);
463 end if;
464 end if;
465
466 -- Now insert the new node into the p_pos location
467 dbms_lob.Write(p_doc, l_nodesize, p_pos + 1 , l_node);
468
469 -- Append the saved portion of the LOB
470 -- If l_tempIdx is still -1, then no LOB was used or initialised
471 -- but for the lob, makesure that there is something in it to be
472 -- used (l_amount > 0).
473 if l_tempIdx = -1 and l_amount > 0 then
474 dbms_lob.write(lob_loc => p_doc,
475 amount => l_amount,
476 offset => p_pos + l_nodesize + 1,
477 buffer => l_tempStr);
478 elsif l_amount > 0 then
479 dbms_lob.copy(dest_lob => p_doc,
480 src_lob => g_LOBTable(l_tempIdx).temp_lob,
481 amount => l_amount ,
482 dest_offset => p_pos + l_nodesize + 1);
483 wf_temp_lob.ReleaseLob(g_LOBTable, l_tempIdx);
484 end if;
485
486 l_pos := (p_pos + l_nodesize) - length(l_end);
487 -- Free up the use of the temporary LOB
488 -- dbms_lob.FreeTemporary(l_temp);
489
490 if (wf_log_pkg.level_statement >= fnd_log.g_current_runtime_level) then
491 wf_log_pkg.string(WF_LOG_PKG.level_statement,
492 'wf.plsql.WF_XML.newLOBTag',
493 'TAG: '||l_start||' POS: '||to_char(l_pos));
494 end if;
495
496 return l_pos;
497
498 exception
499 when others then
500 wf_temp_lob.ReleaseLob(g_LOBTable, l_tempIdx);
501 wf_core.context('WF_XML','NewLOBTag', p_tag);
502 raise;
503 end NewLOBTag;
504
505 -- NewLOBTag - Create a new TAG node and insert it into the
506 -- Document Tree
507 -- IN
508 -- document as a CLOB
509 -- Position to take the new Tag Node
510 -- New Tag to be created
511 -- Data to be added between the start and end TAGs
512 -- Attribute list to be included in the opening TAG
513 -- OUT
514 -- The document containing the new TAG.
515 function NewLOBTag (p_doc in out NOCOPY CLOB,
516 p_pos in integer,
517 p_tag in varchar2,
518 p_data in CLOB,
519 p_attribute_list IN OUT NOCOPY wf_xml_attr_table_type)
520 return integer
521 is
522
523 l_tempIdx pls_integer;
524 l_nodeIdx pls_integer;
525 l_tempStr varchar2(32000);
526 l_start varchar2(250);
527 l_end varchar2(250);
528 l_pos integer;
529 l_nodesize number;
530
531 l_size number;
532 l_dataSize number;
533 l_amount number;
534
535 begin
536
537 -- Create an instance of the node
538 -- A Node is deemed to be <TAG>Data</TAG>
539 l_tempIdx := -1;
540 l_nodeIdx := wf_temp_lob.getLob(g_LOBTable);
541
542 l_start := '<' || upper(p_tag);
543
544 -- If there are any attributes to add to the tag, then
545 -- add them now, otherwise, close off the TAG.
546 if p_attribute_list.COUNT = 0 then
547 l_start := l_start || '>';
548 else
549 for i in 1..p_attribute_list.COUNT loop
550 l_start := l_start || ' ' ||
551 p_attribute_list(i).attribute || '="' ||
552 p_attribute_list(i).value || '"';
553 end loop;
554 l_start := l_start || '>';
555 end if;
556
557 -- Create the end TAG.
558 l_end := '</' || upper(p_tag) || '>'||g_newLine;
559
560 l_size := dbms_lob.getlength(p_doc);
561 l_dataSize := dbms_lob.getlength(p_data);
562
563 -- Create the full node to be inserted.
564 dbms_lob.writeAppend(g_LOBTable(l_nodeIdx).temp_lob, length(l_start),
565 l_start);
566 l_nodesize := length(l_start); -- dbms_lob.getLength(g_LOBTable(l_nodeIdx).temp_lob);
567 dbms_lob.copy(dest_lob => g_LOBTable(l_nodeIdx).temp_lob,
568 src_lob => p_data,
569 amount => l_dataSize,
570 dest_offset => l_nodesize+1,
571 src_offset => 1);
572 dbms_lob.writeAppend(g_LOBTable(l_nodeIdx).temp_lob, length(l_end),
573 l_end);
574 l_nodesize := dbms_lob.getLength(g_LOBTable(l_nodeIdx).temp_lob);
575
576 l_amount := 0;
577 if l_size > 1 and l_size <> p_pos then
578 l_amount := l_size - p_pos;
579 -- Copy the tail end of the LOB to a holder.
580 if l_amount < 32000 then
581 dbms_lob.read(lob_loc => p_doc,
582 amount => l_amount,
583 offset => p_pos + 1,
584 buffer => l_tempStr);
585 else
586 l_tempIdx := wf_temp_lob.GetLob(g_LOBTable);
587 dbms_lob.copy(dest_lob => g_LOBTable(l_tempIdx).temp_lob,
588 src_lob => p_doc,
589 amount => l_amount,
590 dest_offset => 1,
591 src_offset => p_pos +1);
592 end if;
593 end if;
594
595 -- Now insert the new node into the p_pos location
596 dbms_lob.copy(dest_lob => p_doc,
597 src_lob => g_LOBTable(l_nodeIdx).temp_lob,
598 amount => l_nodesize,
599 dest_offset => p_pos + 1);
600
601 -- Append the saved portion of the LOB
602 if l_tempIdx = -1 and l_amount > 0 then
603 dbms_lob.write(lob_loc => p_doc,
604 amount => l_amount,
605 offset => p_pos + l_nodesize + 1,
606 buffer => l_tempStr);
607 elsif l_tempIdx > 0 then
608 if l_amount > 0 then
609 dbms_lob.copy(dest_lob => p_doc,
610 src_lob => g_LOBTable(l_tempIdx).temp_lob,
611 amount => l_amount,
612 dest_offset => p_pos + l_nodesize + 1);
613 end if;
614 -- Free up the use of the temporary LOBs
615 wf_temp_lob.releaseLOB(g_LOBTable, l_tempIdx);
616 end if;
617
618
619 l_pos := (p_pos + l_nodesize) - length(l_end);
620
621 -- Free up the use of the temporary LOBs
622 wf_temp_lob.releaseLOB(g_LOBTable, l_nodeIdx);
623
624 if (wf_log_pkg.level_statement >= fnd_log.g_current_runtime_level) then
625 wf_log_pkg.string(WF_LOG_PKG.level_statement,
626 'wf.plsql.WF_XML.newLOBTag',
627 'TAG: '||l_start||' POS: '||to_char(l_pos));
628 end if;
629
630 return l_pos;
631
632 exception
633 when others then
634 wf_temp_lob.releaseLOB(g_LOBTable, l_tempIdx);
635 wf_temp_lob.releaseLOB(g_LOBTable, l_nodeIdx);
636 wf_core.context('WF_XML','NewLOBTag', p_tag);
637 raise;
638 end NewLOBTag;
639
640 -- NewTag - Create a new TAG node and insert it into the
641 -- Document Tree
642 -- IN
643 -- document as a CLOB
644 -- Position to take the new Tag Node
645 -- New Tag to be created
646 -- Data to be added between the start and end TAGs
647 -- Attribute list to be included in the opening TAG
648 -- OUT
649 -- The document containing the new TAG.
650 function NewTag (p_doc in out NOCOPY VARCHAR2,
651 p_pos in integer ,
652 p_tag in varchar2,
653 p_data in varchar2,
654 p_attribute_list IN OUT NOCOPY wf_xml_attr_table_type)
655 return integer
656 is
657
658 l_temp VARCHAR2(32000);
659 l_node varchar2(32000);
660 l_start varchar2(250);
661 l_end varchar2(250);
662 l_pos integer;
663 l_nodesize number;
664
665 l_size number;
666 l_amount number;
667
668 begin
669
670 -- Create an instance of the node
671 -- A Node is deemed to be <TAG>Data</TAG>
672
673 l_start := '<' || upper(p_tag);
674
675 -- If there are any attributes to add to the tag, then
676 -- add them now, otherwise, close off the TAG.
677 if p_attribute_list.COUNT = 0 then
678 l_start := l_start || '>';
679 else
680 for i in 1..p_attribute_list.COUNT loop
681 l_start := l_start || ' ' ||
682 p_attribute_list(i).attribute || '="' ||
683 p_attribute_list(i).value || '"';
684 end loop;
685 l_start := l_start || '>';
686 end if;
687
688 -- Create the end TAG.
689 l_end := '</' || upper(p_tag) || '>'||g_newLine;
690
691
692 l_size := length(p_doc);
693
694 -- Create the full node to be inserted.
695 l_node := l_start || p_data || l_end;
696 l_nodesize := length(l_node);
697
698 l_amount := 0;
699 if l_size > 1 and l_size <> p_pos then
700 -- Copy the tail end of the LOB to a holder.
701 l_amount := l_size - p_pos;
702 l_temp := substr(p_doc, p_pos +1, l_amount);
703 end if;
704
705 -- Now insert the new node into the p_pos location
706 p_doc := substr(p_doc, 1, p_pos)||l_node;
707
708 if Length(l_temp) > 1 then
709 -- Append the saved portion of the LOB
710 p_doc := p_doc||l_temp;
711 end if;
712
713 l_pos := (p_pos + l_nodesize) - length(l_end);
714
715 if (wf_log_pkg.level_statement >= fnd_log.g_current_runtime_level) then
716 wf_log_pkg.string(WF_LOG_PKG.level_statement,
717 'wf.plsql.WF_XML.newTag',
718 'TAG: '||l_start||' POS: '||to_char(l_pos));
719 end if;
720 return l_pos;
721
722 exception
723 when others then
724 wf_core.context('WF_XML','NewTag', p_tag);
725 raise;
726 end NewTag;
727
728
729
730 -- SkipLOBTag - To move return a pointer past the nominated TAG
731 -- starting from a given position in the document.
732 -- IN
733 -- document
734 -- Position to take the new Tag Node
735 -- New Tag to be created
736 -- Data to be added
737 -- RETURN
738 -- New position past the </TAG>.
739 function SkipLOBTag (p_doc in out NOCOPY CLOB,
740 p_tag in varchar2,
741 p_offset in out NOCOPY integer,
742 p_occurance in out NOCOPY integer) return integer is
743
744 l_pos integer;
745 l_tag varchar2(250);
746
747 begin
748
749 l_tag := '</'||upper(p_tag)||'>';
750 l_pos := dbms_lob.instr(p_doc, l_tag, p_offset, p_occurance);
751
752 return l_pos + length(l_tag);
753
754 exception
755 when others then
756 wf_core.context('WF_XML','SkipLOBTag', p_tag, to_char(p_offset),
757 to_char(p_occurance));
758 raise;
759 end SkipLOBTag;
760
761 -- SkipTag - To move return a pointer past the nominated TAG
762 -- starting from a given position in the document.
763 -- IN
764 -- document
765 -- Position to take the new Tag Node
766 -- New Tag to be created
767 -- Data to be added
768 -- RETURN
769 -- New position past the </TAG>.
770 function SkipTag (p_doc in out NOCOPY VARCHAR2,
771 p_tag in varchar2,
772 p_offset in out NOCOPY integer,
773 p_occurance in out NOCOPY integer) return integer is
774
775 l_pos integer;
776 l_tag varchar2(250);
777
778 begin
779
780 l_tag := '</'||upper(p_tag)||'>';
781 l_pos := instr(p_doc, l_tag, p_offset, p_occurance);
782
783 return l_pos + length(l_tag);
784
785 exception
786 when others then
787 wf_core.context('WF_XML','SkipTag', p_tag, to_char(p_offset),
788 to_char(p_occurance));
789 raise;
790 end SkipTag;
791
792
793 -- GetTagValue - Obtain the value for a given TAG from within the
794 -- Document Tree
795 -- IN
796 -- document as a CLOB
797 -- TAG to find the value of
798 -- The position to start looking for the TAG from
799 -- OUT
800 -- Value of the TAG. ie the value between the start and end TAGs
801 -- The position in the CLOB after the find
802 -- The list of attributes associated with the TAG (Not implemented as yet)
803 procedure GetTagValue(p_doc in out NOCOPY CLOB,
804 p_tag in varchar2,
805 p_value out NOCOPY varchar2,
806 p_pos in out NOCOPY integer,
807 p_attrlist in out NOCOPY wf_xml_attr_table_type)
808 as
809
810 l_value varchar2(32000);
811 l_length integer;
812 l_startTag varchar2(255);
813 l_endTag varchar2(255);
814 l_startPos integer;
815 l_endPos integer;
816 l_pos integer;
817 l_occurance integer := 1;
818
819 begin
820
821 -- The idea is to look for the value of a tag from
822 -- a given point (p_pos)
823 l_pos := p_pos;
824 -- Set the opening TAG. Don't use the '>' as there may be
825 -- attributes set on the TAG.
826 l_startTag := '<'||upper(p_tag);
827 l_endTag := '</'||upper(p_tag)||'>';
828
829 l_startPos := dbms_lob.instr(p_doc, l_startTag, l_pos, l_occurance);
830 l_startPos := dbms_lob.instr(p_doc, '>', l_startPos, l_occurance) + 1;
831
832
833 l_endPos := dbms_lob.instr(p_doc, l_endTag, l_startpos, l_occurance) - 1;
834 l_length := l_endPos - l_startPos + 1;
835
836 dbms_lob.read(p_doc, l_length, l_startPos, l_value);
837
838 -- Reposition the position pointer to after the end
839 -- of the current TAG set.
840 p_pos := l_endPos + length(l_endTag) + 1;
841 p_value := l_value;
842 exception
843 when others then
844 wf_core.context('WF_XML','GetTagValue',p_tag, to_char(p_pos));
845 raise;
846 end GetTagValue;
847
848
849 -- AddElementAttribute - Add an Element Attribute Value pair to the attribute
850 -- list.
851 -- IN
852 -- Name of the attribute
853 -- Value for the attribute
854 -- The attribute list to add the name/value pair to.
855 procedure AddElementAttribute(p_attribute_name IN VARCHAR2,
856 p_attribute_value IN VARCHAR2,
857 p_attribute_list IN OUT NOCOPY wf_xml_attr_table_type)
858 is
859 l_index integer;
860 begin
861 l_index := p_attribute_list.COUNT + 1;
862 p_attribute_list(l_index).attribute := p_attribute_name;
863 p_attribute_list(l_index).value := p_attribute_value;
864 exception
865 when others then
866 wf_core.context('WF_XML','AddElementAttribute',p_attribute_name,
867 p_attribute_value);
868 raise;
869 end;
870
871
872 -- GetAttachment - Create an attachment tag for each of the URLs and
873 -- DOCUMENT attributes.
874 -- IN
875 -- Notification ID
876 -- Document handle
877 -- MIME Agent for the attachment
878 -- Position in the document where to place the attachment.
879 -- OUT
880 -- New location of the position
881 function GetAttachment(p_nid in number,
882 p_doc in out NOCOPY CLOB,
883 p_agent in varchar2,
884 p_disposition in varchar2,
885 p_doc_type in varchar2,
886 p_pos in out NOCOPY integer) return integer
887 is
888
889 l_pos integer;
890 l_occurance integer := 1;
891 l_tmpcontent varchar2(32000);
892 -- l_content CLOB;
893 l_contentIdx pls_integer;
894 l_blob BLOB;
895 l_atthname varchar2(255);
896 l_display_type varchar2(256) := p_doc_type;
897 l_content_type varchar2(256); -- as in fnd_lobs
898
899 l_attrlist wf_xml_attr_table_type;
900 l_cbuf varchar2(32000);
901 l_doc_end integer;
902 l_doc_length number;
903 l_start VARCHAR2(10) := '<![CDATA[';
904 l_end VARCHAR2(4) := ']]>';
905 l_isURLAttrs boolean;
906 l_aname varchar2(30);
907
908 l_error_result varchar2 (2000);
909 l_err_name varchar2(30);
910 l_err_message varchar2(2000);
911 l_err_stack varchar2(4000);
912
913 cursor c_attr(p_nid varchar2) is
914 select WMA.TYPE, WMA.DISPLAY_NAME,
915 decode(WMA.TYPE, 'URL', WF_NOTIFICATION.GetUrlText(WNA.TEXT_VALUE,
916 p_nid), WNA.TEXT_VALUE) URL, WNA.NAME
917 from WF_NOTIFICATION_ATTRIBUTES WNA, WF_NOTIFICATIONS WN,
918 WF_MESSAGE_ATTRIBUTES_VL WMA
919 where WNA.NOTIFICATION_ID = p_nid
920 and WN.NOTIFICATION_ID = WNA.NOTIFICATION_ID
921 and WN.MESSAGE_TYPE = WMA.MESSAGE_TYPE
922 and WN.MESSAGE_NAME = WMA.MESSAGE_NAME
923 and (WMA.TYPE = 'URL' or WMA.TYPE = 'DOCUMENT')
924 and WMA.ATTACH = 'Y'
925 and WMA.NAME = WNA.NAME;
926
927 l_extn varchar2(255);
928
929 l_mimeType varchar2(256);
930 l_encoding varchar2(256);
931 l_filename varchar2(320);
932 l_attr_url varchar2(32000);
933
934 begin
935
936 -- dbms_lob.createTemporary(l_content, TRUE, dbms_lob.CALL);
937
938 -- Allocate LOB from WF_TEMP LOB pool.
939 l_contentIdx := wf_temp_lob.getLOB(g_LOBTable);
940 dbms_lob.createTemporary(l_blob, TRUE, dbms_lob.CALL);
941
942 l_pos := p_pos;
943 for l_crec in c_attr(p_nid) loop
944 dbms_lob.trim(g_LOBTable(l_contentIdx).temp_lob, 0);
945 if (wf_log_pkg.level_statement >= fnd_log.g_current_runtime_level) then
946
947 wf_log_pkg.string(WF_LOG_PKG.level_statement,
948 'wf.plsql.WF_XML.GetAttachment',
949 'Document URL {'||l_crec.url||'}');
950 end if;
951
952 if l_crec.type = 'URL' then
953 l_isURLAttrs := true;
954 else
955 /*
956 ** The mechanism to obtain PLSQL and PLSQLCLOB documents
957 ** as attachments.
958 */
959 if upper(substr(l_crec.url,1, 6)) = 'PLSQL:' then
960
961 -- wf_mail.getDocContent(p_nid, l_crec.name, l_display_type,
962 -- l_tmpcontent, l_error_result);
963 -- bug 2879507. call wf_notification.GetAttrDoc2 to get the
964 -- doc content as well as the document type
965
966 begin
967 wf_notification.GetAttrDoc2(p_nid, l_crec.name, l_display_type,
968 l_tmpcontent, l_content_type);
969 exception
970 when others then
971 if (wf_log_pkg.level_error >=
972 fnd_log.g_current_runtime_level) then
973 wf_log_pkg.string(WF_LOG_PKG.level_error,
974 'wf.plsql.WF_XML.GetAttachment',
975 'Error when getting PLSQL Document attachment -> '||sqlerrm);
976 end if;
977 wf_core.context('WF_XML', 'GetAttachment', to_char(p_nid),
978 l_display_type);
979 raise;
980 end;
981
982 l_tmpContent := replace(l_tmpContent, g_fndapi_misschr);
983 -- default to display type if no document type specified
984 if (l_content_type is null) then
985 l_content_type := l_display_type;
986 end if;
987 -- Derrive the name for the attachment.
988 WF_MAIL_UTIL.parseContentType(l_content_type, l_mimeType, l_filename,
989 l_extn, l_encoding);
990
991 if l_filename is null or l_filename = '' then
992 l_filename := l_crec.display_name ||'.'||l_extn;
993 end if;
994
995 -- Bug 8801597
996 -- <<sstomar>> : File name may have '&' character etc., due to it SAX parser at
997 -- (Mailer) java layer will fail if it finds '&' only, so replace it with '&'
998 l_filename := WF_NOTIFICATION.SubstituteSpecialChars(l_filename);
999
1000 -- l_filename := Wf_Core.SubstituteSpecialChars(l_filename);
1001
1002 AddElementAttribute('content-type',l_mimeType, l_attrlist);
1003 l_pos := NewLOBTag(p_doc, l_pos, 'BODYPART', '', l_attrlist);
1004 l_attrlist.DELETE;
1005 AddElementAttribute('content-type',l_mimeType, l_attrlist);
1006 AddElementAttribute('content-disposition',p_disposition,
1007 l_attrlist);
1008 AddElementAttribute('filename', l_filename, l_attrlist);
1009 AddElementAttribute('encoding', l_encoding, l_attrlist);
1010 dbms_lob.trim(g_LOBTable(l_contentIdx).temp_lob,0);
1011 dbms_lob.writeAppend(g_LOBTable(l_contentIdx).temp_lob,
1012 length(l_start), l_start);
1013 dbms_lob.writeAppend(g_LOBTable(l_contentIdx).temp_lob,
1014 length(l_tmpContent),
1015 l_tmpContent);
1016 dbms_lob.writeAppend(g_LOBTable(l_contentIdx).temp_lob,
1017 length(l_end), l_end);
1018
1019 l_pos := NewLOBTag(p_doc, l_pos, 'MESSAGE',
1020 g_LOBTable(l_contentIdx).temp_lob,
1021 l_attrlist);
1022 l_pos := SkipLOBTag(p_doc, 'MESSAGE', l_pos, l_occurance);
1023 l_pos := SkipLOBTag(p_doc, 'BODYPART', l_pos, l_occurance);
1024 elsif upper(substr(l_crec.url,1, 10)) = 'PLSQLCLOB:' then
1025 /*
1026 ** For PLSQLCLOB documents.
1027 */
1028 dbms_lob.trim(g_LOBTable(l_contentIdx).temp_lob,0);
1029 l_content_type := '';
1030
1031 --
1032 -- Getting Content
1033 -- First we call the existing APIs to render the
1034 -- content and then we fetch the content into
1035 -- the new structure.
1036 -- Note: LOB allocated within wf_mail.getLOBDocContent API
1037 -- is released here after processing by calling
1038 -- WF_MAIL.CloseLob(l_display_type) api.
1039 begin
1040 wf_mail.getLOBDocContent(p_nid, l_crec.name, l_display_type,
1041 l_content_type, l_error_result);
1042 exception
1043 when others then
1044 if (wf_log_pkg.level_error >=
1045 fnd_log.g_current_runtime_level) then
1046 wf_log_pkg.string(WF_LOG_PKG.level_error,
1047 'wf.plsql.WF_XML.GetAttachment',
1048 'Error when getting PLSQL CLOB Document attachment -> '||sqlerrm);
1049 end if;
1050 wf_core.context('WF_XML', 'GetAttachment', to_char(p_nid),
1051 l_display_type);
1052 raise;
1053 end;
1054
1055 -- default to display type is no document type is specified
1056 if (l_content_type is null) then
1057 l_content_type := l_display_type;
1058 end if;
1059 -- Derrive the name for the attachment.
1060 WF_MAIL_UTIL.parseContentType(l_content_type, l_mimeType, l_filename,
1061 l_extn, l_encoding);
1062 if l_filename is null or l_filename = '' then
1063 l_filename := l_crec.display_name ||'.'||l_extn;
1064 end if;
1065
1066 -- Bug 8801597
1067 -- <<sstomar>> : File name may have '&' character etc., due to it SAX parser at
1068 -- (Mailer) java layer will fail if it finds '&' only, so replace it with '&'
1069 -- l_filename := Wf_Core.SubstituteSpecialChars(l_filename);
1070 l_filename := WF_NOTIFICATION.SubstituteSpecialChars(l_filename);
1071
1072 if lower(l_mimeType) not like 'text/%' and
1073 (l_encoding is null or lower(l_encoding) <> 'base64') then
1074 -- Assume that there has been no encoding on a RAW
1075 -- type lob. Do not include it here. Defer attaching
1076 -- the content.
1077 --
1078 -- Build the attribute list for the attachment
1079 -- including the content-type, file name etc.
1080 --
1081
1082 -- First the BODYPART structure to take the MESSAGE
1083 AddElementAttribute('content-type',l_mimeType, l_attrlist);
1084 l_pos := NewLOBTag(p_doc, l_pos, 'BODYPART', '', l_attrlist);
1085 l_attrlist.DELETE;
1086 l_attr_url := Wf_Notification.GetText(l_crec.URL, p_nid, l_display_type);
1087 AddElementAttribute('src', l_attr_url, l_attrlist);
1088 AddElementAttribute('content-type',l_mimeType, l_attrlist);
1089 AddElementAttribute('content-disposition',p_disposition,
1090 l_attrlist);
1091 AddElementAttribute('filename', l_filename, l_attrlist);
1092
1093 l_pos := NewLOBTag(p_doc, l_pos, 'MESSAGE', '',
1094 l_attrlist);
1095 l_pos := SkipLOBTag(p_doc, 'MESSAGE', l_pos, l_occurance);
1096 l_pos := SkipLOBTag(p_doc, 'BODYPART', l_pos, l_occurance);
1097
1098 else
1099
1100 -- Fetch the content
1101 WF_MAIL.InitFetchLOB(l_display_type, l_doc_length);
1102 l_doc_end := 0;
1103 dbms_lob.writeAppend(g_LOBTable(l_contentIdx).temp_lob,
1104 length(l_start), l_start);
1105 while l_doc_end = 0 loop
1106 WF_MAIL.FetchLobContent(l_tmpContent, l_display_type,
1107 l_doc_end);
1108 l_tmpContent := replace(l_tmpContent, g_fndapi_misschr);
1109 dbms_lob.writeAppend(g_LOBTable(l_contentIdx).temp_lob,
1110 length(l_tmpContent), l_tmpContent);
1111 end loop;
1112
1113
1114 dbms_lob.writeAppend(g_LOBTable(l_contentIdx).temp_lob,
1115 length(l_end), l_end);
1116 --
1117 -- Build the attribute list for the attachment
1118 -- including the content-type, file name etc.
1119 --
1120
1121 -- First the BODYPART structure to take the MESSAGE
1122 AddElementAttribute('content-type',l_mimeType, l_attrlist);
1123 l_pos := NewLOBTag(p_doc, l_pos, 'BODYPART', '', l_attrlist);
1124 l_attrlist.DELETE;
1125
1126 AddElementAttribute('content-type', l_mimeType, l_attrlist);
1127 AddElementAttribute('content-disposition',p_disposition,
1128 l_attrlist);
1129 AddElementAttribute('filename', l_filename, l_attrlist);
1130 AddElementAttribute('encoding', l_encoding, l_attrlist);
1131
1132 l_pos := NewLOBTag(p_doc, l_pos, 'MESSAGE',
1133 g_LOBTable(l_contentIdx).temp_lob,
1134 l_attrlist);
1135 l_pos := SkipLOBTag(p_doc, 'MESSAGE', l_pos, l_occurance);
1136 l_pos := SkipLOBTag(p_doc, 'BODYPART', l_pos, l_occurance);
1137 end if;
1138
1139 -- Release temp LOB allocated within wf_mail.getLOBDocContent
1140 -- i.e. wf_mail.g_html_messageIdx or wf_mail.g_text_messageIdx Locators
1141 WF_MAIL.CloseLob(l_display_type);
1142
1143 elsif upper(substr(l_crec.url,1, 10)) = 'PLSQLBLOB:' then
1144 /*
1145 ** For PLSQLBLOB documents.
1146 */
1147 dbms_lob.trim(l_blob,0);
1148
1149 --
1150 -- Getting Content
1151 -- First we call the existing APIs to render the
1152 -- content and then we fetch the content into
1153 -- the new structure.
1154 --
1155 begin
1156 Wf_Notification.GetAttrBLOB(p_nid, l_crec.name,
1157 l_display_type,
1158 l_blob, l_content_type,
1159 l_aname);
1160 exception
1161 when others then
1162 if (wf_log_pkg.level_error >=
1163 fnd_log.g_current_runtime_level) then
1164 wf_log_pkg.string(WF_LOG_PKG.level_error,
1165 'wf.plsql.WF_XML.GetAttachment',
1166 'Error when getting BLOB attachment -> '||sqlerrm);
1167 end if;
1168 wf_core.context('WF_XML', 'GetAttachment', to_char(p_nid),
1169 l_display_type);
1170
1171 raise;
1172 end;
1173
1174 -- default to display type is no document type is specified
1175 if (l_content_type is null) then
1176 l_content_type := l_display_type;
1177 end if;
1178 -- Derrive the name for the attachment.
1179 WF_MAIL_UTIL.parseContentType(l_content_type, l_mimeType, l_filename,
1180 l_extn, l_encoding);
1181
1182 if l_filename is null or l_filename = '' then
1183 l_filename := l_crec.display_name ||'.'||l_extn;
1184 end if;
1185
1186 -- Bug 8801597 ( File name may have '&' character etc. )
1187 -- SAX parser at java layer will fail if it finds '&' only, so replace it with '&'
1188 -- SubstituteSpecialChars API takes care if BLOB API already repalced '&' with '&'
1189 l_filename := WF_NOTIFICATION.SubstituteSpecialChars(l_filename);
1190
1191 -- First the BODYPART structure to take the MESSAGE
1192 AddElementAttribute('content-type',l_mimeType, l_attrlist);
1193 l_pos := NewLOBTag(p_doc, l_pos, 'BODYPART', '', l_attrlist);
1194 l_attrlist.DELETE;
1195
1196 l_attr_url := Wf_Notification.GetText(l_crec.URL, p_nid, l_display_type);
1197
1198 AddElementAttribute('src', l_attr_url, l_attrlist);
1199 AddElementAttribute('content-type',l_mimeType, l_attrlist);
1200 AddElementAttribute('content-disposition',p_disposition,
1201 l_attrlist);
1202 AddElementAttribute('filename', l_filename, l_attrlist);
1203
1204 l_pos := NewLOBTag(p_doc, l_pos, 'MESSAGE', '',
1205 l_attrlist);
1206 l_pos := SkipLOBTag(p_doc, 'MESSAGE', l_pos, l_occurance);
1207 l_pos := SkipLOBTag(p_doc, 'BODYPART', l_pos, l_occurance);
1208
1209 end if;
1210 end if;
1211 l_attrlist.DELETE;
1212 end loop;
1213
1214 -- BUG 3285943 - If this is for a framework notification
1215 -- then we don't need the attached URLs.
1216 -- Bug 5456241 : Pick html / text msg body based on content-type.
1217 if (WF_NOTIFICATION.isFwkRegion(p_nid, l_display_type)='Y' and g_install='EMBEDDED') then
1218 l_isURLAttrs := FALSE;
1219 end if;
1220
1221 if l_isURLAttrs then
1222 dbms_lob.trim(g_LOBTable(l_contentIdx).temp_lob,0);
1223
1224 wf_mail.GetURLAttachment(p_nid, l_tmpContent, l_error_result);
1225 dbms_lob.writeAppend(g_LOBTable(l_contentIdx).temp_lob,
1226 length(l_start), l_start);
1227 dbms_lob.writeAppend(g_LOBTable(l_contentIdx).temp_lob,
1228 length(l_tmpContent), l_tmpContent);
1229 dbms_lob.writeAppend(g_LOBTable(l_contentIdx).temp_lob,
1230 length(l_end), l_end);
1231
1232
1233 if l_error_result is not null or l_error_result <> '' then
1234 wf_core.context('WF_XML', 'GetAttachments', to_char(p_nid),
1235 p_agent, to_char(p_pos));
1236 wf_core.token('SQLERR', l_error_result);
1237 wf_core.raise('WF_URLLIST_ERROR');
1238 end if;
1239
1240 -- No need to handle "&" char in filename here as these names are seeded ones
1241 l_fileName := g_urlListAttachment||'.html';
1242
1243 -- First the BODYPART structure to take the MESSAGE
1244 AddElementAttribute('content-type',l_display_type, l_attrlist);
1245 l_pos := NewLOBTag(p_doc, l_pos, 'BODYPART', '', l_attrlist);
1246 l_attrlist.DELETE;
1247
1248 AddElementAttribute('content-type',g_ntfDocHtml,
1249 l_attrlist);
1250 AddElementAttribute('content-disposition',p_disposition,
1251 l_attrlist);
1252 AddElementAttribute('filename', l_filename, l_attrlist);
1253
1254 l_pos := NewLOBTag(p_doc, l_pos, 'MESSAGE',
1255 g_LOBTable(l_contentIdx).temp_lob, l_attrlist);
1256 l_pos := SkipLOBTag(p_doc, 'MESSAGE', l_pos, l_occurance);
1257 l_pos := SkipLOBTag(p_doc, 'BODYPART', l_pos, l_occurance);
1258
1259 end if;
1260
1261 -- relase TEMP allocated LOB
1262 wf_temp_lob.releaseLob(g_LOBTable, l_contentIdx);
1263
1264 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
1265 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
1266 'wf.plsql.WF_XML.GetAttachment',
1267 'END');
1268 end if;
1269
1270 return l_pos;
1271 exception
1272 when others then
1273 WF_MAIL.CloseLob(l_display_type);
1274 wf_temp_lob.releaseLob(g_LOBTable, l_contentIdx);
1275 wf_core.context('WF_XML', 'GetAttachments', to_char(p_nid), p_agent,
1276 to_char(p_pos));
1277 l_err_message := sqlerrm;
1278 raise;
1279 end GetAttachment;
1280
1281
1282 -- GetAttributes - Create an attribute tag for each of the response
1283 -- required attributes.
1284 -- IN
1285 -- Notification ID
1286 -- Document handle
1287 -- MIME Agent for the attribute
1288 -- Location in the document to insert the new TAG(s)
1289 -- RETURN
1290 -- The new position in the docuemnt.
1291 function GetAttributes(p_nid in number,
1292 p_doc in out NOCOPY CLOB,
1293 p_agent in varchar2,
1294 p_pos in out NOCOPY integer) return integer
1295 is
1296
1297 l_pos integer;
1298 l_attrlist wf_xml_attr_table_type;
1299 l_occurance integer := 1;
1300 l_error_result varchar2 (2000);
1301 l_err_name varchar2(30);
1302 l_err_message varchar2(2000);
1303 l_err_stack varchar2(4000);
1304 l_value varchar2(2000);
1305
1306 cursor c1 is
1307 select WMA.NAME, WMA.DISPLAY_NAME, WMA.DESCRIPTION, WMA.TYPE, WMA.FORMAT,
1308 decode(WMA.TYPE,
1309 'VARCHAR2', decode(WMA.FORMAT,
1310 '', WNA.TEXT_VALUE,
1311 substr(WNA.TEXT_VALUE, 1, to_number(WMA.FORMAT))),
1312 'NUMBER', decode(WMA.FORMAT,
1313 '', to_char(WNA.NUMBER_VALUE),
1314 to_char(WNA.NUMBER_VALUE, WMA.FORMAT)),
1315 'DATE', decode(WMA.FORMAT,
1316 '', to_char(WNA.DATE_VALUE),
1317 to_char(WNA.DATE_VALUE, WMA.FORMAT)),
1318 'LOOKUP', WNA.TEXT_VALUE,
1319 WNA.TEXT_VALUE) VALUE
1320 from WF_NOTIFICATION_ATTRIBUTES WNA,
1321 WF_NOTIFICATIONS WN,
1322 WF_MESSAGE_ATTRIBUTES_VL WMA
1323 where WNA.NOTIFICATION_ID = p_nid
1324 and WN.NOTIFICATION_ID = WNA.NOTIFICATION_ID
1325 and WN.MESSAGE_TYPE = WMA.MESSAGE_TYPE
1326 and WN.MESSAGE_NAME = WMA.MESSAGE_NAME
1327 and WMA.NAME = WNA.NAME
1328 and WMA.SUBTYPE = 'RESPOND'
1329 and WMA.TYPE not in ('FORM', 'URL')
1330 order by WMA.SEQUENCE;
1331
1332 begin
1333
1334 l_pos := p_pos;
1335 for rec in c1 loop
1336 l_attrlist.DELETE;
1337 AddElementAttribute('name',rec.name, l_attrlist);
1338 AddElementAttribute('type',rec.type, l_attrlist);
1339 if rec.format is not NULL then
1340 AddElementAttribute('format',rec.format, l_attrlist);
1341 end if;
1342 l_pos := NewLOBTag(p_doc, l_pos, 'ATTRIBUTE','',l_attrlist);
1343 l_attrlist.DELETE;
1344 l_pos := NewLOBTag(p_doc, l_pos, 'NAME', rec.display_name, l_attrlist);
1345 l_pos := SkipLOBTag(p_doc, 'NAME', l_pos, l_occurance);
1346 l_value := EncodeEntityReference(rec.value);
1347 l_pos := NewLOBTag(p_doc, l_pos, 'VALUE', rec.value, l_attrlist);
1348
1349 l_pos := SkipLOBTag(p_doc, 'ATTRIBUTE', l_pos, l_occurance);
1350
1351 end loop;
1352 return l_pos;
1353 exception
1354 when others then
1355 wf_core.context('WF_XML', 'GetAttributes', to_char(p_nid));
1356 raise;
1357 end GetAttributes;
1358
1359 -- GetXMLMessage - Return a CLOB Document containing an XML encoded version of the
1360 -- notification. No recipients list will be populated. That
1361 -- will be the responsibility of the calling procedure.
1362 --
1363 -- IN
1364 -- notification id
1365 -- Protocol for the message
1366 -- List of recipients to recieve the notification
1367 -- mailer node name
1368 -- Web Agent for the HTML attachments
1369 -- Reply to address for the final notification
1370 -- Language for the notification
1371 -- Territory for the notification
1372 -- OUT
1373 -- Piority for the message
1374 -- A CLOB Containing the XML encoded message.
1375 procedure GetXMLMessage (p_nid in number,
1376 p_protocol in varchar2,
1377 p_recipient_list in WF_DIRECTORY.wf_local_roles_tbl_type,
1378 p_node in varchar2,
1379 p_agent in varchar2,
1380 p_replyto in varchar2,
1381 p_nlang in varchar2,
1382 p_nterr in varchar2,
1383 p_priority out NOCOPY number,
1384 p_message in out NOCOPY CLOB)
1385 is
1386 -- l_doc CLOB;
1387 l_docIdx pls_integer;
1388 l_doctype varchar(100);
1389 l_pos integer;
1390 l_occurance integer := 1;
1391 l_item_type wf_items.item_type%TYPE;
1392 l_item_key wf_items.item_key%TYPE;
1393 l_priority wf_notifications.priority%TYPE;
1394 l_access_key wf_notifications.access_key%TYPE;
1395
1396 l_response integer;
1397
1398 l_attrlist wf_xml_attr_table_type;
1399 l_receiverlist varchar2 (4000);
1400 l_status varchar2 (8);
1401 l_language varchar2 (30);
1402 l_territory varchar2 (30);
1403 l_installed_lang varchar2 (1);
1404 l_str varchar2 (250);
1405 l_subject varchar2 (2000);
1406 l_text_body varchar2 (32000);
1407 l_html_body varchar2 (32000);
1408 l_body_atth varchar2 (32000);
1409 l_error_result varchar2 (2000);
1410 l_err_name varchar2 (30);
1411 l_err_message varchar2 (2000);
1412 l_err_stack varchar2 (4000);
1413
1414 begin
1415
1416 -- Grab the details of the message to be enqueued using the
1417 -- previous interface of WF_MAIL.GetMessage.
1418 begin
1419
1420 select installed_flag
1421 into l_installed_lang
1422 from wf_languages
1423 where nls_language = p_nlang
1424 and nls_territory = p_nterr
1425 and installed_flag = 'Y';
1426
1427 l_language := ''''||p_nlang||'''';
1428 l_territory := ''''||p_nterr||'''';
1429 exception
1430 when others then
1431 l_language := 'AMERICAN';
1432 l_territory := 'AMERICA';
1433 end;
1434 dbms_session.set_nls('NLS_LANGUAGE' , l_language);
1435 dbms_session.set_nls('NLS_TERRITORY' , l_territory);
1436
1437 wf_mail.getmessage(p_nid, p_node, p_agent, p_replyto,
1438 l_subject, l_text_body, l_html_body, l_body_atth,
1439 l_error_result);
1440 -- Check for any problems
1441 if l_error_result is not NULL then
1442 wf_core.token('LANG', l_language);
1443 wf_core.token('TERR', l_territory);
1444 wf_core.token('ERRMSG', l_error_result);
1445 wf_core.raise('WFXMLERR');
1446 end if;
1447
1448
1449 -- Instantiate a handle to the new document.
1450 -- dbms_lob.createTemporary(l_doc, TRUE, dbms_lob.session);
1451 l_docIdx := wf_temp_lob.getLob(g_LOBTable);
1452
1453 -- Initialise the XML Document and then progressively walk
1454 -- through the elements. Populating them as we go.
1455 -- l_pos is crucial as it determines where the next nodes
1456 -- will be placed.
1457 l_str := '<?xml version="1.0"?>';
1458 l_pos := length(l_str);
1459
1460 dbms_lob.write(g_LOBTable(l_docIdx).temp_lob, l_pos, 1, l_str);
1461
1462 l_pos := NewLOBTag(g_LOBTable(l_docIdx).temp_lob, l_pos,
1463 'NOTIFICATION','',l_attrlist);
1464
1465
1466 AddElementAttribute('language',p_nlang, l_attrlist);
1467 AddElementAttribute('territory',p_nterr, l_attrlist);
1468 l_pos := NewLOBTag(g_LOBTable(l_docIdx).temp_lob, l_pos, 'HEADER', '',
1469 l_attrlist);
1470 l_attrlist.DELETE;
1471
1472 -- Attach the NID
1473 l_pos := NewLOBTag(g_LOBTable(l_docIdx).temp_lob, l_pos, 'NID',
1474 to_char(p_nid),l_attrlist);
1475 l_pos := SkipLOBTag(g_LOBTable(l_docIdx).temp_lob, 'NID', l_pos, l_occurance);
1476
1477 begin
1478 select priority, access_key, status
1479 into l_priority, l_access_key, l_status
1480 from wf_notifications_view
1481 where notification_id = p_nid;
1482 exception
1483 when NO_DATA_FOUND then
1484 wf_core.raise('WFNTFGM_FAILED');
1485 end;
1486
1487 l_pos := NewLOBTag(g_LOBTable(l_docIdx).temp_lob, l_pos, 'PRIORITY',
1488 to_char(l_priority), l_attrlist);
1489 l_pos := SkipLOBTag(g_LOBTable(l_docIdx).temp_lob, 'PRIORITY', l_pos,
1490 l_occurance);
1491 l_pos := NewLOBTag(g_LOBTable(l_docIdx).temp_lob, l_pos, 'ACCESSKEY',
1492 l_access_key, l_attrlist);
1493 l_pos := SkipLOBTag(g_LOBTable(l_docIdx).temp_lob, 'ACCESSKEY', l_pos,
1494 l_occurance);
1495
1496 -- Register the receivers as a single string of email addresses
1497 l_receiverlist := NULL;
1498 for i in 1..p_recipient_list.COUNT loop
1499 l_receiverlist := l_receiverlist || p_recipient_list(i).NAME || ',';
1500 end loop;
1501
1502 l_receiverlist := substr(l_receiverlist,1,length(l_receiverlist)-1);
1503 l_pos := NewLOBTag(g_LOBTable(l_docIdx).temp_lob, l_pos, 'RECEIVERLIST',
1504 l_receiverlist, l_attrlist);
1505 l_pos := SkipLOBTag(g_LOBTable(l_docIdx).temp_lob, 'RECEIVERLIST',
1506 l_pos, l_occurance);
1507
1508 l_pos := NewLOBTag(g_LOBTable(l_docIdx).temp_lob, l_pos, 'SENDER', '',
1509 l_attrlist);
1510 l_pos := SkipLOBTag(g_LOBTable(l_docIdx).temp_lob, 'SENDER', l_pos,
1511 l_occurance);
1512
1513 l_pos := NewLOBTag(g_LOBTable(l_docIdx).temp_lob, l_pos, 'STATUS',
1514 l_status, l_attrlist);
1515 l_pos := SkipLOBTag(g_LOBTable(l_docIdx).temp_lob, 'STATUS', l_pos,
1516 l_occurance);
1517
1518 l_pos := NewLOBTag(g_LOBTable(l_docIdx).temp_lob, l_pos, 'SUBJECT',
1519 l_subject, l_attrlist);
1520 l_pos := SkipLOBTag(g_LOBTable(l_docIdx).temp_lob, 'HEADER', l_pos,
1521 l_occurance);
1522
1523 l_text_body := EncodeEntityReference(l_text_body);
1524 l_pos := NewLOBTag(g_LOBTable(l_docIdx).temp_lob, l_pos, 'BODYTEXT',
1525 l_text_body, l_attrlist);
1526 l_pos := SkipLOBTag(g_LOBTable(l_docIdx).temp_lob, 'BODYTEXT', l_pos, l_occurance);
1527
1528 AddElementAttribute('content-type','text/html', l_attrlist);
1529 AddElementAttribute('hmldesc','HTML', l_attrlist);
1530 AddElementAttribute('htmlagent',p_agent, l_attrlist);
1531
1532 l_html_body := EncodeEntityReference(l_html_body);
1533
1534 l_pos := NewLOBTag(g_LOBTable(l_docIdx).temp_lob, l_pos, 'BODYHTML',
1535 l_html_body, l_attrlist);
1536 l_pos := SkipLOBTag(g_LOBTable(l_docIdx).temp_lob, 'BODYHTML', l_pos,
1537 l_occurance);
1538 l_attrlist.DELETE;
1539
1540 l_pos := NewLOBTag(g_LOBTable(l_docIdx).temp_lob, l_pos,
1541 'ATTACHMENTLIST', '', l_attrlist);
1542 -- Next will be to attach all URLs and DOCUMENT attributes
1543 -- as attachments.
1544 l_pos := GetAttachment(p_nid, g_LOBTable(l_docIdx).temp_lob, p_agent,
1545 NULL, l_doctype, l_pos);
1546 l_pos := SkipLOBTag(g_LOBTable(l_docIdx).temp_lob, 'ATTACHMENTLIST',
1547 l_pos, l_occurance);
1548
1549 -- Check to see if the notification is a reponse and attach
1550 -- the response attributes.
1551 l_response := 0;
1552 begin
1553 select 1 into l_response
1554 from dual
1555 where exists (select NULL
1556 from WF_MESSAGE_ATTRIBUTES MA,
1557 WF_NOTIFICATIONS N
1558 where N.NOTIFICATION_ID = p_nid
1559 and MA.MESSAGE_TYPE = N.MESSAGE_TYPE
1560 and MA.MESSAGE_NAME = N.MESSAGE_NAME
1561 and MA.SUBTYPE = 'RESPOND');
1562
1563 l_pos := NewLOBTag(g_LOBTable(l_docIdx).temp_lob, l_pos,
1564 'ATTRIBUTELIST', '', l_attrlist);
1565 l_pos := GetAttributes(p_nid, g_LOBTable(l_docIdx).temp_lob, p_agent,
1566 l_pos);
1567
1568 exception
1569 when NO_DATA_FOUND then
1570 null;
1571 end;
1572
1573 p_priority := l_priority;
1574 dbms_lob.copy(p_message, g_LOBTable(l_docIdx).temp_lob,
1575 dbms_lob.getLength(g_LOBTable(l_docIdx).temp_lob), 1, 1);
1576 -- dbms_lob.freetemporary(l_doc).temp_lob);
1577 wf_temp_lob.releaseLob(g_LOBTable, l_docIdx);
1578
1579 exception
1580 when others then
1581 wf_temp_lob.releaseLob(g_LOBTable, l_docIdx);
1582 wf_core.context('WF_XML', 'GetXMLMessage', to_char(p_nid), p_protocol,
1583 p_node, p_nlang, p_nterr);
1584 raise;
1585 end getXMLMessage;
1586
1587 -- GetShortLOBXMLMessage -
1588 -- Return a CLOB Document containing an XML encoded versi on of the
1589 -- notification. No recipients list will be populated. That
1590 -- will be the responsibility of the calling procedure.
1591 --
1592 -- IN
1593 -- notification id
1594 -- Protocol for the message
1595 -- List of recipients to recieve the notification
1596 -- mailer node name
1597 -- Web Agent for the HTML attachments
1598 -- Reply to address for the final notification
1599 -- Language for the notification
1600 -- Territory for the notification
1601 -- OUT
1602 -- Piority for the message
1603 -- A CLOB Containing the XML encoded message.
1604 procedure GetShortLOBXMLMessage (p_nid in number,
1605 p_priority out NOCOPY number,
1606 p_message in out NOCOPY CLOB)
1607 is
1608 -- l_doc CLOB;
1609 l_docIdx pls_integer;
1610 l_pos integer;
1611 l_occurance integer := 1;
1612 l_priority wf_notifications.priority%TYPE;
1613 l_status wf_notifications.status%TYPE;
1614 l_recipient wf_notifications.recipient_role%TYPE;
1615
1616 l_attrlist wf_xml_attr_table_type;
1617 l_str varchar2 (250);
1618
1619 l_error_result varchar2 (2000);
1620 l_err_name varchar2 (30);
1621 l_err_message varchar2 (2000);
1622 l_err_stack varchar2 (4000);
1623 l_more_info_role varchar2(320);
1624
1625 begin
1626
1627 -- Grab the details of the message to be enqueued using the
1628 -- previous interface of WF_MAIL.GetMessage.
1629
1630 -- Instantiate a handle to the new document.
1631 -- dbms_lob.createTemporary(l_doc, TRUE, dbms_lob.session);
1632 l_docIdx := wf_temp_lob.getLOB(g_LOBTable);
1633
1634 -- Initialise the XML Document and then progressively walk
1635 -- through the elements. Populating them as we go.
1636 -- l_pos is crucial as it determines where the next nodes
1637 -- will be placed.
1638 l_str := '<?xml version="1.0"?>';
1639 l_pos := length(l_str);
1640
1641 dbms_lob.write(g_LOBTable(l_docIdx).temp_lob, l_pos, 1, l_str);
1642
1643 l_pos := NewLOBTag(g_LOBTable(l_docIdx).temp_lob, l_pos,
1644 'NOTIFICATION','',l_attrlist);
1645
1646 l_pos := NewLOBTag(g_LOBTable(l_docIdx).temp_lob, l_pos,
1647 'HEADER', '', l_attrlist);
1648 l_attrlist.DELETE;
1649
1650 -- Attach the NID
1651 l_pos := NewLOBTag(g_LOBTable(l_docIdx).temp_lob, l_pos,
1652 'NID', to_char(p_nid),l_attrlist);
1653 l_pos := SkipLOBTag(g_LOBTable(l_docIdx).temp_lob,
1654 'NID', l_pos, l_occurance);
1655
1656 begin
1657 select recipient_role, priority, status, more_info_role
1658 into l_recipient, l_priority, l_status, l_more_info_role
1659 from wf_notifications
1660 where notification_id = p_nid;
1661 exception
1662 when NO_DATA_FOUND then
1663 wf_core.raise('WFNTFGM_FAILED');
1664 end;
1665
1666 l_pos := NewLOBTag(g_LOBTable(l_docIdx).temp_lob, l_pos,
1667 'PRIORITY', to_char(l_priority), l_attrlist);
1668 l_pos := SkipLOBTag(g_LOBTable(l_docIdx).temp_lob,
1669 'PRIORITY', l_pos, l_occurance);
1670
1671 if (l_more_info_role is not null) then
1672 l_recipient := l_more_info_role;
1673 end if;
1674 l_pos := NewLOBTag(g_LOBTable(l_docIdx).temp_lob, l_pos,
1675 'RECIPIENT', l_recipient, l_attrlist);
1676 l_pos := SkipLOBTag(g_LOBTable(l_docIdx).temp_lob,
1677 'RECIPIENT', l_pos, l_occurance);
1678
1679 l_pos := NewLOBTag(g_LOBTable(l_docIdx).temp_lob, l_pos,
1680 'STATUS', l_status, l_attrlist);
1681 l_pos := SkipLOBTag(g_LOBTable(l_docIdx).temp_lob,
1682 'STATUS', l_pos, l_occurance);
1683
1684 p_priority := l_priority;
1685 dbms_lob.copy(p_message, g_LOBTable(l_docIdx).temp_lob,
1686 dbms_lob.getLength(g_LOBTable(l_docIdx).temp_lob), 1, 1);
1687 -- dbms_lob.freetemporary(g_LOBTable(l_docIdx).temp_lob);
1688 wf_temp_lob.releaseLob(g_LOBTable, l_docIdx);
1689
1690 exception
1691 when others then
1692 wf_temp_lob.releaseLob(g_LOBTable, l_docIdx);
1693 wf_core.context('WF_XML', 'GetShortLOBXMLMessage', to_char(p_nid));
1694 raise;
1695 end getShortLOBXMLMessage;
1696
1697 -- GetShortXMLMessage -
1698 -- Return a VARCHAR Document containing an XML encoded versi on of the
1699 -- notification. No recipients list will be populated. That
1700 -- will be the responsibility of the calling procedure.
1701 --
1702 -- IN
1703 -- notification id
1704 -- Protocol for the message
1705 -- List of recipients to recieve the notification
1706 -- mailer node name
1707 -- Web Agent for the HTML attachments
1708 -- Reply to address for the final notification
1709 -- Language for the notification
1710 -- Territory for the notification
1711 -- OUT
1712 -- Piority for the message
1713 -- A VARCHAR Containing the XML encoded message.
1714 procedure GetShortXMLMessage (p_nid in number,
1715 p_priority out NOCOPY number,
1716 p_message in out NOCOPY VARCHAR2)
1717 is
1718 l_pos integer;
1719 l_occurance integer := 1;
1720 l_priority wf_notifications.priority%TYPE;
1721 l_status wf_notifications.status%TYPE;
1722 l_recipient wf_notifications.recipient_role%TYPE;
1723
1724 l_attrlist wf_xml_attr_table_type;
1725 l_str varchar2 (250);
1726
1727 l_error_result varchar2 (2000);
1728 l_err_name varchar2 (30);
1729 l_err_message varchar2 (2000);
1730 l_err_stack varchar2 (4000);
1731 l_more_info_role varchar2(320);
1732
1733 begin
1734
1735 -- Grab the details of the message to be enqueued using the
1736 -- previous interface of WF_MAIL.GetMessage.
1737
1738 -- Instantiate a handle to the new document.
1739 p_message := '';
1740
1741 -- Initialise the XML Document and then progressively walk
1742 -- through the elements. Populating them as we go.
1743 -- l_pos is crucial as it determines where the next nodes
1744 -- will be placed.
1745 l_str := '<?xml version="1.0"?>';
1746 l_pos := length(l_str);
1747
1748 p_message := p_message||l_str;
1749
1750 l_pos := NewTag(p_message, l_pos, 'NOTIFICATION',NULL,l_attrlist);
1751
1752 l_pos := NewTag(p_message, l_pos, 'HEADER', NULL, l_attrlist);
1753 l_attrlist.DELETE;
1754
1755 -- Attach the NID
1756 l_pos := NewTag(p_message, l_pos, 'NID', to_char(p_nid),l_attrlist);
1757 l_pos := SkipTag(p_message, 'NID', l_pos, l_occurance);
1758
1759 begin
1760 select recipient_role, priority, status, more_info_role
1761 into l_recipient, l_priority, l_status, l_more_info_role
1762 from wf_notifications
1763 where notification_id = p_nid;
1764 exception
1765 when NO_DATA_FOUND then
1766 wf_core.raise('WFNTFGM_FAILED');
1767 end;
1768
1769 l_pos := NewTag(p_message, l_pos, 'PRIORITY', to_char(l_priority),
1770 l_attrlist);
1771 l_pos := SkipTag(p_message, 'PRIORITY', l_pos, l_occurance);
1772
1773 if (l_more_info_role is not null) then
1774 l_recipient := l_more_info_role;
1775 end if;
1776 l_pos := NewTag(p_message, l_pos, 'RECIPIENT', l_recipient, l_attrlist);
1777 l_pos := SkipTag(p_message, 'RECIPIENT', l_pos, l_occurance);
1778
1779 l_pos := NewTag(p_message, l_pos, 'STATUS', l_status, l_attrlist);
1780 l_pos := SkipTag(p_message, 'STATUS', l_pos, l_occurance);
1781
1782 p_priority := l_priority;
1783
1784 exception
1785 when others then
1786 wf_core.context('WF_XML', 'GetShortXMLMessage', to_char(p_nid));
1787 raise;
1788 end getShortXMLMessage;
1789
1790
1791 -- EnqueueFullNotification -
1792 -- To push a notification to the outbound notification queue.
1793 -- IN
1794 -- Notification ID
1795 procedure EnqueueFullNotification(p_nid in number) is
1796
1797 l_queue_name varchar2(255);
1798
1799 l_node varchar2(30);
1800 l_agent varchar(255) := g_webAgent;
1801 l_replyto varchar2(320);
1802
1803 l_nlang wf_languages.nls_language%TYPE;
1804 l_nterr wf_languages.nls_territory%TYPE;
1805 l_priority number;
1806 -- l_message CLOB;
1807 l_messageIdx pls_integer;
1808
1809 l_recipient_role varchar2(320);
1810 l_ntf_pref varchar2(30);
1811 l_language varchar2(30);
1812 l_recipient_list WF_DIRECTORY.wf_local_roles_tbl_type;
1813 l_recipient_lang WF_DIRECTORY.wf_local_roles_tbl_type;
1814 l_wf_schema varchar2(320) := g_wfSchema;
1815
1816 l_err_name varchar2(30);
1817 l_err_message varchar2(2000);
1818 l_err_stack varchar2(4000);
1819
1820 i binary_integer := 0;
1821 j binary_integer := 0;
1822
1823 begin
1824
1825 -- Obtain the name of the recipient role, but only if a
1826 -- notification is needed to go out. ie the mail status
1827 -- indicates that a notification should be sent.
1828 begin
1829 select recipient_role
1830 into l_recipient_role
1831 from wf_notifications
1832 where notification_id = p_nid
1833 and ((MAIL_STATUS = 'MAIL' and STATUS <> 'CLOSED')
1834 or (MAIL_STATUS = 'INVALID'));
1835 exception
1836 when NO_DATA_FOUND then
1837 l_recipient_role := NULL;
1838 when others then
1839 raise;
1840 end;
1841 if l_recipient_role is not null then
1842 -- Determine the total list of individual recipients
1843 -- ordered by Protocol and then Language.
1844 l_recipient_list.DELETE;
1845 GetRecipients(l_recipient_role, l_recipient_list);
1846
1847 end if;
1848
1849 if l_recipient_list.COUNT > 0 then
1850 -- A valid role has been found for a notification
1851 -- that is required to go out.
1852 -- Prepare a LOB to contain the payload message.
1853 -- dbms_lob.createTemporary(l_message, TRUE, dbms_lob.SESSION);
1854 l_messageIdx := wf_temp_lob.getLob(g_LOBTable);
1855
1856 wf_queue.set_queue_names;
1857 wf_queue.get_hash_queue_name (p_protocol => 'SMTP',
1858 p_inbound_outbound => 'OUTBOUND',
1859 p_queue_name => l_queue_name);
1860 l_language := l_recipient_list(1).language;
1861 l_ntf_pref := l_recipient_list(1).notification_preference;
1862 l_recipient_lang.DELETE;
1863 j := 1;
1864 i := 1;
1865
1866
1867 -- Walk through the recipient list. This will be sorted by Notification
1868 -- preference and language. We group the recipients this way to help
1869 -- minimise the number of Queue messages to the number of recipients.
1870 loop
1871 exit when i > l_recipient_list.COUNT;
1872 if l_ntf_pref <> l_recipient_list(i).notification_preference then
1873 wf_queue.get_hash_queue_name (p_protocol => 'SMTP',
1874 p_inbound_outbound => 'OUTBOUND',
1875 p_queue_name => l_queue_name);
1876
1877 end if;
1878 loop
1879 exit when (i > l_recipient_list.COUNT)
1880 or (l_ntf_pref <> l_recipient_list(i).notification_preference);
1881 j := 1;
1882 loop
1883 exit when (i > l_recipient_list.COUNT)
1884 or (l_ntf_pref <> l_recipient_list(i).notification_preference)
1885 or (l_language <> l_recipient_list(i).language);
1886
1887 l_recipient_lang(j) := l_recipient_list(i);
1888 i := i + 1;
1889 j := j + 1;
1890 end loop;
1891 -- Get an encoded payload.
1892 getXMLMessage(p_nid, l_ntf_pref,
1893 l_recipient_lang, l_node, l_agent,
1894 l_replyto,
1895 l_recipient_lang(1).language,
1896 l_recipient_lang(1).territory, l_priority, g_LOBTable(l_messageIdx).temp_lob);
1897
1898 -- Push the message to the queue.
1899 enqueueLOBMessage(p_queue => l_queue_name,
1900 p_priority => l_priority,
1901 p_correlation => wf_queue.account_name ||':'||
1902 to_char(p_nid),
1903 p_message => g_LOBTable(l_messageIdx).temp_lob);
1904
1905 j := 1;
1906 l_recipient_lang.DELETE;
1907 if i <= l_recipient_list.COUNT then
1908 l_ntf_pref := l_recipient_list(i).notification_preference;
1909 end if;
1910 end loop;
1911 end loop;
1912 -- dbms_lob.freetemporary(l_message);
1913 wf_temp_lob.releaseLob(g_LOBTable, l_messageIdx);
1914 end if;
1915
1916 exception
1917 when others then
1918 wf_temp_lob.releaseLob(g_LOBTable, l_messageIdx);
1919 wf_core.context('WF_XML', 'EnqueueFullNotification', to_char(p_nid));
1920 raise;
1921 end EnqueueFullNotification;
1922
1923
1924 -- EnqueueLOBNotification - To push a notification ID to the outbound
1925 -- notification queue.
1926 -- IN
1927 -- Notification ID
1928 procedure EnqueueLOBNotification(p_nid in number) is
1929
1930 l_queue_name varchar2(255);
1931 l_priority number;
1932
1933 l_recipient_role varchar2(320);
1934 -- l_message CLOB;
1935 l_messageIdx pls_integer;
1936
1937 l_err_name varchar2(30);
1938 l_err_message varchar2(2000);
1939 l_err_stack varchar2(4000);
1940
1941 begin
1942
1943 -- Obtain the name of the recipient role, but only if a
1944 -- notification is needed to go out. ie the mail status
1945 -- indicates that a notification should be sent.
1946 begin
1947 select recipient_role
1948 into l_recipient_role
1949 from wf_notifications
1950 where notification_id = p_nid
1951 and MAIL_STATUS in ('MAIL', 'INVALID');
1952 exception
1953 when NO_DATA_FOUND then
1954 l_recipient_role := NULL;
1955 when others then
1956 raise;
1957 end;
1958 if l_recipient_role is not null then
1959 -- A valid role has been found for a notification
1960 -- that is required to go out.
1961
1962 -- dbms_lob.createTemporary(l_message, TRUE, dbms_lob.CALL);
1963 l_messageIdx := wf_temp_lob.getLob(g_LOBTable);
1964 -- Get an encoded payload.
1965 getShortLOBXMLMessage(p_nid, l_priority,
1966 g_LOBTable(l_messageIdx).temp_lob);
1967
1968 wf_queue.set_queue_names;
1969 wf_queue.get_hash_queue_name (p_protocol => 'SMTP',
1970 p_inbound_outbound => 'OUTBOUND',
1971 p_queue_name => l_queue_name);
1972
1973 -- Push the message to the queue.
1974 enqueueLOBMessage(p_queue => l_queue_name,
1975 p_priority => l_priority,
1976 p_correlation => wf_queue.account_name ||':'||
1977 to_char(p_nid),
1978 p_message => g_LOBTable(l_messageIdx).temp_lob);
1979 end if;
1980 wf_temp_lob.releaseLob(g_LOBTable, l_messageIdx);
1981
1982 exception
1983 when others then
1984 wf_temp_lob.releaseLob(g_LOBTable, l_messageIdx);
1985 wf_core.context('WF_XML', 'EnqueueLOBNotification', to_char(p_nid));
1986 raise;
1987 end EnqueueLOBNotification;
1988
1989 -- EnqueueNotification - To push a notification ID to the outbound
1990 -- notification queue.
1991 -- IN
1992 -- Notification ID
1993 procedure EnqueueNotification(p_nid in number) is
1994
1995 l_queue_name varchar2(255);
1996 l_priority number;
1997
1998 l_recipient_role varchar2(320);
1999 l_message VARCHAR2(32000);
2000
2001 l_err_name varchar2(30);
2002 l_err_message varchar2(2000);
2003 l_err_stack varchar2(4000);
2004 l_more_info_role varchar2(320);
2005 begin
2006
2007 -- Obtain the name of the recipient role, but only if a
2008 -- notification is needed to go out. ie the mail status
2009 -- indicates that a notification should be sent.
2010 begin
2011 select recipient_role, more_info_role
2012 into l_recipient_role, l_more_info_role
2013 from wf_notifications
2014 where notification_id = p_nid
2015 and MAIL_STATUS in ('MAIL', 'INVALID')
2016 and STATUS <> 'CLOSED';
2017 exception
2018 when NO_DATA_FOUND then
2019 l_recipient_role := NULL;
2020 l_more_info_role := NULL;
2021 when others then
2022 raise;
2023 end;
2024 if (l_recipient_role is not null or l_more_info_role is not null) then
2025 -- A valid role has been found for a notification
2026 -- that is required to go out.
2027
2028 -- Get an encoded payload.
2029 getShortXMLMessage(p_nid, l_priority, l_message);
2030
2031 wf_queue.set_queue_names;
2032 wf_queue.get_hash_queue_name (p_protocol => 'SMTP',
2033 p_inbound_outbound => 'OUTBOUND',
2034 p_queue_name => l_queue_name);
2035
2036 -- Push the message to the queue.
2037 enqueueMessage(p_queue => l_queue_name,
2038 p_priority => l_priority,
2039 p_correlation => wf_queue.account_name ||':'||
2040 to_char(p_nid),
2041 p_message => l_message);
2042 end if;
2043
2044 exception
2045 when others then
2046 wf_core.context('WF_XML', 'EnqueueNotification', to_char(p_nid));
2047 raise;
2048 end EnqueueNotification;
2049
2050
2051 -- DequeueMessage - Remove a notification from the queue
2052 -- IN
2053 -- Queue name to operate on
2054 -- Correlation for the message - NID in this implementation
2055 -- OUT
2056 -- The message that is obtained from the queue.
2057 -- Timeout to signal whether the queue is empty.
2058 procedure DequeueMessage(p_queue_name in varchar2,
2059 p_correlation in varchar2,
2060 p_message in out NOCOPY CLOB,
2061 p_timeout out NOCOPY boolean)
2062 as
2063
2064 l_dequeue_options dbms_aq.dequeue_options_t;
2065 l_message_properties dbms_aq.message_properties_t;
2066 l_correlation varchar2(255) := NULL;
2067 l_message_handle RAW(16);
2068
2069 begin
2070
2071 /** wf_message_payload_t is obsolete in 2.6.4 onwards **/
2072 null;
2073
2074 exception
2075 when dequeue_timeout then
2076 p_timeout := TRUE;
2077 when others then
2078 Wf_Core.Context('WF_XML', 'DequeueMessage', p_queue_name,
2079 p_correlation);
2080 p_timeout := FALSE;
2081 raise;
2082 end DequeueMessage;
2083
2084
2085
2086 -- GetMessage - Get email message data
2087 -- IN
2088 -- Queue number to operate on
2089 -- OUT
2090 -- Notification ID
2091 -- Comma seperated list of the recipients of the notification
2092 -- Status of the notification - For the purpose of message templating
2093 -- Timout. Returns TRUE where the queue is empty.
2094 -- Error message
2095 procedure GetMessage(
2096 p_queue in number,
2097 p_nid out NOCOPY number,
2098 p_receiverlist out NOCOPY varchar2,
2099 p_status out NOCOPY varchar2,
2100 p_timeout out NOCOPY integer,
2101 p_error_result in out NOCOPY varchar2)
2102 is
2103
2104 l_nid number;
2105 l_queue_name varchar2(255);
2106 l_status varchar2(8);
2107 l_receiverlist varchar2(4000);
2108
2109 l_message CLOB;
2110 l_timeout BOOLEAN;
2111 l_pos integer;
2112 l_attrlist wf_xml_attr_table_type;
2113
2114 l_err_name varchar2(30);
2115 l_err_message varchar2(2000);
2116 l_err_stack varchar2(4000);
2117 no_program_unit exception;
2118 pragma exception_init(no_program_unit, -6508);
2119
2120 begin
2121
2122 l_queue_name := g_wfSchema||'.WF_SMTP_O_'||
2123 to_char(p_queue)||'_QUEUE';
2124
2125 -- Grab the next available message from the queue.
2126 DequeueMessage(p_queue_name => l_queue_name,
2127 p_correlation => NULL,
2128 p_message => l_message,
2129 p_timeout => l_timeout);
2130
2131 -- If the result is from the queue being empty then we want to
2132 -- inform the caller to maybe go and do something else a while.
2133 if NOT l_timeout then
2134 -- We now have a message as a CLOB. we need to parse it
2135 -- to reconstruct the DOM Document.
2136 -- new parser
2137
2138 -- Grab the components of the notification to send
2139 -- back to the caller
2140
2141 l_pos := 1;
2142
2143 GetTagValue(l_message, 'NID', l_nid, l_pos, l_attrlist);
2144 GetTagValue(l_message, 'RECEIVERLIST', l_receiverlist, l_pos,
2145 l_attrlist);
2146 GetTagValue(l_message, 'STATUS', l_status, l_pos, l_attrlist);
2147
2148 end if;
2149
2150 p_nid := to_number(l_nid);
2151 p_receiverlist := l_receiverlist;
2152 p_status := l_status;
2153
2154 if l_timeout then
2155 p_timeout := 1;
2156 else
2157 p_timeout := 0;
2158 end if;
2159
2160 exception
2161 when no_program_unit then
2162 wf_core.context('WF_XML', 'GetMessage', to_char(p_queue));
2163 raise;
2164
2165 when others then
2166 -- First look for a wf_core error.
2167 wf_core.get_error(l_err_name, l_err_message, l_err_stack);
2168
2169 -- If no wf_core error look for a sql error.
2170 if (l_err_name is null) then
2171 l_err_message := sqlerrm;
2172 end if;
2173
2174 p_error_result := l_err_message;
2175 wf_core.context('WF_XML', 'GetMessage', to_char(p_queue));
2176 raise;
2177
2178 end GetMessage;
2179
2180 -- GetShortMessage - Get email message data
2181 -- IN
2182 -- Queue number to operate on
2183 -- OUT
2184 -- Notification ID
2185 -- Comma seperated list of the recipients of the notification
2186 -- Status of the notification - For the purpose of message templating
2187 -- Timout. Returns TRUE where the queue is empty.
2188 -- Error message
2189 procedure GetShortMessage(
2190 p_queue in number,
2191 p_nid out NOCOPY number,
2192 p_recipient out NOCOPY varchar2,
2193 p_status out NOCOPY varchar2,
2194 p_timeout out NOCOPY integer,
2195 p_error_result in out NOCOPY varchar2)
2196 is
2197
2198 l_queue_name varchar2(200);
2199
2200 l_err_name varchar2(30);
2201 l_err_message varchar2(2000);
2202 l_err_stack varchar2(4000);
2203 no_program_unit exception;
2204 pragma exception_init(no_program_unit, -6508);
2205
2206 begin
2207
2208 l_queue_name := g_wfSchema||'.WF_SMTP_O_'||
2209 to_char(p_queue)||'_QUEUE';
2210
2211 GetQueueMessage(l_queue_name, p_nid, p_recipient, p_status,
2212 p_timeout, p_error_result);
2213 exception
2214 when no_program_unit then
2215 wf_core.context('WF_XML', 'GetShortMessage', to_char(p_queue));
2216 raise;
2217
2218 when others then
2219 -- First look for a wf_core error.
2220 wf_core.get_error(l_err_name, l_err_message, l_err_stack);
2221
2222 -- If no wf_core error look for a sql error.
2223 if (l_err_name is null) then
2224 l_err_message := sqlerrm;
2225 end if;
2226
2227 p_error_result := l_err_message;
2228 wf_core.context('WF_XML', 'GetShortMessage', to_char(p_queue));
2229 raise;
2230
2231 end GetShortMessage;
2232
2233
2234 -- GetExceptionMessage - Get email message data
2235 -- IN
2236 -- Queue number to operate on
2237 -- OUT
2238 -- Notification ID
2239 -- Comma seperated list of the recipients of the notification
2240 -- Status of the notification - For the purpose of message templating
2241 -- Timout. Returns TRUE where the queue is empty.
2242 -- Error message
2243 procedure GetExceptionMessage(
2244 p_queue in number,
2245 p_nid out NOCOPY number,
2246 p_recipient out NOCOPY varchar2,
2247 p_status out NOCOPY varchar2,
2248 p_timeout out NOCOPY boolean,
2249 p_error_result in out NOCOPY varchar2)
2250 is
2251 l_timeout integer;
2252 l_queue_name varchar2(200);
2253
2254 l_err_name varchar2(30);
2255 l_err_message varchar2(2000);
2256 l_err_stack varchar2(4000);
2257 no_program_unit exception;
2258 pragma exception_init(no_program_unit, -6508);
2259
2260 begin
2261
2262 l_queue_name := wf_queue.enable_exception_queue(
2263 g_wfSchema||
2264 '.WF_SMTP_O_'||to_char(p_queue)||'_QUEUE');
2265 if l_queue_name is not NULL then
2266 GetQueueMessage(l_queue_name, p_nid, p_recipient, p_status,
2267 l_timeout, p_error_result);
2268 -- GetQueueMessage returns timeout as an integer for the benefit
2269 if l_timeout = 0 then
2270 p_timeout := FALSE;
2271 else
2272 p_timeout := TRUE;
2273 end if;
2274 else
2275 p_timeout := TRUE;
2276 end if;
2277
2278 exception
2279 when no_program_unit then
2280 wf_core.context('WF_XML', 'GetExceptionMessage', to_char(p_queue));
2281 raise;
2282
2283 when others then
2284 -- First look for a wf_core error.
2285 wf_core.get_error(l_err_name, l_err_message, l_err_stack);
2286
2287 -- If no wf_core error look for a sql error.
2288 if (l_err_name is null) then
2289 l_err_message := sqlerrm;
2290 end if;
2291
2292 p_error_result := l_err_message;
2293 wf_core.context('WF_XML', 'GetExceptionMessage', to_char(p_queue));
2294 raise;
2295
2296 end GetExceptionMessage;
2297
2298 -- GetQueueMessage - Get email message data
2299 -- IN
2300 -- Queue name
2301 -- OUT
2302 -- Notification ID
2303 -- Comma seperated list of the recipients of the notification
2304 -- Status of the notification - For the purpose of message templating
2305 -- Timout. Returns TRUE where the queue is empty.
2306 -- Error message
2307 procedure GetQueueMessage(
2308 p_queuename in varchar2,
2309 p_nid out NOCOPY number,
2310 p_recipient out NOCOPY varchar2,
2311 p_status out NOCOPY varchar2,
2312 p_timeout out NOCOPY integer,
2313 p_error_result in out NOCOPY varchar2)
2314 is
2315
2316 l_message CLOB;
2317 l_nid number;
2318 l_queue_name varchar2(255);
2319 l_status varchar2(8) := NULL;
2320 l_currstatus varchar2(8);
2321 l_recipient WF_NOTIFICATIONS.RECIPIENT_ROLE%TYPE := NULL;
2322 l_attrlist wf_xml_attr_table_type;
2323 l_timeout BOOLEAN;
2324 l_pos integer;
2325 l_statusOK boolean;
2326
2327 l_err_name varchar2(30);
2328 l_err_message varchar2(2000);
2329 l_err_stack varchar2(4000);
2330 no_program_unit exception;
2331 pragma exception_init(no_program_unit, -6508);
2332
2333 begin
2334
2335 l_queue_name := p_queuename;
2336
2337 -- Grab the next available message from the queue.
2338 -- The lob located will contain a reference to a persistent
2339 -- LOB so there is not need to pre-create a temporary LOB.
2340 loop
2341 DequeueMessage(p_queue_name => l_queue_name,
2342 p_correlation => NULL,
2343 p_message => l_message,
2344 p_timeout => l_timeout);
2345
2346 -- If the result is from the queue being empty then we want to
2347 -- inform the caller to maybe go and do something else a while.
2348 if NOT l_timeout then
2349 -- We now have a message as a CLOB. we need to parse it
2350 -- to reconstruct the DOM Document.
2351 -- new parser
2352
2353 -- Grab the components of the notification to send
2354 -- back to the caller
2355
2356 l_pos := 1;
2357
2358 GetTagValue(l_message, 'NID', l_nid, l_pos, l_attrlist);
2359 GetTagValue(l_message, 'RECIPIENT', l_recipient, l_pos, l_attrlist);
2360 GetTagValue(l_message, 'STATUS', l_status, l_pos, l_attrlist);
2361
2362 -- Verify that the status of the notification is
2363 -- still OK.
2364 begin
2365 select status into l_currstatus
2366 from wf_notifications
2367 where notification_id = l_nid
2368 and status in ('OPEN','CANCELED', 'CLOSED')
2369 and mail_status in ('MAIL','INVALID','FAILED');
2370 l_statusOK := TRUE;
2371 exception
2372 when no_data_found then
2373 l_statusOK := FALSE;
2374 when others then raise;
2375 end;
2376 end if;
2377 exit when l_timeout or l_statusOK;
2378 end loop;
2379 p_nid := to_number(l_nid);
2380 p_recipient := l_recipient;
2381 p_status := l_status;
2382
2383 if l_timeout then
2384 p_timeout := 1;
2385 else
2386 p_timeout := 0;
2387 end if;
2388
2389 exception
2390 when no_program_unit then
2391 wf_core.context('WF_XML', 'GetQueueMessage', p_queuename);
2392 raise;
2393
2394 when others then
2395 -- First look for a wf_core error.
2396 wf_core.get_error(l_err_name, l_err_message, l_err_stack);
2397
2398 -- If no wf_core error look for a sql error.
2399 if (l_err_name is null) then
2400 l_err_message := sqlerrm;
2401 end if;
2402
2403 p_error_result := l_err_message;
2404 wf_core.context('WF_XML', 'GetQueueMessage', p_queuename);
2405 raise;
2406
2407 end GetQueueMessage;
2408
2409
2410 -- RemoveMessage
2411 -- To remove any messages associated with a particular Notification ID.
2412 -- Note that a notification can contain more than one message. Each of
2413 -- these messages will have a unique message handle and could be
2414 -- enqueued on more than one queue.
2415 -- IN
2416 -- Queue Name to remove the messages from
2417 -- Correlation or the Notification ID of the messages to remove.
2418 -- OUT
2419 -- Timeout. Returns TRUE if there was nothing on the Queue
2420 procedure RemoveMessage(p_queue_name in varchar2,
2421 p_correlation in varchar2,
2422 p_timeout out NOCOPY boolean)
2423 is
2424 l_dequeue_options dbms_aq.dequeue_options_t;
2425 l_message_properties dbms_aq.message_properties_t;
2426 l_correlation varchar2(255) := NULL;
2427 l_message_handle RAW(16);
2428
2429 begin
2430
2431 /** wf_message_payload_t is obsolete in 2.6.4 onwards **/
2432 null;
2433
2434 exception
2435 when others then
2436 Wf_Core.Context('WF_XML', 'RemoveMessage', p_queue_name, p_correlation);
2437 p_timeout := FALSE;
2438 raise;
2439 end RemoveMessage;
2440
2441
2442 -- RemoveNotification
2443 -- To remove all enqueues messages for a given notification.
2444 -- IN
2445 -- Notification ID of the message to locate and remove.
2446 -- NOTE
2447 -- This is a destructive procedure that's sole purpose is to purge the
2448 -- message from the queue. We only call this when we do not care for the
2449 -- content.
2450 procedure RemoveNotification (p_nid in number)
2451 is
2452 l_protocol varchar2(10);
2453 l_iobound varchar2(10);
2454 l_queue_count integer;
2455 l_queue_name varchar2(100);
2456 l_wf_schema varchar2(320);
2457 l_timeout boolean;
2458 begin
2459
2460 select protocol, inbound_outbound, queue_count
2461 into l_protocol, l_iobound, l_queue_count
2462 from wf_queues
2463 where protocol = 'SMTP'
2464 and INBOUND_OUTBOUND = 'OUTBOUND'
2465 and DISABLE_FLAG = 'N';
2466
2467 -- Walk though ALL queue names to hunt for the notifications
2468 wf_queue.set_queue_names;
2469 l_wf_schema := g_wfSchema;
2470 for i in 1..l_queue_count loop
2471 -- Build the queue name from the information we know.
2472 l_queue_name := l_wf_schema||'.WF_'||l_protocol||'_'||
2473 substr(l_iobound,1,1)||'_'||to_char(i)||'_QUEUE';
2474 l_timeout := FALSE;
2475 while not l_timeout loop
2476 -- Kill all traces of the message.
2477 RemoveMessage(l_queue_name, wf_queue.account_name||':'||
2478 to_char(p_nid), l_timeout);
2479 end loop;
2480 end loop;
2481 -- Remove the messages from the default Exception queues also
2482 for i in 1..l_queue_count loop
2483 -- Build the queue name from the information we know.
2484 l_queue_name := wf_queue.enable_exception_queue('WF_'||l_protocol||
2485 '_'||substr(l_iobound,1,1)||'_'||to_char(i)||'_QUEUE');
2486 if l_queue_name is not NULL then
2487 l_timeout := FALSE;
2488 while not l_timeout loop
2489 -- Kill all traces of the message.
2490 RemoveMessage(l_queue_name, wf_queue.account_name||':'||
2491 to_char(p_nid), l_timeout);
2492 end loop;
2493 end if;
2494 end loop;
2495
2496 exception
2497 when others then
2498 wf_core.context('WF_XML','RemoveNotification',to_char(p_nid));
2499 raise;
2500 end RemoveNotification;
2501
2502
2503 -- setFistMessage
2504 -- To set the global variable g_first_message for the deqeuing
2505 -- of the SMTP queue.
2506 -- IN
2507 -- 'Y' to set the flag to TRUE
2508 procedure setFirstMessage(p_first_message IN varchar2)
2509 is
2510 begin
2511 if (upper(substrb(p_first_message, 1, 1)) in ('Y','T')) then
2512 g_first_message := TRUE;
2513 else
2514 g_first_message := FALSE;
2515 end if;
2516 end;
2517
2518 --
2519 -- getBodyPart
2520 --
2521 procedure getBodyPart(p_doc in out NOCOPY CLOB,
2522 p_nid in number,
2523 p_doctype in varchar2)
2524 is
2525 l_message varchar2(32000);
2526 l_doc_length number := 0;
2527 l_doc_end integer := 0;
2528 l_start VARCHAR2(10) := '<![CDATA[';
2529 l_end VARCHAR2(4) := ']]>';
2530 begin
2531
2532 WF_MAIL.InitFetchLOB(p_doctype, l_doc_length);
2533 l_doc_end := 0;
2534 dbms_lob.writeAppend(p_doc, length(l_start), l_start);
2535 while l_doc_end = 0 loop
2536 WF_MAIL.FetchLobContent(l_message, p_doctype, l_doc_end);
2537 l_message := replace(l_message, g_fndapi_misschr);
2538 dbms_lob.writeAppend(p_doc, length(l_message), l_message);
2539 end loop;
2540
2541 -- bug 8515763:
2542 -- Adding PostScript message for Hotmail and Yahoo users here
2543 -- because if we want to add within WF_MAIL.GetMessageLob3 then new global
2544 -- variable or API have to introduce to communicate from one pkg to another pkg.
2545 if( g_WebMail_PostScript_Msg is not null ) then
2546
2547 dbms_lob.writeAppend(p_doc,length(g_newLine), g_newLine);
2548 dbms_lob.writeAppend(p_doc, length(g_WebMail_PostScript_Msg),
2549 g_WebMail_PostScript_Msg);
2550
2551 -- Nullify so that for MAILATTH users, this message should NOT apear in html BODY.
2552 g_WebMail_PostScript_Msg := null;
2553 end if;
2554
2555 dbms_lob.writeAppend(p_doc, length(l_end), l_end);
2556 WF_MAIL.CloseLob(p_doctype);
2557
2558 exception
2559 when others then
2560 wf_core.context('WF_XML','getBodyPart',to_char(p_nid),p_doctype);
2561 raise;
2562 end getBodyPart;
2563
2564
2565 procedure GetNLS(base_lang out NOCOPY varchar2, base_territory OUT NOCOPY VARCHAR2,
2566 base_codeset OUT NOCOPY VARCHAR2)
2567 is
2568 nls_base varchar2(100);
2569 underscore_pos integer;
2570 dot_pos integer;
2571
2572 begin
2573 select userenv('LANGUAGE')
2574 into nls_base
2575 from sys.dual;
2576
2577 underscore_pos := instr(nls_base, '_');
2578 dot_pos := instr(nls_base, '.');
2579
2580 base_lang := substr(nls_base, 1, underscore_pos -1);
2581 base_territory := substr(nls_base, underscore_pos +1,
2582 (dot_pos - underscore_pos)-1);
2583 base_codeset := substr(nls_base, dot_pos + 1);
2584
2585
2586 exception
2587 when others then
2588 wf_core.context('WF_XML','GetNLS');
2589 raise;
2590 end getNLS;
2591
2592
2593 -- SetNLS
2594 -- To set the NLS lang and territory of the current session
2595 -- IN
2596 -- language - a varchar2 of the language code
2597 -- territory - a varchar2 of the territory code.
2598 procedure SetNLS(language in VARCHAR2, territory in VARCHAR2)
2599 is
2600 l_language varchar2(30);
2601 l_territory varchar2(30);
2602 l_installed_flag varchar2(1);
2603 begin
2604 begin
2605 -- If nothing is passed in, force it to AMERICAN_AMERICA
2606 if language is null or language = '' then
2607 l_language := 'AMERICAN';
2608 end if;
2609 if territory is null or territory = '' then
2610 l_territory := 'AMERICA';
2611 end if;
2612
2613 select installed_flag
2614 into l_installed_flag
2615 from wf_languages
2616 where nls_language = language
2617 and installed_flag = 'Y';
2618
2619 l_language := ''''||language||'''';
2620 l_territory := ''''||territory||'''';
2621 exception
2622 when others then
2623 l_language := 'AMERICAN';
2624 l_territory := 'AMERICA';
2625 end;
2626
2627 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
2628 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
2629 'wf.plsql.WF_XML.SetNLS',
2630 'Setting Language {'||l_language||'} {'||
2631 l_territory||'} - Passed in {'||language||
2632 '} {'||territory||'}');
2633 end if;
2634
2635 dbms_session.set_nls('NLS_LANGUAGE' , l_language);
2636 dbms_session.set_nls('NLS_TERRITORY' , l_territory);
2637 exception
2638 when others then
2639 wf_core.context('WF_XML','SetNLS', language, territory);
2640 raise;
2641 end setNLS;
2642
2643 -- Parse the p_doc for the URL attributes and edit
2644 -- their src= reference in preperation for email.
2645 function ParseForInlineImages(msgBody IN OUT NOCOPY CLOB,
2646 nid IN number,
2647 resourceList IN OUT NOCOPY resourceList_t)
2648 return boolean
2649 is
2650
2651 imgStrPos number;
2652 value varchar2(32000);
2653 newValue varchar2(32000);
2654 origValue varchar2(4000);
2655 contentId varchar2(1000);
2656
2657 tmpIdx pls_integer;
2658 nameStart pls_integer;
2659 nameEnd pls_integer;
2660 amount number;
2661 tmpLength number;
2662
2663 imagesFound boolean := false;
2664
2665 renderType varchar2(10);
2666 resourceIdx pls_integer;
2667 fileName varchar2(1000);
2668 contentType varchar2(200);
2669 extPos pls_integer;
2670
2671 begin
2672
2673 resourceIdx := 1;
2674 resourceList.DELETE;
2675
2676 imagesFound := false;
2677
2678 tmpIdx := wf_temp_lob.getLob(g_LOBTable);
2679 for url in g_urls(nid) loop
2680 value := url.text_value;
2681 value := wf_notification.SetFrameworkAgent(value);
2682
2683 -- Check if there is a render type specification on the URL
2684 -- Remove it and set the renderType appropriately.
2685 renderType := substr(value, 1, 4);
2686 if(renderType in ('IMG:','LNK:')) then
2687 value := substr(value, 5);
2688 else
2689 renderType := null;
2690 end if;
2691
2692 if isImageReference(value, renderType) then
2693 origValue := value;
2694 value := '<IMG SRC="'||value||
2695 '" alt="'|| url.display_name||'"></IMG>';
2696 imgStrPos := dbms_lob.instr(msgBody, value, 1, 1);
2697 if imgStrPos > 0 then
2698 dbms_lob.trim(g_LOBTable(tmpIdx).temp_lob, 0);
2699 dbms_lob.copy(g_LOBTable(tmpIdx).temp_lob , msgBody,
2700 imgStrPos-1, 1, 1);
2701
2702 nameStart := instrb(origValue, '/', -1, 1);
2703 if nameStart = 0 then
2704 contentId := trim(value);
2705 fileName := contentId;
2706 contentId := replace(contentId, '.');
2707 else
2708 contentId := trim(substrb(origValue, nameStart+1 ));
2709 fileName := contentId;
2710 contentId := replace(contentId, '.');
2711 end if;
2712 contentId := contentID||'.'||trim(to_char(resourceIdx));
2713
2714 extPos := instrb(fileName, '.', -1, 1);
2715 if (extPos > 0) then
2716 contentType := 'image/'||substr(fileName, extPos+1);
2717 else
2718 contentType := 'image/*';
2719 end if;
2720
2721 newValue := '<IMG SRC="cid:'||contentId||
2722 '" alt="'|| url.display_name||
2723 '"></IMG>';
2724
2725 dbms_lob.writeAppend(g_LOBTable(tmpIdx).temp_lob,
2726 length(newValue), newValue);
2727 amount := dbms_lob.getlength(msgBody)-imgStrPos+length(value);
2728 tmpLength := dbms_lob.getlength(g_LOBTable(tmpIdx).temp_lob);
2729 dbms_lob.Copy(g_LOBTable(tmpIdx).temp_lob, msgBody, amount,
2730 tmpLength+1, imgStrPos+length(value));
2731 dbms_lob.trim(msgBody, 0);
2732 dbms_lob.append(msgBody, g_LOBTable(tmpIdx).temp_lob);
2733
2734 imagesFound := TRUE;
2735 resourceList(resourceIdx).value := origValue;
2736 resourceList(resourceIdx).contentId := contentId;
2737 resourceList(resourceIdx).fileName := fileName;
2738 resourceList(resourceIdx).contentType := contentType;
2739 resourceIdx := resourceIdx + 1;
2740 end if; -- Image TAG is in the messages body
2741 end if; -- The URL is an image reference
2742 end loop;
2743
2744 wf_temp_lob.releaseLob(g_LOBTable, tmpIdx);
2745
2746 return imagesFound;
2747 exception
2748 when others then
2749 -- Release temp LOB if any error , bug 6511028
2750 wf_temp_lob.releaseLob(g_LOBTable, tmpIdx);
2751
2752 wf_core.context('WF_XML','ParseForInlineImages',to_char(nid));
2753 raise;
2754 end ParseForInlineImages;
2755
2756 -- Adds the RESOURCE tags for the inline images.
2757 procedure addInlineImages(doc IN OUT NOCOPY CLOB,
2758 pos IN OUT NOCOPY number,
2759 attrlist IN OUT NOCOPY wf_xml_attr_table_type,
2760 nid IN number,
2761 disposition in varchar2,
2762 resourceList in resourceList_t)
2763 is
2764 extPos pls_integer;
2765 contentType varchar2(1000);
2766 value varchar2(32000);
2767 encodedURL varchar2(32000);
2768 nameStart pls_integer;
2769 contentId varchar2(1000);
2770 fileName varchar2(1000);
2771 occurance number := 1;
2772
2773 renderType varchar2(10);
2774
2775 begin
2776 attrlist.DELETE;
2777
2778 for resourceIdx in 1..resourceList.COUNT loop
2779
2780 encodedURL := wf_mail.urlEncode(resourceList(resourceIdx).value);
2781 AddElementAttribute('content-type', resourceList(resourceIdx).contentType, attrlist);
2782 AddElementAttribute('src', resourceList(resourceIdx).value, attrlist);
2783 AddElementAttribute('content-id', resourceList(resourceIdx).contentId, attrlist);
2784 AddElementAttribute('filename', resourceList(resourceIdx).fileName, attrlist);
2785 AddElementAttribute('content-disposition', disposition, attrlist);
2786
2787 pos := NewLOBTag(doc, pos, 'RESOURCE','',attrlist);
2788 pos := SkipLOBTag(doc, 'RESOURCE', pos, occurance);
2789 attrlist.DELETE;
2790
2791 end loop;
2792
2793 exception
2794 when others then
2795 wf_core.context('WF_XML','addInlineImages', to_char(nid));
2796 raise;
2797 end addInlineImages;
2798
2799
2800 -- Adds a recipient element to the XML in p_doc at position p_pos.
2801 --
2802 -- p_doc The XML document to receive the RECIPIENT element
2803 -- p_role The WF_ROLE name of the recipient
2804 -- p_type The type of recipient - to, cc or bcc
2805 -- p_name The display name for the recipient
2806 -- p_email The email address for the recipient
2807 -- p_pos The position at which the element should be added.
2808
2809 procedure addRecipient(p_doc in out nocopy varchar2,
2810 p_role in varchar2,
2811 p_type in varchar2,
2812 p_name in varchar2,
2813 p_email in varchar2,
2814 p_pos in out nocopy number)
2815 is
2816 display_name varchar2(360);
2817 email varchar2(320);
2818
2819 attrlist wf_xml_attr_table_type;
2820 occurance integer := 1;
2821
2822 begin
2823 AddElementAttribute('name', p_role, attrlist);
2824 AddElementAttribute('type', p_type, attrlist);
2825 p_pos := NewTag(p_doc, p_pos, 'RECIPIENT', '', attrlist);
2826 attrlist.DELETE;
2827 if (p_name is not null or p_name <> '') then
2828 display_name := replace(p_name, g_newLine);
2829 display_name := '<![CDATA['||display_name||']]>';
2830 else
2831 display_name := '';
2832 end if;
2833 p_pos := NewTag(p_doc, p_pos, 'NAME', display_name, attrlist);
2834 p_pos := SkipTag(p_doc, 'NAME', p_pos, occurance);
2835
2836 email := replace(p_email, g_newLine);
2837 email := '<![CDATA['||email||']]>';
2838 p_pos := NewTag(p_doc, p_pos, 'ADDRESS', email, attrlist);
2839 p_pos := SkipTag(p_doc, 'ADDRESS', p_pos, occurance);
2840
2841 p_pos := SkipTag(p_doc, 'RECIPIENT', p_pos, occurance);
2842 end;
2843
2844 -- Adds the recipients identified in p_list to the XML document
2845 -- provided in p_doc. This is a helper procedure for the processing
2846 -- of CC and BCC recipients.
2847 -- p_doc The XML Header document to be modified
2848 -- p_list the semicolon list of recipients
2849 -- p_type The type of recipient to set ("cc" or "bcc").
2850 -- p_pos The current pos in the p_doc to add the recipients. This
2851 -- value will be updated after completion to the current update point.
2852
2853 procedure addCopyRecipients(p_doc in out nocopy varchar2,
2854 p_list in varchar2,
2855 p_type in varchar2,
2856 p_pos in out nocopy integer)
2857 is
2858 copy_recipient_list WF_MAIL_UTIL.parserStack_t;
2859 atPos pls_integer;
2860
2861 display_name varchar2(360);
2862 recipient_role varchar2(320);
2863 email varchar2(320);
2864 pref varchar2(8);
2865 dummy varchar2(1000);
2866 dummy_number number;
2867 orig_system varchar2(30);
2868 orig_system_id number;
2869
2870 cursor members(rname varchar2, rorig varchar2, rorigid number) is
2871 select UR.USER_NAME, UR.USER_ORIG_SYSTEM, UR.USER_ORIG_SYSTEM_ID
2872 from WF_USER_ROLES UR
2873 where UR.ROLE_NAME = rname
2874 and UR.ROLE_ORIG_SYSTEM = rorig
2875 and UR.ROLE_ORIG_SYSTEM_ID = rorigid
2876 and ((UR.USER_NAME <> UR.ROLE_NAME) or
2877 (UR.USER_ORIG_SYSTEM <> UR.ROLE_ORIG_SYSTEM and
2878 UR.USER_ORIG_SYSTEM_ID <> UR.ROLE_ORIG_SYSTEM_ID));
2879
2880 step varchar2(200);
2881
2882 begin
2883 step := 'Initializing the copy list';
2884 copy_recipient_list.DELETE;
2885 copy_recipient_list := WF_MAIL_UTIL.strParser(p_list, ';');
2886 if (copy_recipient_list.COUNT > 0) then
2887
2888 for i in 1..copy_recipient_list.COUNT loop
2889
2890 step := 'Processing {'||copy_recipient_list(i)||'}';
2891 atPos := instrb(copy_recipient_list(i), '@', 1);
2892 if (atPos > 0) then
2893 step := 'Processing email address {'||
2894 copy_recipient_list(i)||'}';
2895 addRecipient(p_doc => p_doc, p_role => '', p_type => p_type,
2896 p_name => '', p_email => copy_recipient_list(i),
2897 p_pos => p_pos);
2898
2899 else
2900
2901 step := 'Processing role {'||copy_recipient_list(i)||'}';
2902
2903 -- Get the qualified email address but the other details
2904 -- are not needed.
2905 WF_DIRECTORY.GetRoleInfoMail(role => copy_recipient_list(i),
2906 display_name => display_name,
2907 email_address => email,
2908 notification_preference => pref,
2909 language => dummy,
2910 territory => dummy,
2911 orig_system => orig_system,
2912 orig_system_id => orig_system_id,
2913 installed_flag => dummy);
2914 if (email is not null and pref <> 'DISABLED') then
2915 step := 'Adding role {'||copy_recipient_list(i)||
2916 '} details to the document';
2917 recipient_role := EncodeEntityReference(copy_recipient_list(i));
2918 addRecipient(p_doc => p_doc,
2919 p_role => recipient_role,
2920 p_type => p_type,
2921 p_name => display_name,
2922 p_email => email,
2923 p_pos => p_pos);
2924
2925 elsif (display_name is not null) then
2926
2927 -- A null email address implies a role with members.
2928
2929 -- Recursion *could* be used here to build a list of
2930 -- single memeber roles and then call the addCopyRecipients
2931 -- to build the XML. Since there is no control then on
2932 -- cyclic references, we will traverse the list only
2933 -- at one level.
2934 for r in members(copy_recipient_list(i), orig_system,
2935 orig_system_id) loop
2936
2937 step := 'Getting member role '||r.user_name||
2938 'details to the document';
2939 WF_DIRECTORY.GetRoleInfoMail(role => r.user_name,
2940 display_name => display_name,
2941 email_address => email,
2942 notification_preference => pref,
2943 language => dummy,
2944 territory => dummy,
2945 orig_system => dummy,
2946 orig_system_id => dummy_number,
2947 installed_flag => dummy);
2948
2949 if (email is not null and pref <> 'DISABLED') then
2950 step := 'Adding member role {'||r.user_name||
2951 '} details to the document';
2952 recipient_role := EncodeEntityReference(r.user_name);
2953 addRecipient(p_doc => p_doc,
2954 p_role => recipient_role,
2955 p_type => p_type,
2956 p_name => display_name,
2957 p_email => email,
2958 p_pos => p_pos);
2959 end if;
2960 end loop; -- Memebers
2961 end if; -- role with members
2962 end if; -- Processing a role
2963 end loop;
2964 end if;
2965 exception
2966 when others then
2967 wf_core.context('WF_XML','addCopyRecipients', p_list, p_type,
2968 step);
2969 end addCopyRecipients;
2970
2971
2972 -- Sets the response template delimiters for HTML messages.
2973 --
2974 -- The delimiter string, rather than containing a set of delimiters
2975 -- to use will contain a code that maps to the delimiters to use.
2976 -- This is to avoid confusion on what this value can be set to and
2977 -- simplifies the parsing of the string.
2978 --
2979 -- Allowable Values:
2980 --
2981 -- DEFAULT or blank - Use the hard coded defaults
2982 -- APOS - '
2983 -- QUOTE - "
2984 -- BRACKET - [ ]
2985 -- IN
2986 -- delimiter_string - The code that represents the HTML delimiters
2987 -- to use.
2988 --
2989 procedure setHtmlDelimiters(delimiter_string IN VARCHAR2)
2990 is
2991 open_html_delimiter VARCHAR2(8);
2992 close_html_delimiter VARCHAR2(8);
2993 begin
2994
2995 if delimiter_string = 'DEFAULT' or delimiter_string is null then
2996 -- No delimiters, then use the hard coded defaults.
2997 open_html_delimiter := null;
2998 close_html_delimiter := null;
2999 elsif delimiter_string = 'APOS' then
3000 open_html_delimiter := '''';
3001 close_html_delimiter := '''';
3002 elsif delimiter_string = 'QUOTE' then
3003 open_html_delimiter := '"';
3004 close_html_delimiter := '"';
3005 elsif delimiter_string = 'BRACKET' then
3006 open_html_delimiter := '[';
3007 close_html_delimiter := ']';
3008 else
3009 -- Unable to recognize the value, so use the hard coded default.
3010 open_html_delimiter := null;
3011 close_html_delimiter := null;
3012 end if;
3013
3014
3015
3016 wf_mail.SetResponseDelimiters(open_text => null,
3017 close_text => null,
3018 open_html => open_html_delimiter,
3019 close_html => close_html_delimiter);
3020
3021 end setHtmlDelimiters;
3022
3023 -- GenerateEmptyDoc (private)
3024 -- This procedure creates an empty XML document that is needed in different
3025 -- scenarios where an empty XML document is required but no e-mail notification
3026 -- is to be sent.
3027 -- IN OUT
3028 -- p_doc: CLOB containing the notification body
3029 -- IN
3030 -- p_nid: the notification Id being processed
3031 -- p_reason: the reason why the document is empty, e-mail is not being sent
3032
3033 procedure GenerateEmptyDoc(p_nid number, p_pos number, p_doc IN OUT NOCOPY CLOB,
3034 p_reason IN VARCHAR2, p_group BOOLEAN) is
3035 l_attrlist wf_xml_attr_table_type;
3036 l_occurance integer;
3037 str varchar2 (2000);
3038 l_pos number;
3039
3040 begin
3041
3042 -- Bug 13716905: added the parameter p_pos also which will be used in the
3043 -- call to NewLOBTag() if the p_group value is false
3044 l_pos := p_pos;
3045
3046 -- 4104735 Empty documents now provide a document type and
3047 -- if a empty document, must provide a reason.
3048 -- <<sstomar>>: Not changing default Lang. territory settings:
3049 if p_group then
3050 str := '<?xml version="1.0" ?>';
3051 l_pos := length(str);
3052 dbms_lob.write(p_doc, l_pos, 1, str);
3053 AddElementAttribute('maxcount','1', l_attrlist);
3054 l_pos := NewLOBTag(p_doc, l_pos, 'NOTIFICATIONGROUP', '', l_attrlist);
3055 l_attrlist.DELETE;
3056 end if;
3057
3058 AddElementAttribute('nid', p_nid, l_attrlist);
3059 AddElementAttribute('language', 'AMERICAN', l_attrlist);
3060 AddElementAttribute('territory', 'AMERICA', l_attrlist);
3061 AddElementAttribute('codeset', 'UTF8', l_attrlist);
3062 -- Though it will not reach to Java layer, but adding.
3063 AddElementAttribute('is-iana-cs', 'N', l_attrlist);
3064 -- Added below default base parameters.
3065 AddElementAttribute('nlsDateformat', wf_core.nls_date_format, l_attrlist);
3066 AddElementAttribute('nlsDateLanguage', wf_core.nls_date_language, l_attrlist);
3067 AddElementAttribute('nlsNumericCharacters', wf_core.nls_numeric_characters, l_attrlist);
3068 AddElementAttribute('nlsSort', wf_core.nls_sort, l_attrlist);
3069
3070 AddElementAttribute('full-document', 'N', l_attrlist);
3071 AddElementAttribute('reason', p_reason, l_attrlist);
3072 l_pos := NewLOBTag(p_doc, l_pos, 'NOTIFICATION', '', l_attrlist);
3073 l_attrlist.DELETE;
3074
3075 if NOT p_group then
3076 l_pos := SkipLOBTag(p_doc, 'NOTIFICATION', l_pos, l_occurance);
3077 end if;
3078
3079 end GenerateEmptyDoc;
3080
3081 --
3082 -- GenerateDoc
3083 -- To generate the XML content for the enqueued notifications.
3084 procedure GenerateDoc (p_doc in out NOCOPY CLOB,
3085 p_pos in out NOCOPY number,
3086 p_recipient_role in varchar2,
3087 p_event_name in varchar2,
3088 p_event_key in varchar2,
3089 p_parameter_list in wf_parameter_list_t)
3090 is
3091 -- message CLOB;
3092 l_sec_policy varchar2(100);
3093 t_name varchar2(100);
3094 messageIdx pls_integer;
3095 nid NUMBER;
3096 msgbody VARCHAR2(32000);
3097 end_of_msgbody BOOLEAN;
3098 doctype VARCHAR2(100);
3099
3100 pos integer;
3101 amt number;
3102 installed VARCHAR2(1);
3103
3104 orig_system VARCHAR2(100);
3105 orig_system_id number;
3106
3107 -- <<sstomar> : nls parameters, l_nlsCurrency can be removed once
3108 -- it being removed from WFDS APIs
3109 l_nlsDateFormat VARCHAR2(120);
3110 l_nlsDateLanguage varchar2(120);
3111 l_nlsCalendar varchar2(120);
3112 l_nlsNumericCharacters varchar2(30);
3113 l_nlsSort varchar2(120);
3114 l_nlsLanguage wf_roles.language%TYPE;
3115 l_nlsTerritory wf_roles.territory%TYPE;
3116 l_nlsCodeset VARCHAR2(30);
3117
3118 --
3119 l_nlsCurrency VARCHAR2(30);
3120
3121 -- whether context has been changes or not.
3122 l_context_changed BOOLEAN := false;
3123
3124 nidStr varchar2(100);
3125 hdrxml varchar2(32000);
3126 hdrxmlPos integer;
3127
3128 access_key VARCHAR2(100);
3129 priority NUMBER;
3130 recipient_role wf_roles.name%TYPE;
3131 status VARCHAR2(100);
3132 subject VARCHAR2(4000);
3133
3134 role wf_roles.name%TYPE;
3135 display_name wf_roles.display_name%TYPE;
3136 email wf_roles.email_address%TYPE;
3137 notification_pref wf_roles.notification_preference%TYPE;
3138
3139 occurance integer := 1;
3140 attrlist wf_xml_attr_table_type;
3141 str varchar2 (250);
3142 nodeName varchar2(100) := '#NODE';
3143 agent varchar2(100) := '#AGENT';
3144 replyto varchar2(100) := '#REPLYTO';
3145 fromName varchar2(100) := '#FROM';
3146 disposition varchar2(100) := '#DISPOSITION';
3147 directResponse varchar2(1);
3148 emailParser varchar2(100);
3149 corrId varchar2(128);
3150 htmlfilename varchar2(100);
3151 urlfilename varchar2(100);
3152 inlineAtt varchar2(10);
3153 sendAccessKey varchar2(10);
3154 stylesheetEnabled varchar2(10);
3155 body_atth varchar2 (32000);
3156 messageType varchar2(8);
3157 messageName varchar2(30);
3158 error_result varchar2 (2000);
3159 err_name varchar2 (30);
3160 err_message varchar2 (2000);
3161 err_stack varchar2 (4000);
3162 moreInfoRole varchar2(320);
3163
3164 frameworkContent boolean;
3165 attachInlineImages varchar2(1);
3166
3167 ntfURL varchar2(2000);
3168 imgFound boolean;
3169
3170 bodyToken varchar2(1);
3171
3172 FromInAttr varchar2(1);
3173 ReplyToInAttr varchar2(1);
3174 EnableStyleInAttr varchar2(1);
3175 dummy varchar2(10);
3176
3177 cc_list varchar2(4000);
3178 bcc_list varchar2(4000);
3179
3180 delimiter_string VARCHAR2(8);
3181
3182 resourceList resourceList_t;
3183
3184 -- For WebBased users, notification pref. will be Overridden.
3185 -- as hotmail and yahoo do not support html response.
3186 l_ntfPref_Overridden BOOLEAN := false;
3187
3188 l_is_iana_cs varchar2(1);
3189
3190 begin
3191
3192 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
3193 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
3194 'wf.plsql.WF_XML.generateDoc', 'BEGIN');
3195 end if;
3196
3197 nid := to_number(p_event_key);
3198
3199 -- retrive base nls parameters
3200 -- Get the Base NLS.
3201 -- 4743123 Only set the value of base NLS params once in a session.
3202 -- <<sstomar>>: already being set in GENERATE function,
3203
3204 -- Obtain notification information
3205 begin -- 3741599 no_data_found should exit gracefully.
3206 select ACCESS_KEY, PRIORITY, STATUS, MESSAGE_TYPE,
3207 MESSAGE_NAME, MORE_INFO_ROLE
3208 into access_key, priority, status, messageType,
3209 messageName, moreInfoRole
3210 from WF_NOTIFICATIONS
3211 where NOTIFICATION_ID = nid;
3212 exception
3213 when no_data_found then
3214 GenerateEmptyDoc(nid, p_pos, p_doc, 'no_data_found', FALSE);
3215 return;
3216 when others then
3217 wf_core.context('WF_XML','GenerateDoc',to_char(nid));
3218 raise;
3219 end;
3220
3221 recipient_role := p_recipient_role;
3222
3223 -- <<sstomar>> :
3224 -- Obtain recipient's NLS information by using new API
3225 WF_DIRECTORY.GetRoleInfoMail2(recipient_role, display_name, email,
3226 notification_pref,
3227 orig_system,
3228 orig_system_id,
3229 installed,
3230 l_nlsLanguage ,
3231 l_nlsTerritory ,
3232 l_nlsDateFormat ,
3233 l_nlsDateLanguage ,
3234 l_nlsCalendar ,
3235 l_nlsNumericCharacters ,
3236 l_nlsSort ,
3237 l_nlsCurrency );
3238
3239
3240 if notification_pref in ('QUERY', 'SUMMARY','SUMHTML', 'DISABLED')
3241 or email is null then
3242 GenerateEmptyDoc(nid, p_pos, p_doc, 'NOTIFICATION_PREFERENCE:'||notification_pref, FALSE);
3243 return;
3244 end if;
3245
3246
3247
3248 corrId := wf_event.getValueForParameter('Q_CORRELATION_ID',
3249 p_parameter_list);
3250 -- Obtain the values for the configurable items
3251 nodename := WF_MAILER_PARAMETER.GetValueForCorr (pNid => nid,
3252 pCorrId => corrId,
3253 pName => 'NODENAME',
3254 pInAttr => dummy);
3255
3256 agent := WF_MAILER_PARAMETER.GetValueForCorr (pNid => nid,
3257 pCorrId => corrId,
3258 pName => 'HTMLAGENT',
3259 pInAttr => dummy);
3260
3261 fromName := WF_MAILER_PARAMETER.GetValueForCorr (pNid => nid,
3262 pCorrId => corrId,
3263 pName => 'FROM',
3264 pInAttr => FromInAttr);
3265
3266 replyto := WF_MAILER_PARAMETER.GetValueForCorr (pNid => nid,
3267 pCorrId => corrId,
3268 pName => 'REPLYTO',
3269 pInAttr => ReplyToInAttr);
3270
3271 inlineAtt := WF_MAILER_PARAMETER.GetValueForCorr (pNid => nid,
3272 pCorrId => corrId,
3273 pName => 'INLINE_ATTACHMENT',
3274 pInAttr => dummy);
3275
3276 sendAccessKey := WF_MAILER_PARAMETER.GetValueForCorr (pNid => nid,
3277 pCorrId => corrId,
3278 pName => 'SEND_ACCESS_KEY',
3279 pInAttr => dummy);
3280
3281 stylesheetEnabled := wf_mailer_parameter.getValueForCorr(pNid => nid,
3282 pCorrId => corrId,
3283 pName => 'ENABLE_STYLESHEET',
3284 pInAttr => EnableStyleInAttr);
3285
3286 -- 5393647 - Parameter to control the text/html response
3287 -- template delimiter
3288 delimiter_string := wf_mailer_parameter.getValueForCorr(pNId => nid,
3289 pCorrId => corrId,
3290 pName => 'HTML_DELIMITER',
3291 pInAttr => dummy);
3292
3293
3294 setHtmlDelimiters(upper(trim(delimiter_string)));
3295
3296 -- 4676402 Support for CC and BCC. These are not configuration parameters
3297 -- so the values can not be retrieved through the wf_mailer_parameter
3298 -- interface.
3299 -- The precedence will be only for normal notifications. Requests
3300 -- for more information will not be subject to the cc and bcc
3301 -- handling.
3302 -- moreInfoRole is null : either FIRST_SEND or wf.notification.answer event.
3303 if (moreInfoRole is null) then
3304 begin
3305 cc_list := upper(Wf_Notification.GetAttrText(nid, '#WFM_CC'));
3306 exception
3307 when others then
3308 if (wf_core.error_name = 'WFNTF_ATTR') then
3309 wf_core.clear();
3310 cc_list := null;
3311 else
3312 raise;
3313 end if;
3314 end;
3315
3316 begin
3317 bcc_list := upper(Wf_Notification.GetAttrText(nid, '#WFM_BCC'));
3318 exception
3319 when others then
3320 if (wf_core.error_name = 'WFNTF_ATTR') then
3321 wf_core.clear();
3322 bcc_list := null;
3323 else
3324 raise;
3325 end if;
3326 end;
3327 end if;
3328 -- Direct Response is not reconfigurable through the message attributes
3329 -- Use the standard API to obtain its value.
3330 -- They are not configurable at the message level because of the
3331 -- confusion caused with multiple mailers and especially those that
3332 -- share the same correlation ID. The value must be consisten in the
3333 -- PL/SQL layer as well as the Java layer.
3334 directResponse := WF_MAILER_PARAMETER.getValueForCorr(pCorrId => corrId,
3335 pName => 'DIRECT_RESPONSE');
3336
3337 attachInlineImages := WF_MAILER_PARAMETER.GetValueForCorr (
3338 pCorrId => corrId,
3339 pName => 'ATTACH_IMAGES');
3340 if inlineAtt = 'Y' then
3341 disposition := 'inline';
3342 else
3343 disposition := 'attachment';
3344 end if;
3345
3346 if sendAccessKey = 'Y' then
3347 wf_mail.Send_Access_Key_On;
3348 else
3349 wf_mail.Send_Access_Key_Off;
3350 end if;
3351
3352 if directResponse = 'Y' then
3353 wf_mail.direct_response_on;
3354 else
3355 wf_mail.direct_response_off;
3356 end if;
3357
3358 -- If we are here, we are going to generate notification xml payload
3359 -- So allocate TEMP LOB now. << bug 6511028 >>
3360 messageIdx := wf_temp_lob.getLob(g_LOBTable);
3361
3362 WF_MAIL.setContext(nid);
3363
3364 -- bug-8515763 : Temporary workaround for HOTMAIL and Yahoo web clients user.
3365 -- list of domains here.
3366
3367 g_WebMail_PostScript_Msg := null;
3368
3369 if (notification_pref = 'MAILHTML' OR notification_pref = 'MAILHTM2') then
3370 if (instr (upper(email), '@HOTMAIL.') > 0 or
3371 instr(upper(email), '@LIVE.') > 0 or
3372 -- yahoo.com, yahoo.co.in
3373 instr(upper(email), '@YAHOO.') > 0 or
3374 instr(upper(email), '@YMAIL.COM') > 0 or
3375 instr(upper(email), '@ROCKETMAIL.COM') > 0
3376
3377 ) then
3378
3379 -- override pref. EXCEPT FYI notification,
3380 if ( WF_Notification.isFYI(nid) = false ) then
3381 -- Overrided ntf pref.
3382 notification_pref := 'MAILATTH';
3383 -- Use this variable to set PostScript message after NLS Context is set.
3384 l_ntfPref_Overridden := true;
3385 end if;
3386 end if; -- end of domain check
3387 end if;
3388 -- bug 8515763 --
3389
3390 -- Set the preferred document type based on the notification preference.
3391 -- This variable doctype will be used when generating ATTACHMENTs as
3392 -- for MAILATTH type will have "Notification Detail.htm" + attachment,if any.
3393 if notification_pref = 'MAILTEXT' then
3394 doctype := g_ntfDocText;
3395 elsif notification_pref in ('MAILHTML','MAILATTH','MAILHTM2') then
3396 doctype := g_ntfDocHtml;
3397 end if;
3398
3399 -- bug 5456241 : Passing doctype parameter
3400 if (WF_NOTIFICATION.isFwkRegion(nid, doctype)='Y' and
3401 g_install ='EMBEDDED') then
3402
3403 frameworkContent := TRUE;
3404 -- 3803327 Text email with framework is currently disabled
3405 -- until the issues with the region facet for text can be
3406 -- fixed.
3407 -- if (notification_pref = 'MAILTEXT') then
3408 -- notification_pref := 'MAILHTM2';
3409 -- elsif (notification_pref = 'MAILATTH') then
3410 -- notification_pref := 'MAILHTML';
3411 -- end if;
3412 -- 3803327 end.
3413 else
3414 frameworkContent := FALSE;
3415 end if;
3416
3417 -- Get the language, territory and codeset for this notification
3418 -- If #WFM_* not defined or not installd, then user's language will be used
3419 -- If user's language also not installed then below API updates OUT params
3420 -- with base language, territory and charset etc..
3421 --
3422 -- TODO : Get_Ntf_Language : optimization required.
3423 WF_MAIL.Get_Ntf_Language(nid, l_nlsLanguage, l_nlsTerritory, l_nlsCodeset, l_is_iana_cs);
3424
3425 -- Set NLS language and territory for this notification
3426 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
3427 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
3428 'wf.plsql.WF_XML.generateDoc',
3429 'Setting User NLS {'|| l_nlsLanguage ||'} {'||l_nlsTerritory||'}'
3430 || l_nlsDateFormat || '} {' || l_nlsDateLanguage || '} {'
3431 || '} {' || l_nlsCalendar || '} {' || l_nlsNumericCharacters
3432 || '} {' || l_nlsSort || '}');
3433 end if;
3434
3435 -- set user's language and territory : charset we can not chage for a session at DB layer.
3436 -- setNLS(l_nlsLanguage, l_nlsTerritory);
3437
3438 -- Bug 11684796: Comparing user NLS parameters with the NLS parameters in WF_NOTIFICATION_UTIL
3439 -- package as WF_NOTIFICATION_UTIL.SetNLSContext() API sets these parameter values only
3440 if( ( WF_NOTIFICATION_UTIL.g_nls_language is null or
3441 nvl(l_nlsLanguage, 'AMERICAN') <> WF_NOTIFICATION_UTIL.g_nls_language) or
3442 ( WF_NOTIFICATION_UTIL.g_nls_territory is null or
3443 nvl( l_nlsTerritory, 'AMERICA') <> WF_NOTIFICATION_UTIL.g_nls_territory) or
3444 ( WF_NOTIFICATION_UTIL.g_nls_date_format is null or
3445 nvl(l_nlsDateFormat , wf_core.nls_date_format) <> WF_NOTIFICATION_UTIL.g_nls_date_format) or
3446 ( WF_NOTIFICATION_UTIL.g_nls_Date_Language is null or
3447 nvl(l_nlsDateLanguage, wf_core.nls_date_language) <> WF_NOTIFICATION_UTIL.g_nls_Date_Language) or
3448 ( WF_NOTIFICATION_UTIL.g_nls_Numeric_Characters is null or
3449 nvl(l_nlsNumericCharacters, wf_core.nls_numeric_characters) <> WF_NOTIFICATION_UTIL.g_nls_Numeric_Characters) or
3450 ( WF_NOTIFICATION_UTIL.g_nls_Sort is null or
3451 nvl(l_nlsSort, wf_core.nls_sort) <> WF_NOTIFICATION_UTIL.g_nls_Sort) ) then
3452
3453 -- nid, l_nlsCalendar, just set here only.
3454 -- at other places pass value as null.
3455 WF_NOTIFICATION_UTIL.SetNLSContext(nid,
3456 l_nlsLanguage ,
3457 l_nlsTerritory ,
3458 l_nlsDateFormat ,
3459 l_nlsDateLanguage ,
3460 l_nlsNumericCharacters ,
3461 l_nlsSort ,
3462 l_nlsCalendar );
3463
3464 l_context_changed := true;
3465 else
3466
3467 -- No need to SET context but set NID, Calendar as these two parameters
3468 -- are being used in WF_NOTIFICATION_UTIL.GetCalendarDate
3469 WF_NOTIFICATION_UTIL.setCurrentNID(nid);
3470 WF_NOTIFICATION_UTIL.setCurrentCalendar(l_nlsCalendar);
3471
3472 END if;
3473
3474 -- bug 8515763
3475 if(l_ntfPref_Overridden) then
3476 -- Assign value, so it can be checked in getBodyPart( ) API and
3477 -- Nullify in same API so subsequeuent call of getBodyPart( ) will not add.
3478 g_WebMail_PostScript_Msg := wf_core.translate('WF_WEBMAIL_POSTSCRIPT_MSG');
3479 end if;
3480
3481
3482 -- Initialise the XML Document and then progressively walk
3483 -- through the elements. Populating them as we go.
3484 -- l_pos is crucial as it determines where the next nodes
3485 -- will be placed.
3486 pos := p_pos;
3487
3488 if frameworkContent = TRUE then
3489 -- Get a modified version of the message. All is rendered
3490 -- except for the &BODY token.
3491 -- NOTE: TEMP LOBs allocated within WF_MAIL.GetLobMessage4 for
3492 -- message body contents should be released here
3493 -- after processsing
3494 -- Bug 10202313: propagating g_status, g_mstatus values to
3495 -- WF_MAIL.GetLOBMessage4() API as these values may update in the meantime
3496 WF_MAIL.GetLobMessage4(nid, nodeName, agent, replyto,
3497 recipient_role, l_nlsLanguage, l_nlsTerritory,
3498 notification_pref, email,
3499 display_name,
3500 'N',
3501 subject, body_atth,
3502 error_result, bodyToken,
3503 g_status, g_mstatus);
3504
3505 else
3506 -- Bug 10202313: propagating g_status, g_mstatus values to
3507 -- WF_MAIL.GetLOBMessage4() API as these values may update in the meantime
3508 WF_MAIL.GetLobMessage4(nid, nodeName, agent, replyto,
3509 recipient_role, l_nlsLanguage, l_nlsTerritory,
3510 notification_pref, email,
3511 display_name,
3512 'Y',
3513 subject, body_atth,
3514 error_result, bodyToken,
3515 g_status, g_mstatus);
3516
3517 end if;
3518
3519 if error_result is not null or error_result <> '' then
3520 wf_core.token('ERROR',error_result);
3521 wf_core.raise('WFMLR_GENERATE_FAILED');
3522 end if;
3523
3524 g_htmlmessage := wf_core.translate('WF_HTML_MESSAGE');
3525 g_urlNotification := wf_core.translate('WF_URL_NOTIFICATION');
3526 g_urlListAttachment := wf_core.translate('WF_URLLIST_ATTACHMENT');
3527
3528 -- Reset base NLS settings
3529 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
3530 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
3531 'wf.plsql.WF_XML.generateDoc',
3532 'Re-Setting Base NLS {'|| g_base_language ||'} {'||g_base_territory||'}'
3533 || g_base_nlsDateFormat || '} {' || g_base_nlsDateLanguage || '} {'
3534 || '} {' || g_base_nlsCalendar || '} {' || g_base_nlsNumericCharacters
3535 || '} {' || g_base_nlsSort || '}');
3536 end if;
3537
3538
3539 -- RESET base setting so that all XML generation
3540 -- processing would be in DEFAULT settings
3541 -- << sstomar>> : RESETTING for base NLS can be done once ..
3542 -- after generating XML Payload but problem may be that
3543 -- Mailer which runs on default NLS may not be able to parse payload??
3544 -- TODO : need to check above case.
3545 if(l_context_changed ) then
3546
3547 -- set nid, calendar once only.
3548 -- <<bug 8220816>> : keep WF_NOTIFICATION_UTIL.g_nid and g_calendar in global variable
3549 -- during life-life cycle of this API.
3550 WF_NOTIFICATION_UTIL.SetNLSContext(
3551 nid,
3552 g_base_language ,
3553 g_base_territory ,
3554 g_base_nlsDateFormat ,
3555 g_base_nlsDateLanguage ,
3556 g_base_nlsNumericCharacters ,
3557 g_base_nlsSort ,
3558 g_base_nlsCalendar );
3559
3560 end if;
3561
3562 htmlfilename := g_htmlmessage||'.html';
3563 urlfilename := g_urlNotification||'.html';
3564
3565 nidStr := 'NID['||to_char(nid)||'/'||access_key||'@'||nodeName||']';
3566 if directResponse = 'Y' then
3567 nidStr := nidStr||'[2]';
3568 end if;
3569
3570 AddElementAttribute('nid', p_event_key, attrlist);
3571 AddElementAttribute('nidstr', nidStr, attrlist);
3572
3573 AddElementAttribute('language', l_nlsLanguage, attrlist);
3574 AddElementAttribute('territory', l_nlsTerritory, attrlist);
3575 AddElementAttribute('codeset', l_nlsCodeset, attrlist);
3576
3577 -- ER: 6449325: Add is_IANA (Y | N)
3578 AddElementAttribute('is-iana-cs', l_is_iana_cs, attrlist);
3579
3580 --
3581 -- <<sstomar>> : NLS changes, bug 7578922
3582 AddElementAttribute('nlsDateformat', l_nlsDateFormat, attrlist);
3583
3584 -- << REMOVE validation later> we can validate if date_language is installed or not.
3585 if(WF_NOTIFICATION_UTIL.isLanguageInstalled(l_nlsDateLanguage)) then
3586 AddElementAttribute('nlsDateLanguage', l_nlsDateLanguage, attrlist);
3587 else
3588 AddElementAttribute('nlsDateLanguage', l_nlsLanguage, attrlist);
3589 end if;
3590
3591 AddElementAttribute('nlsNumericCharacters', l_nlsNumericCharacters, attrlist);
3592 AddElementAttribute('nlsSort', l_nlsSort, attrlist);
3593
3594 AddElementAttribute('priority', to_char(priority), attrlist);
3595 AddElementAttribute('item_type', messageType, attrlist);
3596 AddElementAttribute('message_name', messageName, attrlist);
3597 AddElementAttribute('full-document', 'Y', attrlist);
3598
3599 pos := NewLOBTag(p_doc, pos, 'NOTIFICATION', '', attrlist);
3600 attrlist.DELETE;
3601
3602 hdrxmlPos := 0;
3603 hdrxml := '';
3604
3605 hdrxmlPos := NewTag(hdrxml, hdrxmlPos, 'RECIPIENTLIST', '', attrlist);
3606
3607 -- 4676402 Adding support for CC and BCC. The recipients are
3608 -- straight email addresses in a semi-colon seperated list.
3609 -- Commas should not be used as delimiters as they can appear in the
3610 -- email address.
3611
3612 recipient_role := EncodeEntityReference(recipient_role);
3613 addRecipient(p_doc => hdrxml,
3614 p_role => recipient_role,
3615 p_type => 'to',
3616 p_name => display_name,
3617 p_email => email,
3618 p_pos => hdrxmlPos);
3619
3620 addCopyRecipients(hdrxml, cc_list, 'cc', hdrxmlPos);
3621 addCopyRecipients(hdrxml, bcc_list, 'bcc', hdrxmlPos);
3622
3623 hdrxmlPos := SkipTag(hdrxml, 'RECIPIENTLIST', hdrxmlPos, occurance);
3624
3625 -- 3692786 Only if the FROM and REPLYTO are defined as message
3626 -- attributes will they be put on the XML. Otherwise it will
3627 -- be up to what is defined for the mailer.
3628 if FromInAttr = 'Y' or ReplyToInAttr = 'Y' then
3629 hdrxmlPos := NewTag(hdrxml, hdrxmlPos, 'FROM', '', attrlist);
3630
3631 if FromInAttr = 'Y' then
3632 fromName := replace(fromName, g_newLine);
3633 -- Bug 13786156: Use CDATA for From header value as the XML parser is throwing SAXParseException
3634 -- in java layer when From value is email address of the form "Display Name <name@domain>"
3635 fromName := '<![CDATA['||fromName||']]>';
3636 hdrxmlPos := NewTag(hdrxml, hdrxmlPos, 'NAME', fromName, attrlist);
3637 hdrxmlPos := SkipTag(hdrxml, 'NAME', hdrxmlPos, occurance);
3638 end if;
3639 if ReplyToInAttr = 'Y' then
3640 replyto := replace(replyto, g_newLine);
3641 replyto := '<![CDATA['||replyto||']]>';
3642 hdrxmlPos := NewTag(hdrxml, hdrxmlPos, 'ADDRESS', replyto,
3643 attrlist);
3644 hdrxmlPos := SkipTag(hdrxml, 'ADDRESS', hdrxmlPos, occurance);
3645 end if;
3646 hdrxmlPos := SkipTag(hdrxml, 'FROM', hdrxmlPos, occurance);
3647 end if;
3648
3649 hdrxmlPos := NewTag(hdrxml, hdrxmlPos, 'STATUS', status, attrlist);
3650 hdrxmlPos := SkipTag(hdrxml, 'STATUS', hdrxmlPos, occurance);
3651
3652 subject := replace(subject, g_newLine);
3653 subject := '<![CDATA['||subject||']]>';
3654 hdrxmlPos := NewTag(hdrxml, hdrxmlPos, 'SUBJECT', subject, attrlist);
3655
3656 pos := NewLOBTag(p_doc, pos, 'HEADER', hdrxml, attrlist);
3657 pos := SkipLOBTag(p_doc, 'HEADER', pos, occurance);
3658
3659 -- <<sstomar bug 6993909>> : to get #WF_SECURITY_POLICY
3660 --- Below API returns Template Name based on l_sec_policy . So if 'OPEN_MAIL_SECURE'
3661 -- it means user should view online version of ntf but user will
3662 -- get "notification detail.html" as attachement.
3663 Wf_Mail.ProcessSecurityPolicy(nid, l_sec_policy, t_name);
3664
3665
3666 /*
3667 ** Potentially, it could be possible for a text/plain notification
3668 ** but that would mean looking ahead to ensure that there are
3669 ** absolutely no attachments of any description.
3670 */
3671 /*
3672 ** The body part section of the XML structure will contain
3673 ** a <![CDATA ]]> construct which removes the need to URL
3674 ** encode the data.
3675 */
3676 if notification_pref in ('MAILTEXT','MAILATTH') then
3677 /*
3678 ** MAILTEXT and MAILATTH will have the text/plain as the
3679 ** primary messasge content. The others will be in the
3680 ** from of an attachment.
3681 */
3682 dbms_lob.trim(g_LOBTable(messageIdx).temp_lob, 0);
3683
3684 -- This getBodyPart API releases temp lob allocated within
3685 -- WF_MAIL.GetLobMessage4 for doctype (text/plain )
3686 -- i.e. g_text_messageIdx locator
3687 getBodyPart(g_LOBTable(messageIdx).temp_lob, nid,
3688 g_ntfDocText);
3689
3690 -- bug 6196382 :
3691 -- Outer structure i.e. <CONTENT tag>'s content-type for fwk based ntf.
3692 -- should be multipart/related; otherwise Thunderbird email client
3693 -- will show text/html body part also with text/plain for MAILATTH user
3694 --
3695
3696 -- << sstomar bug 6993909 >> :
3697 -- Always use 'multipart/mixed' with CONTENT tag for 'MAILTEXT','MAILATTH'.
3698 -- It should also be used when #WF_SECURITY_POLICY=NO_EMAIL
3699 -- i.e. t_name (Template name) ='OPEN_MAIL_SECURE'
3700 AddElementAttribute('content-type', 'multipart/mixed', attrlist);
3701
3702
3703 pos := NewLOBTag(p_doc, pos, 'CONTENT', '', attrlist);
3704 attrlist.DELETE;
3705
3706 -- -- BODYPART TAG: This text/plain is a first body part for
3707 -- MAILATTH and MAILTEXT users.
3708
3709 AddElementAttribute('content-type', g_ntfDocText, attrlist);
3710
3711 pos := NewLOBTag(p_doc, pos, 'BODYPART', '', attrlist);
3712
3713 -- Same Content-Type with message TAG as there won't be Images or
3714 -- Other resources referring within first message BODY.
3715 pos := NewLOBTag(p_doc, pos, 'MESSAGE',
3716 g_LOBTable(messageIdx).temp_lob, attrlist);
3717
3718 pos := SkipLOBTag(p_doc, 'MESSAGE', pos, occurance);
3719
3720 if frameworkContent = TRUE and bodyToken = 'Y' then
3721 -- Build the resource section of the XML so that the
3722 -- java layer can locate the notification body to
3723 -- merge into the template.
3724
3725 ntfURL := wf_mail.urlEncode(wf_notification.getFwkBodyURL2(nid,
3726 g_ntfDocText,
3727 l_nlsLanguage,
3728 l_nlsCalendar));
3729
3730 AddElementAttribute('page-type','fwk', attrlist);
3731 AddElementAttribute('src',ntfURL, attrlist);
3732 if EnableStyleInAttr = 'Y' then
3733 AddElementAttribute('enable-stylesheet', stylesheetEnabled,
3734 attrlist);
3735 end if;
3736
3737 -- <<sstomar>>: These parameters may be redundant as Notification
3738 -- level parameter would be used for NLS context at java layer
3739 AddElementAttribute('language',l_nlsLanguage, attrlist);
3740 AddElementAttribute('territory',l_nlsTerritory, attrlist);
3741
3742 AddElementAttribute('token', 'BODY', attrlist);
3743
3744
3745 pos := NewLOBTag(p_doc, pos, 'RESOURCE','',attrlist);
3746 attrlist.DELETE;
3747 pos := SkipLOBTag(p_doc, 'RESOURCE', pos, occurance);
3748 end if;
3749
3750 pos := SkipLOBTag(p_doc, 'BODYPART', pos, occurance);
3751 attrlist.DELETE;
3752 end if; -- END for 'MAILTEXT','MAILATTH'
3753
3754 if notification_pref in ('MAILHTML','MAILATTH','MAILHTM2') then
3755
3756 --
3757 -- The HTML version of the message is only available
3758 -- to MAILHTML and MAILATTH recipients.
3759 -- MAILHTML2 is a text/html message without the additional
3760 -- two framed "Notification Detail.html" attachment, but other attachement
3761 -- may be available.
3762 --
3763 dbms_lob.trim(g_LOBTable(messageIdx).temp_lob, 0);
3764
3765 -- This getBodyPart API releases temp lob allocated within
3766 -- WF_MAIL.GetLobMessage4 for doctype (text/html )
3767 -- i.e. g_html_messageIdx locator
3768 getBodyPart(g_LOBTable(messageIdx).temp_lob, nid,
3769 g_ntfDocHtml);
3770
3771 imgFound := FALSE;
3772 resourceList.DELETE;
3773
3774 if frameworkContent = FALSE AND attachInlineImages = 'Y' then
3775 imgFound := ParseForInlineImages(g_LOBTable(messageIdx).temp_lob,
3776 nid, resourceList);
3777 end if;
3778
3779 --
3780 -- The content-type for the CONTENT tag is based on a set of rules.
3781 -- It can only be multiplart/mixed or multiplart/related if it is a framework region,
3782 -- or there is an inline image. Inline images and framework regions are
3783 -- only allowed for HTML type notifications.
3784 --
3785 -- 4481199 - If the prefernce is MAILATTH, then the CONTENT
3786 -- element is already defined.
3787
3788 -- << sstomar, bug6993909 : commenting below code block >>
3789 -- if (notification_pref in ('MAILHTML', 'MAILHTM2')) then
3790 -- if(frameworkContent = TRUE or imgFound = TRUE) then
3791 -- AddElementAttribute('content-type', 'multipart/related', attrlist);
3792 -- else
3793 -- AddElementAttribute('content-type', 'multipart/mixed', attrlist);
3794 -- end if;
3795 --
3796 -- pos := NewLOBTag(p_doc, pos, 'CONTENT', '', attrlist);
3797 -- attrlist.DELETE;
3798 -- end if;
3799
3800 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
3801 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
3802 'wf.plsql.WF_XML.generateDoc',
3803 ' Template Name returned by Wf_Mail.ProcessSecurityPolicy: [' || t_name || ']' );
3804
3805 if (frameworkContent ) then
3806 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
3807 'wf.plsql.WF_XML.generateDoc', ' framework-Content ?: YES') ;
3808 else
3809 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
3810 'wf.plsql.WF_XML.generateDoc', ' framework-Content ?: NO') ;
3811 end if;
3812 end if;
3813
3814 -- << sstomar bug 6993909>> :
3815 -- CASE 1 : MAILHTM2
3816 if ( notification_pref in ('MAILHTM2') ) then
3817
3818 -- MAILHTM2, text/html only be exist as a FIRST body part but may have
3819 -- additional attachements EXCEPT "Notification Detail.html".
3820
3821 -- For CONTENT tag.
3822 if ((frameworkContent = true or imgFound = true) and
3823 ( t_name is null or t_name <>'OPEN_MAIL_SECURE') ) then
3824
3825 AddElementAttribute('content-type', 'multipart/related', attrlist);
3826 else
3827 -- NOT a Fwk Content:
3828 -- MAILHTM2 may have INLINE / attachements resources.
3829 AddElementAttribute('content-type', 'multipart/mixed', attrlist);
3830 end if;
3831
3832 pos := NewLOBTag(p_doc, pos, 'CONTENT', '', attrlist);
3833 attrlist.DELETE;
3834
3835 -- For BODYPART tag
3836 -- NOTE : This would be a first BODY part so SET it text/html
3837 AddElementAttribute('content-type', 'text/html', attrlist);
3838
3839 -- CASE 2: MAILHTML always will have "Notification Detail.html" attachement
3840 elsif (notification_pref in ('MAILHTML') ) then
3841
3842 -- No need to check t_name ==>'OPEN_MAIL_SECURE' because
3843 -- "Notification Detail.html" always be there for MAILHTML.
3844 AddElementAttribute('content-type', 'multipart/mixed', attrlist);
3845
3846 pos := NewLOBTag(p_doc, pos, 'CONTENT', '', attrlist);
3847 attrlist.DELETE;
3848
3849 -- For BODYPART tag
3850 if ( (frameworkContent = true or imgFound = true) and
3851 ( t_name is null or t_name <>'OPEN_MAIL_SECURE') ) then
3852
3853 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
3854 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
3855 'wf.plsql.WF_XML.generateDoc',
3856 'Setting BODYPART content-type multipart/related');
3857 end if;
3858
3859 -- Set Content-Type = multipart/related because this BODY MAY have
3860 -- other related body-parts which make aggregate body OBJECT ...
3861 AddElementAttribute('content-type', 'multipart/related', attrlist);
3862 else
3863 -- NO Fwk /Image ref : default text/html
3864 AddElementAttribute('content-type', 'text/html', attrlist);
3865 end if;
3866
3867 -- CASE 3: MAILATTH
3868 else
3869 -- Content-Type for CONTENT tag has already been set.
3870
3871 -- For MAILATTH : text/html msg body would be seen as attachement
3872 -- + "Notification Detail.html"
3873 -- BUT text/html will have references of Images / Stylesheets
3874 -- ( NOT be sent as INLINE attachment).
3875
3876 -- For BODYPART tag
3877 AddElementAttribute('content-type', 'text/html', attrlist);
3878
3879 end if;
3880
3881 pos := NewLOBTag(p_doc, pos, 'BODYPART', '', attrlist);
3882 attrlist.DELETE;
3883
3884 -- FOR MESSAGE tag
3885 AddElementAttribute('content-type', g_ntfDocHtml, attrlist);
3886
3887 if notification_pref = 'MAILATTH' then
3888
3889 -- The text/html will be an attachment for MAILTEXT
3890 AddElementAttribute('content-disposition',disposition, attrlist);
3891 AddElementAttribute('filename',htmlfilename, attrlist);
3892 end if;
3893
3894 pos := NewLOBTag(p_doc, pos, 'MESSAGE',
3895 g_LOBTable(messageIdx).temp_lob, attrlist);
3896 pos := SkipLOBTag(p_doc, 'MESSAGE', pos, occurance);
3897
3898 if frameworkContent = TRUE and bodyToken = 'Y' then
3899 -- Build the resource section of the XML so that the
3900 -- java layer can locate the notification body to
3901 -- merge into the template.
3902
3903 ntfURL := wf_mail.urlEncode(wf_notification.getFwkBodyURL2(nid,
3904 g_ntfDocHtml,
3905 l_nlsLanguage,
3906 l_nlsCalendar));
3907
3908
3909 AddElementAttribute('page-type','fwk', attrlist);
3910 AddElementAttribute('src',ntfURL, attrlist);
3911 if EnableStyleInAttr = 'Y' then
3912 AddElementAttribute('enable-stylesheet', stylesheetEnabled,
3913 attrlist);
3914 end if;
3915
3916 AddElementAttribute('language', l_nlsLanguage, attrlist);
3917 AddElementAttribute('territory', l_nlsTerritory, attrlist);
3918 AddElementAttribute('token', 'BODY', attrlist);
3919
3920
3921 pos := NewLOBTag(p_doc, pos, 'RESOURCE','',attrlist);
3922 attrlist.DELETE;
3923 pos := SkipLOBTag(p_doc, 'RESOURCE', pos, occurance);
3924 elsif (frameworkContent = FALSE AND imgFound = TRUE) then
3925 -- Add RESOURCE tags for each of the images pased in
3926 -- in the ParseForInlineImages
3927 addInlineImages(p_doc, pos, attrlist, nid, disposition,
3928 resourceList);
3929 end if;
3930
3931 pos := SkipLOBTag(p_doc, 'BODYPART', pos, occurance);
3932 attrlist.DELETE;
3933 end if;
3934
3935 if notification_pref in ('MAILHTML','MAILATTH') then
3936 /*
3937 ** Adding the text/html component to the notification.
3938 ** This is the little two framed representation of the
3939 ** notification.
3940 **
3941 ** This is only available for the MAILHTML and MAILATTH recipients.
3942 */
3943 AddElementAttribute('content-type',g_ntfDocHtml, attrlist);
3944 pos := NewLOBTag(p_doc, pos, 'BODYPART', '', attrlist);
3945
3946 body_atth := '<![CDATA['||body_atth||']]>';
3947 AddElementAttribute('content-disposition',disposition, attrlist);
3948 AddElementAttribute('filename',urlfilename, attrlist);
3949 pos := NewLOBTag(p_doc, pos, 'MESSAGE', body_atth, attrlist);
3950 pos := SkipLOBTag(p_doc, 'MESSAGE', pos, occurance);
3951 pos := SkipLOBTag(p_doc, 'BODYPART', pos, occurance);
3952 attrlist.DELETE;
3953 end if;
3954
3955
3956 -- Bug 5379861: Notification Reference section and Attachements of a pl/sql
3957 -- notificaton appears as Non-Translated.
3958 -- Set NLS language and territory for this notification
3959 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
3960 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
3961 'wf.plsql.WF_XML.generateDoc',
3962 'Setting User NLS {'|| l_nlsLanguage ||'} {'||l_nlsTerritory||'}'
3963 || l_nlsDateFormat || '} {' || l_nlsDateLanguage || '} {'
3964 || '} {' || l_nlsCalendar || '} {' || l_nlsNumericCharacters
3965 || '} {' || l_nlsSort || '}');
3966 end if;
3967
3968 -- Set notification /user language before processing attachements.
3969 -- SetNLS(l_nlsLanguage, l_nlsTerritory);
3970 if(l_context_changed ) then
3971
3972 -- l_nlsCalendar only will be stored in global variable
3973 WF_NOTIFICATION_UTIL.SetNLSContext(
3974 nid,
3975 l_nlsLanguage ,
3976 l_nlsTerritory ,
3977 l_nlsDateFormat ,
3978 l_nlsDateLanguage ,
3979 l_nlsNumericCharacters ,
3980 l_nlsSort ,
3981 l_nlsCalendar );
3982
3983
3984 END if;
3985
3986 --
3987 -- Next will be to attach all URLs and DOCUMENT attributes
3988 -- as attachments. Disposition for all URL and DOCUMENT attributes
3989 -- with ATTACH=Y should be attachment.
3990 --
3991
3992 --
3993 -- Bug 6671568: When #WF_SECURITY_POLICY = 'NO_EMAIL' or 'ENC_EMAIL_ONLY'
3994 -- we should not send any other content related to the notification, either
3995 -- attachment or inline through e-mail.
3996 --
3997
3998 -- << sstomar : below API is being called above so t_name have assigned (null or somevalue) .
3999 -- Wf_Mail.ProcessSecurityPolicy(nid, l_sec_policy, t_name);
4000
4001 if (t_name is not null) then
4002 if (t_name <> 'OPEN_MAIL_SECURE')
4003 then
4004 pos := GetAttachment(nid, p_doc, agent, 'attachment', doctype, pos);
4005 end if;
4006 else
4007 pos := GetAttachment(nid, p_doc, agent, 'attachment', doctype, pos);
4008 end if;
4009
4010 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
4011 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
4012 'wf.plsql.WF_XML.generateDoc',
4013 'Re-Setting Base NLS {'|| g_base_language ||'} {'||g_base_territory||'}'
4014 || g_base_nlsDateFormat || '} {' || g_base_nlsDateLanguage || '} {'
4015 || '} {' || g_base_nlsCalendar || '} {' || g_base_nlsNumericCharacters
4016 || '} {' || g_base_nlsSort || '}');
4017 end if;
4018
4019 -- Bug 5379861: Reset back base language.
4020 -- SetNLS(g_base_language, g_base_territory);
4021 -- Reset base language
4022 if( l_context_changed ) then
4023
4024 WF_NOTIFICATION_UTIL.SetNLSContext
4025 (null, -- Resetting null for Nid is fine.
4026 g_base_language ,
4027 g_base_territory ,
4028 g_base_nlsDateFormat ,
4029 g_base_nlsDateLanguage ,
4030 g_base_nlsNumericCharacters ,
4031 g_base_nlsSort ,
4032 g_base_nlsCalendar );
4033 end if;
4034
4035 pos := SkipLOBTag(p_doc, 'CONTENT', pos, occurance);
4036 pos := SkipLOBTag(p_doc, 'NOTIFICATION', pos, occurance);
4037
4038 p_pos := pos;
4039 wf_temp_lob.releaseLob(g_LOBTable, messageIdx);
4040
4041
4042 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
4043 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
4044 'wf.plsql.WF_XML.generateDoc', 'END');
4045 end if;
4046 exception
4047 when others then
4048
4049 wf_temp_lob.releaseLob(g_LOBTable, messageIdx);
4050
4051 -- Since within wf_mail.getLOBMessage4 we are releasing
4052 -- TEMP LOBs incase of any exception, so there is no need to
4053 -- release those LOBs here. -- WF_MAIL.CloseLob(doctype)
4054
4055 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
4056 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
4057 'wf.plsql.WF_XML.generateDoc',
4058 'Re-Setting Base NLS {'|| g_base_language ||'} {'||g_base_territory||'}'
4059 || g_base_nlsDateFormat || '} {' || g_base_nlsDateLanguage || '} {'
4060 || '} {' || g_base_nlsCalendar || '} {' || g_base_nlsNumericCharacters
4061 || '} {' || g_base_nlsSort || '}');
4062 end if;
4063
4064 -- Reset base language, in case of exception.
4065 -- SetNLS(g_base_language, g_base_territory);
4066 -- Reset base language
4067 WF_NOTIFICATION_UTIL.SetNLSContext(
4068 null,
4069 g_base_language ,
4070 g_base_territory ,
4071 g_base_nlsDateFormat ,
4072 g_base_nlsDateLanguage ,
4073 g_base_nlsNumericCharacters ,
4074 g_base_nlsSort ,
4075 g_base_nlsCalendar );
4076
4077
4078
4079 wf_core.context('WF_XML', 'GenerateDoc', p_event_name, p_event_key);
4080 raise;
4081 end GenerateDoc;
4082
4083
4084 -- GenerateGroupDoc
4085 -- To generate the complete set of notification for a group.
4086 procedure GenerateGroupDoc(p_doc in out NOCOPY CLOB,
4087 p_pos in out NOCOPY number,
4088 p_recipient_role in varchar2,
4089 p_notification_pref in varchar2,
4090 p_orig_system in varchar2,
4091 p_orig_system_id in number,
4092 p_event_name in varchar2,
4093 p_event_key in varchar2,
4094 p_parameter_list in wf_parameter_list_t)
4095 is
4096
4097 cursor members(rname varchar2, rorig varchar2, rorigid number) is
4098 select UR.USER_NAME, UR.USER_ORIG_SYSTEM, UR.USER_ORIG_SYSTEM_ID
4099 from WF_USER_ROLES UR
4100 where UR.ROLE_NAME = rname
4101 and UR.ROLE_ORIG_SYSTEM = rorig
4102 and UR.ROLE_ORIG_SYSTEM_ID = rorigid
4103 and ((UR.USER_NAME <> UR.ROLE_NAME) or
4104 (UR.USER_ORIG_SYSTEM <> UR.ROLE_ORIG_SYSTEM and
4105 UR.USER_ORIG_SYSTEM_ID <> UR.ROLE_ORIG_SYSTEM_ID));
4106
4107 members_type members%ROWTYPE;
4108 TYPE members_table_type is TABLE OF members%ROWTYPE
4109 INDEX BY BINARY_INTEGER;
4110 i pls_integer := 1;
4111
4112 members_t members_table_type;
4113 attrlist wf_xml_attr_table_type;
4114 inAttr varchar2(1);
4115 resetNls varchar2(10);
4116 corrId varchar2(128);
4117
4118 begin
4119 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
4120 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
4121 'wf.plsql.WF_XML.generateGroupDoc', 'BEGIN');
4122 end if;
4123 i := 1;
4124 for r in members(p_recipient_role, p_orig_system, p_orig_system_id) loop
4125 members_t(i).user_name := r.user_name;
4126 members_t(i).user_orig_system:= r.user_orig_system;
4127 members_t(i).user_orig_system_id:= r.user_orig_system_id;
4128 i := i + 1;
4129 end loop;
4130
4131
4132 -- 4104735 Removing the test for "p_notification_pref not in
4133 -- ('QUERY','SUMMARY','SUMHTML', 'DISABLED')". The rule to
4134 -- send or not should come from the individual memebers and not the
4135 -- parent role. If there are simply no members then the NULL document
4136 -- should be sent. The testing of the notification preference for
4137 -- the members will be performed again in genreateDoc.
4138 if members_t.count = 0 then
4139 -- No role members. Only log it for now and change the
4140 -- notification preference to QUERY.
4141 GenerateEmptyDoc(to_number(p_event_key), p_pos, p_doc, 'no_members', TRUE);
4142 else
4143
4144 -- 4628088 Send the RESET_NLS flag if one is defined
4145 -- at the message level.
4146 corrId := wf_event.getValueForParameter('Q_CORRELATION_ID',
4147 p_parameter_list);
4148 resetNls := WF_MAILER_PARAMETER.GetValueForCorr (pNid => p_event_key,
4149 pCorrId => corrId,
4150 pName => 'RESET_NLS',
4151 pInAttr => inAttr);
4152
4153 AddElementAttribute('maxcount',to_char(members_t.count), attrlist);
4154 -- ER: 6449325 : Alwasy add this parameter, because here value
4155 -- is retrived based on Corr-ID of a Mailer,
4156 --if(inAttr = 'Y') then
4157 AddElementAttribute('reset-nls',resetNls, attrlist);
4158 --end if;
4159 p_pos := NewLOBTag(p_doc, p_pos, 'NOTIFICATIONGROUP', '', attrlist);
4160 attrlist.DELETE;
4161
4162 for i in 1..members_t.count loop
4163 generateDoc(p_doc, p_pos, members_t(i).user_name,
4164 p_event_name, p_event_key, p_parameter_list);
4165 end loop;
4166 end if;
4167
4168 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
4169 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
4170 'wf.plsql.WF_XML.generateGroupDoc', 'END');
4171 end if;
4172 exception
4173 when others then
4174 wf_core.context('WF_XML','GenerateGroupDoc',p_event_name, p_event_key);
4175 raise;
4176 end GenerateGroupDoc;
4177
4178 -- GenerateMessage
4179 -- To generate the XML content for a single notification
4180 procedure GenerateMessage(p_doc in out nocopy CLOB,
4181 p_event_name in varchar2,
4182 p_event_key in varchar2,
4183 p_parameter_list in wf_parameter_list_t)
4184 is
4185 nid NUMBER;
4186
4187 pos integer;
4188 amt number;
4189
4190 installed VARCHAR2(1);
4191 language wf_roles.language%TYPE;
4192 territory wf_roles.territory%TYPE;
4193 codeset VARCHAR2(100);
4194 orig_system VARCHAR2(100);
4195 orig_system_id number;
4196
4197 recipient_role wf_roles.name%TYPE;
4198 status VARCHAR2(100);
4199 mail_status VARCHAR2(100);
4200 str varchar2 (2000);
4201
4202 role wf_roles.name%TYPE;
4203 display_name wf_roles.display_name%TYPE;
4204 email wf_roles.email_address%TYPE;
4205 notification_pref wf_roles.notification_preference%TYPE;
4206
4207 attrlist wf_xml_attr_table_type;
4208
4209 nodename varchar2(100);
4210 messageType varchar2(8);
4211 messageName varchar2(30);
4212
4213 inAttr varchar2(1);
4214 resetNls varchar2(10);
4215
4216 begin
4217
4218 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
4219 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
4220 'wf.plsql.WF_XML.generateMessage', 'BEGIN');
4221 end if;
4222
4223 nid := to_number(p_event_key);
4224
4225 -- Obtain notification information
4226 begin -- 3741599 If there is no notification, exit gracefully
4227 select NVL(MORE_INFO_ROLE, RECIPIENT_ROLE), STATUS, MAIL_STATUS,
4228 MESSAGE_TYPE, MESSAGE_NAME
4229 into recipient_role, status, mail_status, messageType, messageName
4230 from WF_NOTIFICATIONS
4231 where NOTIFICATION_ID = nid;
4232 exception
4233 when no_data_found then
4234 GenerateEmptyDoc(nid, 0, p_doc, 'no_data_found', TRUE);
4235 return;
4236 when others then
4237 wf_core.context('WF_XML','GenerateMessage',to_char(nid));
4238 raise;
4239 end;
4240
4241 -- Bug 10243065. Check if this is a reassigned notification that does
4242 -- not need to be sent
4243 if wf_event.getValueForParameter('IS_DUPLICATE', p_parameter_list) = 'TRUE' then
4244 GenerateEmptyDoc(nid, 0, p_doc, 'Reassigned, not sent to oringinal recipient', TRUE);
4245 return;
4246 end if;
4247
4248 if (wf_mail.test_flag = TRUE) then
4249 mail_status := 'MAIL';
4250 if (status not in ('OPEN','CANCELED','CLOSED')) then
4251 status := 'OPEN';
4252 end if;
4253 end if;
4254
4255 -- Bug 10202313: store status, mail_status values into global variables
4256 g_status := status;
4257 g_mstatus := mail_status;
4258
4259 if MAIL_STATUS is null or MAIL_STATUS not in ('MAIL','INVALID') then
4260 GenerateEmptyDoc(nid, 0, p_doc, 'Reassigned, MAIL_STATUS:'||MAIL_STATUS, TRUE);
4261 return;
4262 end if;
4263
4264 -- <<sstomar>>:
4265 -- Call OLD API instead of WF_DIRECTORY.GetRoleInfoMail2
4266 -- here I think we are OK as we are not using other parameters.
4267 --
4268 -- Obtain recipient information
4269 WF_DIRECTORY.GetRoleInfoMail(recipient_role, display_name, email,
4270 notification_pref,
4271 language, territory,
4272 orig_system, orig_system_id, installed);
4273
4274 if email is not null then
4275 -- Email address is provided. process for one recipient
4276
4277 if notification_pref not in ('QUERY','SUMMARY','SUMHTML',
4278 'DISABLED') then
4279 str := '<?xml version="1.0" ?>';
4280 pos := length(str);
4281 dbms_lob.write(p_doc, pos, 1, str);
4282
4283 -- 4628088 Send the RESET_NLS flag if one is defined
4284 -- at the message level.
4285 resetNls := WF_MAILER_PARAMETER.GetValueForCorr (pNid => nid,
4286 pCorrId => messageType,
4287 pName => 'RESET_NLS',
4288 pInAttr => inAttr);
4289
4290 AddElementAttribute('maxcount','1', attrlist);
4291
4292 -- ERO: 6449325: Corr-ID based RESET_NLS paramter should get precedence.
4293 --
4294 --if(inAttr = 'Y') then
4295 AddElementAttribute('reset-nls',resetNls, attrlist);
4296 --end if;
4297
4298 pos := NewLOBTag(p_doc, pos, 'NOTIFICATIONGROUP', '', attrlist);
4299 attrlist.DELETE;
4300
4301 -- generate XML payload
4302 generateDoc(p_doc, pos, recipient_role,
4303 p_event_name, p_event_key, p_parameter_list);
4304
4305 else
4306 -- This case should not be reached if the notification system
4307 -- is working correctly ie that a NULL is placed in the mail_status
4308 -- However, just in case, generate a blank NOTIFICATION element
4309 -- all the same.
4310 GenerateEmptyDoc(nid, 0, p_doc, 'NOTIFICATION_PREFERENCE:'||notification_pref, TRUE);
4311 end if;
4312 else
4313 -- No email address is provided. Assume that this is a
4314 -- role with members.
4315 -- Failure to yeild members will result in a notification
4316 -- being generated to go to the system admin and the
4317 -- error process to be called.
4318 str := '<?xml version="1.0" ?>';
4319 pos := length(str);
4320 dbms_lob.write(p_doc, pos, 1, str);
4321 generateGroupDoc(p_doc, pos, recipient_role, notification_pref,
4322 orig_system, orig_system_id,
4323 p_event_name, p_event_key, p_parameter_list);
4324 end if;
4325
4326 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
4327 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
4328 'wf.plsql.WF_XML.generateMessage', 'END');
4329 end if;
4330 exception
4331 when others then
4332 wf_core.context('WF_XML','Generate',p_event_name, p_event_key);
4333 raise;
4334 end GenerateMessage;
4335
4336 -- GenerateSummaryDoc
4337 -- To generate the XML content for the OPEN notifications.
4338
4339 procedure GenerateSummaryDoc (p_doc in out NOCOPY CLOB,
4340 p_pos in out NOCOPY number,
4341 p_recipient_role in varchar2,
4342 p_event_name in varchar2,
4343 p_event_key in varchar2,
4344 p_parameter_list in wf_parameter_list_t)
4345 is
4346 pos integer;
4347 attrlist wf_xml_attr_table_type;
4348 occurance integer;
4349
4350 docType VARCHAR2(100);
4351
4352 recipient_role VARCHAR2(100);
4353 display_name VARCHAR2(200);
4354 email VARCHAR2(1000);
4355
4356 notification_pref VARCHAR2(100);
4357
4358 orig_system VARCHAR2(100);
4359 orig_system_id number;
4360 installed VARCHAR2(1);
4361
4362 l_nlsDateFormat VARCHAR2(120);
4363 l_nlsDateLanguage varchar2(120);
4364 l_nlsCalendar varchar2(120);
4365 l_nlsNumericCharacters varchar2(30);
4366 l_nlsSort varchar2(120);
4367 l_nlsCurrency varchar2(30);
4368
4369 l_nlsLanguage VARCHAR2(120);
4370 l_nlsTerritory VARCHAR2(120);
4371 l_nlsCodeset VARCHAR2(30);
4372 l_OverrideCodeset VARCHAR2(30);
4373
4374 l_context_changed BOOLEAN := false;
4375
4376 hdrxml varchar2(32000);
4377 hdrxmlPos integer;
4378
4379 corrId varchar2(128);
4380 nodename varchar2(100);
4381 fromName varchar2(100);
4382 replyto varchar2(100);
4383 subject VARCHAR2(4000);
4384
4385 msgbody VARCHAR2(32000);
4386 -- message CLOB;
4387 messageIdx pls_integer;
4388 l_lob VARCHAR2(1);
4389 resourceSrc varchar2(4000);
4390 l_renderBody varchar2(1);
4391 l_messageName varchar2(30);
4392
4393
4394 begin
4395
4396 if (wf_log_pkg.level_event >= fnd_log.g_current_runtime_level) then
4397 wf_log_pkg.string(wf_log_pkg.level_event,
4398 'wf.plsql.WF_XML.GenerateSummaryDoc',
4399 'BEGIN');
4400 end if;
4401
4402 recipient_role := p_recipient_role;
4403
4404 corrId := wf_event.getValueForParameter('Q_CORRELATION_ID',
4405 p_parameter_list);
4406 messageIdx := 0;
4407 pos := p_pos;
4408 occurance := 1;
4409
4410 -- Obtain recipient information
4411 --WF_DIRECTORY.GetRoleInfoMail(recipient_role, display_name, email,
4412 -- notification_pref,
4413 -- language, territory,
4414 -- orig_system, orig_system_id, installed);
4415
4416 -- Obtain recipient's NLS information too
4417 WF_DIRECTORY.GetRoleInfoMail2(recipient_role, display_name, email,
4418 notification_pref,
4419 orig_system,
4420 orig_system_id,
4421 installed,
4422 l_nlsLanguage ,
4423 l_nlsTerritory ,
4424 l_nlsDateFormat ,
4425 l_nlsDateLanguage ,
4426 l_nlsCalendar ,
4427 l_nlsNumericCharacters ,
4428 l_nlsSort ,
4429 l_nlsCurrency );
4430
4431
4432 if (wf_log_pkg.level_statement >= fnd_log.g_current_runtime_level) then
4433 wf_log_pkg.string(wf_log_pkg.level_statement,
4434 'wf.plsql.WF_XML.GenerateSummaryDoc',
4435 'ROLE {'||recipient_role||'} LANG {'||l_nlsLanguage||
4436 '} TERR {'||l_nlsTerritory||' NTF {'||notification_pref||
4437 '} EMAIL {'||email||'}');
4438
4439 end if;
4440
4441 -- XX TODO Sentinal for DISABLED case? Though there is no NID to be
4442 -- updated, can be used as documentation in the log
4443 if notification_pref not in ('SUMMARY','SUMHTML') or
4444 email is null then
4445 if (wf_log_pkg.level_exception >= fnd_log.g_current_runtime_level) then
4446 if email is null then
4447 wf_log_pkg.string(wf_log_pkg.level_exception,
4448 'wf.plsql.WF_XML.GenerateSummaryDoc',
4449 'Not generating. Recipient has a null '||
4450 'email address');
4451 else
4452 wf_log_pkg.string(wf_log_pkg.level_exception,
4453 'wf.plsql.WF_XML.GenerateSummaryDoc',
4454 'Not generating. Recipient has pref: '||
4455 notification_pref);
4456 end if;
4457 end if;
4458 GenerateEmptyDoc(0, p_pos, p_doc, 'NOTIFICATION_PREFERENCE:'||notification_pref, FALSE);
4459 return;
4460 end if;
4461
4462 -- Set the preferred document type based on the
4463 -- notification preference.
4464 if g_install = 'EMBEDDED' then
4465 l_renderBody := 'N';
4466 l_messageName := 'SUMHTML';
4467 if notification_pref = 'SUMMARY' then
4468 docType := g_ntfDocText;
4469 elsif notification_pref = 'SUMHTML' then
4470 docType := g_ntfDocHtml;
4471 end if;
4472 else
4473 l_renderBody := 'Y';
4474 l_messageName := 'SUMMARY';
4475 docType := g_ntfDocText;
4476 end if;
4477
4478 -- Get the Base NLS.
4479 -- << sstomar>> : already being set in GENERATE function
4480 -- WF_MAIL.GetSessionLanguage(base_lang, base_territory, base_codeset);
4481
4482 -- If requested language is not installed, use base NLS setting
4483 if installed = 'N' then
4484 l_nlsLanguage := g_base_language;
4485 l_nlsTerritory := g_base_territory;
4486 end if;
4487 begin
4488 select nls_codeset, override_email_charset
4489 into l_nlsCodeset, l_OverrideCodeset
4490 from wf_languages
4491 where nls_language = l_nlsLanguage;
4492 exception
4493 when others then
4494 l_nlsCodeset := g_base_codeset;
4495 end;
4496
4497 -- <<sstomar>> :
4498 --
4499 -- setNLS(language, territory);
4500 -- Set user / role's context
4501 if( nvl(l_nlsLanguage, 'AMERICA') <> g_base_language or
4502 nvl(l_nlsTerritory, 'AMERICAN') <> g_base_territory or
4503 nvl(l_nlsDateFormat , wf_core.nls_date_format) <> g_base_nlsDateFormat or
4504 nvl(l_nlsDateLanguage, wf_core.nls_date_language) <> g_base_nlsDateLanguage or
4505 nvl(l_nlsNumericCharacters, wf_core.nls_numeric_characters) <> g_base_nlsNumericCharacters or
4506 nvl(l_nlsSort, wf_core.nls_sort) <> g_base_nlsSort ) then
4507
4508
4509 WF_NOTIFICATION_UTIL.SetNLSContext(0,
4510 l_nlsLanguage ,
4511 l_nlsTerritory ,
4512 l_nlsDateFormat ,
4513 l_nlsDateLanguage ,
4514 l_nlsNumericCharacters ,
4515 l_nlsSort ,
4516 l_nlsCalendar);
4517
4518 l_context_changed := true;
4519
4520
4521 END if;
4522
4523 -- Initialise the XML Document and then progressively walk
4524 -- through the elements. Populating them as we go.
4525 -- l_pos is crucial as it determines where the next nodes
4526 -- will be placed.
4527
4528 l_lob := 'N';
4529
4530 -- <<sstomar>>:
4531 -- This WF_MAIL.GetSummary2 API may allocate temp LOB depending on
4532 -- size of contents. We release within getBodyPart api, getBodyPart
4533 -- is being called below...
4534 WF_MAIL.GetSummary2(
4535 role => recipient_role,
4536 dname => display_name,
4537 node => nodename,
4538 renderBody=> l_renderBody,
4539 contType => docType,
4540 subject => subject,
4541 body_text => msgbody,
4542 lob => l_lob);
4543
4544 --SetNLS(base_lang, base_territory);
4545
4546 -- Reset base NLS Context
4547 if( l_context_changed ) then
4548
4549 WF_NOTIFICATION_UTIL.SetNLSContext(
4550 null,
4551 g_base_language ,
4552 g_base_territory ,
4553 g_base_nlsDateFormat ,
4554 g_base_nlsDateLanguage ,
4555 g_base_nlsNumericCharacters ,
4556 g_base_nlsSort ,
4557 g_base_nlsCalendar );
4558 END if;
4559
4560
4561
4562 -- NID hardcoded to 0 for Summary
4563 AddElementAttribute('nid', '0', attrlist);
4564
4565 AddElementAttribute('language', l_nlsLanguage, attrlist);
4566 AddElementAttribute('territory', l_nlsTerritory, attrlist);
4567
4568
4569 -- Mailer's RESET_NLS parameter will be used.
4570 if(l_OverrideCodeset is not null) then
4571 AddElementAttribute('is-iana-cs', 'Y', attrlist);
4572 AddElementAttribute('codeset', l_OverrideCodeset, attrlist);
4573 else
4574 AddElementAttribute('is-iana-cs', 'N', attrlist);
4575 AddElementAttribute('codeset', l_nlsCodeset, attrlist);
4576 end if;
4577
4578
4579 AddElementAttribute('nlsDateformat', l_nlsDateFormat, attrlist);
4580 AddElementAttribute('nlsDateLanguage', l_nlsDateLanguage, attrlist);
4581
4582 AddElementAttribute('nlsNumericCharacters', l_nlsNumericCharacters, attrlist);
4583 AddElementAttribute('nlsSort', l_nlsSort, attrlist);
4584
4585 -- priority hardcoded to 50
4586 AddElementAttribute('priority', '50', attrlist);
4587 -- Not addding accesskey as no response processing is done for summary email
4588 AddElementAttribute('node', nodename, attrlist);
4589 -- ItemType / messageType hardcoded to WFMAIL
4590 AddElementAttribute('item_type', 'WFMAIL', attrlist);
4591 AddElementAttribute('message_name', l_messageName, attrlist);
4592 AddElementAttribute('full-document', 'Y', attrlist);
4593 pos := NewLOBTag(p_doc, pos, 'NOTIFICATION', '', attrlist);
4594 attrlist.DELETE;
4595
4596 hdrxmlPos := 0;
4597 hdrxml := '';
4598
4599 hdrxmlPos := NewTag(hdrxml, hdrxmlPos, 'RECIPIENTLIST', '', attrlist);
4600
4601 addRecipient(p_doc => hdrxml,
4602 p_role => recipient_role,
4603 p_type => 'to',
4604 p_name => display_name,
4605 p_email => email,
4606 p_pos => hdrxmlPos);
4607
4608 hdrxmlPos := SkipTag(hdrxml, 'RECIPIENTLIST', hdrxmlPos, occurance);
4609
4610 hdrxmlPos := NewTag(hdrxml, hdrxmlPos, 'FROM', '', attrlist);
4611
4612 -- fromName := 'FROM';
4613 fromName := WF_MAILER_PARAMETER.GetValueForCorr (pCorrId => corrId,
4614 pName => 'FROM');
4615 fromName := replace(fromName, g_newLine);
4616 fromName := '<![CDATA['||fromName||']]>';
4617 hdrxmlPos := NewTag(hdrxml, hdrxmlPos, 'NAME', fromName, attrlist);
4618 hdrxmlPos := SkipTag(hdrxml, 'NAME', hdrxmlPos, occurance);
4619
4620 -- replyto := 'REPLYTO';
4621 replyto := WF_MAILER_PARAMETER.GetValueForCorr (pCorrId => corrId,
4622 pName => 'REPLYTO');
4623 replyto := replace(replyto, g_newLine);
4624 replyto := '<![CDATA['||replyto||']]>';
4625 hdrxmlPos := NewTag(hdrxml, hdrxmlPos, 'ADDRESS', replyto, attrlist);
4626 hdrxmlPos := SkipTag(hdrxml, 'ADDRESS', hdrxmlPos, occurance);
4627 hdrxmlPos := SkipTag(hdrxml, 'FROM', hdrxmlPos, occurance);
4628
4629 -- Not addding status as not needed for summary email
4630
4631 subject := replace(subject, g_newLine);
4632 subject := '<![CDATA['||subject||']]>';
4633 hdrxmlPos := NewTag(hdrxml, hdrxmlPos, 'SUBJECT', subject, attrlist);
4634
4635 pos := NewLOBTag(p_doc, pos, 'HEADER', hdrxml, attrlist);
4636 pos := SkipLOBTag(p_doc, 'HEADER', pos, occurance);
4637
4638 -- <sstomar bug 6993909>>
4639 -- So far I did not see any issue with SUMHTML
4640 -- If required then outer structure can be set multipart/related
4641 -- for SUMHTML, text/plain for SUMMARY.
4642 AddElementAttribute('content-type', 'multipart/mixed', attrlist);
4643 pos := NewLOBTag(p_doc, pos, 'CONTENT', '', attrlist);
4644 attrlist.DELETE;
4645
4646 /*
4647 ** The body part section of the XML structure will contain
4648 ** a <![CDATA ]]> construct which removes the need to URL
4649 ** encode the data.
4650 */
4651 if (l_renderBody = 'Y') then
4652 AddElementAttribute('content-type', 'text/plain', attrlist);
4653 else
4654 AddElementAttribute('content-type', 'multipart/related', attrlist);
4655 end if;
4656 pos := NewLOBTag(p_doc, pos, 'BODYPART', '', attrlist);
4657 attrlist.DELETE;
4658
4659 -- Set the content-type of the MESSAGE tag to being the
4660 -- preferred output.
4661 AddElementAttribute('content-type', docType, attrlist);
4662 if (l_lob = 'Y') then
4663
4664 -- dbms_lob.createTemporary(message, TRUE, dbms_lob.CALL);
4665 messageIdx := wf_temp_lob.getLob(g_LOBTable);
4666 dbms_lob.trim(g_LOBTable(messageIdx).temp_lob, 0);
4667
4668 -- << bug 6511028 >>
4669 -- This getBodyPart API also releases temp lob allocated within
4670 -- WF_MAIL.GetSummary2 for doctype (text/plain )
4671 -- i.e. g_text_messageIdx locator
4672 getBodyPart(g_LOBTable(messageIdx).temp_lob, 1,
4673 g_ntfDocText);
4674
4675 pos := NewLOBTag(p_doc, pos, 'MESSAGE',
4676 g_LOBTable(messageIdx).temp_lob, attrlist);
4677 -- release Temp lob to pool.
4678 wf_temp_lob.releaseLob(g_LOBTable, messageIdx);
4679
4680 else
4681
4682 msgbody := '<![CDATA['||msgbody||']]>';
4683
4684 pos := NewLOBTag(p_doc, pos, 'MESSAGE', msgbody, attrlist);
4685
4686 end if;
4687
4688 pos := SkipLOBTag(p_doc, 'MESSAGE', pos, occurance);
4689 if l_renderBody = 'N' then
4690 -- If this is a HTML summary notification then
4691 -- create a RESOURCE tag to obtain the content from
4692 -- the Applications Framework
4693 resourceSrc := wf_mail.urlEncode(wf_notification.getSummaryUrl2(
4694 recipient_role, docType, l_nlsCalendar));
4695 AddElementAttribute('page-type','fwk', attrlist);
4696 AddElementAttribute('src', resourceSrc, attrlist);
4697
4698 -- << sstomar>> : these attribute may not be used at java layer, insead of
4699 -- Notification level attributes would be used,
4700 AddElementAttribute('language', l_nlsLanguage, attrlist);
4701 AddElementAttribute('territory', l_nlsTerritory, attrlist);
4702 AddElementAttribute('token', 'SUMMARY', attrlist);
4703 pos := NewLOBTag(p_doc, pos, 'RESOURCE', '', attrlist);
4704 pos := SkipLOBTag(p_doc, 'RESOURCE', pos, occurance);
4705 attrList.DELETE;
4706 end if;
4707 pos := SkipLOBTag(p_doc, 'BODYPART', pos, occurance);
4708 attrlist.DELETE;
4709
4710 pos := SkipLOBTag(p_doc, 'CONTENT', pos, occurance);
4711 pos := SkipLOBTag(p_doc, 'NOTIFICATION', pos, occurance);
4712
4713 p_pos := pos;
4714
4715 if (wf_log_pkg.level_event >= fnd_log.g_current_runtime_level) then
4716 wf_log_pkg.string(wf_log_pkg.level_event,
4717 'wf.plsql.WF_XML.GenerateSummaryDoc',
4718 'END');
4719 end if;
4720
4721 exception
4722 when others then
4723 if (messageIdx > 0) then
4724 wf_temp_lob.releaseLob(g_LOBTable, messageIdx);
4725 end if;
4726
4727 -- Reset base NLS Context in case of any EXCEPTION
4728 WF_NOTIFICATION_UTIL.SetNLSContext(
4729 null,
4730 g_base_language ,
4731 g_base_territory ,
4732 g_base_nlsDateFormat ,
4733 g_base_nlsDateLanguage ,
4734 g_base_nlsNumericCharacters ,
4735 g_base_nlsSort ,
4736 g_base_nlsCalendar );
4737
4738
4739 wf_core.context('WF_XML', 'GenerateSummaryDoc', p_event_name,
4740 p_event_key);
4741 raise;
4742 end GenerateSummaryDoc;
4743
4744 -- Generate
4745 procedure GenerateGroupSummaryDoc (p_doc in out NOCOPY CLOB,
4746 p_pos in out NOCOPY number,
4747 p_recipient_role in varchar2,
4748 p_orig_system in varchar2,
4749 p_orig_system_id in number,
4750 p_event_name in varchar2,
4751 p_event_key in varchar2,
4752 p_parameter_list in wf_parameter_list_t)
4753 is
4754
4755 cursor members(rname varchar2, rorig varchar2, rorigid number) is
4756 select UR.USER_NAME, UR.USER_ORIG_SYSTEM, UR.USER_ORIG_SYSTEM_ID
4757 from WF_USER_ROLES UR
4758 where UR.ROLE_NAME = rname
4759 and UR.ROLE_ORIG_SYSTEM = rorig
4760 and UR.ROLE_ORIG_SYSTEM_ID = rorigid
4761 and ((UR.USER_NAME <> UR.ROLE_NAME) or
4762 (UR.USER_ORIG_SYSTEM <> UR.ROLE_ORIG_SYSTEM and
4763 UR.USER_ORIG_SYSTEM_ID <> UR.ROLE_ORIG_SYSTEM_ID));
4764
4765 members_type members%ROWTYPE;
4766 TYPE members_table_type is TABLE OF members%ROWTYPE
4767 INDEX BY BINARY_INTEGER;
4768
4769 i pls_integer := 1;
4770
4771 members_t members_table_type;
4772 attrlist wf_xml_attr_table_type;
4773
4774 begin
4775
4776 if (wf_log_pkg.level_event >= fnd_log.g_current_runtime_level) then
4777 wf_log_pkg.string(wf_log_pkg.level_event,
4778 'wf.plsql.WF_XML.GenerateGroupSummaryDoc',
4779 'BEGIN');
4780 end if;
4781
4782 i := 1;
4783 for r in members(p_recipient_role, p_orig_system, p_orig_system_id) loop
4784 members_t(i).user_name := r.user_name;
4785 members_t(i).user_orig_system:= r.user_orig_system;
4786 members_t(i).user_orig_system_id:= r.user_orig_system_id;
4787 i := i + 1;
4788 end loop;
4789
4790 if members_t.count = 0 then
4791 if (wf_log_pkg.level_event >= fnd_log.g_current_runtime_level) then
4792 wf_log_pkg.string(wf_log_pkg.level_event,
4793 'wf.plsql.WF_XML.GenerateGroupSummaryDoc',
4794 'No role members.');
4795 end if;
4796 GenerateEmptyDoc(0, p_pos, p_doc, 'no_members', TRUE);
4797 else
4798
4799 AddElementAttribute('maxcount',to_char(members_t.count), attrlist);
4800 p_pos := NewLOBTag(p_doc, p_pos, 'NOTIFICATIONGROUP', '', attrlist);
4801 attrlist.DELETE;
4802
4803 for i in 1..members_t.count loop
4804 GenerateSummaryDoc (p_doc, p_pos, members_t(i).user_name,
4805 p_event_name, p_event_key, p_parameter_list);
4806 end loop;
4807 end if;
4808
4809 if (wf_log_pkg.level_event >= fnd_log.g_current_runtime_level) then
4810 wf_log_pkg.string(wf_log_pkg.level_event,
4811 'wf.plsql.WF_XML.GenerateGroupSummaryDoc',
4812 'END');
4813 end if;
4814
4815 exception
4816 when others then
4817 wf_core.context('WF_XML','GenerateGroupSummaryDoc ',p_event_name,
4818 p_event_key);
4819 raise;
4820 end GenerateGroupSummaryDoc ;
4821
4822
4823 -- GenerateSummary
4824 -- To generate the XML content for the enqueued Summary notifications.
4825 procedure GenerateSummary (p_doc in out nocopy CLOB,
4826 p_event_name in varchar2,
4827 p_event_key in varchar2,
4828 p_parameter_list in wf_parameter_list_t)
4829 is
4830 pos integer;
4831
4832 attrlist wf_xml_attr_table_type;
4833 str varchar2 (2000);
4834
4835 recipient_role VARCHAR2(100);
4836
4837 display_name VARCHAR2(200);
4838 email VARCHAR2(1000);
4839 notification_pref VARCHAR2(100);
4840 language VARCHAR2(100);
4841 territory VARCHAR2(100);
4842 orig_system VARCHAR2(100);
4843 orig_system_id number;
4844 installed VARCHAR2(1);
4845
4846 e_RoleNameNotSpecified EXCEPTION;
4847
4848 begin
4849
4850 if (wf_log_pkg.level_event >= fnd_log.g_current_runtime_level) then
4851 wf_log_pkg.string(wf_log_pkg.level_event,
4852 'wf.plsql.WF_XML.GenerateSummary',
4853 'BEGIN');
4854 end if;
4855
4856 if p_parameter_list is not null then
4857 recipient_role := wf_event.getValueForParameter('ROLE_NAME',
4858 p_parameter_list);
4859 end if;
4860
4861 if recipient_role is null then
4862 raise e_RoleNameNotSpecified;
4863 end if;
4864
4865 -- Initialise the XML Document and then progressively walk
4866 -- through the elements. Populating them as we go.
4867 -- l_pos is crucial as it determines where the next nodes
4868 -- will be placed.
4869 str := '<?xml version="1.0" ?>';
4870 pos := length(str);
4871 dbms_lob.write(p_doc, pos, 1, str);
4872
4873 -- Obtain recipient information
4874 WF_DIRECTORY.GetRoleInfoMail(recipient_role, display_name, email,
4875 notification_pref,
4876 language, territory,
4877 orig_system, orig_system_id, installed);
4878
4879 if email is not null or email <> '' then
4880
4881 AddElementAttribute('maxcount','1', attrlist);
4882 pos := NewLOBTag(p_doc, pos, 'NOTIFICATIONGROUP', '', attrlist);
4883 attrlist.DELETE;
4884 -- Email address is provided. process for one recipient
4885
4886 GenerateSummaryDoc (p_doc, pos, recipient_role, p_event_name,
4887 p_event_key, p_parameter_list);
4888
4889 else
4890
4891 -- No email address is provided. Assume that this is a
4892 -- role with members.
4893 -- Failure to yeild members will result in a notification
4894 -- being generated to go to the system admin and the
4895 -- error process to be called.
4896
4897 GenerateGroupSummaryDoc (p_doc, pos, recipient_role, orig_system,
4898 orig_system_id, p_event_name, p_event_key,
4899 p_parameter_list);
4900
4901 end if;
4902
4903 if (wf_log_pkg.level_event >= fnd_log.g_current_runtime_level) then
4904 wf_log_pkg.string(wf_log_pkg.level_event,
4905 'wf.plsql.WF_XML.GenerateSummary',
4906 'END');
4907 end if;
4908 exception
4909
4910 when e_RoleNameNotSpecified then
4911 wf_core.context('WF_XML','GenerateSummary',p_event_name, p_event_key);
4912 raise;
4913
4914 when others then
4915 wf_core.context('WF_XML','GenerateSummary',p_event_name, p_event_key);
4916 raise;
4917 end GenerateSummary;
4918
4919 -- Generate
4920 -- To generate the XML content for the enqueued notifications.
4921 function Generate(p_event_name in varchar2,
4922 p_event_key in varchar2,
4923 p_parameter_list in wf_parameter_list_t)
4924 return clob
4925 is
4926 l_doc CLOB;
4927 l_evt wf_event_t;
4928 l_parameters wf_parameter_list_t;
4929 l_erragt wf_agent_t;
4930
4931 begin
4932 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
4933 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
4934 'wf.plsql.WF_XML.generate', 'BEGIN');
4935 end if;
4936 -- We do not use the LOB pooling for the generate as the LOB
4937 -- is to be returned and not reused.
4938 dbms_lob.createTemporary(l_doc, TRUE, dbms_lob.call);
4939
4940 BEGIN
4941
4942 -- <<sstomar>>:
4943 -- Since base NLS parameters / context would be used in subsequent methods
4944 -- So better to set them here.
4945 --
4946 if(g_base_language is null or
4947 g_base_territory is null or
4948 g_base_codeset is NULL OR
4949 g_base_nlsDateFormat is NULL OR
4950 g_base_nlsDateLanguage is NULL OR
4951 g_base_nlsNumericCharacters is NULL OR
4952 g_base_nlsSort is NULL
4953 ) then
4954
4955 WF_NOTIFICATION_UTIL.getNLSContext(
4956 g_base_language ,
4957 g_base_territory ,
4958 g_base_codeset ,
4959 g_base_nlsDateFormat ,
4960 g_base_nlsDateLanguage ,
4961 g_base_nlsNumericCharacters ,
4962 g_base_nlsSort ,
4963 g_base_nlsCalendar );
4964
4965
4966
4967 end if;
4968
4969 -- <sstomar> bug 7130745 : added Question / Answere events
4970 if p_event_name in (wf_xml.WF_NTF_SEND_MESSAGE,
4971 wf_xml.WF_NTF_CANCEL,
4972 wf_xml.WF_NTF_REASIGN,
4973 wf_xml.WF_NTF_SEND_QUESTION,
4974 wf_xml.WF_NTF_SEND_ANSWER ) then
4975
4976 GenerateMessage(l_doc, p_event_name, p_event_key,
4977 p_parameter_list);
4978
4979 elsif p_event_name = WF_NTF_SEND_SUMMARY then
4980
4981
4982 -- Summary events.
4983 GenerateSummary (l_doc, p_event_name, p_event_key, p_parameter_list);
4984
4985 end if;
4986 exception
4987 when others then
4988 wf_core.context('WF_XML','Generate',p_event_name, p_event_key);
4989
4990 -- RESET BASSE LANGUAGE
4991 WF_NOTIFICATION_UTIL.SetNLSContext(null,
4992 g_base_language ,
4993 g_base_territory ,
4994 g_base_nlsDateFormat ,
4995 g_base_nlsDateLanguage ,
4996 g_base_nlsNumericCharacters ,
4997 g_base_nlsSort ,
4998 g_base_nlsCalendar );
4999
5000
5001 raise;
5002 end;
5003
5004 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
5005 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
5006 'wf.plsql.WF_XML.generate', 'END');
5007 end if;
5008 return l_doc;
5009
5010 end Generate;
5011
5012
5013 -- notificationIsOpen
5014 -- Return the current status of the notification
5015 function notificationIsOpen(nid in number) return boolean
5016 is
5017 l_open integer := 0;
5018 begin
5019 begin
5020 select 1
5021 into l_open
5022 from wf_notifications
5023 where notification_id = nid
5024 and status = 'OPEN';
5025 exception
5026 when others then l_open := 0;
5027 end;
5028 return l_open > 0;
5029 end notificationIsOpen;
5030
5031 -- GetResponseDetails
5032 -- Gets the response details from the incoming XML Notifiction
5033 -- structure.
5034 --
5035 -- IN
5036 -- message - The XML Notification structure containing the
5037 -- inbound response
5038 procedure getResponseDetails(message in CLOB)
5039 IS
5040
5041 l_node varchar2(4000);
5042 l_version integer;
5043 l_from_role varchar2(4000);
5044 l_responses wf_responseList_t;
5045
5046 begin
5047
5048 getResponseDetails(message => message,
5049 node => l_node,
5050 version => l_version,
5051 fromRole => l_from_role,
5052 responses => l_responses);
5053
5054 end getResponseDetails;
5055
5056 -- GetResponseDetails
5057 -- Gets the response details from the incoming XML Notifiction
5058 -- structure.
5059 --
5060 -- IN
5061 -- message - The XML Notification structure containing the
5062 -- inbound response
5063 procedure getResponseDetails(message in CLOB, node out NOCOPY varchar2,
5064 version out NOCOPY integer,
5065 fromRole out NOCOPY varchar2,
5066 responses in out NOCOPY wf_responseList_t)
5067 IS
5068
5069 p xmlparser.parser;
5070 doc xmldom.DOMDocument;
5071
5072 nl xmldom.DOMNodeList;
5073 len1 number;
5074 len2 number;
5075 n xmldom.DOMNode;
5076 m xmldom.DOMNode;
5077 nnm xmldom.DOMNamedNodeMap;
5078
5079 fromAddress varchar2(4000);
5080 attrname varchar2(4000);
5081 attrval varchar2(4000);
5082
5083 node_data varchar2(32000);
5084 node_name varchar2(4000);
5085 from_node_found boolean;
5086
5087 attribute_found boolean;
5088 response_count number;
5089
5090 response_attr_name varchar2(4000);
5091 response_attr_val varchar2(32000);
5092 response_attr_type varchar2(4000);
5093 response_attr_format varchar2(4000);
5094
5095 step varchar2(200);
5096
5097 begin
5098
5099 from_node_found := FALSE;
5100 attribute_found := FALSE;
5101 response_count := 0;
5102 responses.delete;
5103 node := '';
5104 fromRole := '';
5105
5106 -- new parser
5107 p := xmlparser.newParser;
5108
5109 -- set some characteristics
5110 xmlparser.setValidationMode(p, FALSE);
5111
5112 -- parse input file
5113 xmlparser.parseClob(p, message);
5114
5115 -- get document
5116 doc := xmlparser.getDocument(p);
5117
5118 -- get all elements
5119 nl := xmldom.getElementsByTagName(doc, '*');
5120 len1 := xmldom.getLength(nl);
5121
5122 -- loop through elements
5123 for j in 0..len1-1 loop
5124
5125 n := xmldom.item(nl, j);
5126 node_name := xmldom.getNodeName(n);
5127
5128 step := 'Processing ['||node_name||']';
5129 if node_name = 'NOTIFICATION' then
5130
5131 -- get all attributes of element
5132 nnm := xmldom.getAttributes(n);
5133
5134 if (xmldom.isNull(nnm) = FALSE) then
5135
5136 len2 := xmldom.getLength(nnm);
5137
5138 -- loop through attributes
5139 for i in 0..len2-1 loop
5140
5141 m := xmldom.item(nnm, i);
5142 attrname := xmldom.getNodeName(m);
5143
5144 step := 'Processing ['||node_name||'] ['||attrname||']';
5145
5146 if attrname = 'node' then
5147
5148 attrval := xmldom.getNodeValue(m);
5149 node := attrval;
5150 elsif attrname = 'version' then
5151
5152 attrval := xmldom.getNodeValue(m);
5153 begin
5154 version := to_number(attrval);
5155 exception
5156 when others then
5157 version := 0;
5158 end;
5159 end if;
5160
5161 end loop;
5162
5163
5164 end if;
5165
5166 elsif node_name = 'FROM' then
5167
5168 from_node_found := TRUE;
5169
5170 elsif node_name = 'NAME' then
5171
5172 if from_node_found then
5173
5174 n := xmldom.getFirstChild(n);
5175
5176 if ((not xmldom.isNull(n))
5177 and (xmldom.getNodeType(n) = xmldom.TEXT_NODE)) then
5178
5179 node_data := xmlDom.getNodeValue(n);
5180 fromRole := node_data;
5181
5182 end if;
5183
5184 end if;
5185
5186 elsif node_name = 'ADDRESS' then
5187
5188 if from_node_found then
5189
5190 from_node_found := FALSE;
5191
5192 n := xmldom.getFirstChild(n);
5193
5194 if ((not xmldom.isNull(n))
5195 and (xmldom.getNodeType(n) = xmldom.TEXT_NODE)) then
5196
5197 node_data := xmlDom.getNodeValue(n);
5198 fromAddress := node_data;
5199
5200 fromRole := '"'||fromRole||'" <'||fromAddress||'>';
5201
5202 end if;
5203
5204 end if;
5205
5206 elsif node_name = 'ATTRIBUTE' then
5207
5208 -- get all attributes of element
5209 nnm := xmldom.getAttributes(n);
5210
5211 if (xmldom.isNull(nnm) = FALSE) then
5212
5213 attribute_found := FALSE;
5214 response_attr_name := '';
5215 response_attr_val := '';
5216 response_attr_type := '';
5217 response_attr_format := '';
5218
5219 len2 := xmldom.getLength(nnm);
5220
5221 -- loop through attributes
5222 for i in 0..len2-1 loop
5223
5224 m := xmldom.item(nnm, i);
5225 attrname := xmldom.getNodeName(m);
5226
5227 step := 'Processing ['||node_name||'] ['||attrname||']';
5228
5229 if attrname = 'name' then
5230
5231 attribute_found := TRUE;
5232 attrval := xmldom.getNodeValue(m);
5233 response_attr_name := attrval;
5234
5235 elsif attrname = 'type' then
5236
5237 attrval := xmldom.getNodeValue(m);
5238 response_attr_type := attrval;
5239
5240 elsif attrname = 'format' then
5241
5242 attrval := xmldom.getNodeValue(m);
5243 response_attr_format := attrval;
5244
5245 end if;
5246
5247 end loop;
5248
5249 if attribute_found then
5250
5251 n := xmldom.getFirstChild(n);
5252
5253 if ((not xmldom.isNull(n)) and
5254 (xmldom.getNodeType(n) = xmldom.TEXT_NODE)) then
5255
5256 node_data := substrb(xmlDom.getNodeValue(n), 1, 32000);
5257 response_attr_val := node_data;
5258 end if;
5259
5260 response_count := response_count + 1;
5261 responses(response_count).NAME := response_attr_name;
5262 responses(response_count).TYPE := response_attr_type;
5263 responses(response_count).FORMAT := response_attr_format;
5264 responses(response_count).VALUE := response_attr_val;
5265
5266
5267 end if;
5268
5269 end if;
5270
5271 end if;
5272 step := 'Fishished {'||step||'}';
5273
5274 end loop;
5275
5276 if (not xmldom.isNull(doc)) then
5277 xmldom.freeDocument (doc);
5278 end if;
5279
5280 xmlparser.freeParser (p);
5281
5282 exception
5283
5284 when xmldom.INDEX_SIZE_ERR then
5285 wf_core.context('WF_XML','getResponseDetails', step);
5286 raise;
5287
5288 when xmldom.DOMSTRING_SIZE_ERR then
5289 wf_core.context('WF_XML','getResponseDetails', step);
5290 raise;
5291
5292 when xmldom.HIERARCHY_REQUEST_ERR then
5293 wf_core.context('WF_XML','getResponseDetails', step);
5294 raise;
5295
5296 when xmldom.WRONG_DOCUMENT_ERR then
5297 wf_core.context('WF_XML','getResponseDetails', step);
5298 raise;
5299
5300 when xmldom.INVALID_CHARACTER_ERR then
5301 wf_core.context('WF_XML','getResponseDetails', step);
5302 raise;
5303
5304 when xmldom.NO_DATA_ALLOWED_ERR then
5305 wf_core.context('WF_XML','getResponseDetails', step);
5306 raise;
5307
5308 when xmldom.NO_MODIFICATION_ALLOWED_ERR then
5309 wf_core.context('WF_XML','getResponseDetails', step);
5310 raise;
5311
5312 when xmldom.NOT_FOUND_ERR then
5313 wf_core.context('WF_XML','getResponseDetails', step);
5314 raise;
5315
5316 when xmldom.NOT_SUPPORTED_ERR then
5317 wf_core.context('WF_XML','getResponseDetails', step);
5318 raise;
5319
5320 when xmldom.INUSE_ATTRIBUTE_ERR then
5321 wf_core.context('WF_XML','getResponseDetails', step);
5322 raise;
5323
5324 when others then
5325 wf_core.context('WF_XML','getResponseDetails', step);
5326 raise;
5327
5328 end getResponseDetails;
5329
5330
5331 -- sendNotification
5332 -- This API is a wrapper to the wf_xml.enqueueNotification. It is provided
5333 -- as forward compatabilty for the original mailer since the call to
5334 -- wf_xml.enqueueNotification has been removed from
5335 -- wf_notification.sendSingle.
5336 -- To use the original mailer, one must enable the subscription that will
5337 -- call this rule function.
5338 -- IN
5339 -- p_subscription
5340 -- p_event
5341 -- RETURN
5342 -- varchar2 of the status
5343 function SendNotification (p_subscription_guid in raw,
5344 p_event in out NOCOPY WF_EVENT_T) return varchar2
5345 is
5346 l_eventName varchar2(80);
5347 l_eventkey varchar(80);
5348 l_nid number;
5349 begin
5350 l_eventkey := p_event.GetEventKey();
5351 l_nid := to_number(l_eventKey);
5352 l_eventName := p_event.GetEventName();
5353 if l_eventName in (wf_xml.WF_NTF_SEND_MESSAGE, wf_xml.WF_NTF_CANCEL,
5354 wf_xml.WF_NTF_REASIGN) then
5355 wf_xml.enqueueNotification(l_nid);
5356 else
5357 return wf_rule.default_rule(p_subscription_guid, p_event);
5358 end if;
5359 return 'SUCCESS';
5360 exception
5361 when others then
5362 wf_core.Context('WF_XML','SendNotification',p_event.getEventName(),
5363 p_subscription_guid);
5364 -- Save error message and set status to INVALID so mailer will
5365 -- bounce an "invalid reply" message to sender.
5366 wf_event.SetErrorInfo(p_event, 'ERROR');
5367 return 'ERROR';
5368 end sendNotification;
5369
5370
5371 -- handleRecevieEvent
5372 --
5373 function handleReceiveEvent(p_subscription_guid in raw,
5374 p_event in out NOCOPY WF_EVENT_T) return varchar2
5375 is
5376 l_eventName varchar2(80);
5377 l_eventkey varchar(80);
5378 l_paramlist wf_parameter_list_t;
5379 l_eventData CLOB;
5380 l_node varchar2(30);
5381 l_version integer;
5382 l_user varchar2(320);
5383 l_comment varchar2(4000);
5384 l_fromAddr varchar2(2000);
5385 l_nid number;
5386 l_template varchar2(30);
5387 l_module varchar2(200);
5388 l_error varchar2(2000);
5389 i int;
5390 l_responses wf_responseList_t;
5391 lk_type varchar2(240);
5392 lk_code varchar2(4000);
5393 lk_meaning varchar2(1000);
5394 l_value varchar2(4000);
5395 l_error_result varchar2(4000);
5396 l_sig_policy varchar2(100);
5397
5398 l_step varchar2(240);
5399 begin
5400
5401 l_eventkey := p_event.GetEventKey();
5402 l_nid := to_number(l_eventKey);
5403 l_eventName := p_event.GetEventName();
5404 l_paramList := p_event.getParameterList();
5405 l_eventData := p_event.getEventData();
5406
5407 -- Recieve the message.
5408 -- Unpack the content and pass it to the
5409 -- routine in charge of parsing it.
5410
5411 -- Allow the response handling handle the closed notification
5412 -- 3736816 Uncommenting and reimplementing this logic to
5413 -- ensure that responses to CANCELED notifications are processed
5414 -- but do not update anything.
5415 l_step := 'Checking the notification status';
5416 if not notificationIsOpen(l_nid) then
5417 begin
5418 lk_type := '';
5419 lk_code := '';
5420 wf_log_pkg.string(WF_LOG_PKG.LEVEL_EXCEPTION,
5421 'WF_XML.handleReceiveEvent',
5422 'Notification is not OPEN. Submitting response '||
5423 'to provide user feedback');
5424 Wf_Notification.Respond(l_nid, NULL, 'email:'||l_fromAddr);
5425 exception
5426 when others then
5427 if (wf_log_pkg.level_statement >= fnd_log.g_current_runtime_level) then
5428 wf_log_pkg.string(WF_LOG_PKG.level_statement,
5429 'wf.plsql.WF_XML.handleReceiveEvent',
5430 'Exception on call to Wf_Notification.Respond NID['||l_nid||'] '||
5431 'Error Msg '||sqlerrm);
5432 end if;
5433
5434 wf_core.Context('WF_XML','handleReceiveEvent',
5435 p_event.getEventName(), p_subscription_guid);
5436 -- Save error message and set status to INVALID so mailer will
5437 -- bounce an "invalid reply" message to sender.
5438 WF_MAIL.HandleResponseError(l_nid, lk_type, lk_code,
5439 l_error_result);
5440 end;
5441 return 'SUCCESS';
5442 end if;
5443
5444 l_step := 'Getting the response details';
5445 getResponseDetails(l_eventData, l_node, l_version, l_fromAddr,
5446 l_responses);
5447
5448 l_step := 'Processing the responses';
5449 if l_responses.COUNT > 0 then
5450 begin
5451 -- Check if this notification requires a Signature. Other than DEFAULT
5452 -- policies, no other policy is processed by the mailer.
5453 Wf_Mail.GetSignaturePolicy(l_nid, l_sig_policy);
5454 if (l_sig_policy is not NULL and upper(l_sig_policy) <> 'DEFAULT') then
5455 if (wf_log_pkg.level_statement >= fnd_log.g_current_runtime_level) then
5456 wf_log_pkg.string(WF_LOG_PKG.level_statement,
5457 'wf.plsql.WF_XML.handleReceiveEvent',
5458 'Signature policy is not DEFAULT');
5459 end if;
5460
5461 -- If a new policy is added, only wfmail.msg needs to be updated
5462 wf_core.context('WF_XML', 'HandleReceiveEvent',
5463 to_char(l_nid), l_node, l_fromAddr);
5464 wf_core.token('NID', to_char(l_nid));
5465 wf_core.raise('WFRSPR_' || l_sig_policy);
5466 end if;
5467
5468 for i in 1..l_responses.COUNT loop
5469 l_step := 'Processing the responses -> '||l_responses(i).name;
5470
5471 lk_type := l_responses(i).format;
5472
5473 lk_code := substrb(l_responses(i).value, 1, 4000);
5474
5475 if (wf_log_pkg.level_statement >= fnd_log.g_current_runtime_level) then
5476 wf_log_pkg.string(WF_LOG_PKG.level_statement,
5477 'wf.plsql.WF_XML.handleReceiveEvent',
5478 'Response VALUE ['||
5479 substrb(lk_code, 1, 100)||
5480 '] TYPE ['||lk_type||']');
5481 end if;
5482
5483 if l_version < 3 then
5484
5485 ----------------------------------
5486 -- verion < 3 is a normal response
5487 ----------------------------------
5488
5489 -- Process the responses for standard responses
5490 if l_responses(i).type = 'LOOKUP' then
5491 -- Verify the content of the lookup. This will raise
5492 -- an exception if it is not matched. GetLovMeaning
5493 -- allows for nulls. This is not acceptable here.
5494
5495 lk_meaning := wf_mail.GetLovMeaning(lk_type,
5496 lk_code);
5497 if lk_meaning is null then
5498 if (wf_log_pkg.level_statement >= fnd_log.g_current_runtime_level) then
5499 wf_log_pkg.string(WF_LOG_PKG.level_statement,
5500 'wf.plsql.WF_XML.handleReceiveEvent',
5501 'LOV Meaning is null');
5502 end if;
5503
5504 wf_core.token('TYPE', lk_type);
5505 wf_core.token('CODE', lk_code);
5506 wf_core.raise('WFSQL_LOOKUP_CODE');
5507 end if;
5508 end if;
5509 if (l_responses(i).type = 'MOREINFO') then
5510 null; -- discard these responses
5511 --else
5512 -- <<sstomar>> bug 8430385
5513 ELSIF ( l_responses(i).type = 'DATE' AND lk_code IS NOT null ) then --
5514 -- Just a note :
5515 -- fnd_date.canonical_to_date stores value in
5516 -- varchar2(30); so it may fail for values larger than (in bytes) that.
5517 --
5518 wf_notification.SetAttrDate(l_nid, l_responses(i).name,
5519 fnd_date.canonical_to_date(lk_code));
5520 elsif (l_responses(i).type = 'NUMBER' ) then
5521 wf_notification.SetAttrNumber(l_nid, l_responses(i).name,
5522 fnd_number.canonical_to_number(lk_code));
5523 else
5524 wf_notification.setAttrText(l_nid, l_responses(i).name,
5525 lk_code);
5526 end if;
5527 end if;
5528
5529 -- Only process attributes of type MOREINFO on
5530 -- version 3 and 4 templates.
5531 if l_responses(i).type = 'MOREINFO'
5532 and l_version in (3, 4) then
5533 if lk_code is not null then
5534 if l_version = 3 then
5535
5536 if l_responses(i).name = 'WFNTF_MOREINFO_FROM' then
5537 l_user := DecodeEntityReference(lk_code);
5538 elsif l_responses(i).name = 'WFNTF_MOREINFO_QPROMPT' then
5539 if length(l_responses(i).value) > 4000 then
5540 wf_core.context('WF_XML', 'HandleReceiveEvent',
5541 l_responses(i).type,
5542 l_responses(i).name, l_step);
5543 lk_code := substrb(l_responses(i).value, 1,
5544 1000);
5545 wf_core.raise('WFNTF_QUESTION_TOO_LARGE');
5546 end if;
5547 l_comment := lk_code;
5548 end if;
5549 elsif l_version = 4 then
5550 if l_responses(i).name = 'WFNTF_MOREINFO_APROMPT' then
5551 if length(l_responses(i).value) > 4000 then
5552 wf_core.context('WF_XML', 'HandleReceiveEvent',
5553 l_responses(i).type,
5554 l_responses(i).name, l_step);
5555 lk_code := substrb(l_responses(i).value, 1,
5556 1000);
5557 wf_core.raise('WFNTF_QUESTION_TOO_LARGE');
5558 end if;
5559 l_comment := lk_code;
5560 end if;
5561 end if;
5562 end if;
5563 end if;
5564 end loop;
5565
5566 -- Update the results of the more information to the
5567 -- comments table by calling the update API in the
5568 -- correct mode based on the template version.
5569 l_step := 'Updating the notification';
5570 if l_version = 3 then
5571 -- Question mode
5572 -- Send a email back to the sender that the More Info User is invalid
5573 if (l_user is null or length(trim(l_user)) = 0) then
5574 wf_core.raise('WFNTF_NO_ROLE');
5575 elsif(l_comment is null or length(trim(l_comment)) = 0) then
5576 wf_core.raise('WFNTF_NO_QUESTION');
5577 else
5578 wf_notification.UpdateInfo2(l_nid, l_user, l_fromAddr,
5579 l_comment);
5580 end if;
5581 elsif l_version = 4 then
5582 -- Answer mode
5583 l_user := null;
5584 if(l_comment is null or length(trim(l_comment)) = 0) then
5585 wf_core.raise('WFNTF_NO_ANSWER');
5586 else
5587 wf_notification.UpdateInfo2(l_nid, l_user, l_fromAddr,
5588 l_comment);
5589 end if;
5590 else
5591 -- Do not need to preserve context
5592 wf_engine.preserved_context := FALSE;
5593
5594 if (wf_log_pkg.level_statement >= fnd_log.g_current_runtime_level) then
5595 wf_log_pkg.string(WF_LOG_PKG.level_statement,
5596 'wf.plsql.WF_XML.handleReceiveEvent',
5597 'Calling Wf_Notification.Respond');
5598 end if;
5599
5600 Wf_Notification.Respond(nid => l_nid,
5601 responder => 'email:'||l_fromAddr);
5602 end if;
5603 exception
5604 when others then
5605 if (wf_log_pkg.level_statement >= fnd_log.g_current_runtime_level) then
5606 wf_log_pkg.string(WF_LOG_PKG.level_statement,
5607 'wf.plsql.WF_XML.handleReceiveEvent',
5608 'Exception in processing the Response. Step '||l_step||
5609 ' Error Msg '||sqlerrm);
5610 end if;
5611
5612 wf_core.Context('WF_XML','handleReceiveEvent',
5613 to_char(l_nid), 'Step '||l_step);
5614 wf_core.context('WF_MAIL','HandleRevieveEvent', to_char(l_nid));
5615 -- Save error message and set status to INVALID so mailer will
5616 -- bounce an "invalid reply" message to sender.
5617 WF_MAIL.HandleResponseError(l_nid, lk_type,
5618 substrb(lk_code, 1, 1000),
5619 l_error_result);
5620 end;
5621 end if;
5622 return 'SUCCESS';
5623
5624 exception
5625
5626 when others then
5627 wf_core.Context('WF_XML','handleReceiveEvent',p_event.getEventName(),
5628 p_subscription_guid);
5629 -- Save error message and set status to INVALID so mailer will
5630 -- bounce an "invalid reply" message to sender.
5631 wf_event.SetErrorInfo(p_event, 'ERROR');
5632 return 'ERROR';
5633
5634 end handleReceiveEvent;
5635
5636
5637 -- receive
5638 -- Handle the notification receive events
5639 -- This will handle the processing of the inbound responses
5640 -- IN
5641 -- p_subscription_guid - The RAW GUID of the event subscription
5642 -- p_event - The WF_EVENT_T containing the event information
5643 -- RETURN
5644 -- varchar2 of the status
5645 function receive (p_subscription_guid in raw,
5646 p_event in out NOCOPY WF_EVENT_T) return varchar2
5647 is
5648 l_eventName varchar2(80);
5649 result varchar2(30);
5650 erragt wf_agent_t;
5651 l_paramlist wf_parameter_list_t;
5652 errMsg varchar2(4000);
5653 errStack varchar2(4000);
5654
5655 begin
5656
5657 l_eventName := p_event.GetEventName();
5658 l_paramList := p_event.getParameterList();
5659
5660 if l_eventName = WF_NTF_RECEIVE_MESSAGE then
5661
5662 result := handleReceiveEvent(p_subscription_guid, p_event);
5663
5664 elsif l_eventName = WF_NTF_RECEIVE_ERROR then
5665 errMsg := wf_event.getValueForParameter('ERROR_MESSAGE',
5666 l_paramList);
5667 errStack := wf_event.getValueForParameter('ERROR_STACK',
5668 l_paramList);
5669 p_event.setErrorSubscription(p_subscription_guid);
5670 p_event.setErrorMessage(substrb(errMsg,1,4000));
5671 p_event.setErrorStack(substrb(errStack,1,4000));
5672 p_event.addParameterToList('ERROR_NAME', 'WF_NTF_RECEIVE_ERROR');
5673 p_event.addParameterToList('ERROR_TYPE', 'ERROR');
5674
5675 erragt := wf_agent_t('WF_ERROR', wf_event.local_system_name);
5676
5677 --
5678 -- sjm - lets just call the API directly
5679 --
5680 wf_error_qh.enqueue(p_event, erragt);
5681
5682 result := 'SUCCESS';
5683
5684 else
5685
5686 return wf_rule.default_rule(p_subscription_guid, p_event);
5687
5688 end if;
5689
5690 return result;
5691
5692 exception
5693
5694 when others then
5695 wf_core.Context('WF_XML','Receive',p_event.getEventName(),
5696 p_subscription_guid);
5697 -- Save error message and set status to INVALID so mailer will
5698 -- bounce an "invalid reply" message to sender.
5699 wf_event.SetErrorInfo(p_event, 'ERROR');
5700 return 'ERROR';
5701 end receive;
5702
5703 -- SummaryRule
5704 -- To handle the summary notification request event
5705 -- and call the approapriate summary generate function for
5706 -- either the role or the member of the role.
5707 -- IN
5708 -- p_subscription_guid The RAW GUID for the subscription
5709 -- p_event The WF_EVENT_T containing the event details
5710 -- OUT
5711 -- VARCHAR2 - The status
5712 function SummaryRule (p_subscription_guid in raw,
5713 p_event in out NOCOPY WF_EVENT_T) return varchar2
5714 is
5715 l_eventName varchar2(80);
5716 l_eventkey varchar(80);
5717 l_paramlist wf_parameter_list_t;
5718 type t_users is table of boolean index by varchar2(320);
5719 l_sum_users t_users ;
5720
5721 l_event_paramlist wf_parameter_list_t;
5722 -- NOTE: For bug 6049086, more_info_role is included in the SQL
5723 -- in order to send summary mail to more_info_role and not
5724 -- to recepient_role if notification more_info_role is not null.
5725 CURSOR c_get_summary_roles is
5726 SELECT recipient from
5727 (SELECT distinct nvl(more_info_role,recipient_role) recipient
5728 FROM wf_notifications
5729 WHERE mail_status is null
5730 AND status = 'OPEN'
5731 AND rownum > 0)
5732 WHERE Wf_Directory.GetRoleNtfPref(recipient) in ('SUMMARY', 'SUMHTML');
5733
5734 -- returns the roles with notification preference of 'QUERY'
5735 -- and having some open notifications
5736 CURSOR c_get_query_roles is
5737 SELECT recipient from
5738 (SELECT distinct nvl(more_info_role,recipient_role) recipient
5739 FROM wf_notifications
5740 WHERE mail_status is null
5741 AND status = 'OPEN'
5742 AND rownum > 0) , wf_roles wr
5743 WHERE recipient = wr.NAME
5744 AND wr.notification_preference = 'QUERY';
5745
5746
5747 -- returns the users having the notification preference of
5748 -- 'SUMMARY' or 'SUMHTML' for the given role
5749 CURSOR c_get_sum_users(p_roleName VARCHAR2) is
5750 SELECT user_name
5751 FROM wf_user_roles wu, wf_roles wr
5752 WHERE wu.role_name = p_roleName
5753 AND wr.name = wu.user_name
5754 AND wu.user_orig_system = wr.orig_system
5755 AND wu.user_orig_system_id = wr.orig_system_id
5756 AND wr.notification_preference in ('SUMMARY', 'SUMHTML');
5757
5758
5759 begin
5760
5761 l_eventkey := p_event.GetEventKey();
5762 l_eventName := p_event.GetEventName();
5763 l_paramList := p_event.getParameterList();
5764
5765 for rec_summary_role in c_get_summary_roles loop
5766
5767 l_event_paramlist := wf_parameter_list_t();
5768 wf_event.addParameterToList('ROLE_NAME',
5769 rec_summary_role.RECIPIENT,
5770 l_event_paramlist);
5771 -- Set AQs correlation id to item type i.e. 'WFMAIL'
5772 wf_event.addParameterToList('Q_CORRELATION_ID', 'WFMAIL:SUM',
5773 l_event_paramlist);
5774 wf_event.addParameterToList('NOTIFICATION_ID', '0',
5775 l_event_paramlist);
5776
5777 wf_event.raise(WF_NTF_SEND_SUMMARY,
5778 rec_summary_role.RECIPIENT||':'||sysdate,
5779 null, l_event_paramlist);
5780 -- adds the users to the table l_sum_users
5781 l_sum_users(rec_summary_role.RECIPIENT) := true;
5782 end loop;
5783
5784 -- Bug 8675013: raises the summary event for the users with notification
5785 -- preference of 'SUMMARY' or 'SUMHTML' and having open
5786 -- notifications received through their roles i.e the users having
5787 -- open notifications with preference of 'SUMMARY' or
5788 -- 'SUMHTML' and whose role preference is 'QUERY'
5789
5790 for rec_query_role IN c_get_query_roles loop
5791
5792 FOR rec_role_user IN c_get_sum_users(rec_query_role.recipient) loop
5793
5794 -- Checks that the summary event is already raised for the user in
5795 -- cursor 'c_get_summary_roles'. If not, then only raise the event here
5796 if(not l_sum_users.exists(rec_role_user.user_name)) then
5797 l_event_paramlist := wf_parameter_list_t();
5798 wf_event.addParameterToList('ROLE_NAME',
5799 rec_role_user.user_name,
5800 l_event_paramlist);
5801 -- Set AQs correlation id to item type i.e. 'WFMAIL'
5802 wf_event.addParameterToList('Q_CORRELATION_ID', 'WFMAIL:SUM',
5803 l_event_paramlist);
5804 wf_event.addParameterToList('NOTIFICATION_ID', '0',
5805 l_event_paramlist);
5806 wf_event.raise(WF_NTF_SEND_SUMMARY,
5807 rec_role_user.user_name||':'||sysdate,
5808 null, l_event_paramlist);
5809 end if;
5810
5811 END LOOP;
5812 END LOOP;
5813
5814 return 'SUCCESS';
5815
5816 exception
5817
5818 when others then
5819 wf_core.Context('WF_XML','SummaryRule',p_event.getEventName(),
5820 p_subscription_guid);
5821 wf_event.SetErrorInfo(p_event, 'ERROR');
5822 return 'ERROR';
5823 end SummaryRule;
5824
5825 -- Parse the XML message and seperate out the main elements
5826 -- so that a new notification can be constructed including
5827 -- the information on the previous email.
5828 procedure getMessageDetails(pmessage IN CLOB,
5829 pnode OUT NOCOPY varchar2,
5830 planguage OUT NOCOPY varchar2,
5831 pterritory OUT NOCOPY varchar2,
5832 pcodeset OUT NOCOPY varchar2,
5833 pcontentBody OUT NOCOPY varchar2,
5834 psubject OUT NOCOPY varchar2,
5835 pFromRole OUT NOCOPY varchar2,
5836 pFromAddress OUT NOCOPY varchar2)
5837 is
5838 p xmlparser.parser;
5839 doc xmldom.DOMDocument;
5840
5841 nl xmldom.DOMNodeList;
5842 len1 number;
5843 len2 number;
5844 n xmldom.DOMNode;
5845 m xmldom.DOMNode;
5846 nnm xmldom.DOMNamedNodeMap;
5847
5848 from_node_found boolean := FALSE;
5849 fromRole varchar2(4000);
5850 fromAddress varchar2(4000);
5851
5852 node_data varchar2(4000);
5853 node_name varchar2(4000);
5854 attrname varchar2(4000);
5855 attrval varchar2(4000);
5856
5857
5858 subject varchar2(4000);
5859
5860 contentType varchar2(4000);
5861 textPlain_found boolean := FALSE;
5862
5863 begin
5864
5865 -- new parser
5866 p := xmlparser.newParser;
5867
5868 -- set some characteristics
5869 xmlparser.setValidationMode(p, FALSE);
5870
5871 -- parse input file
5872 xmlparser.parseClob(p, pmessage);
5873
5874 -- get document
5875 doc := xmlparser.getDocument(p);
5876
5877 -- get all elements
5878 nl := xmldom.getElementsByTagName(doc, '*');
5879 len1 := xmldom.getLength(nl);
5880
5881 -- loop through elements
5882 for j in 0..len1-1 loop
5883 n := xmldom.item(nl, j);
5884 node_name := xmldom.getNodeName(n);
5885
5886 if node_name = 'NOTIFICATION' then
5887 -- get all attributes of element
5888 nnm := xmldom.getAttributes(n);
5889
5890 if (xmldom.isNull(nnm) = FALSE) then
5891
5892 len2 := xmldom.getLength(nnm);
5893
5894 -- loop through attributes
5895 for i in 0..len2-1 loop
5896 m := xmldom.item(nnm, i);
5897 attrname := xmldom.getNodeName(m);
5898 if attrname = 'node' then
5899 attrval := xmldom.getNodeValue(m);
5900 pnode := attrval;
5901 -- exit;
5902 elsif attrname = 'language' then
5903 attrval := xmldom.getNodeValue(m);
5904 planguage := attrval;
5905 elsif attrname = 'territory' then
5906 attrval := xmldom.getNodeValue(m);
5907 pterritory := attrval;
5908 elsif attrname = 'codeset' then
5909 attrval := xmldom.getNodeValue(m);
5910 pcodeset := attrval;
5911 end if;
5912
5913 end loop;
5914 end if;
5915 elsif node_name = 'SUBJECT' then
5916 n := xmldom.getFirstChild(n);
5917
5918 if ((not xmldom.isNull(n)) and
5919 (xmldom.getNodeType(n) = xmldom.TEXT_NODE)) then
5920
5921 node_data := xmlDom.getNodeValue(n);
5922 psubject := node_data;
5923
5924 end if;
5925
5926 elsif node_name = 'FROM' then
5927 from_node_found := TRUE;
5928
5929 elsif node_name = 'NAME' then
5930 if from_node_found then
5931 n := xmldom.getFirstChild(n);
5932
5933 if ((not xmldom.isNull(n)) and
5934 (xmldom.getNodeType(n) = xmldom.TEXT_NODE)) then
5935
5936 node_data := xmlDom.getNodeValue(n);
5937 pfromRole := node_data;
5938
5939 end if;
5940 end if;
5941 elsif node_name = 'ADDRESS' then
5942 if from_node_found then
5943
5944 from_node_found := FALSE;
5945
5946 n := xmldom.getFirstChild(n);
5947
5948 if ((not xmldom.isNull(n)) and
5949 (xmldom.getNodeType(n) = xmldom.TEXT_NODE)) then
5950
5951 node_data := xmlDom.getNodeValue(n);
5952 pfromAddress := node_data;
5953
5954 end if;
5955 end if;
5956 elsif node_name = 'MESSAGE' then
5957
5958 nnm := xmldom.getAttributes(n);
5959
5960 if (xmldom.isNull(nnm) = FALSE) then
5961
5962 len2 := xmldom.getLength(nnm);
5963
5964 -- loop through attributes
5965 for i in 0..len2-1 loop
5966 m := xmldom.item(nnm, i);
5967 attrname := xmldom.getNodeName(m);
5968 if upper(attrname) = 'CONTENT-TYPE' then
5969 attrval := xmldom.getNodeValue(m);
5970 contentType := attrval;
5971 exit;
5972 end if;
5973 end loop;
5974 textPlain_found := upper(contentType) = 'TEXT/PLAIN';
5975 end if;
5976 if textPlain_found then
5977 n := xmldom.getFirstChild(n);
5978
5979 if ((not xmldom.isNull(n)) and
5980 (xmldom.getNodeType(n) = xmldom.TEXT_NODE)) then
5981
5982 node_data := xmlDom.getNodeValue(n);
5983 pcontentBody := node_data;
5984 end if;
5985 end if;
5986 end if;
5987 end loop;
5988
5989 end getMessageDetails;
5990
5991 FUNCTION error_rule(p_subscription_guid in raw,
5992 p_event in out nocopy wf_event_t) return varchar2
5993 is
5994 nid number;
5995 param_list wf_parameter_list_t;
5996 cb varchar2(240);
5997 ctx varchar2(2000);
5998 itemType varchar2(8);
5999 itemKey varchar2(240);
6000 items pls_integer;
6001 role varchar2(320);
6002
6003 colPos1 pls_integer;
6004 colPos2 pls_integer;
6005
6006 error_name varchar2(4000);
6007 error_msg varchar2(4000);
6008 error_stack varchar2(4000);
6009
6010 -- Dynamic sql stuff
6011 sqlbuf varchar2(120);
6012 tvalue varchar2(4000) := '';
6013 nvalue number := '';
6014 dvalue date := '';
6015 command varchar2(200) :='ERROR';
6016
6017 status varchar2(8);
6018 l_dummy varchar2(1);
6019
6020 begin
6021 param_list := p_event.Parameter_List;
6022 nid := to_number(wf_event.getValueForParameter('NOTIFICATION_ID',
6023 param_list));
6024 error_msg := p_event.getErrorMessage;
6025 error_stack := p_event.getErrorStack;
6026 begin
6027 select MESSAGE_TYPE, CALLBACK, CONTEXT, STATUS
6028 into itemType, cb, ctx, status
6029 from WF_NOTIFICATIONS
6030 where NOTIFICATION_ID = nid;
6031
6032 -- If the notification is closed, then do not bother
6033 -- to process any errors.
6034 if status = 'CLOSED' then
6035 return 'SUCCESS';
6036 end if;
6037
6038 update wf_notifications
6039 set mail_status = 'ERROR'
6040 where notification_id = nid;
6041
6042 if ctx is not null then
6043 colPos1 := instrb(ctx, ':', 1);
6044 colPos2 := instrb(ctx, ':', -1);
6045 if colPos1 > 0 and colPos2 > 0 then
6046 itemKey := substrb(ctx, colPos1+1, (colPos2 - colPos1) -1);
6047 else
6048 itemType := null;
6049 itemKey := null;
6050 end if;
6051 else
6052 itemType := null;
6053 itemKey := null;
6054 end if;
6055
6056 exception
6057 when others then
6058 cb := null;
6059 ctx := null;
6060 itemType := null;
6061 itemKey := null;
6062 return 'SUCCESS';
6063 end;
6064
6065 -- Check to see if the item type still exists and is not
6066 -- complete. If it does not exist or is complete, then
6067 -- do not bother with processing the error.
6068 if itemType is not null and itemKey is not null then
6069 begin
6070 select ACTIVITY_STATUS
6071 into status
6072 from wf_item_activity_statuses ias
6073 , wf_process_activities pa
6074 where ias.item_type = itemType
6075 and ias.item_key = itemKey
6076 and ias.process_activity = pa.instance_id
6077 and pa.process_name = 'ROOT';
6078
6079 -- This will prevent FYI message that are in error being reported.
6080 -- if status = wf_engine.eng_completed then
6081 -- return 'SUCCESS';
6082 -- end if;
6083
6084 exception
6085 when no_data_found then
6086 return 'SUCCESS';
6087 when others then
6088 error_msg := sqlerrm;
6089 wf_core.context('WF_XML','ERROR_RULE','NID['||to_char(nid)||']',
6090 'CTX['||ctx||']');
6091 raise;
6092 end;
6093 else
6094 return 'SUCCESS';
6095 end if;
6096
6097 if cb is not null then
6098 -- Put the error onto the stack.
6099 begin
6100 wf_core.token('ERROR_MESSAGE', error_msg);
6101 wf_core.token('ERROR_STACK', error_stack);
6102 wf_core.raise('WF_ERROR');
6103 exception
6104 when others then null;
6105 end;
6106 l_dummy := '';
6107 -- ### cb is from table
6108 -- BINDVAR_SCAN_IGNORE
6109 sqlbuf := 'begin '||cb||
6110 '(:p1, :p2, :p3, :p4, :p5, :p6, :p7); end;';
6111 begin
6112 execute immediate sqlbuf using
6113 in command,
6114 in ctx,
6115 in l_dummy,
6116 in l_dummy,
6117 in out tvalue,
6118 in out nvalue,
6119 in out dvalue;
6120 exception
6121 when others then
6122 error_msg := sqlerrm;
6123 wf_core.context('WF_XML','ERROR_RULE','NID['||to_char(nid)||']',
6124 'CTX['||ctx||']');
6125 raise;
6126 end;
6127 end if;
6128
6129 return wf_rule.error_rule(p_subscription_guid, p_event);
6130
6131 end error_rule;
6132
6133 -- Gets the LOB content for a PLSQLCLOB
6134 -- IN
6135 -- pAPI the API to call
6136 -- pDoc The LOB to take the document
6137 procedure getDocContent(pNid in NUMBER, pAPI in VARCHAR2,
6138 pDoc in out nocopy CLOB)
6139 is
6140 colon pls_integer;
6141 slash pls_integer;
6142 procname varchar2(240);
6143 procarg varchar2(32000);
6144
6145 target varchar2(240) := '_main';
6146 disptype varchar2(240) := g_ntfDocHtml;
6147 doctype varchar2(240);
6148
6149 sqlbuf varchar2(2000);
6150
6151 begin
6152
6153 colon := instr(pAPI, ':');
6154 slash := instr(pAPI, '/');
6155 if (slash = 0) then
6156 procname := substr(pAPI, colon+1);
6157 procarg := '';
6158 else
6159 procname := substr(pAPI, colon+1, slash-colon-1);
6160 procarg := substr(pAPI, slash+1);
6161 end if;
6162
6163 -- Dynamic sql call to procedure
6164
6165 if (procarg is null) then
6166 procarg := '-dummy-';
6167 elsif pNid > 0 then
6168 procarg := Wf_Notification.GetText(procarg, pNid, disptype);
6169 end if;
6170
6171 sqlbuf := 'begin '||procname||'(:p1, :p2, :p3, :p4); end;';
6172 execute immediate sqlbuf using
6173 in procarg,
6174 in disptype,
6175 in out pDoc,
6176 in out doctype;
6177
6178 end getDocContent;
6179
6180 -- Gets the LOB content for a PLSQLCLOB
6181 -- IN
6182 -- pAPI the API to call
6183 -- pDoc The LOB to take the document
6184 procedure getBDocContent(pNid in NUMBER, pAPI in VARCHAR2,
6185 pDoc in out nocopy BLOB)
6186 is
6187
6188 colon pls_integer;
6189 slash pls_integer;
6190 procname varchar2(240);
6191 procarg varchar2(32000);
6192
6193 target varchar2(240) := '_main';
6194 disptype varchar2(240) := g_ntfDocHtml;
6195 doctype varchar2(240);
6196
6197 sqlbuf varchar2(2000);
6198
6199 begin
6200
6201 colon := instr(pAPI, ':');
6202 slash := instr(pAPI, '/');
6203 if (slash = 0) then
6204 procname := substr(pAPI, colon+1);
6205 procarg := '';
6206 else
6207 procname := substr(pAPI, colon+1, slash-colon-1);
6208 procarg := substr(pAPI, slash+1);
6209 end if;
6210
6211 -- Dynamic sql call to procedure
6212
6213 if (procarg is null) then
6214 procarg := '-dummy-';
6215 elsif pNid > 0 then
6216 procarg := Wf_Notification.GetText(procarg, pNid, disptype);
6217 end if;
6218
6219 sqlbuf := 'begin '||procname||'(:p1, :p2, :p3, :p4); end;';
6220 execute immediate sqlbuf using
6221 in procarg,
6222 in disptype,
6223 in out pDoc,
6224 in out doctype;
6225
6226 end getBDocContent;
6227
6228 -- gets the size of the current LOB table
6229 function getLobTableSize return number
6230 is
6231 begin
6232 return g_LOBTable.COUNT;
6233 end;
6234
6235
6236 -- Send_Rule - This is the subscription rule function for the event group
6237 -- 'oracle.apps.wf.notification.send.group'. If the message
6238 -- payload is not complete return 'SUCCESS' from here, hence
6239 -- incomplete message payload/event will not be enqueued to
6240 -- WF_NOTIFICATION_OUT AQ.
6241 -- IN
6242 -- p_subscription_guid Subscription GUID as a CLOB
6243 -- p_event Event Message
6244 -- OUT
6245 -- Status as ERROR, SUCCESS, WARNING
6246 function Send_Rule(p_subscription_guid in raw,
6247 p_event in out nocopy wf_event_t)
6248 return varchar2
6249 is
6250 l_eventdata CLOB := p_event.event_data;
6251 l_fulldocloc number;
6252 l_eventKey varchar2(240) := p_event.getEventKey();
6253 begin
6254
6255 -- If the notification is to be sent to a role whose message payload
6256 -- has multiple values for 'full-document' parameter, in that case
6257 -- we should enqueue the notification to WF_NOTIFICATION_OUT queue
6258 -- so that email notification will be sent to the users having the
6259 -- full-document="Y" value
6260
6261 l_fulldocloc := dbms_lob.instr(l_eventdata, 'full-document="Y"', 1, 1);
6262
6263 -- If string not found checking for the lower case letter
6264 if( l_fulldocloc <= 0) then
6265 l_fulldocloc := dbms_lob.instr(l_eventdata, 'full-document="y"', 1, 1);
6266 end if;
6267
6268 if (l_fulldocloc > 0) then
6269 if (wf_log_pkg.level_statement >= fnd_log.g_current_runtime_level) then
6270 wf_log_pkg.string(wf_log_pkg.level_statement,
6271 'wf.plsql.WF_XML.Send_Rule',
6272 'Full Message for the event key '||l_eventKey||'.'
6273 ||'Running the default rule function.');
6274 end if;
6275 return wf_rule.default_rule(p_subscription_guid, p_event);
6276 else
6277
6278 if (wf_log_pkg.level_statement >= fnd_log.g_current_runtime_level) then
6279 wf_log_pkg.string(wf_log_pkg.level_statement,
6280 'wf.plsql.WF_XML.Send_Rule',
6281 'No Full Message for the event key '||l_eventKey||'.'
6282 ||'NOT enquing the message into WF_NOTIFICATION_OUT queue.');
6283 end if;
6284 return 'SUCCESS';
6285 end if;
6286
6287 end Send_Rule;
6288
6289
6290 end WF_XML;