(file) Return to MessageLoader.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

  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               

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2