Source Code Cross Referenced for TransliteratorRegistry.java in  » Internationalization-Localization » icu4j » com » ibm » icu » text » 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 » Internationalization Localization » icu4j » com.ibm.icu.text 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         **********************************************************************
003:         *   Copyright (c) 2001-2005, International Business Machines
004:         *   Corporation and others.  All Rights Reserved.
005:         **********************************************************************
006:         *   Date        Name        Description
007:         *   08/19/2001  aliu        Creation.
008:         **********************************************************************
009:         */
010:
011:        package com.ibm.icu.text;
012:
013:        //import com.ibm.icu.impl.ICULocaleData;
014:        import com.ibm.icu.impl.ICUResourceBundle;
015:        import com.ibm.icu.impl.LocaleUtility;
016:        import com.ibm.icu.lang.UScript;
017:        import com.ibm.icu.util.CaseInsensitiveString;
018:        import com.ibm.icu.util.UResourceBundle;
019:
020:        import java.util.Enumeration;
021:        import java.util.Hashtable;
022:        import java.util.Locale;
023:        import java.util.MissingResourceException;
024:        import java.util.ResourceBundle;
025:        import java.util.Vector;
026:
027:        class TransliteratorRegistry {
028:
029:            // char constants
030:            private static final char LOCALE_SEP = '_';
031:
032:            // String constants
033:            private static final String NO_VARIANT = ""; // empty string
034:            private static final String ANY = "Any";
035:
036:            /**
037:             * Dynamic registry mapping full IDs to Entry objects.  This
038:             * contains both public and internal entities.  The visibility is
039:             * controlled by whether an entry is listed in availableIDs and
040:             * specDAG or not.
041:             *
042:             * Keys are CaseInsensitiveString objects.
043:             * Values are objects of class Class (subclass of Transliterator),
044:             * RuleBasedTransliterator.Data, Transliterator.Factory, or one
045:             * of the entry classes defined here (AliasEntry or ResourceEntry).
046:             */
047:            private Hashtable registry;
048:
049:            /**
050:             * DAG of visible IDs by spec.  Hashtable: source => (Hashtable:
051:             * target => (Vector: variant)) The Vector of variants is never
052:             * empty.  For a source-target with no variant, the special
053:             * variant NO_VARIANT (the empty string) is stored in slot zero of
054:             * the UVector.
055:             *
056:             * Keys are CaseInsensitiveString objects.
057:             * Values are Hashtable of (CaseInsensitiveString -> Vector of
058:             * CaseInsensitiveString)
059:             */
060:            private Hashtable specDAG;
061:
062:            /**
063:             * Vector of public full IDs (CaseInsensitiveString objects).
064:             */
065:            private Vector availableIDs;
066:
067:            //----------------------------------------------------------------------
068:            // class Spec
069:            //----------------------------------------------------------------------
070:
071:            /**
072:             * A Spec is a string specifying either a source or a target.  In more
073:             * general terms, it may also specify a variant, but we only use the
074:             * Spec class for sources and targets.
075:             *
076:             * A Spec may be a locale or a script.  If it is a locale, it has a
077:             * fallback chain that goes xx_YY_ZZZ -> xx_YY -> xx -> ssss, where
078:             * ssss is the script mapping of xx_YY_ZZZ.  The Spec API methods
079:             * hasFallback(), next(), and reset() iterate over this fallback
080:             * sequence.
081:             *
082:             * The Spec class canonicalizes itself, so the locale is put into
083:             * canonical form, or the script is transformed from an abbreviation
084:             * to a full name.
085:             */
086:            static class Spec {
087:
088:                private String top; // top spec
089:                private String spec; // current spec
090:                private String nextSpec; // next spec
091:                private String scriptName; // script name equivalent of top, if != top
092:                private boolean isSpecLocale; // TRUE if spec is a locale
093:                private boolean isNextLocale; // TRUE if nextSpec is a locale
094:                private ICUResourceBundle res;
095:
096:                public Spec(String theSpec) {
097:                    top = theSpec;
098:                    spec = null;
099:                    scriptName = null;
100:                    try {
101:                        // Canonicalize script name.  If top is a script name then
102:                        // script != UScript.INVALID_CODE.
103:                        int script = UScript.getCodeFromName(top);
104:
105:                        // Canonicalize script name -or- do locale->script mapping
106:                        int[] s = UScript.getCode(top);
107:                        if (s != null) {
108:                            scriptName = UScript.getName(s[0]);
109:                            // If the script name is the same as top then it's redundant
110:                            if (scriptName.equalsIgnoreCase(top)) {
111:                                scriptName = null;
112:                            }
113:                        }
114:
115:                        isSpecLocale = false;
116:                        res = null;
117:                        // If 'top' is not a script name, try a locale lookup
118:                        if (script == UScript.INVALID_CODE) {
119:                            Locale toploc = LocaleUtility
120:                                    .getLocaleFromName(top);
121:                            res = (ICUResourceBundle) UResourceBundle
122:                                    .getBundleInstance(
123:                                            ICUResourceBundle.ICU_TRANSLIT_BASE_NAME,
124:                                            toploc);
125:                            // Make sure we got the bundle we wanted; otherwise, don't use it
126:                            if (res != null
127:                                    && LocaleUtility.isFallbackOf(res
128:                                            .getULocale().toString(), top)) {
129:                                isSpecLocale = true;
130:                            }
131:                        }
132:                    } catch (MissingResourceException e) {
133:                        scriptName = null;
134:                    }
135:                    // assert(spec != top);
136:                    reset();
137:                }
138:
139:                public boolean hasFallback() {
140:                    return nextSpec != null;
141:                }
142:
143:                public void reset() {
144:                    if (spec != top) { // [sic] pointer comparison
145:                        spec = top;
146:                        isSpecLocale = (res != null);
147:                        setupNext();
148:                    }
149:                }
150:
151:                private void setupNext() {
152:                    isNextLocale = false;
153:                    if (isSpecLocale) {
154:                        nextSpec = spec;
155:                        int i = nextSpec.lastIndexOf(LOCALE_SEP);
156:                        // If i == 0 then we have _FOO, so we fall through
157:                        // to the scriptName.
158:                        if (i > 0) {
159:                            nextSpec = spec.substring(0, i);
160:                            isNextLocale = true;
161:                        } else {
162:                            nextSpec = scriptName; // scriptName may be null
163:                        }
164:                    } else {
165:                        // Fallback to the script, which may be null
166:                        if (nextSpec != scriptName) {
167:                            nextSpec = scriptName;
168:                        } else {
169:                            nextSpec = null;
170:                        }
171:                    }
172:                }
173:
174:                // Protocol:
175:                // for(String& s(spec.get());
176:                //     spec.hasFallback(); s(spec.next())) { ...
177:
178:                public String next() {
179:                    spec = nextSpec;
180:                    isSpecLocale = isNextLocale;
181:                    setupNext();
182:                    return spec;
183:                }
184:
185:                public String get() {
186:                    return spec;
187:                }
188:
189:                public boolean isLocale() {
190:                    return isSpecLocale;
191:                }
192:
193:                /**
194:                 * Return the ResourceBundle for this spec, at the current
195:                 * level of iteration.  The level of iteration goes from
196:                 * aa_BB_CCC to aa_BB to aa.  If the bundle does not
197:                 * correspond to the current level of iteration, return null.
198:                 * If isLocale() is false, always return null.
199:                 */
200:                public ResourceBundle getBundle() {
201:                    if (res != null && res.getULocale().toString().equals(spec)) {
202:                        return res;
203:                    }
204:                    return null;
205:                }
206:
207:                public String getTop() {
208:                    return top;
209:                }
210:            }
211:
212:            //----------------------------------------------------------------------
213:            // Entry classes
214:            //----------------------------------------------------------------------
215:
216:            static class ResourceEntry {
217:                public String resource;
218:                public String encoding;
219:                public int direction;
220:
221:                public ResourceEntry(String n, String enc, int d) {
222:                    resource = n;
223:                    encoding = enc;
224:                    direction = d;
225:                }
226:            }
227:
228:            // An entry representing a rule in a locale resource bundle
229:            static class LocaleEntry {
230:                public String rule;
231:                public int direction;
232:
233:                public LocaleEntry(String r, int d) {
234:                    rule = r;
235:                    direction = d;
236:                }
237:            }
238:
239:            static class AliasEntry {
240:                public String alias;
241:
242:                public AliasEntry(String a) {
243:                    alias = a;
244:                }
245:            }
246:
247:            static class CompoundRBTEntry {
248:                private String ID;
249:                private Vector idBlockVector;
250:                private Vector dataVector;
251:                private UnicodeSet compoundFilter;
252:
253:                public CompoundRBTEntry(String theID, Vector theIDBlockVector,
254:                        Vector theDataVector, UnicodeSet theCompoundFilter) {
255:                    ID = theID;
256:                    idBlockVector = theIDBlockVector;
257:                    dataVector = theDataVector;
258:                    compoundFilter = theCompoundFilter;
259:                }
260:
261:                public Transliterator getInstance() {
262:                    Vector transliterators = new Vector();
263:                    int passNumber = 1;
264:
265:                    int limit = Math.max(idBlockVector.size(), dataVector
266:                            .size());
267:                    for (int i = 0; i < limit; i++) {
268:                        if (i < idBlockVector.size()) {
269:                            String idBlock = (String) idBlockVector.get(i);
270:                            if (idBlock.length() > 0)
271:                                transliterators.add(Transliterator
272:                                        .getInstance(idBlock));
273:                        }
274:                        if (i < dataVector.size()) {
275:                            RuleBasedTransliterator.Data data = (RuleBasedTransliterator.Data) dataVector
276:                                    .get(i);
277:                            transliterators.add(new RuleBasedTransliterator(
278:                                    "%Pass" + passNumber++, data, null));
279:                        }
280:                    }
281:
282:                    Transliterator t = new CompoundTransliterator(
283:                            transliterators, passNumber - 1);
284:                    t.setID(ID);
285:                    if (compoundFilter != null) {
286:                        t.setFilter(compoundFilter);
287:                    }
288:                    return t;
289:                }
290:            }
291:
292:            //----------------------------------------------------------------------
293:            // class TransliteratorRegistry: Basic public API
294:            //----------------------------------------------------------------------
295:
296:            public TransliteratorRegistry() {
297:                registry = new Hashtable();
298:                specDAG = new Hashtable();
299:                availableIDs = new Vector();
300:            }
301:
302:            /**
303:             * Given a simple ID (forward direction, no inline filter, not
304:             * compound) attempt to instantiate it from the registry.  Return
305:             * 0 on failure.
306:             *
307:             * Return a non-empty aliasReturn value if the ID points to an alias.
308:             * We cannot instantiate it ourselves because the alias may contain
309:             * filters or compounds, which we do not understand.  Caller should
310:             * make aliasReturn empty before calling.
311:             */
312:            public Transliterator get(String ID, StringBuffer aliasReturn) {
313:                Object[] entry = find(ID);
314:                return (entry == null) ? null : instantiateEntry(ID, entry,
315:                        aliasReturn);
316:            }
317:
318:            /**
319:             * Register a class.  This adds an entry to the
320:             * dynamic store, or replaces an existing entry.  Any entry in the
321:             * underlying static locale resource store is masked.
322:             */
323:            public void put(String ID, Class transliteratorSubclass,
324:                    boolean visible) {
325:                registerEntry(ID, transliteratorSubclass, visible);
326:            }
327:
328:            /**
329:             * Register an ID and a factory function pointer.  This adds an
330:             * entry to the dynamic store, or replaces an existing entry.  Any
331:             * entry in the underlying static locale resource store is masked.
332:             */
333:            public void put(String ID, Transliterator.Factory factory,
334:                    boolean visible) {
335:                registerEntry(ID, factory, visible);
336:            }
337:
338:            /**
339:             * Register an ID and a resource name.  This adds an entry to the
340:             * dynamic store, or replaces an existing entry.  Any entry in the
341:             * underlying static locale resource store is masked.
342:             */
343:            public void put(String ID, String resourceName, String encoding,
344:                    int dir, boolean visible) {
345:                registerEntry(ID,
346:                        new ResourceEntry(resourceName, encoding, dir), visible);
347:            }
348:
349:            /**
350:             * Register an ID and an alias ID.  This adds an entry to the
351:             * dynamic store, or replaces an existing entry.  Any entry in the
352:             * underlying static locale resource store is masked.
353:             */
354:            public void put(String ID, String alias, boolean visible) {
355:                registerEntry(ID, new AliasEntry(alias), visible);
356:            }
357:
358:            /**
359:             * Register an ID and a Transliterator object.  This adds an entry
360:             * to the dynamic store, or replaces an existing entry.  Any entry
361:             * in the underlying static locale resource store is masked.
362:             */
363:            public void put(String ID, Transliterator trans, boolean visible) {
364:                registerEntry(ID, trans, visible);
365:            }
366:
367:            /**
368:             * Unregister an ID.  This removes an entry from the dynamic store
369:             * if there is one.  The static locale resource store is
370:             * unaffected.
371:             */
372:            public void remove(String ID) {
373:                String[] stv = TransliteratorIDParser.IDtoSTV(ID);
374:                // Only need to do this if ID.indexOf('-') < 0
375:                String id = TransliteratorIDParser.STVtoID(stv[0], stv[1],
376:                        stv[2]);
377:                registry.remove(new CaseInsensitiveString(id));
378:                removeSTV(stv[0], stv[1], stv[2]);
379:                availableIDs.removeElement(new CaseInsensitiveString(id));
380:            }
381:
382:            //----------------------------------------------------------------------
383:            // class TransliteratorRegistry: Public ID and spec management
384:            //----------------------------------------------------------------------
385:
386:            /**
387:             * An internal class that adapts an enumeration over
388:             * CaseInsensitiveStrings to an enumeration over Strings.
389:             */
390:            private static class IDEnumeration implements  Enumeration {
391:                Enumeration en;
392:
393:                public IDEnumeration(Enumeration e) {
394:                    en = e;
395:                }
396:
397:                public boolean hasMoreElements() {
398:                    return en != null && en.hasMoreElements();
399:                }
400:
401:                public Object nextElement() {
402:                    return ((CaseInsensitiveString) en.nextElement())
403:                            .getString();
404:                }
405:            }
406:
407:            /**
408:             * Returns an enumeration over the programmatic names of visible
409:             * registered transliterators.
410:             *
411:             * @return An <code>Enumeration</code> over <code>String</code> objects
412:             */
413:            public Enumeration getAvailableIDs() {
414:                // Since the cache contains CaseInsensitiveString objects, but
415:                // the caller expects Strings, we have to use an intermediary.
416:                return new IDEnumeration(availableIDs.elements());
417:            }
418:
419:            /**
420:             * Returns an enumeration over all visible source names.
421:             *
422:             * @return An <code>Enumeration</code> over <code>String</code> objects
423:             */
424:            public Enumeration getAvailableSources() {
425:                return new IDEnumeration(specDAG.keys());
426:            }
427:
428:            /**
429:             * Returns an enumeration over visible target names for the given
430:             * source.
431:             *
432:             * @return An <code>Enumeration</code> over <code>String</code> objects
433:             */
434:            public Enumeration getAvailableTargets(String source) {
435:                CaseInsensitiveString cisrc = new CaseInsensitiveString(source);
436:                Hashtable targets = (Hashtable) specDAG.get(cisrc);
437:                if (targets == null) {
438:                    return new IDEnumeration(null);
439:                }
440:                return new IDEnumeration(targets.keys());
441:            }
442:
443:            /**
444:             * Returns an enumeration over visible variant names for the given
445:             * source and target.
446:             *
447:             * @return An <code>Enumeration</code> over <code>String</code> objects
448:             */
449:            public Enumeration getAvailableVariants(String source, String target) {
450:                CaseInsensitiveString cisrc = new CaseInsensitiveString(source);
451:                CaseInsensitiveString citrg = new CaseInsensitiveString(target);
452:                Hashtable targets = (Hashtable) specDAG.get(cisrc);
453:                if (targets == null) {
454:                    return new IDEnumeration(null);
455:                }
456:                Vector variants = (Vector) targets.get(citrg);
457:                if (variants == null) {
458:                    return new IDEnumeration(null);
459:                }
460:                return new IDEnumeration(variants.elements());
461:            }
462:
463:            //----------------------------------------------------------------------
464:            // class TransliteratorRegistry: internal
465:            //----------------------------------------------------------------------
466:
467:            /**
468:             * Convenience method.  Calls 6-arg registerEntry().
469:             */
470:            private void registerEntry(String source, String target,
471:                    String variant, Object entry, boolean visible) {
472:                String s = source;
473:                if (s.length() == 0) {
474:                    s = ANY;
475:                }
476:                String ID = TransliteratorIDParser.STVtoID(source, target,
477:                        variant);
478:                registerEntry(ID, s, target, variant, entry, visible);
479:            }
480:
481:            /**
482:             * Convenience method.  Calls 6-arg registerEntry().
483:             */
484:            private void registerEntry(String ID, Object entry, boolean visible) {
485:                String[] stv = TransliteratorIDParser.IDtoSTV(ID);
486:                // Only need to do this if ID.indexOf('-') < 0
487:                String id = TransliteratorIDParser.STVtoID(stv[0], stv[1],
488:                        stv[2]);
489:                registerEntry(id, stv[0], stv[1], stv[2], entry, visible);
490:            }
491:
492:            /**
493:             * Register an entry object (adopted) with the given ID, source,
494:             * target, and variant strings.
495:             */
496:            private void registerEntry(String ID, String source, String target,
497:                    String variant, Object entry, boolean visible) {
498:                CaseInsensitiveString ciID = new CaseInsensitiveString(ID);
499:
500:                // Store the entry within an array so it can be modified later
501:                if (!(entry instanceof  Object[])) {
502:                    entry = new Object[] { entry };
503:                }
504:
505:                registry.put(ciID, entry);
506:                if (visible) {
507:                    registerSTV(source, target, variant);
508:                    if (!availableIDs.contains(ciID)) {
509:                        availableIDs.addElement(ciID);
510:                    }
511:                } else {
512:                    removeSTV(source, target, variant);
513:                    availableIDs.removeElement(ciID);
514:                }
515:            }
516:
517:            /**
518:             * Register a source-target/variant in the specDAG.  Variant may be
519:             * empty, but source and target must not be.  If variant is empty then
520:             * the special variant NO_VARIANT is stored in slot zero of the
521:             * UVector of variants.
522:             */
523:            private void registerSTV(String source, String target,
524:                    String variant) {
525:                // assert(source.length() > 0);
526:                // assert(target.length() > 0);
527:                CaseInsensitiveString cisrc = new CaseInsensitiveString(source);
528:                CaseInsensitiveString citrg = new CaseInsensitiveString(target);
529:                CaseInsensitiveString civar = new CaseInsensitiveString(variant);
530:                Hashtable targets = (Hashtable) specDAG.get(cisrc);
531:                if (targets == null) {
532:                    targets = new Hashtable();
533:                    specDAG.put(cisrc, targets);
534:                }
535:                Vector variants = (Vector) targets.get(citrg);
536:                if (variants == null) {
537:                    variants = new Vector();
538:                    targets.put(citrg, variants);
539:                }
540:                // assert(NO_VARIANT == "");
541:                // We add the variant string.  If it is the special "no variant"
542:                // string, that is, the empty string, we add it at position zero.
543:                if (!variants.contains(civar)) {
544:                    if (variant.length() > 0) {
545:                        variants.addElement(civar);
546:                    } else {
547:                        variants.insertElementAt(civar, 0);
548:                    }
549:                }
550:            }
551:
552:            /**
553:             * Remove a source-target/variant from the specDAG.
554:             */
555:            private void removeSTV(String source, String target, String variant) {
556:                // assert(source.length() > 0);
557:                // assert(target.length() > 0);
558:                CaseInsensitiveString cisrc = new CaseInsensitiveString(source);
559:                CaseInsensitiveString citrg = new CaseInsensitiveString(target);
560:                CaseInsensitiveString civar = new CaseInsensitiveString(variant);
561:                Hashtable targets = (Hashtable) specDAG.get(cisrc);
562:                if (targets == null) {
563:                    return; // should never happen for valid s-t/v
564:                }
565:                Vector variants = (Vector) targets.get(citrg);
566:                if (variants == null) {
567:                    return; // should never happen for valid s-t/v
568:                }
569:                variants.removeElement(civar);
570:                if (variants.size() == 0) {
571:                    targets.remove(citrg); // should delete variants
572:                    if (targets.size() == 0) {
573:                        specDAG.remove(cisrc); // should delete targets
574:                    }
575:                }
576:            }
577:
578:            private static final boolean DEBUG = false;
579:
580:            /**
581:             * Attempt to find a source-target/variant in the dynamic registry
582:             * store.  Return 0 on failure.
583:             */
584:            private Object[] findInDynamicStore(Spec src, Spec trg,
585:                    String variant) {
586:                String ID = TransliteratorIDParser.STVtoID(src.get(),
587:                        trg.get(), variant);
588:                if (DEBUG) {
589:                    System.out
590:                            .println("TransliteratorRegistry.findInDynamicStore:"
591:                                    + ID);
592:                }
593:                return (Object[]) registry.get(new CaseInsensitiveString(ID));
594:            }
595:
596:            /**
597:             * Attempt to find a source-target/variant in the static locale
598:             * resource store.  Do not perform fallback.  Return 0 on failure.
599:             *
600:             * On success, create a new entry object, register it in the dynamic
601:             * store, and return a pointer to it, but do not make it public --
602:             * just because someone requested something, we do not expand the
603:             * available ID list (or spec DAG).
604:             */
605:            private Object[] findInStaticStore(Spec src, Spec trg,
606:                    String variant) {
607:                if (DEBUG) {
608:                    String ID = TransliteratorIDParser.STVtoID(src.get(), trg
609:                            .get(), variant);
610:                    System.out
611:                            .println("TransliteratorRegistry.findInStaticStore:"
612:                                    + ID);
613:                }
614:                Object[] entry = null;
615:                if (src.isLocale()) {
616:                    entry = findInBundle(src, trg, variant,
617:                            Transliterator.FORWARD);
618:                } else if (trg.isLocale()) {
619:                    entry = findInBundle(trg, src, variant,
620:                            Transliterator.REVERSE);
621:                }
622:
623:                // If we found an entry, store it in the Hashtable for next
624:                // time.
625:                if (entry != null) {
626:                    registerEntry(src.getTop(), trg.getTop(), variant, entry,
627:                            false);
628:                }
629:
630:                return entry;
631:            }
632:
633:            /**
634:             * Attempt to find an entry in a single resource bundle.  This is
635:             * a one-sided lookup.  findInStaticStore() performs up to two such
636:             * lookups, one for the source, and one for the target.
637:             *
638:             * Do not perform fallback.  Return 0 on failure.
639:             *
640:             * On success, create a new Entry object, populate it, and return it.
641:             * The caller owns the returned object.
642:             */
643:            private Object[] findInBundle(Spec specToOpen, Spec specToFind,
644:                    String variant, int direction) {
645:                // assert(specToOpen.isLocale());
646:                ResourceBundle res = specToOpen.getBundle();
647:
648:                if (res == null) {
649:                    // This means that the bundle's locale does not match
650:                    // the current level of iteration for the spec.
651:                    return null;
652:                }
653:
654:                for (int pass = 0; pass < 2; ++pass) {
655:                    StringBuffer tag = new StringBuffer();
656:                    // First try either TransliteratorTo_xxx or
657:                    // TransliterateFrom_xxx, then try the bidirectional
658:                    // Transliterate_xxx.  This precedence order is arbitrary
659:                    // but must be consistent and documented.
660:                    if (pass == 0) {
661:                        tag
662:                                .append(direction == Transliterator.FORWARD ? "TransliterateTo"
663:                                        : "TransliterateFrom");
664:                    } else {
665:                        tag.append("Transliterate");
666:                    }
667:                    tag.append(specToFind.get().toUpperCase());
668:
669:                    try {
670:                        // The Transliterate*_xxx resource is an array of
671:                        // strings of the format { <v0>, <r0>, ... }.  Each
672:                        // <vi> is a variant name, and each <ri> is a rule.
673:                        String[] subres = res.getStringArray(tag.toString());
674:
675:                        // assert(subres != null);
676:                        // assert(subres.length % 2 == 0);
677:                        int i = 0;
678:                        if (variant.length() != 0) {
679:                            for (i = 0; i < subres.length; i += 2) {
680:                                if (subres[i].equalsIgnoreCase(variant)) {
681:                                    break;
682:                                }
683:                            }
684:                        }
685:
686:                        if (i < subres.length) {
687:                            // We have a match, or there is no variant and i == 0.
688:                            // We have succeeded in loading a string from the
689:                            // locale resources.  Return the rule string which
690:                            // will itself become the registry entry.
691:
692:                            // The direction is always forward for the
693:                            // TransliterateTo_xxx and TransliterateFrom_xxx
694:                            // items; those are unidirectional forward rules.
695:                            // For the bidirectional Transliterate_xxx items,
696:                            // the direction is the value passed in to this
697:                            // function.
698:                            int dir = (pass == 0) ? Transliterator.FORWARD
699:                                    : direction;
700:                            return new Object[] { new LocaleEntry(
701:                                    subres[i + 1], dir) };
702:                        }
703:
704:                    } catch (MissingResourceException e) {
705:                        if (DEBUG)
706:                            System.out.println("missing resource: " + e);
707:                    }
708:                }
709:
710:                // If we get here we had a missing resource exception or we
711:                // failed to find a desired variant.
712:                return null;
713:            }
714:
715:            /**
716:             * Convenience method.  Calls 3-arg find().
717:             */
718:            private Object[] find(String ID) {
719:                String[] stv = TransliteratorIDParser.IDtoSTV(ID);
720:                return find(stv[0], stv[1], stv[2]);
721:            }
722:
723:            /**
724:             * Top-level find method.  Attempt to find a source-target/variant in
725:             * either the dynamic or the static (locale resource) store.  Perform
726:             * fallback.
727:             *
728:             * Lookup sequence for ss_SS_SSS-tt_TT_TTT/v:
729:             *
730:             *   ss_SS_SSS-tt_TT_TTT/v -- in hashtable
731:             *   ss_SS_SSS-tt_TT_TTT/v -- in ss_SS_SSS (no fallback)
732:             *
733:             *     repeat with t = tt_TT_TTT, tt_TT, tt, and tscript
734:             *
735:             *     ss_SS_SSS-t/*
736:             *     ss_SS-t/*
737:             *     ss-t/*
738:             *     sscript-t/*
739:             *
740:             * Here * matches the first variant listed.
741:             *
742:             * Caller does NOT own returned object.  Return 0 on failure.
743:             */
744:            private Object[] find(String source, String target, String variant) {
745:
746:                Spec src = new Spec(source);
747:                Spec trg = new Spec(target);
748:                Object[] entry = null;
749:
750:                if (variant.length() != 0) {
751:
752:                    // Seek exact match in hashtable
753:                    entry = findInDynamicStore(src, trg, variant);
754:                    if (entry != null) {
755:                        return entry;
756:                    }
757:
758:                    // Seek exact match in locale resources
759:                    entry = findInStaticStore(src, trg, variant);
760:                    if (entry != null) {
761:                        return entry;
762:                    }
763:                }
764:
765:                for (;;) {
766:                    src.reset();
767:                    for (;;) {
768:                        // Seek match in hashtable
769:                        entry = findInDynamicStore(src, trg, NO_VARIANT);
770:                        if (entry != null) {
771:                            return entry;
772:                        }
773:
774:                        // Seek match in locale resources
775:                        entry = findInStaticStore(src, trg, NO_VARIANT);
776:                        if (entry != null) {
777:                            return entry;
778:                        }
779:                        if (!src.hasFallback()) {
780:                            break;
781:                        }
782:                        src.next();
783:                    }
784:                    if (!trg.hasFallback()) {
785:                        break;
786:                    }
787:                    trg.next();
788:                }
789:
790:                return null;
791:            }
792:
793:            /**
794:             * Given an Entry object, instantiate it.  Caller owns result.  Return
795:             * 0 on failure.
796:             *
797:             * Return a non-empty aliasReturn value if the ID points to an alias.
798:             * We cannot instantiate it ourselves because the alias may contain
799:             * filters or compounds, which we do not understand.  Caller should
800:             * make aliasReturn empty before calling.
801:             *
802:             * The entry object is assumed to reside in the dynamic store.  It may be
803:             * modified.
804:             */
805:            private Transliterator instantiateEntry(String ID,
806:                    Object[] entryWrapper, StringBuffer aliasReturn) {
807:                // We actually modify the entry object in some cases.  If it
808:                // is a string, we may partially parse it and turn it into a
809:                // more processed precursor.  This makes the next
810:                // instantiation faster and allows sharing of immutable
811:                // components like the RuleBasedTransliterator.Data objects.
812:                // For this reason, the entry object is an Object[] of length
813:                // 1.
814:
815:                for (;;) {
816:                    Object entry = entryWrapper[0];
817:
818:                    if (entry instanceof  RuleBasedTransliterator.Data) {
819:                        RuleBasedTransliterator.Data data = (RuleBasedTransliterator.Data) entry;
820:                        return new RuleBasedTransliterator(ID, data, null);
821:                    } else if (entry instanceof  Class) {
822:                        try {
823:                            return (Transliterator) ((Class) entry)
824:                                    .newInstance();
825:                        } catch (InstantiationException e) {
826:                        } catch (IllegalAccessException e2) {
827:                        }
828:                        return null;
829:                    } else if (entry instanceof  AliasEntry) {
830:                        aliasReturn.append(((AliasEntry) entry).alias);
831:                        return null;
832:                    } else if (entry instanceof  Transliterator.Factory) {
833:                        return ((Transliterator.Factory) entry).getInstance(ID);
834:                    } else if (entry instanceof  CompoundRBTEntry) {
835:                        return ((CompoundRBTEntry) entry).getInstance();
836:                    } else if (entry instanceof  Transliterator) {
837:                        return (Transliterator) entry;
838:                    }
839:
840:                    // At this point entry type must be either RULES_FORWARD or
841:                    // RULES_REVERSE.  We process the rule data into a
842:                    // TransliteratorRuleData object, and possibly also into an
843:                    // .id header and/or footer.  Then we modify the registry with
844:                    // the parsed data and retry.
845:
846:                    TransliteratorParser parser = new TransliteratorParser();
847:
848:                    try {
849:
850:                        ResourceEntry re = (ResourceEntry) entry;
851:                        parser.parse(re.resource, re.direction);
852:
853:                    } catch (ClassCastException e) {
854:                        // If we pull a rule from a locale resource bundle it will
855:                        // be a LocaleEntry.
856:                        LocaleEntry le = (LocaleEntry) entry;
857:                        parser.parse(le.rule, le.direction);
858:                    }
859:
860:                    // Reset entry to something that we process at the
861:                    // top of the loop, then loop back to the top.  As long as we
862:                    // do this, we only loop through twice at most.
863:                    // NOTE: The logic here matches that in
864:                    // Transliterator.createFromRules().
865:                    if (parser.idBlockVector.size() == 0
866:                            && parser.dataVector.size() == 0) {
867:                        // No idBlock, no data -- this is just an
868:                        // alias for Null
869:                        entryWrapper[0] = new AliasEntry(NullTransliterator._ID);
870:                    } else if (parser.idBlockVector.size() == 0
871:                            && parser.dataVector.size() == 1) {
872:                        // No idBlock, data != 0 -- this is an
873:                        // ordinary RBT_DATA
874:                        entryWrapper[0] = parser.dataVector.get(0);
875:                    } else if (parser.idBlockVector.size() == 1
876:                            && parser.dataVector.size() == 0) {
877:                        // idBlock, no data -- this is an alias.  The ID has
878:                        // been munged from reverse into forward mode, if
879:                        // necessary, so instantiate the ID in the forward
880:                        // direction.
881:                        if (parser.compoundFilter != null)
882:                            entryWrapper[0] = new AliasEntry(
883:                                    parser.compoundFilter.toPattern(false)
884:                                            + ";"
885:                                            + (String) parser.idBlockVector
886:                                                    .get(0));
887:                        else
888:                            entryWrapper[0] = new AliasEntry(
889:                                    (String) parser.idBlockVector.get(0));
890:                    } else {
891:                        entryWrapper[0] = new CompoundRBTEntry(ID,
892:                                parser.idBlockVector, parser.dataVector,
893:                                parser.compoundFilter);
894:                    }
895:                }
896:            }
897:        }
898:
899:        //eof
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.