KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > util > NbBundle


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.openide.util;
21
22 import java.io.IOException JavaDoc;
23 import java.io.InputStream JavaDoc;
24 import java.lang.ref.Reference JavaDoc;
25 import java.lang.ref.WeakReference JavaDoc;
26 import java.net.URL JavaDoc;
27 import java.util.ArrayList JavaDoc;
28 import java.util.Collections JavaDoc;
29 import java.util.Enumeration JavaDoc;
30 import java.util.HashMap JavaDoc;
31 import java.util.Iterator JavaDoc;
32 import java.util.LinkedList JavaDoc;
33 import java.util.List JavaDoc;
34 import java.util.Locale JavaDoc;
35 import java.util.Map JavaDoc;
36 import java.util.MissingResourceException JavaDoc;
37 import java.util.NoSuchElementException JavaDoc;
38 import java.util.Properties JavaDoc;
39 import java.util.ResourceBundle JavaDoc;
40 import java.util.WeakHashMap JavaDoc;
41 import java.util.jar.Attributes JavaDoc;
42 import java.util.logging.Level JavaDoc;
43 import java.util.logging.Logger JavaDoc;
44
45 /** Convenience class permitting easy loading of localized resources of various sorts.
46 * Extends the functionality of the default Java resource support, and interacts
47 * better with class loaders in a multiple-loader system.
48 * <p>Example usage:
49 * <p><code><pre>
50 * package com.mycom;
51 * public class Foo {
52 * // Search for tag Foo_theMessage in /com/mycom/Bundle.properties:
53 * private static String theMessage = {@link NbBundle#getMessage(Class, String) NbBundle.getMessage} (Foo.class, "Foo_theMessage");
54 * // Might also look in /com/mycom/Bundle_de.properties, etc.
55 * }
56 * </pre></code>
57 */

58 public class NbBundle extends Object JavaDoc {
59     
60     private static final boolean USE_DEBUG_LOADER = Boolean.getBoolean("org.openide.util.NbBundle.DEBUG"); // NOI18N
61
private static String JavaDoc brandingToken = null;
62
63     /**
64      * Cache of URLs for localized files.
65      * Keeps only weak references to the class loaders.
66      * @see "#9275"
67      */

68     static final Map JavaDoc<ClassLoader JavaDoc,Map JavaDoc<String JavaDoc,URL JavaDoc>> localizedFileCache = new WeakHashMap JavaDoc<ClassLoader JavaDoc,Map JavaDoc<String JavaDoc,URL JavaDoc>>();
69
70     /**
71      * Cache of resource bundles.
72      */

73     static final Map JavaDoc<ClassLoader JavaDoc,Map JavaDoc<String JavaDoc,Reference JavaDoc<ResourceBundle JavaDoc>>> bundleCache = new WeakHashMap JavaDoc<ClassLoader JavaDoc,Map JavaDoc<String JavaDoc,Reference JavaDoc<ResourceBundle JavaDoc>>>();
74
75     /**
76      * Do not call.
77      * @deprecated There is no reason to instantiate or subclass this class.
78      * All methods in it are static.
79      */

80     @Deprecated JavaDoc
81     public NbBundle() {
82     }
83
84     /** Get the current branding token.
85      * @return the branding, or <code>null</code> for none
86      */

87     public static String JavaDoc getBranding() {
88         return brandingToken;
89     }
90
91     /** Set the current branding token.
92      * The permitted format, as a regular expression:
93      * <pre>[a-z][a-z0-9]*(_[a-z][a-z0-9]*)*</pre>
94      * <p class="nonnormative">
95      * This is normally only called by NetBeans startup code and unit tests.
96      * Currently the branding may be specified by passing the <code>--branding</code>
97      * command-line option to the launcher.
98      * </p>
99      * @param bt the new branding, or <code>null</code> to clear
100      * @throws IllegalArgumentException if in an incorrect format
101      */

102     public static void setBranding(String JavaDoc bt) throws IllegalArgumentException JavaDoc {
103         if (bt != null && !bt.matches("[a-z][a-z0-9]*(_[a-z][a-z0-9]*)*")) { // NOI18N
104
throw new IllegalArgumentException JavaDoc("Malformed branding token: " + bt); // NOI18N
105
}
106         brandingToken = bt;
107     }
108
109     /**
110      * Get a localized and/or branded file in the default locale with the default class loader.
111     * <p>Note that use of this call is similar to using the URL protocol <code>nbresloc</code>
112     * (which may in fact be implemented using the fuller form of the method).
113     * <p>The extension may be null, in which case no final dot will be appended.
114     * If it is the empty string, the resource will end in a dot.
115     * @param baseName base name of file, as dot-separated path (e.g. <code>some.dir.File</code>)
116     * @param ext extension of file (or <code>null</code>)
117     * @return URL of matching localized file
118     * @throws MissingResourceException if not found
119      * @deprecated Use the <code>nbresloc</code> URL protocol instead. This method does a poor
120      * job of handling resources such as <samp>/some.dir/res.txt</samp> or
121      * <samp>/some/res.txt.sample</samp>.
122     */

123     @Deprecated JavaDoc
124     public static synchronized URL JavaDoc getLocalizedFile(String JavaDoc baseName, String JavaDoc ext)
125     throws MissingResourceException JavaDoc {
126         return getLocalizedFile(baseName, ext, Locale.getDefault(), getLoader());
127     }
128
129     /**
130      * Get a localized and/or branded file with the default class loader.
131     * @param baseName base name of file, as dot-separated path (e.g. <code>some.dir.File</code>)
132     * @param ext extension of file (or <code>null</code>)
133     * @param locale locale of file
134     * @return URL of matching localized file
135     * @throws MissingResourceException if not found
136      * @deprecated Use the <code>nbresloc</code> URL protocol instead. This method does a poor
137      * job of handling resources such as <samp>/some.dir/res.txt</samp> or
138      * <samp>/some/res.txt.sample</samp>.
139     */

140     @Deprecated JavaDoc
141     public static synchronized URL JavaDoc getLocalizedFile(String JavaDoc baseName, String JavaDoc ext, Locale JavaDoc locale)
142     throws MissingResourceException JavaDoc {
143         return getLocalizedFile(baseName, ext, locale, getLoader());
144     }
145
146     /**
147      * Get a localized and/or branded file.
148     * @param baseName base name of file, as dot-separated path (e.g. <code>some.dir.File</code>)
149     * @param ext extension of file (or <code>null</code>)
150     * @param locale locale of file
151     * @param loader class loader to use
152     * @return URL of matching localized file
153     * @throws MissingResourceException if not found
154      * @deprecated Use the <code>nbresloc</code> URL protocol instead. This method does a poor
155      * job of handling resources such as <samp>/some.dir/res.txt</samp> or
156      * <samp>/some/res.txt.sample</samp>.
157     */

158     @Deprecated JavaDoc
159     public static synchronized URL JavaDoc getLocalizedFile(String JavaDoc baseName, String JavaDoc ext, Locale JavaDoc locale, ClassLoader JavaDoc loader)
160     throws MissingResourceException JavaDoc {
161         // [PENDING] in the future, could maybe do something neat if
162
// USE_DEBUG_LOADER and ext is "html" or "txt" etc...
163
URL JavaDoc lookup = null;
164         Iterator JavaDoc<String JavaDoc> it = new LocaleIterator(locale);
165         List JavaDoc<String JavaDoc> cacheCandidates = new ArrayList JavaDoc<String JavaDoc>(10);
166         String JavaDoc baseNameSlashes = baseName.replace('.', '/');
167         Map JavaDoc<String JavaDoc,URL JavaDoc> perLoaderCache = localizedFileCache.get(loader);
168
169         if (perLoaderCache == null) {
170             localizedFileCache.put(loader, perLoaderCache = new HashMap JavaDoc<String JavaDoc,URL JavaDoc>());
171         }
172
173         // #31008: better use of domain cache priming.
174
// [PENDING] remove this hack in case the domain cache is precomputed
175
URL JavaDoc baseVariant;
176         String JavaDoc path;
177
178         if (ext != null) {
179             path = baseNameSlashes + '.' + ext;
180         } else {
181             path = baseNameSlashes;
182         }
183
184         lookup = perLoaderCache.get(path);
185
186         if (lookup == null) {
187             baseVariant = loader.getResource(path);
188         } else {
189             // who cares? already in cache anyway
190
baseVariant = null;
191         }
192
193         while (it.hasNext()) {
194             String JavaDoc suffix = it.next();
195
196             if (ext != null) {
197                 path = baseNameSlashes + suffix + '.' + ext;
198             } else {
199                 path = baseNameSlashes + suffix;
200             }
201
202             lookup = perLoaderCache.get(path);
203
204             if (lookup != null) {
205                 break;
206             }
207
208             cacheCandidates.add(path);
209
210             if (suffix.length() == 0) {
211                 lookup = baseVariant;
212             } else {
213                 lookup = loader.getResource(path);
214             }
215
216             if (lookup != null) {
217                 break;
218             }
219         }
220
221         if (lookup == null) {
222             path = baseName.replace('.', '/');
223
224             if (ext != null) {
225                 path += ('.' + ext);
226             }
227
228             throw new MissingResourceException JavaDoc(
229                 "Cannot find localized resource " + path + " in " + loader, loader.toString(), path
230             ); // NOI18N
231
} else {
232             // Note that this is not 100% accurate. If someone calls gLF on something
233
// with a locale/branding combo such as _brand_ja, and the answer is found
234
// as _ja, then a subsequent call with param _brand will find this _ja
235
// version - since the localizing iterator does *not* have the property that
236
// each subsequent item is more general than the previous. However, this
237
// situation is very unlikely, so consider this close enough.
238
it = cacheCandidates.iterator();
239
240             while (it.hasNext()) {
241                 perLoaderCache.put(it.next(), lookup);
242             }
243
244             return lookup;
245         }
246     }
247
248     /**
249      * Find a localized and/or branded value for a given key and locale.
250     * Scans through a map to find
251     * the most localized match possible. For example:
252     * <p><code><PRE>
253     * findLocalizedValue (hashTable, "keyName", new Locale ("cs_CZ"))
254     * </PRE></code>
255     * <p>This would return the first non-<code>null</code> value obtained from the following tests:
256     * <UL>
257     * <LI> <CODE>hashTable.get ("keyName_cs_CZ")</CODE>
258     * <LI> <CODE>hashTable.get ("keyName_cs")</CODE>
259     * <LI> <CODE>hashTable.get ("keyName")</CODE>
260     * </UL>
261     *
262     * @param table mapping from localized strings to objects
263     * @param key the key to look for
264     * @param locale the locale to use
265     * @return the localized object or <code>null</code> if no key matches
266     */

267     public static <T> T getLocalizedValue(Map JavaDoc<String JavaDoc,T> table, String JavaDoc key, Locale JavaDoc locale) {
268         for (String JavaDoc suffix : NbCollections.iterable(new LocaleIterator(locale))) {
269             String JavaDoc physicalKey = key + suffix;
270             T v = table.get(physicalKey);
271
272             if (v != null) {
273                 // ok
274
if (USE_DEBUG_LOADER && (v instanceof String JavaDoc)) {
275                     // Not read from a bundle, but still localized somehow:
276
@SuppressWarnings JavaDoc("unchecked")
277                     T _v = (T) (((String JavaDoc) v) + " (?:" + physicalKey + ")"); // NOI18N;
278
return _v;
279                 } else {
280                     return v;
281                 }
282             }
283         }
284
285         return null;
286     }
287
288     /**
289      * Find a localized and/or branded value for a given key in the default system locale.
290     *
291     * @param table mapping from localized strings to objects
292     * @param key the key to look for
293     * @return the localized object or <code>null</code> if no key matches
294     * @see #getLocalizedValue(Map,String,Locale)
295     */

296     public static <T> T getLocalizedValue(Map JavaDoc<String JavaDoc,T> table, String JavaDoc key) {
297         return getLocalizedValue(table, key, Locale.getDefault());
298     }
299
300     /**
301      * Find a localized and/or branded value in a JAR manifest.
302     * @param attr the manifest attributes
303     * @param key the key to look for (case-insensitive)
304     * @param locale the locale to use
305     * @return the value if found, else <code>null</code>
306     */

307     public static String JavaDoc getLocalizedValue(Attributes JavaDoc attr, Attributes.Name JavaDoc key, Locale JavaDoc locale) {
308         return getLocalizedValue(attr2Map(attr), key.toString().toLowerCase(Locale.US), locale);
309     }
310
311     /**
312      * Find a localized and/or branded value in a JAR manifest in the default system locale.
313     * @param attr the manifest attributes
314     * @param key the key to look for (case-insensitive)
315     * @return the value if found, else <code>null</code>
316     */

317     public static String JavaDoc getLocalizedValue(Attributes JavaDoc attr, Attributes.Name JavaDoc key) {
318         // Yes, US locale is intentional! The attribute name may only be ASCII anyway.
319
// It is necessary to lowercase it *as ASCII* as in Turkish 'I' does not go to 'i'!
320
return getLocalizedValue(attr2Map(attr), key.toString().toLowerCase(Locale.US));
321     }
322
323     /** Necessary because Attributes implements Map; however this is dangerous!
324     * The keys are Attributes.Name's, not Strings.
325     * Also manifest lookups should not be case-sensitive.
326     * (Though the locale suffix still will be!)
327     */

328     private static Map JavaDoc<String JavaDoc,String JavaDoc> attr2Map(Attributes JavaDoc attr) {
329         return new AttributesMap(attr);
330     }
331
332     // ---- LOADING RESOURCE BUNDLES ----
333

334     /**
335     * Get a resource bundle with the default class loader and locale/branding.
336     * <strong>Caution:</strong> {@link #getBundle(Class)} is generally
337     * safer when used from a module as this method relies on the module's
338     * classloader to currently be part of the system classloader. NetBeans
339     * does add enabled modules to this classloader, however calls to
340     * this variant of the method made in <a HREF="@org-openide-modules@/org/openide/modules/ModuleInstall.html#validate()">ModuleInstall.validate</a>,
341     * or made soon after a module is uninstalled (due to background threads)
342     * could fail unexpectedly.
343     * @param baseName bundle basename
344     * @return the resource bundle
345     * @exception MissingResourceException if the bundle does not exist
346     */

347     public static final ResourceBundle JavaDoc getBundle(String JavaDoc baseName)
348     throws MissingResourceException JavaDoc {
349         return getBundle(baseName, Locale.getDefault(), getLoader());
350     }
351
352     /** Get a resource bundle in the same package as the provided class,
353     * with the default locale/branding and the class' own classloader.
354     * This is the usual style of invocation.
355     *
356     * @param clazz the class to take the package name from
357     * @return the resource bundle
358     * @exception MissingResourceException if the bundle does not exist
359     */

360     public static ResourceBundle JavaDoc getBundle(Class JavaDoc clazz)
361     throws MissingResourceException JavaDoc {
362         String JavaDoc name = findName(clazz);
363
364         return getBundle(name, Locale.getDefault(), clazz.getClassLoader());
365     }
366
367     /** Finds package name for given class */
368     private static String JavaDoc findName(Class JavaDoc clazz) {
369         String JavaDoc pref = clazz.getName();
370         int last = pref.lastIndexOf('.');
371
372         if (last >= 0) {
373             pref = pref.substring(0, last + 1);
374
375             return pref + "Bundle"; // NOI18N
376
} else {
377             // base package, search for bundle
378
return "Bundle"; // NOI18N
379
}
380     }
381
382     /**
383     * Get a resource bundle with the default class loader and branding.
384     * @param baseName bundle basename
385     * @param locale the locale to use (but still uses {@link #getBranding default branding})
386     * @return the resource bundle
387     * @exception MissingResourceException if the bundle does not exist
388     */

389     public static final ResourceBundle JavaDoc getBundle(String JavaDoc baseName, Locale JavaDoc locale)
390     throws MissingResourceException JavaDoc {
391         return getBundle(baseName, locale, getLoader());
392     }
393
394     /** Get a resource bundle the hard way.
395     * @param baseName bundle basename
396     * @param locale the locale to use (but still uses {@link #getBranding default branding})
397     * @param loader the class loader to use
398     * @return the resource bundle
399     * @exception MissingResourceException if the bundle does not exist
400     */

401     public static final ResourceBundle JavaDoc getBundle(String JavaDoc baseName, Locale JavaDoc locale, ClassLoader JavaDoc loader)
402     throws MissingResourceException JavaDoc {
403         if (USE_DEBUG_LOADER) {
404             loader = DebugLoader.get(loader);
405         }
406
407         // Could more simply use ResourceBundle.getBundle (plus some special logic
408
// with MergedBundle to handle branding) instead of manually finding bundles.
409
// However this code is faster and has some other desirable properties.
410
// Cf. #13847.
411
ResourceBundle JavaDoc b = getBundleFast(baseName, locale, loader);
412
413         if (b != null) {
414             return b;
415         } else {
416             MissingResourceException JavaDoc e = new MissingResourceException JavaDoc("No such bundle " + baseName, baseName, null); // NOI18N
417

418             if (Lookup.getDefault().lookup(ClassLoader JavaDoc.class) == null) {
419                 Exceptions.attachMessage(e,
420                                          "Class loader not yet initialized in lookup"); // NOI18N
421
} else {
422                 Exceptions.attachMessage(e, "Offending classloader: " + loader); // NOI18N
423
}
424
425             throw e;
426         }
427     }
428
429     /**
430      * Get a resource bundle by name.
431      * Like {@link ResourceBundle#getBundle(String,Locale,ClassLoader)} but faster,
432      * and also understands branding.
433      * First looks for <samp>.properties</samp>-based bundles, then <samp>.class</samp>-based.
434      * @param name the base name of the bundle, e.g. <samp>org.netbeans.modules.foo.Bundle</samp>
435      * @param locale the locale to use
436      * @param loader a class loader to search in
437      * @return a resource bundle (locale- and branding-merged), or null if not found
438      */

439     private static ResourceBundle JavaDoc getBundleFast(String JavaDoc name, Locale JavaDoc locale, ClassLoader JavaDoc loader) {
440         Map JavaDoc<String JavaDoc,Reference JavaDoc<ResourceBundle JavaDoc>> m;
441
442         synchronized (bundleCache) {
443             m = bundleCache.get(loader);
444
445             if (m == null) {
446                 bundleCache.put(loader, m = new HashMap JavaDoc<String JavaDoc,Reference JavaDoc<ResourceBundle JavaDoc>>());
447             }
448         }
449
450         //A minor optimization to cut down on StringBuffer allocations - OptimizeIt
451
//showed the commented out code below was a major source of them. This
452
//just does the same thing with a char array - Tim
453
String JavaDoc localeStr = locale.toString();
454         char[] k = new char[name.length() + ((brandingToken != null) ? brandingToken.length() : 1) + 2 +
455             localeStr.length()];
456         name.getChars(0, name.length(), k, 0);
457         k[name.length()] = '/'; //NOI18N
458

459         int pos = name.length() + 1;
460
461         if (brandingToken == null) {
462             k[pos] = '-'; //NOI18N
463
pos++;
464         } else {
465             brandingToken.getChars(0, brandingToken.length(), k, pos);
466             pos += brandingToken.length();
467         }
468
469         k[pos] = '/'; //NOI18N
470
pos++;
471         localeStr.getChars(0, localeStr.length(), k, pos);
472
473         String JavaDoc key = new String JavaDoc(k);
474
475         /*
476         String key = name + '/' + (brandingToken != null ? brandingToken : "-") + '/' + locale; // NOI18N
477          */

478         synchronized (m) {
479             Reference JavaDoc<ResourceBundle JavaDoc> o = m.get(key);
480             ResourceBundle JavaDoc b = o != null ? o.get() : null;
481
482             if (b != null) {
483                 return b;
484             } else {
485                 b = loadBundle(name, locale, loader);
486
487                 if (b != null) {
488                     m.put(key, new TimedSoftReference<ResourceBundle JavaDoc>(b, m, key));
489                 } else {
490                     // Used to cache misses as well, to make the negative test faster.
491
// However this caused problems: see #31578.
492
}
493
494                 return b;
495             }
496         }
497     }
498
499     /**
500      * Load a resource bundle (without caching).
501      * @param name the base name of the bundle, e.g. <samp>org.netbeans.modules.foo.Bundle</samp>
502      * @param locale the locale to use
503      * @param loader a class loader to search in
504      * @return a resource bundle (locale- and branding-merged), or null if not found
505      */

506     private static ResourceBundle JavaDoc loadBundle(String JavaDoc name, Locale JavaDoc locale, ClassLoader JavaDoc loader) {
507         String JavaDoc sname = name.replace('.', '/');
508         Iterator JavaDoc<String JavaDoc> it = new LocaleIterator(locale);
509         LinkedList JavaDoc<String JavaDoc> l = new LinkedList JavaDoc<String JavaDoc>();
510
511         while (it.hasNext()) {
512             l.addFirst(it.next());
513         }
514
515         Properties JavaDoc p = new Properties JavaDoc();
516
517         for (String JavaDoc suffix : l) {
518             String JavaDoc res = sname + suffix + ".properties";
519
520             // #49961: don't use getResourceAsStream; catch all errors opening it
521
URL JavaDoc u = loader != null ? loader.getResource(res) : ClassLoader.getSystemResource(res);
522
523             if (u != null) {
524                 //System.err.println("Loading " + res);
525
try {
526                     // #51667: but in case we are in USE_DEBUG_LOADER mode, use gRAS (since getResource is not overridden)
527
InputStream JavaDoc is = USE_DEBUG_LOADER ?
528                         (loader != null ? loader.getResourceAsStream(res) : ClassLoader.getSystemResourceAsStream(res)) :
529                             u.openStream();
530
531                     try {
532                         p.load(is);
533                     } finally {
534                         is.close();
535                     }
536                 } catch (IOException JavaDoc e) {
537                     Exceptions.attachMessage(e, "While loading: " + res); // NOI18N
538
Logger.getLogger(NbBundle.class.getName()).log(Level.WARNING, null, e);
539
540                     return null;
541                 }
542             } else if (suffix.length() == 0) {
543                 // No base *.properties. Try *.class.
544
// Note that you may not mix *.properties w/ *.class this way.
545
return loadBundleClass(name, sname, locale, l, loader);
546             }
547         }
548
549         return new PBundle(NbCollections.checkedMapByFilter(p, String JavaDoc.class, String JavaDoc.class, true), locale);
550     }
551
552     /**
553      * Load a class-based resource bundle.
554      * @param name the base name of the bundle, e.g. <samp>org.netbeans.modules.foo.Bundle</samp>
555      * @param sname the name with slashes, e.g. <samp>org/netbeans/modules/foo/Bundle</samp>
556      * @param locale the locale to use
557      * @param suffixes a list of suffixes to apply to the bundle name, in <em>increasing</em> order of specificity
558      * @param loader a class loader to search in
559      * @return a resource bundle (merged according to the suffixes), or null if not found
560      */

561     private static ResourceBundle JavaDoc loadBundleClass(
562         String JavaDoc name, String JavaDoc sname, Locale JavaDoc locale, List JavaDoc<String JavaDoc> suffixes, ClassLoader JavaDoc l
563     ) {
564         if (l != null && l.getResource(sname + ".class") == null) { // NOI18N
565

566             // No chance - no base bundle. Don't waste time catching CNFE.
567
return null;
568         }
569
570         ResourceBundle JavaDoc master = null;
571
572         for (String JavaDoc suffix : suffixes) {
573             try {
574                 Class JavaDoc<? extends ResourceBundle JavaDoc> c = Class.forName(name + suffix, true, l).asSubclass(ResourceBundle JavaDoc.class);
575                 ResourceBundle JavaDoc b = c.newInstance();
576
577                 if (master == null) {
578                     master = b;
579                 } else {
580                     master = new MergedBundle(locale, b, master);
581                 }
582             } catch (ClassNotFoundException JavaDoc cnfe) {
583                 // fine - ignore
584
} catch (Exception JavaDoc e) {
585                 Logger.getLogger(NbBundle.class.getName()).log(Level.WARNING, null, e);
586             } catch (LinkageError JavaDoc e) {
587                 Logger.getLogger(NbBundle.class.getName()).log(Level.WARNING, null, e);
588             }
589         }
590
591         return master;
592     }
593
594     //
595
// Helper methods to simplify localization of messages
596
//
597

598     /**
599      * Finds a localized and/or branded string in a bundle.
600     * @param clazz the class to use to locate the bundle
601     * @param resName name of the resource to look for
602     * @return the string associated with the resource
603     * @throws MissingResourceException if either the bundle or the string cannot be found
604     */

605     public static String JavaDoc getMessage(Class JavaDoc clazz, String JavaDoc resName)
606     throws MissingResourceException JavaDoc {
607         return getBundle(clazz).getString(resName);
608     }
609
610     /**
611      * Finds a localized and/or branded string in a bundle and formats the message
612     * by passing requested parameters.
613     *
614     * @param clazz the class to use to locate the bundle
615     * @param resName name of the resource to look for
616     * @param param1 the argument to use when formatting the message
617     * @return the string associated with the resource
618     * @throws MissingResourceException if either the bundle or the string cannot be found
619     * @see java.text.MessageFormat#format(String,Object[])
620     */

621     public static String JavaDoc getMessage(Class JavaDoc clazz, String JavaDoc resName, Object JavaDoc param1)
622     throws MissingResourceException JavaDoc {
623         return getMessage(clazz, resName, new Object JavaDoc[] { param1 });
624     }
625
626     /**
627      * Finds a localized and/or branded string in a bundle and formats the message
628     * by passing requested parameters.
629     *
630     * @param clazz the class to use to locate the bundle
631     * @param resName name of the resource to look for
632     * @param param1 the argument to use when formatting the message
633     * @param param2 the second argument to use for formatting
634     * @return the string associated with the resource
635     * @throws MissingResourceException if either the bundle or the string cannot be found
636     * @see java.text.MessageFormat#format(String,Object[])
637     */

638     public static String JavaDoc getMessage(Class JavaDoc clazz, String JavaDoc resName, Object JavaDoc param1, Object JavaDoc param2)
639     throws MissingResourceException JavaDoc {
640         return getMessage(clazz, resName, new Object JavaDoc[] { param1, param2 });
641     }
642
643     /**
644      * Finds a localized and/or branded string in a bundle and formats the message
645     * by passing requested parameters.
646     *
647     * @param clazz the class to use to locate the bundle
648     * @param resName name of the resource to look for
649     * @param param1 the argument to use when formatting the message
650     * @param param2 the second argument to use for formatting
651     * @param param3 the third argument to use for formatting
652     * @return the string associated with the resource
653     * @throws MissingResourceException if either the bundle or the string cannot be found
654     * @see java.text.MessageFormat#format(String,Object[])
655     */

656     public static String JavaDoc getMessage(Class JavaDoc clazz, String JavaDoc resName, Object JavaDoc param1, Object JavaDoc param2, Object JavaDoc param3)
657     throws MissingResourceException JavaDoc {
658         return getMessage(clazz, resName, new Object JavaDoc[] { param1, param2, param3 });
659     }
660
661     /**
662      * Finds a localized and/or branded string in a bundle and formats the message
663     * by passing requested parameters.
664     *
665     * @param clazz the class to use to locate the bundle
666     * @param resName name of the resource to look for
667     * @param arr array of parameters to use for formatting the message
668     * @return the string associated with the resource
669     * @throws MissingResourceException if either the bundle or the string cannot be found
670     * @see java.text.MessageFormat#format(String,Object[])
671     */

672     public static String JavaDoc getMessage(Class JavaDoc clazz, String JavaDoc resName, Object JavaDoc[] arr)
673     throws MissingResourceException JavaDoc {
674         return java.text.MessageFormat.format(getMessage(clazz, resName), arr);
675     }
676
677     /** @return default class loader which is used, when we don't have
678     * any other class loader. (in function getBundle(String), getLocalizedFile(String),
679     * and so on...
680     */

681     private static ClassLoader JavaDoc getLoader() {
682         ClassLoader JavaDoc c = Lookup.getDefault().lookup(ClassLoader JavaDoc.class);
683
684         return (c != null) ? c : ClassLoader.getSystemClassLoader();
685     }
686
687     /**
688      * Get a list of all suffixes used to search for localized/branded resources.
689      * Based on the default locale and branding, returns the list of suffixes
690      * which various <code>NbBundle</code> methods use as the search order.
691      * For example, when {@link #getBranding} returns <code>branding</code>
692      * and the default locale is German, you might get a sequence such as:
693      * <ol>
694      * <li><samp>"_branding_de"</samp>
695      * <li><samp>"_branding"</samp>
696      * <li><samp>"_de"</samp>
697      * <li><samp>""</samp>
698      * </ol>
699      * @return a read-only iterator of type <code>String</code>
700      * @since 1.1.5
701      */

702     public static Iterator JavaDoc<String JavaDoc> getLocalizingSuffixes() {
703         return new LocaleIterator(Locale.getDefault());
704     }
705
706     /**
707      * Do not use.
708      * @param loaderFinder ignored
709      * @deprecated Useless.
710      */

711     @Deprecated JavaDoc
712     public static void setClassLoaderFinder(ClassLoaderFinder loaderFinder) {
713         throw new Error JavaDoc();
714     }
715
716     /**
717      * Do not use.
718      * @deprecated Useless.
719      */

720     @Deprecated JavaDoc
721     public static interface ClassLoaderFinder {
722         /**
723          * Do not use.
724          * @return nothing
725          * @deprecated Useless.
726          */

727         @Deprecated JavaDoc
728         public ClassLoader JavaDoc find();
729     }
730
731     private static class AttributesMap extends HashMap JavaDoc<String JavaDoc,String JavaDoc> {
732         private Attributes JavaDoc attrs;
733
734         public AttributesMap(Attributes JavaDoc attrs) {
735             super(7);
736             this.attrs = attrs;
737         }
738
739         public String JavaDoc get(Object JavaDoc _k) {
740             if (!(_k instanceof String JavaDoc)) {
741                 return null;
742             }
743             String JavaDoc k = (String JavaDoc) _k;
744
745             Attributes.Name JavaDoc an;
746
747             try {
748                 an = new Attributes.Name JavaDoc(k);
749             } catch (IllegalArgumentException JavaDoc iae) {
750                 // Robustness, and workaround for reported MRJ locale bug:
751
Exceptions.attachLocalizedMessage(iae,
752                     getMessage(NbBundle.class, "EXC_bad_attributes_name", k, Locale.getDefault().toString())
753                 );
754                 Exceptions.printStackTrace(iae);
755
756                 return null;
757             }
758
759             return attrs.getValue(an);
760         }
761     }
762
763     /**
764      * A resource bundle based on <samp>.properties</samp> files (or any map).
765      */

766     private static final class PBundle extends ResourceBundle JavaDoc {
767         private final Map JavaDoc<String JavaDoc,String JavaDoc> m;
768         private final Locale JavaDoc locale;
769
770         /**
771          * Create a new bundle based on a map.
772          * @param m a map from resources keys to values (typically both strings)
773          * @param locale the locale it represents <em>(informational)</em>
774          */

775         public PBundle(Map JavaDoc<String JavaDoc,String JavaDoc> m, Locale JavaDoc locale) {
776             this.m = m;
777             this.locale = locale;
778         }
779
780         public Enumeration JavaDoc<String JavaDoc> getKeys() {
781             return Collections.enumeration(m.keySet());
782         }
783
784         protected Object JavaDoc handleGetObject(String JavaDoc key) {
785             return m.get(key);
786         }
787
788         public Locale JavaDoc getLocale() {
789             return locale;
790         }
791     }
792
793     /** Special resource bundle which delegates to two others.
794      * Ideally could just set the parent on the first, but this is protected, so...
795      */

796     private static class MergedBundle extends ResourceBundle JavaDoc {
797         private Locale JavaDoc loc;
798         private ResourceBundle JavaDoc sub1;
799         private ResourceBundle JavaDoc sub2;
800
801         /**
802          * Create a new bundle delegating to two others.
803          * @param loc the locale it represents <em>(informational)</em>
804          * @param sub1 one delegate (taking precedence over the other in case of overlap)
805          * @param sub2 the other (weaker) delegate
806          */

807         public MergedBundle(Locale JavaDoc loc, ResourceBundle JavaDoc sub1, ResourceBundle JavaDoc sub2) {
808             this.loc = loc;
809             this.sub1 = sub1;
810             this.sub2 = sub2;
811         }
812
813         public Locale JavaDoc getLocale() {
814             return loc;
815         }
816
817         public Enumeration JavaDoc<String JavaDoc> getKeys() {
818             return Enumerations.removeDuplicates(Enumerations.concat(sub1.getKeys(), sub2.getKeys()));
819         }
820
821         protected Object JavaDoc handleGetObject(String JavaDoc key) throws MissingResourceException JavaDoc {
822             try {
823                 return sub1.getObject(key);
824             } catch (MissingResourceException JavaDoc mre) {
825                 // Ignore exception, and...
826
return sub2.getObject(key);
827             }
828         }
829     }
830
831     /** This class (enumeration) gives all localized sufixes using nextElement
832     * method. It goes through given Locale and continues through Locale.getDefault()
833     * Example 1:
834     * Locale.getDefault().toString() -> "_en_US"
835     * you call new LocaleIterator(new Locale("cs", "CZ"));
836     * ==> You will gets: "_cs_CZ", "_cs", "", "_en_US", "_en"
837     *
838     * Example 2:
839     * Locale.getDefault().toString() -> "_cs_CZ"
840     * you call new LocaleIterator(new Locale("cs", "CZ"));
841     * ==> You will gets: "_cs_CZ", "_cs", ""
842     *
843     * If there is a branding token in effect, you will get it too as an extra
844     * prefix, taking precedence, e.g. for the token "f4jce":
845     *
846     * "_f4jce_cs_CZ", "_f4jce_cs", "_f4jce", "_f4jce_en_US", "_f4jce_en", "_cs_CZ", "_cs", "", "_en_US", "_en"
847     *
848     * Branding tokens with underscores are broken apart naturally: so e.g.
849     * branding "f4j_ce" looks first for "f4j_ce" branding, then "f4j" branding, then none.
850     */

851     private static class LocaleIterator extends Object JavaDoc implements Iterator JavaDoc<String JavaDoc> {
852         /** this flag means, if default locale is in progress */
853         private boolean defaultInProgress = false;
854
855         /** this flag means, if empty suffix was exported yet */
856         private boolean empty = false;
857
858         /** current locale, and initial locale */
859         private Locale JavaDoc locale;
860
861         /** current locale, and initial locale */
862         private Locale JavaDoc initLocale;
863
864         /** current suffix which will be returned in next calling nextElement */
865         private String JavaDoc current;
866
867         /** the branding string in use */
868         private String JavaDoc branding;
869
870         /** Creates new LocaleIterator for given locale.
871         * @param locale given Locale
872         */

873         public LocaleIterator(Locale JavaDoc locale) {
874             this.locale = this.initLocale = locale;
875
876             if (locale.equals(Locale.getDefault())) {
877                 defaultInProgress = true;
878             }
879
880             current = '_' + locale.toString();
881
882             if (brandingToken == null) {
883                 branding = null;
884             } else {
885                 branding = "_" + brandingToken; // NOI18N
886
}
887
888             //System.err.println("Constructed: " + this);
889
}
890
891         /** @return next suffix.
892         * @exception NoSuchElementException if there is no more locale suffix.
893         */

894         public String JavaDoc next() throws NoSuchElementException JavaDoc {
895             if (current == null) {
896                 throw new NoSuchElementException JavaDoc();
897             }
898
899             final String JavaDoc ret;
900
901             if (branding == null) {
902                 ret = current;
903             } else {
904                 ret = branding + current;
905             }
906
907             int lastUnderbar = current.lastIndexOf('_');
908
909             if (lastUnderbar == 0) {
910                 if (empty) {
911                     reset();
912                 } else {
913                     current = ""; // NOI18N
914
empty = true;
915                 }
916             } else {
917                 if (lastUnderbar == -1) {
918                     if (defaultInProgress) {
919                         reset();
920                     } else {
921                         // [PENDING] stuff with trying the default locale
922
// after the real one does not actually seem to work...
923
locale = Locale.getDefault();
924                         current = '_' + locale.toString();
925                         defaultInProgress = true;
926                     }
927                 } else {
928                     current = current.substring(0, lastUnderbar);
929                 }
930             }
931
932             //System.err.println("Returning: `" + ret + "' from: " + this);
933
return ret;
934         }
935
936         /** Finish a series.
937          * If there was a branding prefix, restart without that prefix
938          * (or with a shorter prefix); else finish.
939          */

940         private void reset() {
941             if (branding != null) {
942                 current = '_' + initLocale.toString();
943
944                 int idx = branding.lastIndexOf('_');
945
946                 if (idx == 0) {
947                     branding = null;
948                 } else {
949                     branding = branding.substring(0, idx);
950                 }
951
952                 empty = false;
953             } else {
954                 current = null;
955             }
956         }
957
958         /** Tests if there is any sufix.*/
959         public boolean hasNext() {
960             return (current != null);
961         }
962
963         public void remove() throws UnsupportedOperationException JavaDoc {
964             throw new UnsupportedOperationException JavaDoc();
965         }
966     }
967      // end of LocaleIterator
968

969     /** Classloader whose special trick is inserting debug information
970      * into any *.properties files it loads.
971      */

972     static final class DebugLoader extends ClassLoader JavaDoc {
973         /** global bundle index, each loaded bundle gets its own */
974         private static int count = 0;
975
976         /** indices of known bundles; needed since DebugLoader's can be collected
977          * when softly reachable, but this should be transparent to the user
978          */

979         private static final Map JavaDoc<String JavaDoc,Integer JavaDoc> knownIDs = new HashMap JavaDoc<String JavaDoc,Integer JavaDoc>();
980
981         /** cache of existing debug loaders for regular loaders */
982         private static final Map JavaDoc<ClassLoader JavaDoc,Reference JavaDoc<ClassLoader JavaDoc>> existing = new WeakHashMap JavaDoc<ClassLoader JavaDoc,Reference JavaDoc<ClassLoader JavaDoc>>();
983
984         private DebugLoader(ClassLoader JavaDoc cl) {
985             super(cl);
986
987             //System.err.println ("new DebugLoader: cl=" + cl);
988
}
989
990         private static int getID(String JavaDoc name) {
991             synchronized (knownIDs) {
992                 Integer JavaDoc i = knownIDs.get(name);
993
994                 if (i == null) {
995                     i = ++count;
996                     knownIDs.put(name, i);
997                     System.err.println("NbBundle trace: #" + i + " = " + name); // NOI18N
998
}
999
1000                return i;
1001            }
1002        }
1003
1004        public static ClassLoader JavaDoc get(ClassLoader JavaDoc normal) {
1005            //System.err.println("Lookup: normal=" + normal);
1006
synchronized (existing) {
1007                Reference JavaDoc<ClassLoader JavaDoc> r = existing.get(normal);
1008
1009                if (r != null) {
1010                    ClassLoader JavaDoc dl = r.get();
1011
1012                    if (dl != null) {
1013                        //System.err.println("\tcache hit");
1014
return dl;
1015                    } else {
1016                        //System.err.println("\tcollected ref");
1017
}
1018                } else {
1019                    //System.err.println("\tnot in cache");
1020
}
1021
1022                ClassLoader JavaDoc dl = new DebugLoader(normal);
1023                existing.put(normal, new WeakReference JavaDoc<ClassLoader JavaDoc>(dl));
1024
1025                return dl;
1026            }
1027        }
1028
1029        public InputStream JavaDoc getResourceAsStream(String JavaDoc name) {
1030            InputStream JavaDoc base = super.getResourceAsStream(name);
1031
1032            if (base == null) {
1033                return null;
1034            }
1035
1036            if (name.endsWith(".properties")) { // NOI18N
1037

1038                int id = getID(name);
1039
1040                //System.err.println ("\tthis=" + this + " parent=" + getParent ());
1041
boolean loc = name.indexOf("Bundle") != -1; // NOI18N
1042

1043                return new DebugInputStream(base, id, loc);
1044            } else {
1045                return base;
1046            }
1047        }
1048
1049        // [PENDING] getResource not overridden; but ResourceBundle uses getResourceAsStream anyhow
1050

1051        /** Wrapper input stream which parses the text as it goes and adds annotations.
1052         * Resource-bundle values are annotated with their current line number and also
1053         * the supplied it, so e.g. if in the original input stream on line 50 we have:
1054         * somekey=somevalue
1055         * so in the wrapper stream (id 123) this line will read:
1056         * somekey=somevalue (123:50)
1057         * Since you see on stderr what #123 is, you can then pinpoint where any bundle key
1058         * originally came from, assuming NbBundle loaded it from a *.properties file.
1059         * @see {@link Properties#load} for details on the syntax of *.properties files.
1060         */

1061        static final class DebugInputStream extends InputStream JavaDoc {
1062            /** state transition diagram constants */
1063            private static final int WAITING_FOR_KEY = 0;
1064
1065            /** state transition diagram constants */
1066            private static final int IN_COMMENT = 1;
1067
1068            /** state transition diagram constants */
1069            private static final int IN_KEY = 2;
1070
1071            /** state transition diagram constants */
1072            private static final int IN_KEY_BACKSLASH = 3;
1073
1074            /** state transition diagram constants */
1075            private static final int AFTER_KEY = 4;
1076
1077            /** state transition diagram constants */
1078            private static final int WAITING_FOR_VALUE = 5;
1079
1080            /** state transition diagram constants */
1081            private static final int IN_VALUE = 6;
1082
1083            /** state transition diagram constants */
1084            private static final int IN_VALUE_BACKSLASH = 7;
1085            private final InputStream JavaDoc base;
1086            private final int id;
1087            private final boolean localizable;
1088
1089            /** current line number */
1090            private int line = 0;
1091            
1092            /** line number in effect for last-encountered key */
1093            private int keyLine = 0;
1094
1095            /** current state in state machine */
1096            private int state = WAITING_FOR_KEY;
1097
1098            /** if true, the last char was a CR, waiting to see if we get a NL too */
1099            private boolean twixtCrAndNl = false;
1100
1101            /** if non-null, a string to serve up before continuing (length must be > 0) */
1102            private String JavaDoc toInsert = null;
1103
1104            /** if true, the next value encountered should be localizable if normally it would not be, or vice-versa */
1105            private boolean reverseLocalizable = false;
1106
1107            /** text of currently read comment, including leading comment character */
1108            private StringBuffer JavaDoc lastComment = null;
1109
1110            /** Create a new InputStream which will annotate resource bundles.
1111             * Bundles named Bundle*.properties will be treated as localizable by default,
1112             * and so annotated; other bundles will be treated as nonlocalizable and not annotated.
1113             * Messages can be individually marked as localizable or not to override this default,
1114             * in accordance with some I18N conventions for NetBeans.
1115             * @param base the unannotated stream
1116             * @param id an identifying number to use in annotations
1117             * @param localizable if true, this bundle is expected to be localizable
1118             * @see http://www.netbeans.org/i18n/
1119             */

1120            public DebugInputStream(InputStream JavaDoc base, int id, boolean localizable) {
1121                this.base = base;
1122                this.id = id;
1123                this.localizable = localizable;
1124            }
1125
1126            public int read() throws IOException JavaDoc {
1127                if (toInsert != null) {
1128                    char result = toInsert.charAt(0);
1129
1130                    if (toInsert.length() > 1) {
1131                        toInsert = toInsert.substring(1);
1132                    } else {
1133                        toInsert = null;
1134                    }
1135
1136                    return result;
1137                }
1138
1139                int next = base.read();
1140
1141                if (next == '\n') {
1142                    twixtCrAndNl = false;
1143                    line++;
1144                } else if (next == '\r') {
1145                    if (twixtCrAndNl) {
1146                        line++;
1147                    } else {
1148                        twixtCrAndNl = true;
1149                    }
1150                } else {
1151                    twixtCrAndNl = false;
1152                }
1153
1154                switch (state) {
1155                case WAITING_FOR_KEY:
1156
1157                    switch (next) {
1158                    case '#':
1159                    case '!':
1160                        state = IN_COMMENT;
1161                        lastComment = new StringBuffer JavaDoc();
1162                        lastComment.append((char) next);
1163
1164                        return next;
1165
1166                    case ' ':
1167                    case '\t':
1168                    case '\n':
1169                    case '\r':
1170                    case -1:
1171                        return next;
1172
1173                    case '\\':
1174                        state = IN_KEY_BACKSLASH;
1175
1176                        return next;
1177
1178                    default:
1179                        state = IN_KEY;
1180                        keyLine = line + 1;
1181
1182                        return next;
1183                    }
1184
1185                case IN_COMMENT:
1186
1187                    switch (next) {
1188                    case '\n':
1189                    case '\r':
1190
1191                        String JavaDoc comment = lastComment.toString();
1192                        lastComment = null;
1193
1194                        if (localizable && comment.equals("#NOI18N")) { // NOI18N
1195
reverseLocalizable = true;
1196                        } else if (localizable && comment.equals("#PARTNOI18N")) { // NOI18N
1197
System.err.println(
1198                                "NbBundle WARNING (" + id + ":" + line +
1199                                "): #PARTNOI18N encountered, will not annotate I18N parts"
1200                            ); // NOI18N
1201
reverseLocalizable = true;
1202                        } else if (!localizable && comment.equals("#I18N")) { // NOI18N
1203
reverseLocalizable = true;
1204                        } else if (!localizable && comment.equals("#PARTI18N")) { // NOI18N
1205
System.err.println(
1206                                "NbBundle WARNING (" + id + ":" + line +
1207                                "): #PARTI18N encountered, will not annotate I18N parts"
1208                            ); // NOI18N
1209
reverseLocalizable = false;
1210                        } else if (
1211                            (localizable && (comment.equals("#I18N") || comment.equals("#PARTI18N"))) || // NOI18N
1212
(!localizable && (comment.equals("#NOI18N") || comment.equals("#PARTNOI18N")))
1213                        ) { // NOI18N
1214
System.err.println(
1215                                "NbBundle WARNING (" + id + ":" + line + "): incongruous comment " + comment +
1216                                " found for bundle"
1217                            ); // NOI18N
1218
reverseLocalizable = false;
1219                        }
1220
1221                        state = WAITING_FOR_KEY;
1222
1223                        return next;
1224
1225                    default:
1226                        lastComment.append((char) next);
1227
1228                        return next;
1229                    }
1230
1231                case IN_KEY:
1232
1233                    switch (next) {
1234                    case '\\':
1235                        state = IN_KEY_BACKSLASH;
1236
1237                        return next;
1238
1239                    case ' ':
1240                    case '\t':
1241                        state = AFTER_KEY;
1242
1243                        return next;
1244
1245                    case '=':
1246                    case ':':
1247                        state = WAITING_FOR_VALUE;
1248
1249                        return next;
1250
1251                    case '\r':
1252                    case '\n':
1253                        state = WAITING_FOR_KEY;
1254
1255                        return next;
1256
1257                    default:
1258                        return next;
1259                    }
1260
1261                case IN_KEY_BACKSLASH:
1262                    state = IN_KEY;
1263
1264                    return next;
1265
1266                case AFTER_KEY:
1267
1268                    switch (next) {
1269                    case '=':
1270                    case ':':
1271                        state = WAITING_FOR_VALUE;
1272
1273                        return next;
1274
1275                    case '\r':
1276                    case '\n':
1277                        state = WAITING_FOR_KEY;
1278
1279                        return next;
1280
1281                    default:
1282                        return next;
1283                    }
1284
1285                case WAITING_FOR_VALUE:
1286
1287                    switch (next) {
1288                    case '\r':
1289                    case '\n':
1290                        state = WAITING_FOR_KEY;
1291
1292                        return next;
1293
1294                    case ' ':
1295                    case '\t':
1296                        return next;
1297
1298                    case '\\':
1299                        state = IN_VALUE_BACKSLASH;
1300
1301                        return next;
1302
1303                    default:
1304                        state = IN_VALUE;
1305
1306                        return next;
1307                    }
1308
1309                case IN_VALUE:
1310
1311                    switch (next) {
1312                    case '\\':
1313
1314                        // Gloss over distinction between simple escapes and \u1234, which is not important for us.
1315
// Also no need to deal specially with continuation lines; for us, there is an escaped
1316
// newline, after which will be more value, and that is all that is important.
1317
state = IN_VALUE_BACKSLASH;
1318
1319                        return next;
1320
1321                    case '\n':
1322                    case '\r':
1323                    case -1:
1324
1325                        // End of value. This is the tricky part.
1326
boolean revLoc = reverseLocalizable;
1327                        reverseLocalizable = false;
1328                        state = WAITING_FOR_KEY;
1329
1330                        if (localizable ^ revLoc) {
1331                            // This value is intended to be localizable. Annotate it.
1332
assert keyLine > 0;
1333                            toInsert = "(" + id + ":" + keyLine + ")"; // NOI18N
1334
if (next != -1) {
1335                                toInsert += new Character JavaDoc((char) next);
1336                            }
1337                            keyLine = 0;
1338
1339                            // Now return the space before the rest of the string explicitly.
1340
return ' ';
1341                        } else {
1342                            // This is not supposed to be a localizable value, leave it alone.
1343
return next;
1344                        }
1345
1346                    default:
1347                        return next;
1348                    }
1349
1350                case IN_VALUE_BACKSLASH:
1351                    state = IN_VALUE;
1352
1353                    return next;
1354
1355                default:
1356                    throw new IOException JavaDoc("should never happen"); // NOI18N
1357
}
1358            }
1359
1360        }
1361    }
1362}
1363
Popular Tags