1 PACKAGE BODY JDR_UTILS AS
2 /* $Header: JDRUTEXB.pls 120.3 2005/10/26 06:15:47 akbansal noship $ */
3
4 NEWLINE CONSTANT VARCHAR2(1) := '
5 ';
6
7 -----------------------------------------------------------------------------
8 ---------------------------- PRIVATE METHODS --------------------------------
9 -----------------------------------------------------------------------------
10
11 -- Gets the document ID for a fully qualified document name.
12 --
13 -- Parameters:
14 -- p_document - fully qualified name
15 --
16 -- p_type - the type of document to search for. In the jrad
17 -- repository, there are the following types of
18 -- jrad paths.
19 -- (1) Document file - XML file representing a document
20 -- (2) Package file - XML file representing a package
21 -- (3) Child document - document inside a package file
22 -- (4) Package directory - a directory
23 --
24 -- This parameter can be one of the following:
25 -- DOCUMENT - matches (1) and (3) above
26 -- PACKAGE - matches (2) and (4) above
27 -- FILE - matches (1) and (2) above
28 -- NONPATH - matches (1) and (2) and (3)
29 -- PATH - matches (4) above
30 -- ANY - matches (1) and (2) and (3) and (4) above
31 FUNCTION getDocumentID(
32 p_document VARCHAR2,
33 p_type VARCHAR2 DEFAULT 'ANY') RETURN jdr_paths.path_docid%TYPE
34 IS
35 docID jdr_paths.path_docid%TYPE;
36 pathType jdr_paths.path_type%TYPE;
37 pathSeq jdr_paths.path_seq%TYPE;
38 BEGIN
39 -- Get the ID of the document
40 docID := jdr_mds_internal.getDocumentID(p_document);
41
42 -- Verify that we have found a document of the correct type
43 IF ((docID <> -1) AND (p_type <> 'ANY')) THEN
44 SELECT path_type, path_seq INTO pathType, pathSeq
45 FROM jdr_paths WHERE path_docid = docID;
46
47 IF (p_type = 'FILE') THEN
48 -- Make sure we are dealing with a document or package file
49 IF ((pathType = 'DOCUMENT' AND pathSeq = -1) OR
50 (pathType = 'PACKAGE' AND pathSeq = 0)) THEN
51 RETURN (docID);
52 END IF;
53 ELSIF (p_type = 'DOCUMENT') THEN
54 -- Make sure we are dealing with a document
55 IF (pathType = 'DOCUMENT') THEN
56 RETURN (docID);
57 END IF;
58 ELSIF (p_type = 'PACKAGE') THEN
59 IF (pathType = 'PACKAGE') THEN
60 RETURN (docID);
61 END IF;
62 ELSIF (p_type = 'PATH') THEN
63 IF ((pathType = 'PACKAGE') AND (pathSeq = -1)) THEN
64 RETURN (docID);
65 END IF;
66 ELSIF (p_type = 'NONPATH') THEN
67 IF ((pathType <> 'PACKAGE') OR (pathSeq = 0)) THEN
68 RETURN (docID);
69 END IF;
70 END IF;
71
72 -- No match found
73 RETURN (-1);
74 END IF;
75
76 RETURN (docID);
77
78 EXCEPTION
79 WHEN OTHERS THEN
80 RETURN (-1);
81 END;
82
83
84 -- Prints a chunk of JRAD XML. Since we are using DBMS_OUPUT to print
85 -- the document to the console and since DBMS_OUPUT has lots of limitations,
86 -- this procedure is a lot more complicated that it should be.
87 --
88 -- Parameters:
89 -- p_chunk - the chunk of XML to print
90 --
91 -- p_maxLineSize - the maximum allowable size for the line.
92 --
93 -- p_unclosedQuote - TRUE indicates that the previous line was in the
94 -- middle of a name/value pair. Also, if the current
95 -- line is in the middle of a name/value pair, this
96 -- will be set to TRUE; if not, this will be set to
97 -- FALSE.
98 --
99 -- p_indent - amount of whitespace which the current line should be
100 -- indented. ALso, this will be set to the amount of
101 -- whitespace the next line should be indented. This
102 -- is needed for when an element does not completely
103 -- fit on one line.
104 --
105 PROCEDURE printChunk(
106 p_chunk IN VARCHAR2,
107 p_maxLineSize IN NUMBER,
108 p_unclosedQuote IN OUT NOCOPY /* file.sql.39 change */ BOOLEAN,
109 p_indent IN OUT NOCOPY /* file.sql.39 change */ NUMBER)
110 IS
111 left VARCHAR2(255);
112 right VARCHAR2(32767);
113 tmppos NUMBER;
114 pos NUMBER;
115 len NUMBER;
116 BEGIN
117 -- If the chunk is less than the maximum line size (including the
118 -- starting position), then all we need to do is simply print the chunk
119 -- and reset the starting position.
120 len := LENGTH(p_chunk) + p_indent;
121 IF (len <= p_maxLineSize) THEN
122 DBMS_OUTPUT.PUT_LINE(LPAD(p_chunk, len));
123
124 -- As we are "ending" an element, we can safely reset the "state"
125 p_indent := 0;
126 p_unclosedQuote := FALSE;
127
128 RETURN;
129 END IF;
130
131 -- We could not put the chunk in one line, so we have some work to do.
132 -- Here is an explanation of the general algorithm...
133 --
134 -- (1) Find the position in which the element ends. If it ends before
135 -- the maximum line size is ended, then we can print the element here
136 -- and recursively call printChunk() to print the remaining portion
137 -- of the chunk.
138 --
139 -- (2) If the element can not fit on the line, then we will print as
140 -- many name/value pairs of the element which will fit on the line.
141 -- And to make the printing "prettier", we will indent the next line
142 -- to the beginning of where the first name/value pair started.
143 --
144 -- (3) If not a single name/value pair can fit on the line, then we attempt
145 -- to break up the name/value pair using whitespace; and set the
146 -- p_unclosedQuote parameter to indicate we are in the middle of a
147 -- name/value pair.
148 --
149 -- (4) If we can not even break up the name/value pair using whitespace,
150 -- then we simply print as much of the value as we can and hope that
151 -- it will look ok.
152 pos := INSTR(p_chunk, NEWLINE, 1);
153 IF (pos = 0) THEN
154 pos := INSTR(p_chunk, '>', 1);
155 ELSE
156 pos := pos - 1;
157 END IF;
158
159 -- There should always be an end tag. If not something is very wrong.
160 IF (pos = 0) THEN
161 DBMS_OUTPUT.PUT_LINE('Error printing document, no end tag encountered.');
162 RETURN;
163 END IF;
164
165 -- If the current element can not fit on the line, so we will have to put
166 -- part of the element on this line, and the rest on future lines.
167 IF ((pos + p_indent) > p_maxLineSize) THEN
168 tmppos := 0;
169 pos := 0;
170 left := SUBSTR(p_chunk, 1, p_maxLineSize - p_indent);
171 LOOP
172 -- Find as many name/value pairs as will fit on this line. If
173 -- p_unclosedQuote is TRUE, then the previous line did not complete
174 -- the name/value pair, so we just need to look for one double quote.
175 -- Otherwise, two double quotes indicate that a name/value pair is
176 -- ended.
177 IF (p_unclosedQuote) THEN
178 tmppos := INSTR(left, '"', pos + 1, 1);
179 ELSE
180 tmppos := INSTR(left, '"', pos + 1, 2);
181 END IF;
182
183 -- Look for another name/value pair if we found a match.
184 IF (tmppos = 0) THEN
185 IF (pos > 0) THEN
186 -- If we found at least one name/value pair, then we are ok to
187 -- print the parial element. This corresponds to (2) above.
188 p_unclosedQuote := FALSE;
189 EXIT;
190 ELSE
191 -- We are not able to put a name/value pair on the current line.
192 -- This is likely because of a very long value. The best thing we
193 -- can do is try to end the line on a space. If we do find a
194 -- space, this will correspond to (3) above.
195 pos := INSTR(left, ' ', -1);
196 IF (pos = 0) THEN
197 -- We have a very long value with no spaces in it - this
198 -- corresponds to (4) above.
199 pos := p_maxLineSize - p_indent;
200 END IF;
201 p_unclosedQuote := TRUE;
202 EXIT;
203 END IF;
204 END IF;
205
206 -- A name/value pair which fits on the current line has been found.
207 -- Save the position and check if any more name/value pairs can fit on
208 -- this line.
209 pos := tmppos;
210 END LOOP;
211
212 -- Print the partial element
213 left := LPAD(SUBSTR(p_chunk, 1, pos), pos + p_indent);
214 DBMS_OUTPUT.PUT_LINE(left);
215
216 -- Remember indentation for the next line
217 IF (p_indent = 0) THEN
218 p_indent := LENGTH(left) -
219 LENGTH(LTRIM(left)) +
220 INSTR(LTRIM(left), ' ', 1);
221 END IF;
222
223 -- Get the remaining portion of the chunk
224 right := LTRIM(SUBSTR(p_chunk, pos + 1));
225 ELSE
226 -- This corresponds to (1) above, the element fitting on one line.
227 -- Print the element
228 left := LPAD(SUBSTR(p_chunk, 1, pos), pos + p_indent);
229 DBMS_OUTPUT.PUT_LINE(left);
230
231 -- As we are "ending" an element, we can safely reset the "state"
232 p_indent := 0;
233 p_unclosedQuote := FALSE;
234
235 -- Get the remaining portion of the chunk
236 tmppos := INSTR(p_chunk, NEWLINE, pos + 1);
237 right := SUBSTR(p_chunk, tmppos + 1);
238 END IF;
239
240 -- Print the remaining string
241 printChunk(right, p_maxLineSize, p_unclosedQuote, p_indent);
242 END;
243
244
245 PROCEDURE printChunk(p_chunk IN VARCHAR2, p_maxLineSize NUMBER)
246 IS
247 unclosedQuote BOOLEAN := FALSE;
248 indent NUMBER := 0;
249 BEGIN
250 printChunk(p_chunk, p_maxLineSize, unclosedQuote, indent);
251 END;
252
253
254 -----------------------------------------------------------------------------
255 ---------------------------- PUBLIC METHODS ---------------------------------
256 -----------------------------------------------------------------------------
257
258 -- Deletes the document from the repository.
259 --
260 -- Parameters:
261 -- p_document - the fully qualified document name, which can represent
262 -- either a document or package file.
263 -- (i.e. '/oracle/apps/ak/attributeSets')
264 --
265 PROCEDURE deleteDocument(p_document VARCHAR2)
266 IS
267 docID JDR_PATHS.PATH_DOCID%TYPE;
268 BEGIN
269 -- Get the ID of the document
270 docID := getDocumentID(p_document, 'FILE');
271 IF (docID = -1) THEN
272 dbms_output.put_line('Error: Could not find document ' || p_document);
273 RETURN;
274 END IF;
275
276 -- Drop the document
277 jdr_mds_internal.dropDocument(docID);
278 dbms_output.put_line('Successfully deleted document ' || p_document || '.');
279 END;
280
281 -- Deletes all empty customization documents from the repository
282 PROCEDURE deleteEmptyCustomizations
283 IS
284 CURSOR c_docs IS
285 SELECT path_docid
286 FROM jdr_paths
287 WHERE jdr_mds_internal.getDocumentName(path_docid)
288 LIKE '%/customizations/%' AND
289 path_type = 'DOCUMENT';
290 CURSOR c_comps(docID JDR_COMPONENTS.COMP_DOCID%TYPE) IS
291 SELECT comp_element
292 FROM jdr_components
293 WHERE comp_docid = docID;
294 CURSOR c_atts(docID JDR_ATTRIBUTES.ATT_COMP_DOCID%TYPE,
295 compID JDR_ATTRIBUTES.ATT_COMP_SEQ%TYPE) IS
296 SELECT att_name
297 FROM jdr_attributes
298 WHERE att_comp_docid = docID AND
299 att_comp_seq = compID;
300 docID JDR_PATHS.PATH_DOCID%TYPE;
301 compElem JDR_COMPONENTS.COMP_ELEMENT%TYPE;
302 attName JDR_ATTRIBUTES.ATT_NAME%TYPE;
303 compsIsEmpty BOOLEAN;
304 attsIsEmpty BOOLEAN;
305 BEGIN
306 dbms_output.enable(1000000);
307 -- Loop through all customization documents in the repository
308 OPEN c_docs;
309 LOOP
310 FETCH c_docs INTO docID;
311 IF (c_docs%NOTFOUND) THEN
312 CLOSE c_docs;
313 EXIT;
314 END IF;
315 compsIsEmpty := TRUE;
316 attsIsEmpty := FALSE;
317 -- For each document, loop through all component names
318 OPEN c_comps(docID);
319 LOOP
320 FETCH c_comps INTO compElem;
321 IF (c_comps%NOTFOUND) THEN
322 CLOSE c_comps;
323 EXIT;
324 END IF;
325 -- If the component name is not 'customization', 'modifications', or
326 -- 'view', then this is not an empty customization document.
327 -- Modifications may be an element, rather than a grouping, if it
328 -- appears in the form <modifications/>
329 IF compElem <> 'customization' AND
330 compElem <> 'modifications' AND
331 compElem <> 'view' THEN
332 compsIsEmpty := FALSE;
333 CLOSE c_comps;
334 EXIT;
335 END IF;
336 END LOOP;
337 IF compsIsEmpty THEN
338 attsIsEmpty := TRUE;
339 -- Look at all attributes of the <customization> element.
340 OPEN c_atts(docID, 0);
341 LOOP
342 FETCH c_atts INTO attName;
343 IF (c_atts%NOTFOUND) THEN
344 CLOSE c_atts;
345 EXIT;
346 END IF;
347 IF attName <> 'customizes' AND
348 attName <> 'xml:lang' AND
349 attName <> 'version' AND
350 attName <> 'file-version' AND
351 attName <> 'developerMode' AND
352 attName <> 'MDSActiveDoc' AND
353 instr(attName, 'xmlns') <> 1 THEN
354 attsIsEmpty := FALSE;
355 CLOSE c_atts;
356 EXIT;
357 END IF;
358 END LOOP;
359 END IF;
360 IF attsIsEmpty THEN
361 -- This is an empty customization document
362 dbms_output.put_line('Deleting ' ||
363 jdr_mds_internal.getDocumentName(docID));
364 jdr_mds_internal.dropDocument(docID);
365 END IF;
366 END LOOP;
367 END;
368
369
370 -- Deletes the package from the repository if the package is empty.
371 --
372 -- Parameters:
373 -- p_package - the fully qualified package name
374 -- (i.e. '/oracle/apps')
375 --
376 PROCEDURE deletePackage(p_package VARCHAR2)
377 IS
378 docID JDR_PATHS.PATH_DOCID%TYPE;
379 contents INTEGER;
380 BEGIN
381 -- Get the ID of the document
382 docID := getDocumentID(p_package, 'PATH');
383 IF (docID = -1) THEN
384 dbms_output.put_line('Error: Could not find package ' || p_package);
385 RETURN;
386 END IF;
387
388 -- Make sure that the package is empty
389 SELECT COUNT(*) INTO contents
390 FROM jdr_paths
391 WHERE path_owner_docid = docID;
392
393 IF (contents <> 0) THEN
394 dbms_output.put_line('Error: Unable to delete ' || p_package ||
395 ' since it contains documents and/or packages.');
396 RETURN;
397 END IF;
398
399 jdr_mds_internal.dropDocument(docID);
400 dbms_output.put_line('Successfully deleted package ' || p_package || '.');
401 END;
402
403
404 --
405 -- Export the XML for a document and pass it back in 32k chunks. This
406 -- function will return XML chunks, with a maximum size of 32k.
407 FUNCTION exportDocument(
408 p_document VARCHAR2,
409 p_exportFinished OUT NOCOPY /* file.sql.39 change */ BOOLEAN,
410 p_formatted BOOLEAN DEFAULT TRUE) RETURN VARCHAR2
411 IS
412 chunk VARCHAR2(32000);
413 exportFinished INTEGER;
414 formatted INTEGER;
415 BEGIN
416 IF (p_formatted) THEN
417 formatted := 1;
418 ELSE
419 formatted := 0;
420 END IF;
421
422 -- Get the the contents of the XML document. If p_document is not null,
423 -- this will retrieve the first chunk of the document. If p_document is
424 -- null, then we are retrieving a subsequent chunk of the document.
425 --
426 -- It's a little ugly that we have to switch between INTEGERs and BOOLEANs,
427 -- but jdr_mds_internal.exportDocumentAsXML is called from JDBC and,
428 -- unfortunately, JDBC does not have support for BOOLEAN parameters, so
429 -- that's why we have to do the conversion.
430 chunk := jdr_mds_internal.exportDocumentAsXML(exportFinished,
431 p_document,
432 formatted);
433
434 p_exportFinished := (exportFinished = 1);
435
436 return (chunk);
437 END;
438
439
440 -- Gets the fully qualified name of the component.
441 --
442 -- Parameters:
443 -- p_docid - the ID of the document which contains the component
444 --
445 -- p_compid - the ID of the component (from comp_id in the
446 -- jdr_components table
447 --
448 FUNCTION getComponentName(
449 p_docid jdr_paths.path_docid%TYPE,
450 p_compid jdr_components.comp_id%TYPE) RETURN VARCHAR2
451 IS
452 separator VARCHAR2(1) := NULL;
453 BEGIN
454 IF (p_compid IS NOT NULL) THEN
455 separator := '.';
456 END IF;
457
458 RETURN (getDocumentName(p_docid)||separator||p_compid);
459 END;
460
461
462 -- Gets the fully qualified name of the document.
463 --
464 -- Parameters:
465 -- p_docid - the ID of the document
466 FUNCTION getDocumentName(
467 p_docid jdr_paths.path_docid%TYPE) RETURN VARCHAR2
468 IS
469 BEGIN
470 RETURN (jdr_mds_internal.getDocumentName(p_docid));
471 END;
472
473
474 -- Gets all of the translations of the specified document.
475 FUNCTION getTranslations(
476 p_document VARCHAR2) RETURN translationList
477 IS
478 CURSOR cTrans(p_docID jdr_paths.path_docid%TYPE) IS
479 SELECT
480 atl_lang, atl_comp_ref, atl_name, atl_value
481 FROM
482 jdr_attributes_trans
483 WHERE
484 atl_comp_docid = p_docID
485 ORDER BY
486 atl_lang;
487
488 docID jdr_paths.path_docid%TYPE;
489 trans translationList;
490 pos BINARY_INTEGER;
491 BEGIN
492 -- Get the document ID for this document
493 docID := getDocumentID(p_document, 'FILE');
494 IF (docID = -1) THEN
495 RAISE no_such_document;
496 END IF;
497
498 -- Fetch all of the translations into the translation list
499 pos := 0;
500 FOR tranRec IN cTrans(docID) LOOP
501 IF (pos = 0) THEN
502 -- Initialize the translation list
503 trans := translationList(NULL);
504 ELSE
505 -- Extend the list to make room for this translation
506 trans.EXTEND;
507 END IF;
508
509 pos := pos + 1;
510 trans(pos) := tranRec;
511
512 -- Since the compref attribute can not be NULL (as it is part of an index),
513 -- we have to save NULL values as '.' in the database. As this might
514 -- be confusing to users, we revert the '.' back to NULL.
515 IF (tranRec.atl_comp_ref = '.') THEN
516 trans(pos).compref := '';
517 END IF;
518 END LOOP;
519
520 RETURN (trans);
521 EXCEPTION
522 WHEN NO_DATA_FOUND THEN
523 RETURN (NULL);
524 END;
525
526
527 -- Lists the contents of a package.
528 PROCEDURE listContents(p_path VARCHAR2, p_recursive BOOLEAN DEFAULT FALSE)
529 IS
530 -- Selects documents in the current directory
531 CURSOR c_docs(docid JDR_PATHS.PATH_DOCID%TYPE) IS
532 SELECT
533 jdr_mds_internal.getDocumentName(path_docid), path_type, path_seq
534 FROM
535 jdr_paths
536 WHERE
537 path_owner_docid = docid AND
538 ((path_type = 'DOCUMENT' AND path_seq = -1) OR
539 (path_type = 'PACKAGE' AND (path_seq = 0 OR path_seq = -1)));
540
541 -- Selects documents in the current directory, plus its children
542 CURSOR c_alldocs(docid JDR_PATHS.PATH_DOCID%TYPE) IS
543 SELECT
544 jdr_mds_internal.getDocumentName(path_docid), path_type, path_seq
545 FROM
546 (SELECT path_docid, path_type, path_seq
547 FROM jdr_paths
548 START WITH path_owner_docid = docid
549 CONNECT BY PRIOR path_docid = path_owner_docid) paths
550 WHERE
551 (path_type = 'DOCUMENT' AND path_seq = -1) OR
552 (path_type = 'PACKAGE' AND path_seq = 0) OR
553 (path_type = 'PACKAGE' AND path_seq = -1 AND
554 NOT EXISTS (SELECT * FROM jdr_paths
555 WHERE path_owner_docid = paths.path_docid));
556
557 docID JDR_PATHS.PATH_DOCID%TYPE;
558 pathSeq JDR_PATHS.PATH_SEQ%TYPE;
559 pathType JDR_PATHS.PATH_TYPE%TYPE;
560 docname VARCHAR2(1024);
561 BEGIN
562 dbms_output.enable(1000000);
563
564 docID := getDocumentID(p_path, 'ANY');
565
566 -- Nothing to do if the path does not exist
567 IF (docID = -1) THEN
568 dbms_output.put_line('Error: Could not find path ' || p_path);
569 RETURN;
570 END IF;
571
572 IF (p_recursive) THEN
573 dbms_output.put_line('Printing contents of ' || p_path || ' recursively');
574 OPEN c_alldocs(docID);
575 LOOP
576 FETCH c_alldocs INTO docname, pathType, pathSeq;
577 IF (c_alldocs%NOTFOUND) THEN
578 CLOSE c_alldocs;
579 EXIT;
580 END IF;
581
582 -- Make package directories distinct from files. Note that when
583 -- listing the document recursively, the only packages that are
584 -- listed are the ones which contain no child documents or packages
585 IF ((pathType = 'PACKAGE') AND (pathSeq = -1)) THEN
586 docname := docname || '/';
587 END IF;
588
589 -- Print the document, but make sure it does not exceed 255 characters
590 -- or else dbms_output will fail
591 WHILE (length(docname) > 255) LOOP
592 dbms_output.put_line(substr(docname, 1, 255));
593 docname := substr(docname, 256);
594 END LOOP;
595 dbms_output.put_line(docname);
596 END LOOP;
597 ELSE
598 dbms_output.put_line('Printing contents of ' || p_path);
599 OPEN c_docs(docID);
600 LOOP
601 FETCH c_docs INTO docname, pathType, pathSeq;
602 IF (c_docs%NOTFOUND) THEN
603 CLOSE c_docs;
604 EXIT;
605 END IF;
606
607 -- Make package directories distinct from files.
608 IF ((pathType = 'PACKAGE') AND (pathSeq = -1)) THEN
609 docname := docname || '/';
610 END IF;
611
612 -- Print the document, but make sure it does not exceed 255 characters
613 -- or else dbms_output will fail
614 WHILE (length(docname) > 255) LOOP
615 dbms_output.put_line(substr(docname, 1, 255));
616 docname := substr(docname, 256);
617 END LOOP;
618 dbms_output.put_line(docname);
619 END LOOP;
620 END IF;
621 END;
622
623
624 -- List the customizations for the specified document.
625 PROCEDURE listCustomizations(p_document VARCHAR2)
626 IS
627 CURSOR c(pathName VARCHAR2, docName VARCHAR2) IS
628 SELECT jdr_mds_internal.getDocumentName(path_docid)
629 FROM jdr_paths, jdr_attributes
630 WHERE path_docid = att_comp_docid AND
631 path_name = pathName AND
632 att_comp_seq = 0 AND
633 att_name = 'customizes' AND
634 att_value = docName;
635 pathName JDR_PATHS.PATH_NAME%TYPE;
636 oldCustName VARCHAR2(1024);
637 startDoc VARCHAR2(1024);
638 endDoc VARCHAR2(1024);
639 name VARCHAR2(1024);
640 lenApp NUMBER;
641 lenPkg NUMBER;
642 lenRoot NUMBER;
643 BEGIN
644 -- First determine the pathName of the base document
645 -- i.e. baseDocName - /oracle/apps/ak/pages/page1
646 -- pathName - page1
647 lenPkg := INSTR(p_document, '/', -1, 1);
648 IF lenPkg = 0 OR
649 lenPkg = LENGTH(p_document)
650 THEN
651 RETURN;
652 END IF;
653 pathName := SUBSTR(p_document, lenPkg + 1);
654 OPEN c(pathName, p_document);
655 LOOP
656 FETCH c INTO name;
657 IF (c%NOTFOUND) THEN
658 CLOSE c;
659 EXIT;
660 END IF;
661 dbms_output.put_line(name);
662 END LOOP;
663 END;
664
665
666 -- Lists the contents of a package.
667 PROCEDURE listDocuments(p_path VARCHAR2, p_recursive BOOLEAN DEFAULT FALSE)
668 IS
669 BEGIN
670 listContents(p_path, p_recursive);
671 END;
672
673
674 -- Lists the supported languages for the specified document.
675 --
676 -- Parameters:
677 -- p_document - the fully qualified document name, which can represent
678 -- either a document or package file.
679 -- (i.e. '/oracle/apps/ak/attributeSets')
680 --
681 PROCEDURE listLanguages(p_document VARCHAR2)
682 IS
683 CURSOR c_languages(docid jdr_paths.path_docid%TYPE) IS
684 SELECT DISTINCT(atl_lang) FROM jdr_attributes_trans
685 WHERE atl_comp_docid IN (SELECT path_docid FROM jdr_paths
686 START WITH path_docid = docID
687 CONNECT BY PRIOR path_docid=path_owner_docid);
688
689 lang jdr_attributes_trans.atl_lang%TYPE;
690 docID jdr_paths.path_docid%TYPE;
691 BEGIN
692 dbms_output.enable(1000000);
693
694 docID := getDocumentID(p_document, 'FILE');
695
696 -- Nothing to do if the path does not exist
697 IF (docID = -1) THEN
698 dbms_output.put_line('Error: Could not find document ' || p_document);
699 RETURN;
700 END IF;
701
702 dbms_output.put_line('Printing languages for document ' || p_document);
703 OPEN c_languages(docID);
704 LOOP
705 FETCH c_languages INTO lang;
706 IF (c_languages%NOTFOUND) THEN
707 CLOSE c_languages;
708 EXIT;
709 END IF;
710
711 dbms_output.put_line(lang);
712 END LOOP;
713 END;
714
715
716 -- Prints the contents of a JRAD document to the console.
717 PROCEDURE printDocument(p_document VARCHAR2,
718 p_maxLineSize NUMBER DEFAULT MAX_LINE_SIZE)
719 IS
720 chunk VARCHAR2(32000);
721 maxLineSize NUMBER := p_maxLineSize;
722 BEGIN
723 dbms_output.enable(1000000);
724
725 IF (p_maxLineSize > MAX_LINE_SIZE) THEN
726 maxLineSize := MAX_LINE_SIZE;
727 END IF;
728
729 chunk := jdr_mds_internal.exportDocumentAsXML(p_document);
730
731 IF chunk IS NULL THEN
732 dbms_output.put_line('Error: Could not find document ' || p_document);
733 ELSE
734 printChunk(chunk, maxLineSize);
735 LOOP
736 chunk := jdr_mds_internal.exportDocumentAsXML(NULL);
737 EXIT WHEN chunk IS NULL;
738 printChunk(chunk, maxLineSize);
739 END LOOP;
740 END IF;
741 END;
742
743
744 -- Prints the translations for the document in XLIFF format.
745 PROCEDURE printTranslations(p_document VARCHAR2,
746 p_language VARCHAR2,
747 p_maxLineSize NUMBER DEFAULT MAX_LINE_SIZE)
748 IS
749 chunk VARCHAR2(32000);
750 maxLineSize NUMBER := p_maxLineSize;
751 exportFinished INTEGER;
752 BEGIN
753 dbms_output.enable(1000000);
754
755 IF (p_maxLineSize > MAX_LINE_SIZE) THEN
756 maxLineSize := MAX_LINE_SIZE;
757 END IF;
758
759 chunk := jdr_mds_internal.exportXLIFFDocument(exportFinished,
760 p_document,
761 p_language);
762
763 IF chunk IS NULL THEN
764 dbms_output.put_line('Error: Could not find document ' || p_document);
765 ELSE
766 printChunk(chunk, maxLineSize);
767 WHILE (exportFinished = 0) LOOP
768 chunk := jdr_mds_internal.exportXLIFFDocument(exportFinished,
769 NULL,
770 NULL);
771 IF (chunk IS NOT NULL) THEN
772 printChunk(chunk, maxLineSize);
773 END IF;
774 END LOOP;
775 END IF;
776 END;
777
778 PROCEDURE saveTranslations(
779 p_document VARCHAR2,
780 p_translations translationList,
781 p_commit BOOLEAN := TRUE)
782 IS
783 docID jdr_paths.path_docid%TYPE;
784 lang jdr_attributes_trans.atl_lang%TYPE;
785 pos BINARY_INTEGER;
786 dashpos BINARY_INTEGER;
787 BEGIN
788 -- Get the document ID for this document
789 docID := getDocumentID(p_document, 'FILE');
790 IF (docID = -1) THEN
791 RAISE no_such_document;
792 END IF;
793
794 -- Create a savepoint in case of an exception
795 SAVEPOINT saveTranslations_1;
796
797 -- Lock the document
798 jdr_mds_internal.lockDocument(docID, 100);
799
800 -- Delete all of the translations
801 DELETE FROM jdr_attributes_trans WHERE atl_comp_docid = docID;
802
803 -- Insert the new translations
804 FOR pos IN 1..p_translations.COUNT LOOP
805
806 -- Insure that the language is in the form 'xx-YY'. That is, the first
807 -- part must be in lower case and the latter part in uppercase.
808 IF (UPPER(NVL(lang, 'INVALID')) <> UPPER(p_translations(pos).lang)) THEN
809 dashpos := INSTR(p_translations(pos).lang, '-');
810 lang := LOWER(SUBSTR(p_translations(pos).lang, 1, dashpos)) ||
811 UPPER(SUBSTR(p_translations(pos).lang, dashpos + 1));
812 END IF;
813
814 INSERT
815 INTO jdr_attributes_trans
816 (atl_comp_docid,
817 atl_lang,
818 atl_comp_ref,
819 atl_name,
820 atl_value)
821 VALUES
822 (docID,
823 lang,
824 NVL(p_translations(pos).compref, '.'),
825 p_translations(pos).name,
826 p_translations(pos).value);
827 END LOOP;
828
829 -- Commit the data (if requested to)
830 IF (p_commit) THEN
831 COMMIT;
832 END IF;
833
834 EXCEPTION
835 WHEN OTHERS THEN
836 ROLLBACK TO saveTranslations_1;
837 RAISE;
838 END;
839
840 END;