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