1 chuck 1.1 <!doctype html public "-//w3c//dtd html 4.0 transitional//en">
2 <html>
3 <head>
4 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
5 <meta name="GENERATOR" content="Mozilla/4.78 [en] (X11; U; Linux 2.4.7-10 i686) [Netscape]">
6 </head>
7 <body text="#000000" bgcolor="#FFFFFF" link="#0000EF" vlink="#55188A" alink="#FF0000">
8
9 <center><font size=+4>Globalization HOWTO</font>
10 <p>Release: Pegasus 2.3
11 <p>Author: Chuck Carmack (carmack@us.ibm.com)
12 <p>July 2, 2003</center>
13
14 <p><br>
15 <br>
16 <br>
17 <br>
18 <br>
19 <br>
20 <br>
21 <br>
22 chuck 1.1 <br>
23 <br>
24 <p>NOTE: THIS IS A WORK-IN-PROGRESS
25 <br>
26 <h2>
27 1.0 Introduction</h2>
28
29 <p><br>As part of the Pegasus 2.3 release, functions were added for globalization
30 support. Globalization involves two major aspects: internationalization
31 and localization.
32 <br>
33 <p>Internationalization is the process of writing a program that is locale-neutral.
34 In other words, the program should be able to run in any locale without
35 change. There are several categories in a locale, including the language
36 of message strings, date format, time format, etc. For release 2.3,
37 the Pegasus server is concerned with the language of the message strings
38 it returns to its clients.
39 <br>
40 <p>To support internationalization, a program is designed to do the following:
41 <br>
42 <blockquote>
43 chuck 1.1 <li>
44 Support character sets that can represent customer data in any language.
45 Typically, the program supports some variation of Unicode for internal
46 data. There is usually some conversion between the supported character
47 sets for external data, and the internal character set. Since Unicode
48 covers all characters, and usually has converters on the platform, it is
49 a good choice for the 'normalized' internal character set.
50 The most 'interoperable' solution for external data is to support UTF-8
51 (eg. network and file system data). The internal data is usually
52 UTF-16 (or UCS-2, but that is deprecated).</li>
53
54 <br>
55 <li>
56 Extract locale-sensitive resources, such as message strings, from the code
57 to external resource files. Typically, the resources are loaded based
58 on the locale requested by the end-user, and returned to the end-user for
59 display.</li>
60 </blockquote>
61
62 <p><br>Localization is the process of customizing a software product to
63 support particular locales. For example, a product that is internationalized
64 chuck 1.1 might want to only localize for certain countries. This would mean
65 that the localized resources (eg. message files) would only be translated
66 and shipped for the countries that the product supports. Since the
67 code for the product is locale-neutral, it will be easy to drop in new
68 translations as more countries are supported.
69 <br>
70 <p>The Pegasus 2.3 release added support for globalization. At a
71 high-level, the following additions were made to Pegasus 2.3:
72 <br>
73 <ul>
74 <li>
75 Support UTF-8 for external data.</li>
76
77 <br>
78 <ul>
79 <li>
80 The CIM-XML documents contained in the HTTP messages</li>
81
82 <li>
83 Repository files and MOF files (<b>TODO</b> - remove MOF files if
84 we can't get this into 2.3)</li>
85 chuck 1.1 </ul>
86
87 <li>
88 Support UTF-16 for internal data.</li>
89
90 <br>
91 <li>
92 Extract the hardcoded messages from the Pegasus code into message files.
93 An API was added to load messages from the message files.</li>
94
95 <br>
96 <li>
97 APIs were added for clients to associate a language with the CIM objects
98 they are sending to Pegasus. Also, APIs were added for clients to
99 determine the language of the error message or CIM object that Pegasus
100 returns.</li>
101
102 <br>
103 <li>
104 APIs were added for providers to determine the language of CIM objects
105 sent by the client. Also, APIs were added for providers to associate
106 chuck 1.1 a language with the CIM object, or error message, they return to the client.</li>
107 </ul>
108
109 <p><br>Please refer to PEPs 56 and 58 for details about the globalization
110 support in Pegasus 2.3.
111 <br>
112 <p>This document provides a HOWTO guide to be used by developers to globalize
113 code that is being added to Pegasus. The audience for this document
114 are:
115 <br>
116 <ul>
117 <li>
118 Provider developers - both CMPI and C++</li>
119
120 <li>
121 Client developers</li>
122
123 <li>
124 Pegasus developers</li>
125 </ul>
126
127 chuck 1.1 <p><br>The quickest way to approach this document is to read the General
128 section, and then the developer section that relates to what you are doing.
129 <br>
130 <h2>
131 2.0 General</h2>
132
133 <h3>
134 2.1 Unicode Support</h3>
135
136 <p><br>Pegasus 2.3 supports Unicode throughout the processing of requests.
137 External data to Pegasus is encoded in UTF-8. Internal data is encoded
138 in UTF-16.
139 <br>
140 <p>External data includes the CIM-XML messages passed over the network,
141 the repository files, and the MOF files. For the CIM-XML messages,
142 Pegasus follows section 4.8 of the <a href="http://www.dmtf.org/standards/documents/WBEM/DSP200.html">CIM-HTTP
143 specification</a> Specifically, Pegasus supports the
144 "utf-8" setting for the charset parameter of the Content-Type header and
145 the XML encoding attribute. If no charset is specified, the 7-bit
146 ASCII is assumed. The Pegasus MOF compiler supports UTF-8 encoding
147 in the MOF files. (<b>TODO</b> - remove this statement if this is
148 chuck 1.1 not in 2.3)
149 <br>
150 <p>The internal support of UTF-16 is encapsulated in the Pegasus String
151 class. This class has been updated to contain UTF-16 characters.
152 Specifically, the Char16 objects inside the String contain UTF-16 characters.
153 Note: a UTF-16 surrogate pair is contained in two consecutive Char16 objects.
154 To keep backwards compatibilty, the methods on the String class have not
155 changed. New methods have been added as needed. The following
156 describes this in more detail:
157 <ul>
158 <li>
159 The Pegasus 2.2 methods that take a char *, or return char *, are unchanged.
160 Code written to Pegasus 2.2 may have expected to store 8-bit ASCII (ISO-8859-1)
161 characters into String. These methods will convert the input to UTF-16
162 from 8-bit ASCII. (This is simple because UTF-16 is a superset of
163 8-bit ASCII - simply need to prepend '\0' to each char). The Pegasus
164 2.2 methods that return char data will attempt to convert from the UTF-16
165 internal representation to 8-bit ASCII. Characters that cannot be
166 converted will be replaced with a substitution character.</li>
167
168 <br>
169 chuck 1.1 <li>
170 All methods that take or return Char16 data are unchanged. The String
171 class now supports UTF-16 data in Char16, although surrogate pairs will
172 require two consecutive Char16 objects. The String class does NO
173 checking for unmatched surrogate pairs.</li>
174
175 <br>
176 <li>
177 New methods have been added to take and return UTF-8 data. The String
178 class will convert between UTF-8 and the UTF-16 internal representation
179 as needed. These new methods will use char * parameters, but will
180 be clearly labelled as UTF-8 methods.</li>
181
182 <br> </ul>
183 PROGRAMMING NOTE: Putting EBCDIC data into the String class is dangerous.
184 The String class is designed for UTF-16, which is a superset of 8-bit ASCII.
185 Any String object containing EBCDIC data will not work if it is used by
186 Pegasus to read or write data from external sources, such as the network
187 or repository files. In other words, any String containing EBCDIC
188 data should not leave the code using it.
189 <br>
190 chuck 1.1 <br>
191 <h3>
192 2.2 Localization Support</h3>
193
194 <h4>
195 2.2.1 Language Headers</h4>
196
197 <p><br>Pegasus 2.3 supports clients and providers that wish to localize.
198 There are two areas to be localized: <a href="http://www.dmtf.org/standards/documents/WBEM/DSP201.html#SecERROR">ERROR</a>
199 elements in the CIM-XML; and <a href="http://www.dmtf.org/standards/documents/WBEM/DSP201.html#SecObjectDefinitionElements">Object
200 Definition</a> elements in the CIM-XML. Clients can request
201 the server to return error messages and CIM objects in a set of languages
202 of their choosing. Clients can also tag a language to the CIM objects
203 they are sending to the server. Providers and the server can return
204 error messages and CIM objects that are tagged with one of languages
205 requested by the client.
206 <br>
207 <p>The localization design is based on section 4.8 of the <a href="http://www.dmtf.org/standards/documents/WBEM/DSP200.html">CIM-HTTP
208 specification</a> , which refers to <a href="http://www.ietf.org/rfc/rfc2616.txt?number=2616">RFC
209 2616</a>. The method used to tag a language to the CIM-XML is through
210 the Accept-Language and Content-Language HTTP headers. These headers
211 chuck 1.1 are basically lists of language tags. An HTTP request can contain
212 an Accept-Language header, which indicates the list of preferred languages
213 that the client wants in the response. This list can be prioritized
214 by using the quality numbers. An HTTP request or response can contain
215 a Content-Language header, which indicates the language(s) of the content
216 in the message. In the Pegasus case, this would be the CIM-XML.
217 Note that the Content-Language header is a list of language tags.
218 This allows the content of an HTTP message to contain more than one translation.
219 However, in the Pegasus case, there is only one CIM-XML document in the
220 HTTP message, and thus one translation.
221 <br>
222 <p>CIM clients may use the Accept-Language HTTP header to specify the languages
223 they wish to be returned in the CIM response message. CIM clients
224 may also use the Content-Language header to tag the language of any CIM
225 objects they are sending to the server in the CIM request message.
226 The server, and providers, should attempt to return error messages and
227 CIM objects in one of the accept languages requested by the client.
228 The server and providers should set the Content-Language header in the
229 CIM response message to indicate which of the requested languages they
230 are returning.
231 <br>
232 chuck 1.1 <p>NOTE: Localization support was not added for the MOF files and
233 repository in Pegasus 2.3. The #pragma locale, #pragma instancelocale,
234 and translatable qualifier flavor are not supported in the Pegasus 2.3
235 MOF compiler. From the client perspective, classes, qualifiers, and
236 instances stored in the repository as not tagged with a language.
237 The Accept-Language and Content-Language headers will be ignored for repository
238 operations. However, since the repository will support UTF-8,
239 characters for any language may be stored there.
240 <br>
241 <p>NOTE: Since the Content-Language header applies to the entire
242 HTTP message, it applies to the entire CIM-XML document. This includes
243 all the objects in the document, including enumerated objects, and all
244 the values in the objects. This is a limitation that will remain
245 until the CIM standard has been updated to support language tags tied to
246 individual CIM values. From the client perspective, it is possible
247 for Pegasus to send a CIM response with NO Content-Language, even if the
248 client had sent Accept-Language. This can happen if Pegasus
249 does not know the language of the response. An example is a request
250 that was sent to a Pegasus 2.2 provider. Another example is an enumerated
251 response where each provider returned a different language. Please
252 refer to PEP58 for details on these provider scenarios.
253 chuck 1.1 <br>
254 <p>Pegasus 2.3 has added classes for the localization support. There
255 are new classes called AcceptLanguages and ContentLanguages that encapsulate
256 the Accept-Language and Content-Language headers, respectively. These
257 classes are basically containers of AcceptLanguageElement and ContentLanguageElement,
258 where a language element represents one language tag. The AcceptLanguages
259 class will keep the AcceptLanguageElement's prioritized based on quality,
260 according to RFC 2616.
261 <br>
262 <p>AcceptLanguages and ContentLanguages are the objects used by code throughout
263 the request/response processing, from the client to the server to the providers
264 and back. The server handles the creation of these objects from the
265 HTTP headers. Code at each point in the process will have access
266 to these objects.
267 <br>
268 <p>Please refer to the following files for details on the new Pegasus classes.
269 <br>
270 <ul>
271 <li>
272 pegasus/src/Pegasus/Common/AcceptLanguages.h</li>
273
274 chuck 1.1 <li>
275 pegasus/src/Pegasus/Common/AcceptLanguageElement.h</li>
276
277 <li>
278 pegasus/src/Pegasus/Common/ContentLanguages.h</li>
279
280 <li>
281 pegasus/src/Pegasus/Common/ContentLanguageElement.h</li>
282
283 <li>
284 pegasus/src/Pegasus/Common/LanguageElementContainer.h</li>
285
286 <li>
287 pegasus/src/Pegasus/Common/LanguageElement.h</li>
288 </ul>
289
290 <p><br>See the sections below for details on how to write clients and providers
291 to use these classes.
292 <br>
293 <br>
294 <h4>
295 chuck 1.1 2.2.2 Message Loading</h4>
296
297 <p><br>One of the goals of globalization for Pegasus 2.3 is the extraction
298 of hardcoded messages into external message files, and loading messages
299 from those files. The topics in this section are: how to create
300 message files, and how to load messages.
301 <br>
302 <p>At the time of writing, the message loading function in Pegasus 2.3
303 used the International Components for Unicode (<a href="http://oss.software.ibm.com/icu">ICU)</a>
304 libraries. This is expected to be the future direction for Pegasus.
305 <a href="http://oss.software.ibm.com/icu">ICU
306 </a>uses
307 a resource bundle format for their message files. In order
308 to load the messages, ICU requires that the resource bundles are compiled
309 into a binary form (.res file) using their genrb tool.
310 <br>
311 <p>The documentation for ICU resource bundles is in the <a href="http://oss.software.ibm.com/icu/userguide/ResourceManagement.html">Resource
312 Management</a> section of the <a href="http://oss.software.ibm.com/icu/userguide/">ICU
313 User Guide</a> . This section will tell you how to
314 <br>create, organize, and compile your resource bundles for different languages.
315 Note: your resource bundles should be organized in a tree structure
316 chuck 1.1 similiar to the one shown in the Resource Management section, including
317 the empty bundles in the tree.
318 <br>
319 <p>NOTE: Pegasus 2.3 only supports simple string resources in the
320 ICU resource bundles. String resources may only be loaded by key.
321 Tables, arrays, and other complex resource types, are not supported.
322 <br>
323 <p>Code that needs to load a message in Pegasus does not call ICU directly.
324 Two message loading classes were added for Pegasus 2.3: MessageLoader
325 and MessageLoaderParms. These classes are abstractions designed to
326 hide of the actual loader used. The MessageLoader is used to
327 load a message using a list of preferrred languages. The parameters
328 to MessageLoader are encapsulated in a MessageLoaderParms object.
329 <br>
330 <p>The MessageLoaderParms object contains the parameters to load the message.
331 There are many parameters, but many can be allowed to default. Here
332 is a description of the parameters:
333 <br>
334 <p>NOTE: WORK-IN- PROGRESS
335 <br>
336 <br>
337 chuck 1.1 <table BORDER COLS=3 WIDTH="100%" NOSAVE >
338 <tr>
339 <td>String msg_id; </td>
340
341 <td>Input.
342 <br>Required.</td>
343
344 <td>Message ID of the message to load from the resource bundle.
345 This is the key that ICU will use to load the message.</td>
346 </tr>
347
348 <tr>
349 <td>String default_msg;</td>
350
351 <td>Input.
352 <br>Required</td>
353
354 <td>Message to return if the no message can be loaded for msg_id from a
355 resource bundle. Note: The args parameters below are substituted
356 into this string.
357 <br>Note: For the args into this string, use the Pegasus '$'
358 chuck 1.1 form, as described in pegasus/src/Pegasus/Common/Formatter.h. Don't
359 use the ICU substitution format for the default message string.</td>
360 </tr>
361
362 <tr>
363 <td>String msg_src_path; </td>
364
365 <td>Input.
366 <br>Optional
367 <br>Default: $PEGASUS_HOME/msg/pegasus/pegasusServer</td>
368
369 <td>Path to the root resource bundle file which contains the msg_id.
370 Do not include the language or file extension as part of the path.
371 <br>Note: relative paths start at $PEGASUS_HOME/msg. </td>
372 </tr>
373
374 <tr>
375 <td>AcceptLanguages acceptlanguages;</td>
376
377 <td>Input.
378 <br>Optional
379 chuck 1.1 <br>Default: AcceptLanguages::EMPTY</td>
380
381 <td>Contains the list of preferred languages, in priority order.
382 This is combined with msg_src_path to determine which resource bundles
383 to search for for the msg_id. If not EMPTY, overrides useThreadLocale
384 and useProcessLocale.</td>
385 </tr>
386
387 <tr>
388 <td>ContentLanguages contentlanguages;</td>
389
390 <td>Output</td>
391
392 <td>Contains the language that MessageLoader found for the msg_id. </td>
393 </tr>
394
395 <tr>
396 <td>Boolean useProcessLocale;</td>
397
398 <td>Input
399 <br>Optional
400 chuck 1.1 <br>Default = false</td>
401
402 <td>If true, MessageLoader will use the default locale of the process.
403 If true, overrides useThreadLocale.</td>
404 </tr>
405
406 <tr>
407 <td>Boolean useThreadLocale;</td>
408
409 <td>Input
410 <br>Optional
411 <br>Default = <font color="#FF0000">true</font></td>
412
413 <td>If true, MessageLoader will use the locale of the caller's thread. </td>
414 </tr>
415
416 <tr>
417 <td>Boolean useICUfallback</td>
418
419 <td>Input
420 <br>Optional
421 chuck 1.1 <br>Default = false</td>
422
423 <td>If true, use ICU's fallback mechnism to search more general resource
424 bundles if the msg_id cannot be found. Note: the recommended setting
425 is false if you are using an AcceptLanguages from a CIM client. The
426 Accept-Languages HTTP header from the client contains the fallback specifications.</td>
427 </tr>
428
429 <tr>
430 <td>Formatter::Arg arg0;
431 <br> Formatter::Arg arg1;
432 <br> Formatter::Arg arg2;
433 <br> Formatter::Arg arg3;
434 <br> Formatter::Arg arg4;
435 <br> Formatter::Arg arg5;
436 <br> Formatter::Arg arg6;
437 <br> Formatter::Arg arg7;
438 <br> Formatter::Arg arg8;
439 <br> Formatter::Arg arg9;</td>
440
441 <td>Input
442 chuck 1.1 <br>Optional
443 <br>Default: Formatter::Arg( ) // empty arg</td>
444
445 <td>These are the substitution variables, using the Pegasus Formatter::Arg
446 class.</td>
447 </tr>
448 </table>
449
450 <p>Please refer to the following files for details on the new Pegasus classes.
451 <br>
452 <ul>
453 <li>
454 pegasus/src/Pegasus/Common/MessageLoader.h</li>
455 </ul>
456
457 <h4>
458 2.2.3 Message Loading Example</h4>
459
460 <p>
461 <br>
462 <br>
463 chuck 1.1 <br>
464 <br>
465 <br>
466 <br>
467 <br>
468 <br>
469 <br>
470 <br>
471 <p>The following example shows how a message may be loaded using the classes
472 described above. Note: this a generic example. Each of the
473 developer sections below have 'real-life' examples that are better suited
474 to each type of code.
475 <p>// Build an AcceptLanguages with some language elements
476 <br>AcceptLanguages acceptLangs;
477 <br>acceptLangs.add(AcceptLanguageElement("fr", 0.5));
478 <br>acceptLangs.add(AcceptLanguageElement("de", 0.8));
479 <br>acceptLangs.add(AcceptLanguageElement("es", 0.4));
480 <p>// Construct a MessageLoaderParms
481 <br>MessageLoaderParms parms("msgID", "default message");
482 <br>parms. msg_src_path = "/my_msg_dir/my_bundle";
483 <br>parms.acceptlanguages = acceptLangs;
484 chuck 1.1 <p>// Note: If you have args, set them into MessageLoaderParms
485 <p>// Load the localized String
486 <br>String localizedMsg = MessageLoader::getMessage(parms);
487 <br>
488 <br>
489 <h4>
490 2.2.4 Message Writing Guidelines</h4>
491
492 <p><br>Here are some basic rules for writing messages:
493 <br>
494 <ul>
495 <li>
496 If you want to claim that you are globalized, no hardcoded messages!</li>
497
498 <li>
499 Avoid combining messages in the code from other messages. When you
500 do this you are assuming that you know the grammar for every language.</li>
501
502 <li>
503 String substitutions into messages are generally untranslated, ie. not
504 loaded from the resource bundle. Example: a file name.</li>
505 chuck 1.1
506 <li>
507 Avoid jargon, humour, and cultural idioms. Use full sentences.
508 Have your messages reviewed by your globalization team. Your messages
509 need to make sense to the translators, and ultimately the customer.</li>
510
511 <li>
512 <b>TODO </b>- find a good message writing guide to link to</li>
513 </ul>
514
515 <h2>
516 3.0 Provider Developers</h2>
517
518 <h3>
519 3.1 Design Issues</h3>
520
521 <p><br>Providers that wish to globalize should consider the following in
522 their design:
523 <br>
524 <ul>
525 <li>
526 chuck 1.1 Are there localized string properties that need to be supported?
527 If so, then the client will use Accept-Language to request specific languages
528 for these properties. If the properties are read-only, use MessageLoader
529 to load the localized strings for the properties.</li>
530
531 <li>
532 If you have a localized read/write string property, then the client will
533 use Content-Language to set the property with an associated language.
534 The client will expect to be able to retrieve the property in that same
535 language later (using Accept-Language).</li>
536
537 <li>
538 Note: only the string property types in CIM are candidates for localization.
539 The other types, including datetime, are locale-neutral.</li>
540
541 <li>
542 Are there error messages that need to returned to the client in different
543 languages? The client will use Accept-Language to request specific
544 languages for the error messages.</li>
545
546 <li>
547 chuck 1.1 What resource bundle translations, if any, will be shipped with the provider?</li>
548
549 <li>
550 Do any codepage conversions need to be done between the UTF-16 characters
551 in the String objects and the codepage of data stored on the system?
552 This is a concern for EBCDIC platforms. All EBCDIC data needs to
553 be converted to at least 7-bit ASCII before it is passed into the String
554 object.</li>
555 </ul>
556
557 <p><br>To help providers handle the situations described above, Pegasus
558 2.3 will pass the Accept-Language received from the client to the provider.
559 The provider should load strings from its resource bundle based on the
560 client's Accept-Language. The client's Accept-Language is passed
561 to the provider in two ways:
562 <br>
563 <ul>
564 <li>
565 Pegasus will set the Accept-Language from the client into the thread in
566 which the provider is running. By using the useThreadLocale setting
567 in MessageLoaderParms, providers can easily load strings using the client's
568 chuck 1.1 requested Accept-Language. The provider does not need to know what
569 the Accept-Language is. This is the recommended method to load messages
570 based on the client's request.</li>
571
572 <br>
573 <li>
574 The OperationContext will contain an AcceptLanguages object that has the
575 Accept-Language requested by the client. The provider can use this
576 AcceptLanguages object to load strings with MessageLoader.</li>
577 </ul>
578
579 <p><br>The OperationContext will also contain a ContentLanguages object
580 that is set from the Content-Language in the client request. This
581 is the language of the CIM objects being passed to the provider on that
582 request. A localized provider should store the content language along
583 with the data from the CIM objects. This will allow the client to
584 use Accept-Language later to retreive the data in that language.
585 <br>
586 <p>The provider should indicate the language of CIM objects it is returning
587 by calling setLanguage( ) on the ResponseHandler. This will be used
588 to set the Content-Language in the CIM response message sent back to the
589 chuck 1.1 client. If setLanguage( ) is not called, then no Content-Language
590 will be returned to the client. setLanguage( ) should only be called
591 once per response.
592 <br>
593 <h3>
594 3.2 Sample Code</h3>
595
596 <p><br>The following sample code shows a localized getInstance( ) where
597 the instance returned is localized based on the Accept-Language of the
598 client request. Note that this example also throws a localized exception.
599 <br>
600 <p>void LocalizedProvider::getInstance(
601 <br> const OperationContext & context,
602 <br> const CIMObjectPath & instanceReference,
603 <br> const Boolean includeQualifiers,
604 <br> const Boolean includeClassOrigin,
605 <br> const CIMPropertyList & propertyList,
606 <br> InstanceResponseHandler & handler)
607 <br>{
608 <br> // convert a potential fully qualified reference
609 into a local reference
610 chuck 1.1 <br> // (class name and keys only).
611 <br> CIMObjectPath localReference = CIMObjectPath(
612 <br> String(),
613 <br> String(),
614 <br> instanceReference.getClassName(),
615 <br> instanceReference.getKeyBindings());
616 <p> // begin processing the request
617 <br> handler.processing();
618 <p> // Find the instance to be returned.
619 <br> Uint32 i;
620 <br> Uint32 n = _instances.size();
621 <br> for (i = 0; i < n; i++)
622 <br> {
623 <br> if(localReference
624 == _instanceNames[i])
625 <br> {
626 <br>
627 // We found the instance to return
628 <p>
629 // Build the parameters for loading the localized string property.
630 <br>
631 chuck 1.1 // We are going to let the message loader parameters default to use the
632 <br>
633 // AcceptLanguages that Pegasus set into our thread.
634 <br>
635 // (this equals the AcceptLanguages requested by the client)
636 <br>
637 // Note: This parms object could be constructed once and
638 <br>
639 // reused.
640 <br>
641 MessageLoaderParms parms("myMsgID", "myDefaultString");
642 <br>
643 parms.msg_src_path = "/myprovider/msg/myResourceBundle";
644 <p>
645 // Load the string for the localized property from the resource bundle
646 <br>
647 String localizedString = MessageLoader::getMessage(parms);
648 <p>
649 // Remove the old property from the instance to be returned
650 <br>
651 Uint32 index = instances[i].findProperty("myProperty");
652 chuck 1.1 <br>
653 if (index != PEG_NOT_FOUND)
654 <br>
655 {
656 <br>
657 _instances[i].removeProperty(index);
658 <br>
659 }
660 <p>
661 // Add the localized string property to the instance
662 <br>
663 instances[i].addProperty(CIMProperty("myProperty", localizedString));
664 <p>
665 // The MessageLoader set the contentlanguages member
666 <br>
667 // of parms to the language that it found for the message.
668 <br>
669 ContentLanguages rtnLangs = parms.contentlanguages;
670 <p>
671 // We need to tag the instance we are returning with the
672 <br>
673 chuck 1.1 // the content language.
674 <br>
675 handler.setLanguages(rtnLangs);
676 <p>
677 // deliver requested instance
678 <br>
679 handler.deliver(_instances[i]);
680 <p>
681 break;
682 <br>
683 } // end if
684 <br> }
685 // end for
686 <p> // throw an exception if
687 the instance wasn't found
688 <br> if (i == n)
689 <br> {
690 <br>
691 // Build the parameters for loading the localized error message.
692 <br>
693 // We are going to let the message loader parameters default to use the
694 chuck 1.1 <br>
695 // AcceptLanguages that Pegasus set into our thread.
696 <br>
697 // (this equals the AcceptLanguages requested by the client)
698 <br>
699 // Note: This parms object could be constructed once and
700 <br>
701 // reused.
702 <br>
703 MessageLoaderParms errParms("myErrorMsgID", "myErrorDefaultString");
704 <br>
705 errParms.msg_src_path = "/myprovider/msg/myResourceBundle";
706 <p>
707 // Note: the exception calls MessageLoader::getMessage( )
708 <br>
709 // Note: no need to call handler.setLanguages( ) in this case
710 <br>
711 throw CIMObjectNotFoundException(errParms);
712 <br> }
713 <br>
714 <p> // complete processing the
715 chuck 1.1 request
716 <br> handler.complete();
717 <br>}
718 <br>
719 <p>NOTE: A sample provider has been written that fully demonstates the
720 design issues described above. This provider is located at:
721 <br>
722 <ul>
723 <li>
724 pegasus/src/Providers/sample/LocalizedProvider/</li>
725 </ul>
726
727 <p><br>This sample provider also demonstrates how some of the special issues
728 can be handled. The special issues are caused by having a read/only
729 localized property and a read/write localized property. What happens
730 if the client sets the read/write property with a Content-Language that
731 is not one of the supported languages for the read/only property?
732 This provider allows the client to set any language into the read/write
733 property, and get that property back in the same language. This becomes
734 an issue when the client does a getInstance( ) later, because the Content-Language
735 on the returned instance applies to all the properties. A related
736 chuck 1.1 issue is what to return for Content-Language when the client does enumerateInstances,
737 but the instances have different languages. Recall that Content-Language
738 applies to the entire response (a limitation in the CIM specification).
739 <br>
740 <p>NOTE: Indication Providers have other special considerations for
741 language support. Please refer to PEP58.
742 <br>
743 <p>NOTE: The CMPI interface has been updated for language support.
744 Please refer to the CMPI documentation for details.
745 <br>
746 <p>NOTE: SPECIAL ISSUES FOR OS/400 PROVIDERS:
747 <ul>
748 <li>
749 Convert between UTF-16 in the String objects and EBCDIC system data as
750 needed. The converters in Pegasus/Common/OS400ConvertChar.h may be
751 used to convert between EBCDIC CCSID 37 and ASCII CCSID 819 (a subset of
752 UTF-16).</li>
753
754 <li>
755 The Pegasus program, and all bound service programs, will run in
756 a UTF-8 locale even though the job CCSID is 37. The C-runtime library
757 chuck 1.1 (printf, fopen, isalpha, strcmp, etc) will expect UTF-8, or at least 7-bit
758 ASCII, characters.</li>
759
760 <li>
761 Consideration should be given to the codepage for the compiled string literals.
762 Use #pragma convert as needed. But, remember that the C-runtime will
763 expect UTF-8.</li>
764
765 <li>
766 For more details, refer to "Unicode support" in chapter 3 of the <u>ILE
767 C/C++ for iSeries Run-Time Functions, Version 5</u> publication for V5R3
768 (SC41-5607-02). The Pegasus string literals will be compiled with
769 the UTF-8 compile switch described in this section. OS/400 provider
770 developers should strongly consider using the same compile switch for their
771 string literals. This would allow the literals to match the UTF-8
772 encoding expected by the C-runtime.</li>
773 </ul>
774
775 <h2>
776 4. 0 Client Developers</h2>
777
778 chuck 1.1 <p><br>Methods have been added to CIMClient to set the Accept-Language
779 and Content-Language on the request, and retrieve Content-Language on the
780 response.
781 <br>
782 <p>Please refer to
783 <br>
784 <ul>
785 <li>
786 pegasus/src/Pegasus/Client/CIMClient.h</li>
787
788 <br> </ul>
789 for the new methods on CIMClient.
790 <br>
791 <p>Here is a code fragment that uses the new methods on CIMClient
792 <p> //
793 <br> // Get a localized instance in French
794 <br> //
795 <p> // Language priority is martian, pig-latin, and french.
796 We should
797 <br> // get french back, even though its the lowest priority
798 <br> AcceptLanguages acceptLangs;
799 chuck 1.1 <br> acceptLangs.add(AcceptLanguageElement("x-martian"));
800 <br> acceptLangs.add(AcceptLanguageElement("fr", 0.1));
801 <br> acceptLangs.add(AcceptLanguageElement("x-pig-latin", 0.4));
802 <p> // Set the requested languages into the CIMClient
803 <br> client.setRequestAcceptLanguages(acceptLangs);
804 <p> // Get the instance
805 <br> CIMInstance instance = client.getInstance(
806 <br> NAMESPACE,
807 <br> cimNInstances[0].buildPath(sampleClass),
808 <br> localOnly,
809 <br> includeQualifiers,
810 <br> includeClassOrigin);
811 <p> // Get the string property that should be french
812 <br> String returnedString;
813 <br> instance.getProperty (
814 <br> instance.findProperty("myProp")).
815 <br>
816 getValue().
817 <br>
818 get(returnedString);
819 <p> // Check that we got back french
820 chuck 1.1 <br> ContentLanguages CL_FR("fr");
821 <br> String expectedFRString = "oui";
822 <br> PEGASUS_ASSERT(CL_FR == client.getResponseContentLanguages());
823 <br> PEGASUS_ASSERT(expectedFRString == returnedString);
824 <p> //
825 <br> // Create an instance in French
826 <br> //
827 <p> String oui = "Oui";
828 <br> CIMInstance frInstance(CLASSNAME);
829 <br> frInstance.addProperty(CIMProperty(
830 <br>
831 CIMName("myProp"),
832 <br>
833 oui));
834 <p> CIMObjectPath frInstanceName = frInstance.buildPath(sampleClass);
835 <p> client.setRequestContentLanguages(CL_FR);
836 <p> client.createInstance(NAMESPACE, frInstance);
837 <br>
838 <br>
839 <br>
840 <p>Also, refer to
841 chuck 1.1 <ul>
842 <li>
843 pegasus/src/Clients/g11ntest/</li>
844 </ul>
845 for more examples of a client that uses Accept-Language and Content-Language.
846 <br>
847 <p>NOTE: Consideration should be given for converting the UTF-16
848 characters in the String objects passed over the CIMClient interface to
849 a platform codepage. This is especially needed for EBCDIC platforms.
850 See the Provider developer section for details of the EBCDIC considerations.
851 <br>
852 <p><b>TODO</b> - some info on how CIMClient defaults the Accept-Languages.
853 <br>
854 <h2>
855 5. 0 Pegasus Developers</h2>
856
857 <p><br>The design for Pegasus releases beyond 2.3 is to avoid using hardcoded
858 messages. All new messages should be loaded from a Pegasus resource
859 bundle. This section describes the process to follow if you are creating
860 a new message. The process depends on where you are in the code.
861 <br>
862 chuck 1.1 <br>
863 <h3>
864 <b>5.1 Pegasus Resource Bundles</b></h3>
865
866 <p><br>Place any new Pegasus messages into one of the following resource
867 bundles:
868 <br>
869 <ul>
870 <li>
871 pegasus/src/Pegasus/msg/Server/pegasusServer.txt for server messages</li>
872
873 <li>
874 pegasus/src/Clients/<cli_name>/msg/<cli_name>.txt for CLI messages</li>
875 </ul>
876 Note: As described above, the resource bundle path in MessageLoaderParms
877 defaults to the server resource bundle. For CLI messages, you will
878 need to specify the bundle for your CLI.
879 <br>
880 <h3>
881 5.2 Server Messages</h3>
882
883 chuck 1.1 <p><br>For messages returned from one of the services in the Pegasus server
884 (eg. CIMOperationRequestDispatcher, or ProviderManagerService), the goal
885 is to make it easy for any code in the call chain to throw an exception
886 with a localized error string. The code throwing the exception will
887 not need to know the Accept-Language that the client requested. To
888 understand how this works, some design points need to described:
889 <br>
890 <p><b>Server Design Points:</b>
891 <br>
892 <p>The CIMMessage object has been expanded to include an AcceptLanguages
893 object and a ContentLanguages object. For CIMRequestMessage, these
894 objects contain the Accept-Language and Content-Language headers that were
895 built from the client request. For CIMResponseMessage, the ContentLanguages
896 object is used to build the Content-Language header associated with the
897 CIM <i>objects </i>in the response message. The AcceptLanguages object
898 in the CIMResponseMessage is ignored.
899 <br>
900 <p>The localization of the cimException object in the CIMResponseMessage
901 is handled separately from the CIM objects. The message string in
902 the cimException object is assumed to have been localized by the time it
903 is built into the XML. For this reason, the localization of the exception
904 chuck 1.1 is the responsibility of the code throwing the exception. (The goal
905 of the design is to make that easy - see below). The ContentLanguages
906 object in the CIMResponseMessage has NO relation to this exception.
907 The cimException object keeps its own localization information once it
908 is created.
909 <br>
910 <p>To enable exceptions to be localized, the ability was added to set a
911 global language for all the code running from a Pegasus Thread object.
912 The top level code for a Thread can set a global AcceptLanguages object
913 that can accessed by all the low-level functions that it calls. This
914 will allow an exception thrown by low-level code to be localized based
915 on this global AcceptLanguages object. Note: This applies only
916 to Threads that are managed by a ThreadPool.
917 <br>
918 <p>Each service in the request path of the Pegasus server sets the AcceptLanguages
919 into its Thread from the AcceptLanguages in the CIMRequestMessage object
920 that it dequeues. This sets the global langauge for all the functions
921 in the same thread that are called below handleEnqueue. <i>If you
922 are writing a new service that processes requests, or discover a request
923 service that was missed, please do this. </i> The CIMOperationRequestDispatcher
924 service is an example.
925 chuck 1.1 <br>
926 <p><b>How to Throw a Localized Exception from Server code:</b>
927 <br>
928 <p>With all that background, here is how code running in a Pegasus service
929 can throw a localized exception:
930 <br>This example assumes that the top-level code in the service had set
931 the global thread language beforehand. As described above, every
932 service in Pegasus should do that.
933 <p>// First, construct a MessageLoaderParms
934 <br>//
935 <br>// Notes:
936 <br>// 1) The errorMessageID must be in the Pegasus server resource
937 bundle.
938 <br>// 2) The default message is the old "hardcoded" message.
939 <br>// 3) The MessageLoaderParms will default to use the Pegasus
940 server resource bundle
941 <br>// 4) The MessageLoaderParms will default to use the locale of
942 the current thread. Don't change this!
943 <br>// 5) You might need to set the arguments for the message into
944 the MessageLoaderParms
945 <br>MessageLoaderParms parms("errorMessageID", "default message");
946 chuck 1.1 <p>// Second, throw the Exception
947 <br>// Note: this applies to all the derived classes from Exception, including
948 the CIMException's
949 <br>throw new Exception(parms);
950 <br>
951 <p>NOTE: If you are throwing an Exception with un-localized data,
952 use the constructor that takes a String. An example of this would
953 be an Exception where you are passing in a file name. Most of the
954 "non-CIM" exceptions defined in Exception.h and InternalException.h take
955 un-localized data.
956 <br>
957 <p><b>How to Load a Localized Message</b>
958 <p>For code that may <i>not </i>be running in a Thread with the global
959 language set, but has access to the AcceptLanguages object from the CIMMessage,
960 <br>the code is simple:
961 <p>// Construct a MessageLoaderParms
962 <br>//
963 <br>// Notes:
964 <br>// 1) The errorMessageID must be in the Pegasus server resource
965 bundle.
966 <br>// 2) The default message is the old "hardcoded" message.
967 chuck 1.1 <br>// 3) The MessageLoaderParms will default to use the Pegasus
968 server resource bundle
969 <br>// 4) The MessageLoaderParms will default to use the locale of
970 the current thread. You will change this below.
971 <br>// 5) You might need to set the arguments for the message into
972 the MessageLoaderParms
973 <br>MessageLoaderParms parms("errorMessageID", "default message");
974 <p>// Tell the MessageLoaderParms which languages to search for.
975 <br>// MessageLoaderParms will not use the thread locale in this case.
976 <br>parms.acceptlanguages = <pass in the AcceptLanguages object>
977 <p>// Load the localized String
978 <br>String localizedMsg = MessageLoader::getMessage(parms);
979 <br>
980 <h3>
981 5.2 Logger Messages</h3>
982
983 <p><br>New methods have been added to Logger to take a message ID of a
984 message to be loaded from the Pegasus server resource bundle. The
985 caller is only required to pass in the message ID, and the old "hardcoded"
986 message, and the args. The Logger will use MessageLoader to load
987 the message in the locale of the Pegasus server <i>process</i>, using the
988 chuck 1.1 hardcoded message as the default string. Please refer to pegasus/src/Pegasus/Logger.h
989 <br>
990 <h3>
991 5.3 CLI Messages</h3>
992
993 <p><br>Code in the client side of the client/server CLIs (eg. cimconfig,
994 cimmof), or in directly linked CLIs (cimmofl), should use the useProcessLocale
995 setting in MessageLoaderParms. This will cause the messages to be
996 loaded in the locale based on the environment in which the program is running.
997 This locale can be set by the user before running the program.
998 <p><b>TODO - </b>describe how CIMClient will default the Accept-Language
999 from the process locale.
1000 <br>
1001 <br>
1002 <p>
1003 <hr>
1004 <p><i>Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company,
1005 L.P.; IBM Corp.; The Open Group</i>
1006 <p><i>Permission is hereby granted, free of charge, to any person obtaining
1007 a copy of this software and associated documentation files (the "Software"),
1008 to deal in the Software without restriction, including without limitation
1009 chuck 1.1 the rights to use, copy, modify, merge, publish, distribute, sublicense,
1010 and/or sell copies of the Software, and to permit persons to whom the Software
1011 is furnished to do so, subject to the following conditions:</i>
1012 <p><i>THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED
1013 IN ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS
1014 PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
1015 INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
1016 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
1017 OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
1018 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
1019 OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1020 SOFTWARE.</i>
1021 <br>
1022 <br>
1023 </body>
1024 </html>
|