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

  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           

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2