1 karl 1.9 //%2003////////////////////////////////////////////////////////////////////////
|
2 humberto 1.4 //
|
3 karl 1.9 // Copyright (c) 2000, 2001, 2002 BMC Software, Hewlett-Packard Development
4 // Company, L. P., IBM Corp., The Open Group, Tivoli Systems.
5 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L. P.;
6 // IBM Corp.; EMC Corporation, The Open Group.
|
7 humberto 1.4 //
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
9 // of this software and associated documentation files (the "Software"), to
10 // deal in the Software without restriction, including without limitation the
11 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12 // sell copies of the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
14 //
15 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
16 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
17 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
18 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
19 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 //
24 //==============================================================================
25 //
26 // Author: Humberto Rivero (hurivero@us.ibm.com)
27 //
28 humberto 1.4 // Modified By:
29 //
30 //%/////////////////////////////////////////////////////////////////////////////
31
32 #include <Pegasus/Common/MessageLoader.h>
33 #include <Pegasus/Common/Thread.h>
34 #include <Pegasus/Common/Tracer.h>
|
35 humberto 1.6 #include <iostream>
36 #ifdef PEGASUS_OS_OS400
37 #include "OS400ConvertChar.h"
38 #endif
39 PEGASUS_NAMESPACE_BEGIN
40 PEGASUS_USING_STD;
|
41 humberto 1.4
42 static const int ID_INVALID = -1;
43 static const String server_resbundl_name = "pegasus/pegasusServer";
|
44 humberto 1.7 String MessageLoader::pegasus_MSG_HOME = String();
|
45 humberto 1.4 Boolean MessageLoader::_useProcessLocale = false;
46 Boolean MessageLoader::_useDefaultMsg = false;
47 AcceptLanguages MessageLoader::_acceptlanguages = AcceptLanguages();
48
49 String MessageLoader::getMessage(MessageLoaderParms &parms){
50 PEG_METHOD_ENTER(TRC_L10N, "MessageLoader::getMessage");
|
51 humberto 1.8 try{
|
52 humberto 1.4 String msg;
53 parms.contentlanguages.clear();
54
55 // if message loading is DISABLED return the default message
56 #ifndef PEGASUS_HAS_MESSAGES
57 return formatDefaultMessage(parms);
58 #endif
59
60 // if someone has set the global behaviour to use default messages
61 if(_useDefaultMsg) return formatDefaultMessage(parms);
62
63 #ifdef PEGASUS_HAS_ICU
64 //cout << "PEGASUS_HAS_ICU" << endl;
65 msg = loadICUMessage(parms);
66 if(msg.size() == 0){ // we didnt get a message from ICU for some reason, return the default message
67 //cout << "didnt get a message from ICU, using default message" << endl;
68 return formatDefaultMessage(parms);
69 }
70 return msg;
71 #else
72 // NOTE TO PROGRAMMERS:
73 humberto 1.4 // call a non-ICU message loading function here that has
74 // non-ICU process locale discovery code and non-ICU message loading
75 // otherwise the default message is always returned
76 //cout << "PEGASUS_HAS_ICU is NOT defined, using default message" << endl;
77 return formatDefaultMessage(parms);
78 #endif
|
79 kumpf 1.10 }catch(Exception&){
|
80 humberto 1.8 return String("AN INTERNAL ERROR OCCURED IN MESSAGELOADER: ").append(parms.default_msg);
81 }
|
82 humberto 1.4 PEG_METHOD_EXIT();
83 }
84
85 #ifdef PEGASUS_HAS_ICU
86
87 String MessageLoader::loadICUMessage(MessageLoaderParms &parms){
88
89 PEG_METHOD_ENTER(TRC_L10N, "MessageLoader::loadICUMessage");
90 String msg;
91 UResourceBundle* resbundl;
92 UErrorCode status = U_ZERO_ERROR;
93 //String resbundl_path_ICU;
94 CString resbundl_path_ICU;
95
96 // the static AcceptLangauges takes precedence over what parms.acceptlangauges has
97 AcceptLanguages acceptlanguages;
98 acceptlanguages = (_acceptlanguages.size() > 0) ? _acceptlanguages : parms.acceptlanguages;
99
100 // get the correct path to the resource bundles
|
101 humberto 1.6 resbundl_path_ICU = getQualifiedMsgPath(parms.msg_src_path).getCString();
102 //cout << "USING PACKAGE PATH: " << endl;
103 //cout << resbundl_path_ICU << endl;
104 #ifdef PEGASUS_OS_OS400
105 const char *atoe = resbundl_path_ICU;
106 AtoE((char*)atoe);
107 #endif
|
108 humberto 1.4
|
109 humberto 1.6
|
110 humberto 1.4
111 if(_useProcessLocale || (acceptlanguages.size() == 0 && parms.useProcessLocale)){ // use the system default resource bundle
|
112 humberto 1.6
113 resbundl = ures_open((const char*)resbundl_path_ICU, uloc_getDefault() , &status);
|
114 humberto 1.4
115 if(U_SUCCESS(status)) {
116 //cout << "PROCESS_LOCALE: opened resource bundle" << endl;
|
117 humberto 1.6 UErrorCode cout_status = U_ZERO_ERROR;
118 //cout << "PROCESS_LOCALE = " << ures_getLocale(resbundl, &cout_status) << endl;
|
119 humberto 1.4 if(status == U_USING_FALLBACK_WARNING || status == U_USING_DEFAULT_WARNING){
120 //cout << "PROCESS_LOCALE: using fallback or default" << endl;
121 }
122 msg = extractICUMessage(resbundl,parms);
|
123 humberto 1.6
124 String cl_str(ures_getLocale(resbundl,&status));
125 #ifdef PEGASUS_OS_OS400
126 CString cstr = cl_str.getCString();
127 const char *etoa = cstr;
128 EtoA((char*)etoa);
129 cl_str = etoa;
130 #endif
131 parms.contentlanguages.append(ContentLanguageElement(cl_str));
|
132 humberto 1.4 ures_close(resbundl);
133 } else {
134 //cout << "PROCESS_LOCALE: could not open resouce, formatting default message" << endl;
135 msg = formatDefaultMessage(parms);
136 }
137 return msg;
138 } else if (acceptlanguages.size() == 0 && parms.useThreadLocale){ // get AcceptLanguages from the current Thread
139 AcceptLanguages *al = Thread::getLanguages();
140 if(al != NULL){
141 acceptlanguages = *al;
142 //cout << "THREAD_LOCALE: got acceptlanguages from thread" << endl;
143 }else {
144 //cout << "THREAD_LOCALE: thread returned NULL for acceptlanguages" << endl;
145 }
146 }
147
148 const int size_locale_ICU = 50;
149 char locale_ICU[size_locale_ICU];
150 AcceptLanguageElement language_element = AcceptLanguageElement::EMPTY;
151
152 // iterate through AcceptLanguages, use the first resource bundle match
153 humberto 1.4 acceptlanguages.itrStart();
154 //cout << "LOOPING THROUGH ACCEPTLANGUAGES..." << endl;
155 while((language_element = acceptlanguages.itrNext()) != AcceptLanguageElement::EMPTY_REF){
|
156 humberto 1.6 #ifdef PEGASUS_OS_OS400
157 CString cstr = language_element.getTag().getCString();
158 const char *atoe = cstr;
159 AtoE((char*)atoe);
160 String tag(atoe);
161 uloc_getName((const char*)tag.getCString(), locale_ICU, size_locale_ICU, &status);
162 #else
163 uloc_getName((const char*)(language_element.getTag()).getCString(), locale_ICU, size_locale_ICU, &status);
164 #endif
|
165 humberto 1.4 //cout << "locale_ICU = " << locale_ICU << endl;
166 // TODO: check to see if we have previously cached the resource bundle
167
168 resbundl = ures_open((const char*)resbundl_path_ICU, locale_ICU, &status);
169
170 if(U_SUCCESS(status)) {
171 //cout << "ACCEPTLANGUAGES LOOP: opened resource bundle with " << language_element.getTag() << endl;
172 if(status == U_USING_FALLBACK_WARNING || status == U_USING_DEFAULT_WARNING){
173 //we want to use the ICU fallback behaviour in the following cases ONLY
174 //cout << "ACCEPTLANGUAGES LOOP: ICU warns using FALLBACK or DEFAULT" << endl;
175 if(acceptlanguages.size() == 1 || parms.useICUfallback){
176 //cout << "ACCEPTLANGUAGES LOOP: acceptlanguages.size == 1 or useICUfallback true, using ICU fallback behaviour..." << endl;
|
177 humberto 1.6 msg = extractICUMessage(resbundl,parms);
178
179 String cl_str(ures_getLocale(resbundl,&status));
180 #ifdef PEGASUS_OS_OS400
181 CString cstr = cl_str.getCString();
182 const char *etoa = cstr;
183 EtoA((char*)etoa);
184 cl_str = etoa;
185 #endif
186 parms.contentlanguages.append(ContentLanguageElement(cl_str));
|
187 humberto 1.4 ures_close(resbundl);
188 break;
189 }
190 }
191 else{ // we found an exact resource bundle match, extract, and set ContentLanguage
192 //cout << "ACCEPTLANGUAGES LOOP: found an EXACT resource bundle MATCH" << endl;
193 msg = extractICUMessage(resbundl,parms);
194 parms.contentlanguages.append(ContentLanguageElement(language_element.getTag()));
195 ures_close(resbundl);
196 break;
197 }
198 } else { // possible errors, ex: message path incorrect
199 // for now do nothing, let the while loop continue
200 //cout << "ACCEPTLANGUAGES LOOP: could NOT open a resource for: " << language_element.getTag() << endl;
201 }
202 status = U_ZERO_ERROR; // reset status
203 }
|
204 humberto 1.2 // now if we DIDNT get a message, we want to enable ICU fallback for the highest priority language
|
205 humberto 1.4 if(msg.size() == 0 && acceptlanguages.size() > 0){
|
206 humberto 1.3 //cout << "USING ICU FALLBACK" << endl;
|
207 humberto 1.2 language_element = acceptlanguages.getLanguageElement(0);
|
208 humberto 1.6
209 #ifdef PEGASUS_OS_OS400
210 CString cstr = language_element.getTag().getCString();
211 const char *atoe = cstr;
212 AtoE((char*)atoe);
213 String tag(atoe);
214 uloc_getName((const char*)tag.getCString(), locale_ICU, size_locale_ICU, &status);
215 #else
216 uloc_getName((const char*)(language_element.getTag()).getCString(), locale_ICU, size_locale_ICU, &status);
217 #endif
|
218 humberto 1.3 //cout << "locale_ICU in fallback = " << locale_ICU << endl;
|
219 humberto 1.6 status = U_ZERO_ERROR;
|
220 humberto 1.4 resbundl = ures_open((const char*)resbundl_path_ICU, locale_ICU, &status);
|
221 humberto 1.6 String cl_str_;
222 if(U_SUCCESS(status)) {
223 if(status == U_USING_DEFAULT_WARNING){
224 //cout << "PRIORITY ICU FALLBACK: using default resource bundle with " << language_element.getTag() << endl;
225 status = U_ZERO_ERROR;
226 resbundl = ures_open((const char*)resbundl_path_ICU, "", &status);
227 if(U_SUCCESS(status)) {
228 msg = extractICUMessage(resbundl,parms);
229 cl_str_ = ures_getLocale(resbundl,&status);
230 }
231 }else{
232 msg = extractICUMessage(resbundl,parms);
233 cl_str_ = ures_getLocale(resbundl,&status);
234 }
235 #ifdef PEGASUS_OS_OS400
236 CString cstr_ = cl_str_.getCString();
237 const char *etoa = cstr_;
238 EtoA((char*)etoa);
239 cl_str_ = etoa;
240 #endif
241 if(cl_str_ != "root")
242 humberto 1.6 parms.contentlanguages.append(ContentLanguageElement(cl_str_));
243 ures_close(resbundl);
|
244 humberto 1.5 }
|
245 humberto 1.2 }
|
246 humberto 1.6 if(msg.size() == 0){ // else if no message, load message from root bundle explicitly
|
247 humberto 1.4 //cout << "EXHAUSTED ACCEPTLANGUAGES: using root bundle to extract message" << endl;
248 status = U_ZERO_ERROR;
249 resbundl = ures_open((const char*)resbundl_path_ICU, "", &status);
250 if(U_SUCCESS(status)){
251 //cout << "EXHAUSTED ACCEPTLANGUAGES: opened root resource bundle" << endl;
252 msg = extractICUMessage(resbundl,parms);
253 //parms.contentlanguages.append(ContentLanguageElement(String(ures_getLocale(resbundl,&status))));
254 }else {
255 //cout << "EXHAUSTED ACCEPTLANGUAGES: could NOT open root resource bundle" << endl;
256 }
257
258 }
259 PEG_METHOD_EXIT();
260 return msg;
261 }
262
263 String MessageLoader::extractICUMessage(UResourceBundle * resbundl, MessageLoaderParms &parms){
264 UErrorCode status = U_ZERO_ERROR;
265 int32_t msgLen = 0;
|
266 humberto 1.6
267 #ifdef PEGASUS_OS_OS400
268 CString cstr = parms.msg_id.getCString();
269 const char *atoe = cstr;
270 AtoE((char*)atoe);
271 const UChar *msg = ures_getStringByKey(resbundl, (const char*)atoe, &msgLen, &status);
272 #else
|
273 humberto 1.4 const UChar *msg = ures_getStringByKey(resbundl, (const char*)parms.msg_id.getCString(), &msgLen, &status);
|
274 humberto 1.6 #endif
|
275 humberto 1.4 if(U_FAILURE(status)) {
276 //cout << "could not extract ICU Message" << endl;
277 return String::EMPTY;
278 }
279
280 return formatICUMessage(resbundl, msg, msgLen, parms);
281 }
282
283 String MessageLoader::uChar2String(UChar * uchar_str){
284 return String((const Char16 *)uchar_str);
285 }
286
287 String MessageLoader::uChar2String(UChar * uchar_str, int len){
288 return String((const Char16 *)uchar_str, len);
289 }
290
291 UChar* MessageLoader::string2UChar(String s){
292 return (UChar*)((uint16_t *)s.getChar16Data());
293 }
294
295
296 humberto 1.4 String MessageLoader::formatICUMessage(UResourceBundle * resbundl, const UChar * msg, int msg_len, MessageLoaderParms &parms){
297
298 // format the message
299 UnicodeString msg_pattern(msg, msg_len);
300 UnicodeString msg_formatted;
301 UErrorCode status = U_ZERO_ERROR;
302 const int arg_count = 10;
303 char * locale;
304 if(resbundl == NULL)
305 locale = ULOC_US;
306 else
307 locale = const_cast<char *>(ures_getLocale(resbundl, &status));
308
309 //cout << "FORMAT ICU MESSAGE: using locale = " << locale << endl;
310
311 char lang[4];
312 char cc[4];
313 char var[arg_count];
314 uloc_getLanguage(locale, lang, 4, &status);
315 uloc_getCountry(locale, cc, 4, &status);
316 uloc_getVariant(locale, var, 10, &status);
317 humberto 1.4 Locale localeID(lang,cc,var);
318
319 status = U_ZERO_ERROR;
320 MessageFormat formatter(msg_pattern, localeID, status);
321 Formattable args[arg_count];
322 xferFormattables(parms, args);
323 Formattable args_obj(args,arg_count);
324 status = U_ZERO_ERROR;
325 msg_formatted = formatter.format(args_obj, msg_formatted, status);
326
327 return uChar2String(const_cast<UChar *>(msg_formatted.getBuffer()), msg_formatted.length());
328 }
329
330 void MessageLoader::xferFormattables(MessageLoaderParms &parms, Formattable *formattables){
331
332 Formatter::Arg arg_arr[10] = {parms.arg0,parms.arg1,parms.arg2,parms.arg3,parms.arg4,parms.arg5,
333 parms.arg6,parms.arg7,parms.arg8,parms.arg9};
334 //cout << "XFERFORMATTABLES" << endl;
335 for(int i = 0; i < 10; i++){
336 //cout << "arg" << i << " = " << arg_arr[i].toString() << endl;
337 switch (arg_arr[i]._type)
338 humberto 1.4 {
339 case Formatter::Arg::INTEGER: formattables[i] = (int32_t)arg_arr[i]._integer;break;
340 case Formatter::Arg::UINTEGER: formattables[i] = (int32_t)arg_arr[i]._uinteger;break;
341 case Formatter::Arg::BOOLEAN: formattables[i] = (int32_t)arg_arr[i]._boolean;break;
342 case Formatter::Arg::REAL: formattables[i] = (float)arg_arr[i]._real;break;
343 case Formatter::Arg::LINTEGER: formattables[i] = (double)arg_arr[i]._lInteger;break;
344 case Formatter::Arg::ULINTEGER: formattables[i] = (double)arg_arr[i]._lUInteger;break;
345 case Formatter::Arg::STRING: formattables[i] = Formattable(string2UChar(arg_arr[i]._string));break;
346 case Formatter::Arg::VOIDT: formattables[i] = "";break;
347 }
348 }
349 }
350
351 #endif
352
353 String MessageLoader::formatDefaultMessage(MessageLoaderParms &parms){
354
355 PEG_METHOD_ENTER(TRC_L10N, "MessageLoader::formatDefaultMessage");
356 // NOTE TO PROGRAMMERS: using native substitution functions
357 // ie. calling Formatter::format()
358 // can result in incorrect locale handling of substitutions
359 humberto 1.4
360 // locale INSENSITIVE formatting code
361 //cout << "using locale INSENSITIVE formatting" << endl;
362 parms.contentlanguages.clear(); // this could have previously been set by ICU
363 //cout << parms.toString() << endl;
364 //cout << "ml:" << parms.default_msg << endl;
365 return Formatter::format(parms.default_msg,
366 parms.arg0,
367 parms.arg1,
368 parms.arg2,
369 parms.arg3,
370 parms.arg4,
371 parms.arg5,
372 parms.arg6,
373 parms.arg7,
374 parms.arg8,
375 parms.arg9);
376
377
378 PEG_METHOD_EXIT();
379 }
380 humberto 1.4
381 String MessageLoader::getQualifiedMsgPath(String path){
382 PEG_METHOD_ENTER(TRC_L10N, "MessageLoader::getQualifiedPackageName");
383
384 if(pegasus_MSG_HOME.size() == 0)
385 initPegasusMsgHome();
386
387 if(path.size() == 0)
388 return pegasus_MSG_HOME + server_resbundl_name;
389
390 Char16 delim = '/'; // NOTE TO PROGRAMMERS: WINDOWS and non-UNIX platforms should redefine delim here
391 Uint32 i;
392 if(( i = path.find(delim)) != PEG_NOT_FOUND && i == 0){ // fully qualified package name
393 return path;
394 }
395
396 return pegasus_MSG_HOME + path; // relative path and package name
397
398 PEG_METHOD_EXIT();
399 }
400
401 humberto 1.4 void MessageLoader::setPegasusMsgHome(String home){
402 PEG_METHOD_ENTER(TRC_L10N, "MessageLoader::setPegasusMsgHome");
403 //cout << "MessageLoader::setPegasusMsgHome()" << endl;
404 pegasus_MSG_HOME = home + "/";
|
405 humberto 1.6 // TODO: remove the next call once test cases are compatible with ICU messages
406 checkDefaultMsgLoading();
|
407 humberto 1.4 PEG_METHOD_EXIT();
408 }
409
410 void MessageLoader::initPegasusMsgHome(){
411 //cout << "INITPEGASUSMSGHOME:" << endl;
412 #ifdef PEGASUS_OS_OS400
413 pegasus_MSG_HOME = OS400_DEFAULT_MESSAGE_SOURCE;
|
414 chuck 1.11 pegasus_MSG_HOME.append('/');
|
415 humberto 1.4 #else
416 const char* env = getenv("PEGASUS_HOME");
417 if (env != NULL){
418 pegasus_MSG_HOME = env;
419 pegasus_MSG_HOME.append("/msg/");
420 }
421
422 #endif
|
423 humberto 1.6 }
424
425 void MessageLoader::checkDefaultMsgLoading(){
426 // TODO: remove this function once test cases are compatible with ICU messages
427 const char* env = getenv("PEGASUS_USE_DEFAULT_MESSAGES");
428 if (env != NULL)
429 _useDefaultMsg = true;
|
430 humberto 1.4 }
431
432 PEGASUS_NAMESPACE_END
433
434
|