1 PACKAGE BODY HR_MESSAGE AS
2 /* $Header: hrmesage.pkb 115.4 99/07/17 16:42:53 porting ship $ */
3
4 --
5 -- ----------------------------------------------------------------------------
6 -- | Global Record Type Specification |
7 -- ----------------------------------------------------------------------------
8 --
9 TYPE g_error_info_type IS RECORD
10 (
11 sqlcode NUMBER := 0,
12 sqlerrm VARCHAR2(2000) := '',
13 encoded_error_text VARCHAR2(2000) := '',
14 last_message_name VARCHAR2(2000) := '',
15 last_message_app VARCHAR2(2000) := '',
16 last_message_data VARCHAR2(2000) := '');
17
18 --
19 -- ----------------------------------------------------------------------------
20 -- | Global Definitions |
21 -- ----------------------------------------------------------------------------
22 --
23
24 g_error_rec g_error_info_type;
25
26 --
27 -- ----------------------------------------------------------------------------
28 -- | Global Package Name |
29 -- ----------------------------------------------------------------------------
30 --
31
32 g_package varchar2(33) := ' hr_message_pkg.';
33
34 function get_separator_string(p_encoded_error in varchar2) return varchar2 is
35
36 -- This function works out what AOL are using as the separator between the
37 -- data in the encoded data string. As of August 1998, the encoded error
38 -- message had the form:
39 --
40 -- MSG_APP||(sep)||MSG_NAME||(sep)||MSG_DATA
41 --
42 -- The length is determined by finding the start of the MSG_NAME, and
43 -- subtracting the length of the message application short name (PER, PAY
44 -- etc.)
45 --
46 -- The separator is then determined by substr starting at the position
47 -- one character past the length of the message application, and continuing
48 -- for the length just determined. This function protects us a little bit
49 -- from changes in the AOL encoding string when we are trying to determine
50 -- the token values.
51 --
52
53 l_sep_length NUMBER(4);
54 l_sep_string VARCHAR2(2000);
55
56 begin
57
58 l_sep_length:=to_number(INSTR(p_encoded_error,g_error_rec.last_message_name)
59 - LENGTH(g_error_rec.last_message_app) - 1);
60
61 l_sep_string:=substr(p_encoded_error,length(g_error_rec.last_message_app)+1,
62 l_sep_length);
63
64 return l_sep_string;
65
66 end get_separator_string;
67
68 procedure provide_error is
69
70 -- This is the main procedure, which makes calls to the FND_MESSAGE package
71 -- to populate the global record structure with the name of the last message
72 -- application, and the last message name. The other data supplied in
73 -- the encoded error message string is token information, and is not used
74 -- until a call to get_token_value is made.
75
76 l_encoded_error VARCHAR2(2000);
77 l_hr_error_app VARCHAR2(2000);
78 l_hr_error_name VARCHAR2(2000);
79 l_sep_string VARCHAR2(2000) :='';
80
81 begin
82
83 -- Set up global variables with error information
84
85 g_error_rec.sqlcode := sqlcode;
86 g_error_rec.sqlerrm := sqlerrm;
87
88 if ((g_error_rec.sqlcode = -20001) or (g_error_rec.sqlcode = -20002)) then
89
90 -- An error has been raised by APPS code - populate other global variables
91
92 l_encoded_error := fnd_message.get_encoded;
93 g_error_rec.encoded_error_text := l_encoded_error;
94
95 if (l_encoded_error is not null) then
96
97 -- FND MESSAGE still knows which message we are talking about
98 -- Reset the message, so that the FND_MESSAGE state is not altered by
99 -- this procedure
100
101 fnd_message.set_encoded(l_encoded_error);
102
103 -- Now decode the encoded error message into required components
104
105 fnd_message.parse_encoded(encoded_message => l_encoded_error,
106 app_short_name => g_error_rec.last_message_app,
107 message_name => g_error_rec.last_message_name);
108
109 g_error_rec.last_message_data := '';
110
111 else
112 --
113 -- We can't find anything out from FND_MESSAGE. Perhaps the
114 -- message text has been retrieved, or some other call has
115 -- reset the global state. Treat as non-APP error.
116 --
117 g_error_rec.last_message_name := '';
118 g_error_rec.last_message_app := '';
119 g_error_rec.last_message_data := '';
120 g_error_rec.encoded_error_text := '';
121 --
122 end if; -- l_encoded_error is null
123 else
124
125 -- This was not an error raised by an application procedure -
126 -- set global definitions to NULL
127
128 g_error_rec.last_message_name := '';
129 g_error_rec.last_message_app := '';
130 g_error_rec.last_message_data := '';
131 g_error_rec.encoded_error_text := '';
132
133 end if; -- Check for error raised by APPS
134
135 end provide_error;
136
137 procedure parse_encoded(p_encoded_error in varchar2) is
138
139 -- This procedure assumes that the calling procedure already
140 -- has knowledge of the encoded error message (e.g.
141 -- as in the case of the flexfield server validation
142 -- routines.). The string passed in must be in the same
143 -- format as the encoded string in FND_MESSAGE. I.e. it should
144 -- have been retrieved with a call to FND_MESSAGE.get_encoded.
145
146 begin
147
148 -- Use the FND routine to parse the encoded error message into
149 -- the global variables to make them available to the APIS,
150 -- forms, other packages etc. in a way consistent with provide_error
151 -- Do not reset the error message on the FND_MESSAGE stack, since
152 -- this would alter the state of that package.
153
154 fnd_message.parse_encoded(encoded_message => p_encoded_error,
155 app_short_name => g_error_rec.last_message_app,
156 message_name => g_error_rec.last_message_name);
157
158 g_error_rec.encoded_error_text := p_encoded_error;
159 g_error_rec.last_message_data := '';
160
161
162 end;
163 --
164 function last_message_number return varchar2 is
165
166 -- A call to this function will return the message error code in
167 -- the following format:
168 --
169 l_error_code_text VARCHAR2(30) := 'APP-MSGNUM';
170 l_message_num VARCHAR2(10);
171 --
172 -- If you wish to change the format, change the default assignment above,
173 -- noting that the (sub) string MSGNUM will be replaced with the
174 -- message number.
175 --
176 begin
177 --
178 -- Check to see if we have a valid message on the stack
179 --
180 if (g_error_rec.last_message_name is not null) then
181 --
182 -- Have a valid message. Lets form the number by assuming a form
183 -- for the message name of the following:
184 -- HR_(MSGNUM)_ERROR_MESSAGE_DESCR
185 --
186 l_message_num := substr(g_error_rec.last_message_name,
187 (instr(g_error_rec.last_message_name,'_')+1),
188 (instr(g_error_rec.last_message_name,'_',1,2) -
189 instr(g_error_rec.last_message_name,'_')-1));
190 --
191 if (translate(l_message_num,'A0123456789','A') is null) then
192 --
193 -- substr above worked correctly - we have a message number, can output
194 -- a valid message code.
195 --
196 l_error_code_text := replace(l_error_code_text,'MSGNUM',
197 l_message_num);
198 --
199 else
200 --
201 -- substr failed. Should return NULL
202 --
203 l_error_code_text := '';
204 --
205 end if;
206 --
207 else
208 --
209 --
210 -- We don't have a valid message on the stack, therefore I should return
211 -- null for this.
212 --
213 l_error_code_text := '';
214 --
215 end if;
216 --
217 return l_error_code_text;
218 --
219 end last_message_number;
220 --
221 function last_message_name return varchar2 is
222
223 -- A call to this function simply returns whatever is contained
224 -- in the current global variable record structure for the last
225 -- message name raised.
226
227 begin
228
229 return g_error_rec.last_message_name;
230
231 end;
232
233 function last_message_app return varchar2 is
234
235 -- A call to this function simply returns whatever is contained
236 -- in the current global variable record structure for the last
237 -- app that raised a message followed by a call to provide_error.
238
239 begin
240
241 return g_error_rec.last_message_app;
242
243 end;
244
245 function get_token_value(p_token_name in varchar2
246 ) return varchar2 is
247
248 -- This function uses the MSG_DATA component of the encoded error string
249 -- to determine the value of a given token.
250 -- The message data has the following structure:
251 --
252 -- MSG_DATA = TKN_TRANSLATE||(sep)||TKN_NAME||(sep)||TKN_VALUE||(sep)
253 --
254 -- and so on for each token set with this message. (sep) is the
255 -- encoding separator used beforehand.
256
257 l_sep_string VARCHAR2(2000);
258 l_msg_data_start NUMBER(4);
259 l_data_start NUMBER(4);
260 l_data_end NUMBER(4);
261 l_token_value VARCHAR2(2000);
262
263
264 begin
265
266 -- To be able to return the token values, we need to assume something about
267 -- the encoded nature of the message - this is a big assumption, and we
268 -- shouldn't really do it. It would be better if the get_encoded returned
269 -- this along with the other data shown above - but it does not. This is
270 -- therefore, unsupported (by AOL) code
271
272 -- Use the function described above to work out what the format of the
273 -- message data separator.
274
275 l_sep_string := get_separator_string(p_encoded_error =>
276 g_error_rec.encoded_error_text);
277
278 -- The compete encoded message data has structure:
279 --
280 -- MSG_APP||(sep)||MSG_NAME||(sep)||MSG_DATA
281 --
282 -- so the message data starts at the character past the second
283 -- instance of the encoded string separator character.
284
285 l_msg_data_start := INSTR(g_error_rec.encoded_error_text,
286 l_sep_string,1,2)+1;
287
288 g_error_rec.last_message_data := substr(g_error_rec.encoded_error_text,
289 l_msg_data_start);
290 --
291 -- First check to see whether there is information on tokens available,
292 -- and that information exists for the token requested. If not, return
293 -- a NULL value.
294 --
295 -- Note: We will cause an error if the value of a token is
296 -- also a valid token name. We should introduce a check on
297 -- the number of separator strings to ensure that we have a
298 -- valid token value.
299 --
300 if ((g_error_rec.last_message_data is null) or
301 (INSTR(g_error_rec.last_message_data,p_token_name)=0)) then
302
303 return null;
304
305 else
306
307 -- The starting position (in the string) of the value for the given token
308 -- can be found using the standard character functions. From the structure
309 -- seen above for MSG_DATA, it can be found by finding the position of the
310 -- token name, then adding the length of the token name, and the length of
311 -- the separator string.
312
313 l_data_start := INSTR(g_error_rec.last_message_data,p_token_name)
314 +length(p_token_name)
315 +length(l_sep_string);
316
317 -- The end of the token value corresponds to the next instance of the
318 -- separator string starting from the start of the token value.
319
320 l_data_end := INSTR(substr(g_error_rec.last_message_data,l_data_start)
321 ,l_sep_string);
322
323 if(l_data_end>0) then
324
325 -- If the data end variable contains a value larger than zero, it means
326 -- that another separator string was found. Thus another token record
327 -- exists, and we should make sure that we only return the part of the
328 -- string between data_start and data_end, which will be the token value
329
330 l_token_value := substr(g_error_rec.last_message_data,l_data_start,
331 (l_data_end-1));
332
333 else
334
335 -- This token value was the last information in the MSG_DATA record.
336 -- The valid value is the whole string starting at the data_start
337
338 l_token_value := substr(g_error_rec.last_message_data,l_data_start);
339
340 end if;
341
342 return l_token_value;
343 end if;
344
345 end;
346
347 function get_message_text return varchar2 is
348
349 -- Call this function to retrieve the message text corresponding
350 -- to the message information held in the error information structure -
351 -- i.e. the last message after which provide_error was called. If that
352 -- structure contains no information, the error is not likely to have been
353 -- raised by an application, hence just sqlerrm is returned in this case.
354
355 l_message_text varchar2(2000);
356
357 begin
358
359 if (g_error_rec.encoded_error_text is null) then
360
361 -- This message is not known about inside FND_MESSAGE, either the FND_MESSAGE
362 -- globals have been reset - in which case, no message text can be retrieved,
363 -- or this was not an APP error. In either case, return the SQL error message
364 -- as this is the only place we can obtain the error message
365
366 return sqlerrm;
367
368 else
369
370 -- The message text has not been asked for by any application yet - we can get
371 -- the message text straight from FND_MESSAGE, and reset the FND_MESSAGE
372 -- package state by reinitiating the message, so that this call does not disturb
373 -- the global environment
374
375 l_message_text := FND_MESSAGE.get;
376
377 FND_MESSAGE.set_encoded(ENCODED_MESSAGE => g_error_rec.encoded_error_text);
378
379 return l_message_text;
380
381 end if;
382
383 end;
384
385 END HR_MESSAGE;