Source Code Cross Referenced for NbBundle.java in  » IDE-Netbeans » openide » org » openide » util » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Netbeans » openide » org.openide.util 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003:         *
0004:         * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005:         *
0006:         * The contents of this file are subject to the terms of either the GNU
0007:         * General Public License Version 2 only ("GPL") or the Common
0008:         * Development and Distribution License("CDDL") (collectively, the
0009:         * "License"). You may not use this file except in compliance with the
0010:         * License. You can obtain a copy of the License at
0011:         * http://www.netbeans.org/cddl-gplv2.html
0012:         * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013:         * specific language governing permissions and limitations under the
0014:         * License.  When distributing the software, include this License Header
0015:         * Notice in each file and include the License file at
0016:         * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
0017:         * particular file as subject to the "Classpath" exception as provided
0018:         * by Sun in the GPL Version 2 section of the License file that
0019:         * accompanied this code. If applicable, add the following below the
0020:         * License Header, with the fields enclosed by brackets [] replaced by
0021:         * your own identifying information:
0022:         * "Portions Copyrighted [year] [name of copyright owner]"
0023:         *
0024:         * Contributor(s):
0025:         *
0026:         * The Original Software is NetBeans. The Initial Developer of the Original
0027:         * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0028:         * Microsystems, Inc. All Rights Reserved.
0029:         *
0030:         * If you wish your version of this file to be governed by only the CDDL
0031:         * or only the GPL Version 2, indicate your decision by adding
0032:         * "[Contributor] elects to include this software in this distribution
0033:         * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034:         * single choice of license, a recipient has the option to distribute
0035:         * your version of this file under either the CDDL, the GPL Version 2 or
0036:         * to extend the choice of license to its licensees as provided above.
0037:         * However, if you add GPL Version 2 code and therefore, elected the GPL
0038:         * Version 2 license, then the option applies only if the new code is
0039:         * made subject to such option by the copyright holder.
0040:         */
0041:
0042:        package org.openide.util;
0043:
0044:        import java.io.IOException;
0045:        import java.io.InputStream;
0046:        import java.lang.ref.Reference;
0047:        import java.lang.ref.WeakReference;
0048:        import java.net.URL;
0049:        import java.util.ArrayList;
0050:        import java.util.Collections;
0051:        import java.util.Enumeration;
0052:        import java.util.HashMap;
0053:        import java.util.Iterator;
0054:        import java.util.LinkedList;
0055:        import java.util.List;
0056:        import java.util.Locale;
0057:        import java.util.Map;
0058:        import java.util.MissingResourceException;
0059:        import java.util.NoSuchElementException;
0060:        import java.util.Properties;
0061:        import java.util.ResourceBundle;
0062:        import java.util.WeakHashMap;
0063:        import java.util.jar.Attributes;
0064:        import java.util.logging.Level;
0065:        import java.util.logging.Logger;
0066:
0067:        /** Convenience class permitting easy loading of localized resources of various sorts.
0068:         * Extends the functionality of the default Java resource support, and interacts
0069:         * better with class loaders in a multiple-loader system.
0070:         * <p>Example usage:
0071:         * <p><code><pre>
0072:         * package com.mycom;
0073:         * public class Foo {
0074:         *   // Search for tag Foo_theMessage in /com/mycom/Bundle.properties:
0075:         *   private static String theMessage = {@link NbBundle#getMessage(Class, String) NbBundle.getMessage} (Foo.class, "Foo_theMessage");
0076:         *   // Might also look in /com/mycom/Bundle_de.properties, etc.
0077:         * }
0078:         * </pre></code>
0079:         */
0080:        public class NbBundle extends Object {
0081:
0082:            private static final boolean USE_DEBUG_LOADER = Boolean
0083:                    .getBoolean("org.openide.util.NbBundle.DEBUG"); // NOI18N
0084:            private static String brandingToken = null;
0085:
0086:            /**
0087:             * Cache of URLs for localized files.
0088:             * Keeps only weak references to the class loaders.
0089:             * @see "#9275"
0090:             */
0091:            static final Map<ClassLoader, Map<String, URL>> localizedFileCache = new WeakHashMap<ClassLoader, Map<String, URL>>();
0092:
0093:            /**
0094:             * Cache of resource bundles.
0095:             */
0096:            static final Map<ClassLoader, Map<String, Reference<ResourceBundle>>> bundleCache = new WeakHashMap<ClassLoader, Map<String, Reference<ResourceBundle>>>();
0097:
0098:            /**
0099:             * Do not call.
0100:             * @deprecated There is no reason to instantiate or subclass this class.
0101:             *             All methods in it are static.
0102:             */
0103:            @Deprecated
0104:            public NbBundle() {
0105:            }
0106:
0107:            /** Get the current branding token.
0108:             * @return the branding, or <code>null</code> for none
0109:             */
0110:            public static String getBranding() {
0111:                return brandingToken;
0112:            }
0113:
0114:            /** Set the current branding token.
0115:             * The permitted format, as a regular expression:
0116:             * <pre>[a-z][a-z0-9]*(_[a-z][a-z0-9]*)*</pre>
0117:             * <p class="nonnormative">
0118:             * This is normally only called by NetBeans startup code and unit tests.
0119:             * Currently the branding may be specified by passing the <code>--branding</code>
0120:             * command-line option to the launcher.
0121:             * </p>
0122:             * @param bt the new branding, or <code>null</code> to clear
0123:             * @throws IllegalArgumentException if in an incorrect format
0124:             */
0125:            public static void setBranding(String bt)
0126:                    throws IllegalArgumentException {
0127:                if (bt != null
0128:                        && !bt.matches("[a-z][a-z0-9]*(_[a-z][a-z0-9]*)*")) { // NOI18N
0129:                    throw new IllegalArgumentException(
0130:                            "Malformed branding token: " + bt); // NOI18N
0131:                }
0132:                brandingToken = bt;
0133:            }
0134:
0135:            /**
0136:             * Get a localized and/or branded file in the default locale with the default class loader.
0137:             * <p>Note that use of this call is similar to using the URL protocol <code>nbresloc</code>
0138:             * (which may in fact be implemented using the fuller form of the method).
0139:             * <p>The extension may be null, in which case no final dot will be appended.
0140:             * If it is the empty string, the resource will end in a dot.
0141:             * @param baseName base name of file, as dot-separated path (e.g. <code>some.dir.File</code>)
0142:             * @param ext      extension of file (or <code>null</code>)
0143:             * @return URL of matching localized file
0144:             * @throws MissingResourceException if not found
0145:             * @deprecated Use the <code>nbresloc</code> URL protocol instead. This method does a poor
0146:             *             job of handling resources such as <samp>/some.dir/res.txt</samp> or
0147:             *             <samp>/some/res.txt.sample</samp>.
0148:             */
0149:            @Deprecated
0150:            public static synchronized URL getLocalizedFile(String baseName,
0151:                    String ext) throws MissingResourceException {
0152:                return getLocalizedFile(baseName, ext, Locale.getDefault(),
0153:                        getLoader());
0154:            }
0155:
0156:            /**
0157:             * Get a localized and/or branded file with the default class loader.
0158:             * @param baseName base name of file, as dot-separated path (e.g. <code>some.dir.File</code>)
0159:             * @param ext      extension of file (or <code>null</code>)
0160:             * @param locale   locale of file
0161:             * @return URL of matching localized file
0162:             * @throws MissingResourceException if not found
0163:             * @deprecated Use the <code>nbresloc</code> URL protocol instead. This method does a poor
0164:             *             job of handling resources such as <samp>/some.dir/res.txt</samp> or
0165:             *             <samp>/some/res.txt.sample</samp>.
0166:             */
0167:            @Deprecated
0168:            public static synchronized URL getLocalizedFile(String baseName,
0169:                    String ext, Locale locale) throws MissingResourceException {
0170:                return getLocalizedFile(baseName, ext, locale, getLoader());
0171:            }
0172:
0173:            /**
0174:             * Get a localized and/or branded file.
0175:             * @param baseName base name of file, as dot-separated path (e.g. <code>some.dir.File</code>)
0176:             * @param ext      extension of file (or <code>null</code>)
0177:             * @param locale   locale of file
0178:             * @param loader  class loader to use
0179:             * @return URL of matching localized file
0180:             * @throws MissingResourceException if not found
0181:             * @deprecated Use the <code>nbresloc</code> URL protocol instead. This method does a poor
0182:             *             job of handling resources such as <samp>/some.dir/res.txt</samp> or
0183:             *             <samp>/some/res.txt.sample</samp>.
0184:             */
0185:            @Deprecated
0186:            public static synchronized URL getLocalizedFile(String baseName,
0187:                    String ext, Locale locale, ClassLoader loader)
0188:                    throws MissingResourceException {
0189:                // [PENDING] in the future, could maybe do something neat if
0190:                // USE_DEBUG_LOADER and ext is "html" or "txt" etc...
0191:                URL lookup = null;
0192:                Iterator<String> it = new LocaleIterator(locale);
0193:                List<String> cacheCandidates = new ArrayList<String>(10);
0194:                String baseNameSlashes = baseName.replace('.', '/');
0195:                Map<String, URL> perLoaderCache = localizedFileCache
0196:                        .get(loader);
0197:
0198:                if (perLoaderCache == null) {
0199:                    localizedFileCache.put(loader,
0200:                            perLoaderCache = new HashMap<String, URL>());
0201:                }
0202:
0203:                // #31008: better use of domain cache priming.
0204:                // [PENDING] remove this hack in case the domain cache is precomputed
0205:                URL baseVariant;
0206:                String path;
0207:
0208:                if (ext != null) {
0209:                    path = baseNameSlashes + '.' + ext;
0210:                } else {
0211:                    path = baseNameSlashes;
0212:                }
0213:
0214:                lookup = perLoaderCache.get(path);
0215:
0216:                if (lookup == null) {
0217:                    baseVariant = loader.getResource(path);
0218:                } else {
0219:                    // who cares? already in cache anyway
0220:                    baseVariant = null;
0221:                }
0222:
0223:                while (it.hasNext()) {
0224:                    String suffix = it.next();
0225:
0226:                    if (ext != null) {
0227:                        path = baseNameSlashes + suffix + '.' + ext;
0228:                    } else {
0229:                        path = baseNameSlashes + suffix;
0230:                    }
0231:
0232:                    lookup = perLoaderCache.get(path);
0233:
0234:                    if (lookup != null) {
0235:                        break;
0236:                    }
0237:
0238:                    cacheCandidates.add(path);
0239:
0240:                    if (suffix.length() == 0) {
0241:                        lookup = baseVariant;
0242:                    } else {
0243:                        lookup = loader.getResource(path);
0244:                    }
0245:
0246:                    if (lookup != null) {
0247:                        break;
0248:                    }
0249:                }
0250:
0251:                if (lookup == null) {
0252:                    path = baseName.replace('.', '/');
0253:
0254:                    if (ext != null) {
0255:                        path += ('.' + ext);
0256:                    }
0257:
0258:                    throw new MissingResourceException(
0259:                            "Cannot find localized resource " + path + " in "
0260:                                    + loader, loader.toString(), path); // NOI18N
0261:                } else {
0262:                    // Note that this is not 100% accurate. If someone calls gLF on something
0263:                    // with a locale/branding combo such as _brand_ja, and the answer is found
0264:                    // as _ja, then a subsequent call with param _brand will find this _ja
0265:                    // version - since the localizing iterator does *not* have the property that
0266:                    // each subsequent item is more general than the previous. However, this
0267:                    // situation is very unlikely, so consider this close enough.
0268:                    it = cacheCandidates.iterator();
0269:
0270:                    while (it.hasNext()) {
0271:                        perLoaderCache.put(it.next(), lookup);
0272:                    }
0273:
0274:                    return lookup;
0275:                }
0276:            }
0277:
0278:            /**
0279:             * Find a localized and/or branded value for a given key and locale.
0280:             * Scans through a map to find
0281:             * the most localized match possible. For example:
0282:             * <p><code><PRE>
0283:             *   findLocalizedValue (hashTable, "keyName", new Locale ("cs_CZ"))
0284:             * </PRE></code>
0285:             * <p>This would return the first non-<code>null</code> value obtained from the following tests:
0286:             * <UL>
0287:             * <LI> <CODE>hashTable.get ("keyName_cs_CZ")</CODE>
0288:             * <LI> <CODE>hashTable.get ("keyName_cs")</CODE>
0289:             * <LI> <CODE>hashTable.get ("keyName")</CODE>
0290:             * </UL>
0291:             *
0292:             * @param table mapping from localized strings to objects
0293:             * @param key the key to look for
0294:             * @param locale the locale to use
0295:             * @return the localized object or <code>null</code> if no key matches
0296:             */
0297:            public static <T> T getLocalizedValue(Map<String, T> table,
0298:                    String key, Locale locale) {
0299:                for (String suffix : NbCollections.iterable(new LocaleIterator(
0300:                        locale))) {
0301:                    String physicalKey = key + suffix;
0302:                    T v = table.get(physicalKey);
0303:
0304:                    if (v != null) {
0305:                        // ok
0306:                        if (USE_DEBUG_LOADER && (v instanceof  String)) {
0307:                            // Not read from a bundle, but still localized somehow:
0308:                            @SuppressWarnings("unchecked")
0309:                            T _v = (T) (((String) v) + " (?:" + physicalKey + ")"); // NOI18N;
0310:                            return _v;
0311:                        } else {
0312:                            return v;
0313:                        }
0314:                    }
0315:                }
0316:
0317:                return null;
0318:            }
0319:
0320:            /**
0321:             * Find a localized and/or branded value for a given key in the default system locale.
0322:             *
0323:             * @param table mapping from localized strings to objects
0324:             * @param key the key to look for
0325:             * @return the localized object or <code>null</code> if no key matches
0326:             * @see #getLocalizedValue(Map,String,Locale)
0327:             */
0328:            public static <T> T getLocalizedValue(Map<String, T> table,
0329:                    String key) {
0330:                return getLocalizedValue(table, key, Locale.getDefault());
0331:            }
0332:
0333:            /**
0334:             * Find a localized and/or branded value in a JAR manifest.
0335:             * @param attr the manifest attributes
0336:             * @param key the key to look for (case-insensitive)
0337:             * @param locale the locale to use
0338:             * @return the value if found, else <code>null</code>
0339:             */
0340:            public static String getLocalizedValue(Attributes attr,
0341:                    Attributes.Name key, Locale locale) {
0342:                return getLocalizedValue(attr2Map(attr), key.toString()
0343:                        .toLowerCase(Locale.US), locale);
0344:            }
0345:
0346:            /**
0347:             * Find a localized and/or branded value in a JAR manifest in the default system locale.
0348:             * @param attr the manifest attributes
0349:             * @param key the key to look for (case-insensitive)
0350:             * @return the value if found, else <code>null</code>
0351:             */
0352:            public static String getLocalizedValue(Attributes attr,
0353:                    Attributes.Name key) {
0354:                // Yes, US locale is intentional! The attribute name may only be ASCII anyway.
0355:                // It is necessary to lowercase it *as ASCII* as in Turkish 'I' does not go to 'i'!
0356:                return getLocalizedValue(attr2Map(attr), key.toString()
0357:                        .toLowerCase(Locale.US));
0358:            }
0359:
0360:            /** Necessary because Attributes implements Map; however this is dangerous!
0361:             * The keys are Attributes.Name's, not Strings.
0362:             * Also manifest lookups should not be case-sensitive.
0363:             * (Though the locale suffix still will be!)
0364:             */
0365:            private static Map<String, String> attr2Map(Attributes attr) {
0366:                return new AttributesMap(attr);
0367:            }
0368:
0369:            // ---- LOADING RESOURCE BUNDLES ----
0370:
0371:            /**
0372:             * Get a resource bundle with the default class loader and locale/branding.
0373:             * <strong>Caution:</strong> {@link #getBundle(Class)} is generally
0374:             * safer when used from a module as this method relies on the module's
0375:             * classloader to currently be part of the system classloader. NetBeans
0376:             * does add enabled modules to this classloader, however calls to
0377:             * this variant of the method made in <a href="@org-openide-modules@/org/openide/modules/ModuleInstall.html#validate()">ModuleInstall.validate</a>,
0378:             * or made soon after a module is uninstalled (due to background threads)
0379:             * could fail unexpectedly.
0380:             * @param baseName bundle basename
0381:             * @return the resource bundle
0382:             * @exception MissingResourceException if the bundle does not exist
0383:             */
0384:            public static final ResourceBundle getBundle(String baseName)
0385:                    throws MissingResourceException {
0386:                return getBundle(baseName, Locale.getDefault(), getLoader());
0387:            }
0388:
0389:            /** Get a resource bundle in the same package as the provided class,
0390:             * with the default locale/branding and the class' own classloader.
0391:             * This is the usual style of invocation.
0392:             *
0393:             * @param clazz the class to take the package name from
0394:             * @return the resource bundle
0395:             * @exception MissingResourceException if the bundle does not exist
0396:             */
0397:            public static ResourceBundle getBundle(Class clazz)
0398:                    throws MissingResourceException {
0399:                String name = findName(clazz);
0400:
0401:                return getBundle(name, Locale.getDefault(), clazz
0402:                        .getClassLoader());
0403:            }
0404:
0405:            /** Finds package name for given class */
0406:            private static String findName(Class clazz) {
0407:                String pref = clazz.getName();
0408:                int last = pref.lastIndexOf('.');
0409:
0410:                if (last >= 0) {
0411:                    pref = pref.substring(0, last + 1);
0412:
0413:                    return pref + "Bundle"; // NOI18N
0414:                } else {
0415:                    // base package, search for bundle
0416:                    return "Bundle"; // NOI18N
0417:                }
0418:            }
0419:
0420:            /**
0421:             * Get a resource bundle with the default class loader and branding.
0422:             * @param baseName bundle basename
0423:             * @param locale the locale to use (but still uses {@link #getBranding default branding})
0424:             * @return the resource bundle
0425:             * @exception MissingResourceException if the bundle does not exist
0426:             */
0427:            public static final ResourceBundle getBundle(String baseName,
0428:                    Locale locale) throws MissingResourceException {
0429:                return getBundle(baseName, locale, getLoader());
0430:            }
0431:
0432:            /** Get a resource bundle the hard way.
0433:             * @param baseName bundle basename
0434:             * @param locale the locale to use (but still uses {@link #getBranding default branding})
0435:             * @param loader the class loader to use
0436:             * @return the resource bundle
0437:             * @exception MissingResourceException if the bundle does not exist
0438:             */
0439:            public static final ResourceBundle getBundle(String baseName,
0440:                    Locale locale, ClassLoader loader)
0441:                    throws MissingResourceException {
0442:                if (USE_DEBUG_LOADER) {
0443:                    loader = DebugLoader.get(loader);
0444:                }
0445:
0446:                // Could more simply use ResourceBundle.getBundle (plus some special logic
0447:                // with MergedBundle to handle branding) instead of manually finding bundles.
0448:                // However this code is faster and has some other desirable properties.
0449:                // Cf. #13847.
0450:                ResourceBundle b = getBundleFast(baseName, locale, loader);
0451:
0452:                if (b != null) {
0453:                    return b;
0454:                } else {
0455:                    MissingResourceException e = new MissingResourceException(
0456:                            "No such bundle " + baseName, baseName, null); // NOI18N
0457:
0458:                    if (Lookup.getDefault().lookup(ClassLoader.class) == null) {
0459:                        Exceptions.attachMessage(e,
0460:                                "Class loader not yet initialized in lookup"); // NOI18N
0461:                    } else {
0462:                        Exceptions.attachMessage(e, "Offending classloader: "
0463:                                + loader); // NOI18N
0464:                    }
0465:
0466:                    throw e;
0467:                }
0468:            }
0469:
0470:            /**
0471:             * Get a resource bundle by name.
0472:             * Like {@link ResourceBundle#getBundle(String,Locale,ClassLoader)} but faster,
0473:             * and also understands branding.
0474:             * First looks for <samp>.properties</samp>-based bundles, then <samp>.class</samp>-based.
0475:             * @param name the base name of the bundle, e.g. <samp>org.netbeans.modules.foo.Bundle</samp>
0476:             * @param locale the locale to use
0477:             * @param loader a class loader to search in
0478:             * @return a resource bundle (locale- and branding-merged), or null if not found
0479:             */
0480:            private static ResourceBundle getBundleFast(String name,
0481:                    Locale locale, ClassLoader loader) {
0482:                Map<String, Reference<ResourceBundle>> m;
0483:
0484:                synchronized (bundleCache) {
0485:                    m = bundleCache.get(loader);
0486:
0487:                    if (m == null) {
0488:                        bundleCache
0489:                                .put(
0490:                                        loader,
0491:                                        m = new HashMap<String, Reference<ResourceBundle>>());
0492:                    }
0493:                }
0494:
0495:                //A minor optimization to cut down on StringBuffer allocations - OptimizeIt
0496:                //showed the commented out code below was a major source of them.  This
0497:                //just does the same thing with a char array - Tim
0498:                String localeStr = locale.toString();
0499:                char[] k = new char[name.length()
0500:                        + ((brandingToken != null) ? brandingToken.length() : 1)
0501:                        + 2 + localeStr.length()];
0502:                name.getChars(0, name.length(), k, 0);
0503:                k[name.length()] = '/'; //NOI18N
0504:
0505:                int pos = name.length() + 1;
0506:
0507:                if (brandingToken == null) {
0508:                    k[pos] = '-'; //NOI18N
0509:                    pos++;
0510:                } else {
0511:                    brandingToken.getChars(0, brandingToken.length(), k, pos);
0512:                    pos += brandingToken.length();
0513:                }
0514:
0515:                k[pos] = '/'; //NOI18N
0516:                pos++;
0517:                localeStr.getChars(0, localeStr.length(), k, pos);
0518:
0519:                String key = new String(k);
0520:
0521:                /*
0522:                String key = name + '/' + (brandingToken != null ? brandingToken : "-") + '/' + locale; // NOI18N
0523:                 */
0524:                synchronized (m) {
0525:                    Reference<ResourceBundle> o = m.get(key);
0526:                    ResourceBundle b = o != null ? o.get() : null;
0527:
0528:                    if (b != null) {
0529:                        return b;
0530:                    } else {
0531:                        b = loadBundle(name, locale, loader);
0532:
0533:                        if (b != null) {
0534:                            m.put(key, new TimedSoftReference<ResourceBundle>(
0535:                                    b, m, key));
0536:                        } else {
0537:                            // Used to cache misses as well, to make the negative test faster.
0538:                            // However this caused problems: see #31578.
0539:                        }
0540:
0541:                        return b;
0542:                    }
0543:                }
0544:            }
0545:
0546:            /**
0547:             * Load a resource bundle (without caching).
0548:             * @param name the base name of the bundle, e.g. <samp>org.netbeans.modules.foo.Bundle</samp>
0549:             * @param locale the locale to use
0550:             * @param loader a class loader to search in
0551:             * @return a resource bundle (locale- and branding-merged), or null if not found
0552:             */
0553:            private static ResourceBundle loadBundle(String name,
0554:                    Locale locale, ClassLoader loader) {
0555:                String sname = name.replace('.', '/');
0556:                Iterator<String> it = new LocaleIterator(locale);
0557:                LinkedList<String> l = new LinkedList<String>();
0558:
0559:                while (it.hasNext()) {
0560:                    l.addFirst(it.next());
0561:                }
0562:
0563:                Properties p = new Properties();
0564:
0565:                for (String suffix : l) {
0566:                    String res = sname + suffix + ".properties";
0567:
0568:                    // #49961: don't use getResourceAsStream; catch all errors opening it
0569:                    URL u = loader != null ? loader.getResource(res)
0570:                            : ClassLoader.getSystemResource(res);
0571:
0572:                    if (u != null) {
0573:                        //System.err.println("Loading " + res);
0574:                        try {
0575:                            // #51667: but in case we are in USE_DEBUG_LOADER mode, use gRAS (since getResource is not overridden)
0576:                            InputStream is = USE_DEBUG_LOADER ? (loader != null ? loader
0577:                                    .getResourceAsStream(res)
0578:                                    : ClassLoader
0579:                                            .getSystemResourceAsStream(res))
0580:                                    : u.openStream();
0581:
0582:                            try {
0583:                                p.load(is);
0584:                            } finally {
0585:                                is.close();
0586:                            }
0587:                        } catch (IOException e) {
0588:                            Exceptions
0589:                                    .attachMessage(e, "While loading: " + res); // NOI18N
0590:                            Logger.getLogger(NbBundle.class.getName()).log(
0591:                                    Level.WARNING, null, e);
0592:
0593:                            return null;
0594:                        }
0595:                    } else if (suffix.length() == 0) {
0596:                        // No base *.properties. Try *.class.
0597:                        // Note that you may not mix *.properties w/ *.class this way.
0598:                        return loadBundleClass(name, sname, locale, l, loader);
0599:                    }
0600:                }
0601:
0602:                return new PBundle(NbCollections.checkedMapByFilter(p,
0603:                        String.class, String.class, true), locale);
0604:            }
0605:
0606:            /**
0607:             * Load a class-based resource bundle.
0608:             * @param name the base name of the bundle, e.g. <samp>org.netbeans.modules.foo.Bundle</samp>
0609:             * @param sname the name with slashes, e.g. <samp>org/netbeans/modules/foo/Bundle</samp>
0610:             * @param locale the locale to use
0611:             * @param suffixes a list of suffixes to apply to the bundle name, in <em>increasing</em> order of specificity
0612:             * @param loader a class loader to search in
0613:             * @return a resource bundle (merged according to the suffixes), or null if not found
0614:             */
0615:            private static ResourceBundle loadBundleClass(String name,
0616:                    String sname, Locale locale, List<String> suffixes,
0617:                    ClassLoader l) {
0618:                if (l != null && l.getResource(sname + ".class") == null) { // NOI18N
0619:
0620:                    // No chance - no base bundle. Don't waste time catching CNFE.
0621:                    return null;
0622:                }
0623:
0624:                ResourceBundle master = null;
0625:
0626:                for (String suffix : suffixes) {
0627:                    try {
0628:                        Class<? extends ResourceBundle> c = Class.forName(
0629:                                name + suffix, true, l).asSubclass(
0630:                                ResourceBundle.class);
0631:                        ResourceBundle b = c.newInstance();
0632:
0633:                        if (master == null) {
0634:                            master = b;
0635:                        } else {
0636:                            master = new MergedBundle(locale, b, master);
0637:                        }
0638:                    } catch (ClassNotFoundException cnfe) {
0639:                        // fine - ignore
0640:                    } catch (Exception e) {
0641:                        Logger.getLogger(NbBundle.class.getName()).log(
0642:                                Level.WARNING, null, e);
0643:                    } catch (LinkageError e) {
0644:                        Logger.getLogger(NbBundle.class.getName()).log(
0645:                                Level.WARNING, null, e);
0646:                    }
0647:                }
0648:
0649:                return master;
0650:            }
0651:
0652:            //
0653:            // Helper methods to simplify localization of messages
0654:            //
0655:
0656:            /**
0657:             * Finds a localized and/or branded string in a bundle.
0658:             * @param clazz the class to use to locate the bundle
0659:             * @param resName name of the resource to look for
0660:             * @return the string associated with the resource
0661:             * @throws MissingResourceException if either the bundle or the string cannot be found
0662:             */
0663:            public static String getMessage(Class clazz, String resName)
0664:                    throws MissingResourceException {
0665:                return getBundle(clazz).getString(resName);
0666:            }
0667:
0668:            /**
0669:             * Finds a localized and/or branded string in a bundle and formats the message
0670:             * by passing requested parameters.
0671:             *
0672:             * @param clazz the class to use to locate the bundle
0673:             * @param resName name of the resource to look for
0674:             * @param param1 the argument to use when formatting the message
0675:             * @return the string associated with the resource
0676:             * @throws MissingResourceException if either the bundle or the string cannot be found
0677:             * @see java.text.MessageFormat#format(String,Object[])
0678:             */
0679:            public static String getMessage(Class clazz, String resName,
0680:                    Object param1) throws MissingResourceException {
0681:                return getMessage(clazz, resName, new Object[] { param1 });
0682:            }
0683:
0684:            /**
0685:             * Finds a localized and/or branded string in a bundle and formats the message
0686:             * by passing requested parameters.
0687:             *
0688:             * @param clazz the class to use to locate the bundle
0689:             * @param resName name of the resource to look for
0690:             * @param param1 the argument to use when formatting the message
0691:             * @param param2 the second argument to use for formatting
0692:             * @return the string associated with the resource
0693:             * @throws MissingResourceException if either the bundle or the string cannot be found
0694:             * @see java.text.MessageFormat#format(String,Object[])
0695:             */
0696:            public static String getMessage(Class clazz, String resName,
0697:                    Object param1, Object param2)
0698:                    throws MissingResourceException {
0699:                return getMessage(clazz, resName,
0700:                        new Object[] { param1, param2 });
0701:            }
0702:
0703:            /**
0704:             * Finds a localized and/or branded string in a bundle and formats the message
0705:             * by passing requested parameters.
0706:             *
0707:             * @param clazz the class to use to locate the bundle
0708:             * @param resName name of the resource to look for
0709:             * @param param1 the argument to use when formatting the message
0710:             * @param param2 the second argument to use for formatting
0711:             * @param param3 the third argument to use for formatting
0712:             * @return the string associated with the resource
0713:             * @throws MissingResourceException if either the bundle or the string cannot be found
0714:             * @see java.text.MessageFormat#format(String,Object[])
0715:             */
0716:            public static String getMessage(Class clazz, String resName,
0717:                    Object param1, Object param2, Object param3)
0718:                    throws MissingResourceException {
0719:                return getMessage(clazz, resName, new Object[] { param1,
0720:                        param2, param3 });
0721:            }
0722:
0723:            /**
0724:             * Finds a localized and/or branded string in a bundle and formats the message
0725:             * by passing requested parameters.
0726:             *
0727:             * @param clazz the class to use to locate the bundle
0728:             * @param resName name of the resource to look for
0729:             * @param arr array of parameters to use for formatting the message
0730:             * @return the string associated with the resource
0731:             * @throws MissingResourceException if either the bundle or the string cannot be found
0732:             * @see java.text.MessageFormat#format(String,Object[])
0733:             */
0734:            public static String getMessage(Class clazz, String resName,
0735:                    Object[] arr) throws MissingResourceException {
0736:                return java.text.MessageFormat.format(
0737:                        getMessage(clazz, resName), arr);
0738:            }
0739:
0740:            /** @return default class loader which is used, when we don't have
0741:             * any other class loader. (in function getBundle(String), getLocalizedFile(String),
0742:             * and so on...
0743:             */
0744:            private static ClassLoader getLoader() {
0745:                ClassLoader c = Lookup.getDefault().lookup(ClassLoader.class);
0746:
0747:                return (c != null) ? c : ClassLoader.getSystemClassLoader();
0748:            }
0749:
0750:            /**
0751:             * Get a list of all suffixes used to search for localized/branded resources.
0752:             * Based on the default locale and branding, returns the list of suffixes
0753:             * which various <code>NbBundle</code> methods use as the search order.
0754:             * For example, when {@link #getBranding} returns <code>branding</code>
0755:             * and the default locale is German, you might get a sequence such as:
0756:             * <ol>
0757:             * <li><samp>"_branding_de"</samp>
0758:             * <li><samp>"_branding"</samp>
0759:             * <li><samp>"_de"</samp>
0760:             * <li><samp>""</samp>
0761:             * </ol>
0762:             * @return a read-only iterator of type <code>String</code>
0763:             * @since 1.1.5
0764:             */
0765:            public static Iterator<String> getLocalizingSuffixes() {
0766:                return new LocaleIterator(Locale.getDefault());
0767:            }
0768:
0769:            /**
0770:             * Do not use.
0771:             * @param loaderFinder ignored
0772:             * @deprecated Useless.
0773:             */
0774:            @Deprecated
0775:            public static void setClassLoaderFinder(
0776:                    ClassLoaderFinder loaderFinder) {
0777:                throw new Error();
0778:            }
0779:
0780:            /**
0781:             * Do not use.
0782:             * @deprecated Useless.
0783:             */
0784:            @Deprecated
0785:            public static interface ClassLoaderFinder {
0786:                /**
0787:                 * Do not use.
0788:                 * @return nothing
0789:                 * @deprecated Useless.
0790:                 */
0791:                @Deprecated
0792:                public ClassLoader find();
0793:            }
0794:
0795:            private static class AttributesMap extends HashMap<String, String> {
0796:                private Attributes attrs;
0797:
0798:                public AttributesMap(Attributes attrs) {
0799:                    super (7);
0800:                    this .attrs = attrs;
0801:                }
0802:
0803:                public String get(Object _k) {
0804:                    if (!(_k instanceof  String)) {
0805:                        return null;
0806:                    }
0807:                    String k = (String) _k;
0808:
0809:                    Attributes.Name an;
0810:
0811:                    try {
0812:                        an = new Attributes.Name(k);
0813:                    } catch (IllegalArgumentException iae) {
0814:                        // Robustness, and workaround for reported MRJ locale bug:
0815:                        Exceptions.attachLocalizedMessage(iae, getMessage(
0816:                                NbBundle.class, "EXC_bad_attributes_name", k,
0817:                                Locale.getDefault().toString()));
0818:                        Exceptions.printStackTrace(iae);
0819:
0820:                        return null;
0821:                    }
0822:
0823:                    return attrs.getValue(an);
0824:                }
0825:            }
0826:
0827:            /**
0828:             * A resource bundle based on <samp>.properties</samp> files (or any map).
0829:             */
0830:            private static final class PBundle extends ResourceBundle {
0831:                private final Map<String, String> m;
0832:                private final Locale locale;
0833:
0834:                /**
0835:                 * Create a new bundle based on a map.
0836:                 * @param m a map from resources keys to values (typically both strings)
0837:                 * @param locale the locale it represents <em>(informational)</em>
0838:                 */
0839:                public PBundle(Map<String, String> m, Locale locale) {
0840:                    this .m = m;
0841:                    this .locale = locale;
0842:                }
0843:
0844:                public Enumeration<String> getKeys() {
0845:                    return Collections.enumeration(m.keySet());
0846:                }
0847:
0848:                protected Object handleGetObject(String key) {
0849:                    return m.get(key);
0850:                }
0851:
0852:                public Locale getLocale() {
0853:                    return locale;
0854:                }
0855:            }
0856:
0857:            /** Special resource bundle which delegates to two others.
0858:             * Ideally could just set the parent on the first, but this is protected, so...
0859:             */
0860:            private static class MergedBundle extends ResourceBundle {
0861:                private Locale loc;
0862:                private ResourceBundle sub1;
0863:                private ResourceBundle sub2;
0864:
0865:                /**
0866:                 * Create a new bundle delegating to two others.
0867:                 * @param loc the locale it represents <em>(informational)</em>
0868:                 * @param sub1 one delegate (taking precedence over the other in case of overlap)
0869:                 * @param sub2 the other (weaker) delegate
0870:                 */
0871:                public MergedBundle(Locale loc, ResourceBundle sub1,
0872:                        ResourceBundle sub2) {
0873:                    this .loc = loc;
0874:                    this .sub1 = sub1;
0875:                    this .sub2 = sub2;
0876:                }
0877:
0878:                public Locale getLocale() {
0879:                    return loc;
0880:                }
0881:
0882:                public Enumeration<String> getKeys() {
0883:                    return Enumerations.removeDuplicates(Enumerations.concat(
0884:                            sub1.getKeys(), sub2.getKeys()));
0885:                }
0886:
0887:                protected Object handleGetObject(String key)
0888:                        throws MissingResourceException {
0889:                    try {
0890:                        return sub1.getObject(key);
0891:                    } catch (MissingResourceException mre) {
0892:                        // Ignore exception, and...
0893:                        return sub2.getObject(key);
0894:                    }
0895:                }
0896:            }
0897:
0898:            /** This class (enumeration) gives all localized sufixes using nextElement
0899:             * method. It goes through given Locale and continues through Locale.getDefault()
0900:             * Example 1:
0901:             *   Locale.getDefault().toString() -> "_en_US"
0902:             *   you call new LocaleIterator(new Locale("cs", "CZ"));
0903:             *  ==> You will gets: "_cs_CZ", "_cs", "", "_en_US", "_en"
0904:             *
0905:             * Example 2:
0906:             *   Locale.getDefault().toString() -> "_cs_CZ"
0907:             *   you call new LocaleIterator(new Locale("cs", "CZ"));
0908:             *  ==> You will gets: "_cs_CZ", "_cs", ""
0909:             *
0910:             * If there is a branding token in effect, you will get it too as an extra
0911:             * prefix, taking precedence, e.g. for the token "f4jce":
0912:             *
0913:             * "_f4jce_cs_CZ", "_f4jce_cs", "_f4jce", "_f4jce_en_US", "_f4jce_en", "_cs_CZ", "_cs", "", "_en_US", "_en"
0914:             *
0915:             * Branding tokens with underscores are broken apart naturally: so e.g.
0916:             * branding "f4j_ce" looks first for "f4j_ce" branding, then "f4j" branding, then none.
0917:             */
0918:            private static class LocaleIterator extends Object implements 
0919:                    Iterator<String> {
0920:                /** this flag means, if default locale is in progress */
0921:                private boolean defaultInProgress = false;
0922:
0923:                /** this flag means, if empty suffix was exported yet */
0924:                private boolean empty = false;
0925:
0926:                /** current locale, and initial locale */
0927:                private Locale locale;
0928:
0929:                /** current locale, and initial locale */
0930:                private Locale initLocale;
0931:
0932:                /** current suffix which will be returned in next calling nextElement */
0933:                private String current;
0934:
0935:                /** the branding string in use */
0936:                private String branding;
0937:
0938:                /** Creates new LocaleIterator for given locale.
0939:                 * @param locale given Locale
0940:                 */
0941:                public LocaleIterator(Locale locale) {
0942:                    this .locale = this .initLocale = locale;
0943:
0944:                    if (locale.equals(Locale.getDefault())) {
0945:                        defaultInProgress = true;
0946:                    }
0947:
0948:                    current = '_' + locale.toString();
0949:
0950:                    if (brandingToken == null) {
0951:                        branding = null;
0952:                    } else {
0953:                        branding = "_" + brandingToken; // NOI18N
0954:                    }
0955:
0956:                    //System.err.println("Constructed: " + this);
0957:                }
0958:
0959:                /** @return next suffix.
0960:                 * @exception NoSuchElementException if there is no more locale suffix.
0961:                 */
0962:                public String next() throws NoSuchElementException {
0963:                    if (current == null) {
0964:                        throw new NoSuchElementException();
0965:                    }
0966:
0967:                    final String ret;
0968:
0969:                    if (branding == null) {
0970:                        ret = current;
0971:                    } else {
0972:                        ret = branding + current;
0973:                    }
0974:
0975:                    int lastUnderbar = current.lastIndexOf('_');
0976:
0977:                    if (lastUnderbar == 0) {
0978:                        if (empty) {
0979:                            reset();
0980:                        } else {
0981:                            current = ""; // NOI18N
0982:                            empty = true;
0983:                        }
0984:                    } else {
0985:                        if (lastUnderbar == -1) {
0986:                            if (defaultInProgress) {
0987:                                reset();
0988:                            } else {
0989:                                // [PENDING] stuff with trying the default locale
0990:                                // after the real one does not actually seem to work...
0991:                                locale = Locale.getDefault();
0992:                                current = '_' + locale.toString();
0993:                                defaultInProgress = true;
0994:                            }
0995:                        } else {
0996:                            current = current.substring(0, lastUnderbar);
0997:                        }
0998:                    }
0999:
1000:                    //System.err.println("Returning: `" + ret + "' from: " + this);
1001:                    return ret;
1002:                }
1003:
1004:                /** Finish a series.
1005:                 * If there was a branding prefix, restart without that prefix
1006:                 * (or with a shorter prefix); else finish.
1007:                 */
1008:                private void reset() {
1009:                    if (branding != null) {
1010:                        current = '_' + initLocale.toString();
1011:
1012:                        int idx = branding.lastIndexOf('_');
1013:
1014:                        if (idx == 0) {
1015:                            branding = null;
1016:                        } else {
1017:                            branding = branding.substring(0, idx);
1018:                        }
1019:
1020:                        empty = false;
1021:                    } else {
1022:                        current = null;
1023:                    }
1024:                }
1025:
1026:                /** Tests if there is any sufix.*/
1027:                public boolean hasNext() {
1028:                    return (current != null);
1029:                }
1030:
1031:                public void remove() throws UnsupportedOperationException {
1032:                    throw new UnsupportedOperationException();
1033:                }
1034:            }
1035:
1036:            // end of LocaleIterator
1037:
1038:            /** Classloader whose special trick is inserting debug information
1039:             * into any *.properties files it loads.
1040:             */
1041:            static final class DebugLoader extends ClassLoader {
1042:                /** global bundle index, each loaded bundle gets its own */
1043:                private static int count = 0;
1044:
1045:                /** indices of known bundles; needed since DebugLoader's can be collected
1046:                 * when softly reachable, but this should be transparent to the user
1047:                 */
1048:                private static final Map<String, Integer> knownIDs = new HashMap<String, Integer>();
1049:
1050:                /** cache of existing debug loaders for regular loaders */
1051:                private static final Map<ClassLoader, Reference<ClassLoader>> existing = new WeakHashMap<ClassLoader, Reference<ClassLoader>>();
1052:
1053:                private DebugLoader(ClassLoader cl) {
1054:                    super (cl);
1055:
1056:                    //System.err.println ("new DebugLoader: cl=" + cl);
1057:                }
1058:
1059:                private static int getID(String name) {
1060:                    synchronized (knownIDs) {
1061:                        Integer i = knownIDs.get(name);
1062:
1063:                        if (i == null) {
1064:                            i = ++count;
1065:                            knownIDs.put(name, i);
1066:                            System.err.println("NbBundle trace: #" + i + " = "
1067:                                    + name); // NOI18N
1068:                        }
1069:
1070:                        return i;
1071:                    }
1072:                }
1073:
1074:                public static ClassLoader get(ClassLoader normal) {
1075:                    //System.err.println("Lookup: normal=" + normal);
1076:                    synchronized (existing) {
1077:                        Reference<ClassLoader> r = existing.get(normal);
1078:
1079:                        if (r != null) {
1080:                            ClassLoader dl = r.get();
1081:
1082:                            if (dl != null) {
1083:                                //System.err.println("\tcache hit");
1084:                                return dl;
1085:                            } else {
1086:                                //System.err.println("\tcollected ref");
1087:                            }
1088:                        } else {
1089:                            //System.err.println("\tnot in cache");
1090:                        }
1091:
1092:                        ClassLoader dl = new DebugLoader(normal);
1093:                        existing
1094:                                .put(normal, new WeakReference<ClassLoader>(dl));
1095:
1096:                        return dl;
1097:                    }
1098:                }
1099:
1100:                public InputStream getResourceAsStream(String name) {
1101:                    InputStream base = super .getResourceAsStream(name);
1102:
1103:                    if (base == null) {
1104:                        return null;
1105:                    }
1106:
1107:                    if (name.endsWith(".properties")) { // NOI18N
1108:
1109:                        int id = getID(name);
1110:
1111:                        //System.err.println ("\tthis=" + this + " parent=" + getParent ());
1112:                        boolean loc = name.indexOf("Bundle") != -1; // NOI18N
1113:
1114:                        return new DebugInputStream(base, id, loc);
1115:                    } else {
1116:                        return base;
1117:                    }
1118:                }
1119:
1120:                // [PENDING] getResource not overridden; but ResourceBundle uses getResourceAsStream anyhow
1121:
1122:                /** Wrapper input stream which parses the text as it goes and adds annotations.
1123:                 * Resource-bundle values are annotated with their current line number and also
1124:                 * the supplied it, so e.g. if in the original input stream on line 50 we have:
1125:                 *   somekey=somevalue
1126:                 * so in the wrapper stream (id 123) this line will read:
1127:                 *   somekey=somevalue (123:50)
1128:                 * Since you see on stderr what #123 is, you can then pinpoint where any bundle key
1129:                 * originally came from, assuming NbBundle loaded it from a *.properties file.
1130:                 * @see {@link Properties#load} for details on the syntax of *.properties files.
1131:                 */
1132:                static final class DebugInputStream extends InputStream {
1133:                    /** state transition diagram constants */
1134:                    private static final int WAITING_FOR_KEY = 0;
1135:
1136:                    /** state transition diagram constants */
1137:                    private static final int IN_COMMENT = 1;
1138:
1139:                    /** state transition diagram constants */
1140:                    private static final int IN_KEY = 2;
1141:
1142:                    /** state transition diagram constants */
1143:                    private static final int IN_KEY_BACKSLASH = 3;
1144:
1145:                    /** state transition diagram constants */
1146:                    private static final int AFTER_KEY = 4;
1147:
1148:                    /** state transition diagram constants */
1149:                    private static final int WAITING_FOR_VALUE = 5;
1150:
1151:                    /** state transition diagram constants */
1152:                    private static final int IN_VALUE = 6;
1153:
1154:                    /** state transition diagram constants */
1155:                    private static final int IN_VALUE_BACKSLASH = 7;
1156:                    private final InputStream base;
1157:                    private final int id;
1158:                    private final boolean localizable;
1159:
1160:                    /** current line number */
1161:                    private int line = 0;
1162:
1163:                    /** line number in effect for last-encountered key */
1164:                    private int keyLine = 0;
1165:
1166:                    /** current state in state machine */
1167:                    private int state = WAITING_FOR_KEY;
1168:
1169:                    /** if true, the last char was a CR, waiting to see if we get a NL too */
1170:                    private boolean twixtCrAndNl = false;
1171:
1172:                    /** if non-null, a string to serve up before continuing (length must be > 0) */
1173:                    private String toInsert = null;
1174:
1175:                    /** if true, the next value encountered should be localizable if normally it would not be, or vice-versa */
1176:                    private boolean reverseLocalizable = false;
1177:
1178:                    /** text of currently read comment, including leading comment character */
1179:                    private StringBuffer lastComment = null;
1180:
1181:                    /** Create a new InputStream which will annotate resource bundles.
1182:                     * Bundles named Bundle*.properties will be treated as localizable by default,
1183:                     * and so annotated; other bundles will be treated as nonlocalizable and not annotated.
1184:                     * Messages can be individually marked as localizable or not to override this default,
1185:                     * in accordance with some I18N conventions for NetBeans.
1186:                     * @param base the unannotated stream
1187:                     * @param id an identifying number to use in annotations
1188:                     * @param localizable if true, this bundle is expected to be localizable
1189:                     * @see http://www.netbeans.org/i18n/
1190:                     */
1191:                    public DebugInputStream(InputStream base, int id,
1192:                            boolean localizable) {
1193:                        this .base = base;
1194:                        this .id = id;
1195:                        this .localizable = localizable;
1196:                    }
1197:
1198:                    public int read() throws IOException {
1199:                        if (toInsert != null) {
1200:                            char result = toInsert.charAt(0);
1201:
1202:                            if (toInsert.length() > 1) {
1203:                                toInsert = toInsert.substring(1);
1204:                            } else {
1205:                                toInsert = null;
1206:                            }
1207:
1208:                            return result;
1209:                        }
1210:
1211:                        int next = base.read();
1212:
1213:                        if (next == '\n') {
1214:                            twixtCrAndNl = false;
1215:                            line++;
1216:                        } else if (next == '\r') {
1217:                            if (twixtCrAndNl) {
1218:                                line++;
1219:                            } else {
1220:                                twixtCrAndNl = true;
1221:                            }
1222:                        } else {
1223:                            twixtCrAndNl = false;
1224:                        }
1225:
1226:                        switch (state) {
1227:                        case WAITING_FOR_KEY:
1228:
1229:                            switch (next) {
1230:                            case '#':
1231:                            case '!':
1232:                                state = IN_COMMENT;
1233:                                lastComment = new StringBuffer();
1234:                                lastComment.append((char) next);
1235:
1236:                                return next;
1237:
1238:                            case ' ':
1239:                            case '\t':
1240:                            case '\n':
1241:                            case '\r':
1242:                            case -1:
1243:                                return next;
1244:
1245:                            case '\\':
1246:                                state = IN_KEY_BACKSLASH;
1247:
1248:                                return next;
1249:
1250:                            default:
1251:                                state = IN_KEY;
1252:                                keyLine = line + 1;
1253:
1254:                                return next;
1255:                            }
1256:
1257:                        case IN_COMMENT:
1258:
1259:                            switch (next) {
1260:                            case '\n':
1261:                            case '\r':
1262:
1263:                                String comment = lastComment.toString();
1264:                                lastComment = null;
1265:
1266:                                if (localizable && comment.equals("#NOI18N")) { // NOI18N
1267:                                    reverseLocalizable = true;
1268:                                } else if (localizable
1269:                                        && comment.equals("#PARTNOI18N")) { // NOI18N
1270:                                    System.err
1271:                                            .println("NbBundle WARNING ("
1272:                                                    + id
1273:                                                    + ":"
1274:                                                    + line
1275:                                                    + "): #PARTNOI18N encountered, will not annotate I18N parts"); // NOI18N
1276:                                    reverseLocalizable = true;
1277:                                } else if (!localizable
1278:                                        && comment.equals("#I18N")) { // NOI18N
1279:                                    reverseLocalizable = true;
1280:                                } else if (!localizable
1281:                                        && comment.equals("#PARTI18N")) { // NOI18N
1282:                                    System.err
1283:                                            .println("NbBundle WARNING ("
1284:                                                    + id
1285:                                                    + ":"
1286:                                                    + line
1287:                                                    + "): #PARTI18N encountered, will not annotate I18N parts"); // NOI18N
1288:                                    reverseLocalizable = false;
1289:                                } else if ((localizable && (comment
1290:                                        .equals("#I18N") || comment
1291:                                        .equals("#PARTI18N")))
1292:                                        || // NOI18N
1293:                                        (!localizable && (comment
1294:                                                .equals("#NOI18N") || comment
1295:                                                .equals("#PARTNOI18N")))) { // NOI18N
1296:                                    System.err.println("NbBundle WARNING ("
1297:                                            + id + ":" + line
1298:                                            + "): incongruous comment "
1299:                                            + comment + " found for bundle"); // NOI18N
1300:                                    reverseLocalizable = false;
1301:                                }
1302:
1303:                                state = WAITING_FOR_KEY;
1304:
1305:                                return next;
1306:
1307:                            default:
1308:                                lastComment.append((char) next);
1309:
1310:                                return next;
1311:                            }
1312:
1313:                        case IN_KEY:
1314:
1315:                            switch (next) {
1316:                            case '\\':
1317:                                state = IN_KEY_BACKSLASH;
1318:
1319:                                return next;
1320:
1321:                            case ' ':
1322:                            case '\t':
1323:                                state = AFTER_KEY;
1324:
1325:                                return next;
1326:
1327:                            case '=':
1328:                            case ':':
1329:                                state = WAITING_FOR_VALUE;
1330:
1331:                                return next;
1332:
1333:                            case '\r':
1334:                            case '\n':
1335:                                state = WAITING_FOR_KEY;
1336:
1337:                                return next;
1338:
1339:                            default:
1340:                                return next;
1341:                            }
1342:
1343:                        case IN_KEY_BACKSLASH:
1344:                            state = IN_KEY;
1345:
1346:                            return next;
1347:
1348:                        case AFTER_KEY:
1349:
1350:                            switch (next) {
1351:                            case '=':
1352:                            case ':':
1353:                                state = WAITING_FOR_VALUE;
1354:
1355:                                return next;
1356:
1357:                            case '\r':
1358:                            case '\n':
1359:                                state = WAITING_FOR_KEY;
1360:
1361:                                return next;
1362:
1363:                            default:
1364:                                return next;
1365:                            }
1366:
1367:                        case WAITING_FOR_VALUE:
1368:
1369:                            switch (next) {
1370:                            case '\r':
1371:                            case '\n':
1372:                                state = WAITING_FOR_KEY;
1373:
1374:                                return next;
1375:
1376:                            case ' ':
1377:                            case '\t':
1378:                                return next;
1379:
1380:                            case '\\':
1381:                                state = IN_VALUE_BACKSLASH;
1382:
1383:                                return next;
1384:
1385:                            default:
1386:                                state = IN_VALUE;
1387:
1388:                                return next;
1389:                            }
1390:
1391:                        case IN_VALUE:
1392:
1393:                            switch (next) {
1394:                            case '\\':
1395:
1396:                                // Gloss over distinction between simple escapes and \u1234, which is not important for us.
1397:                                // Also no need to deal specially with continuation lines; for us, there is an escaped
1398:                                // newline, after which will be more value, and that is all that is important.
1399:                                state = IN_VALUE_BACKSLASH;
1400:
1401:                                return next;
1402:
1403:                            case '\n':
1404:                            case '\r':
1405:                            case -1:
1406:
1407:                                // End of value. This is the tricky part.
1408:                                boolean revLoc = reverseLocalizable;
1409:                                reverseLocalizable = false;
1410:                                state = WAITING_FOR_KEY;
1411:
1412:                                if (localizable ^ revLoc) {
1413:                                    // This value is intended to be localizable. Annotate it.
1414:                                    assert keyLine > 0;
1415:                                    toInsert = "(" + id + ":" + keyLine + ")"; // NOI18N
1416:                                    if (next != -1) {
1417:                                        toInsert += new Character((char) next);
1418:                                    }
1419:                                    keyLine = 0;
1420:
1421:                                    // Now return the space before the rest of the string explicitly.
1422:                                    return ' ';
1423:                                } else {
1424:                                    // This is not supposed to be a localizable value, leave it alone.
1425:                                    return next;
1426:                                }
1427:
1428:                            default:
1429:                                return next;
1430:                            }
1431:
1432:                        case IN_VALUE_BACKSLASH:
1433:                            state = IN_VALUE;
1434:
1435:                            return next;
1436:
1437:                        default:
1438:                            throw new IOException("should never happen"); // NOI18N
1439:                        }
1440:                    }
1441:
1442:                }
1443:            }
1444:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.