]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_4_2-src/main/classes/core/src/com/ibm/icu/text/BreakIterator.java
go
[Dictionary.git] / jars / icu4j-4_4_2-src / main / classes / core / src / com / ibm / icu / text / BreakIterator.java
1 /*\r
2  *******************************************************************************\r
3  * Copyright (C) 1996-2010, International Business Machines Corporation and    *\r
4  * others. All Rights Reserved.                                                *\r
5  *******************************************************************************\r
6  */\r
7 \r
8 package com.ibm.icu.text;\r
9 \r
10 import java.lang.ref.SoftReference;\r
11 import java.text.CharacterIterator;\r
12 import java.text.StringCharacterIterator;\r
13 import java.util.Locale;\r
14 import java.util.MissingResourceException;\r
15 \r
16 import com.ibm.icu.impl.ICUDebug;\r
17 import com.ibm.icu.util.ULocale;\r
18 \r
19 /**\r
20  * {@icuenhanced java.text.BreakIterator}.{@icu _usage_}\r
21  *\r
22  * <p>A class that locates boundaries in text.  This class defines a protocol for\r
23  * objects that break up a piece of natural-language text according to a set\r
24  * of criteria.  Instances or subclasses of BreakIterator can be provided, for\r
25  * example, to break a piece of text into words, sentences, or logical characters\r
26  * according to the conventions of some language or group of languages.\r
27  *\r
28  * We provide five built-in types of BreakIterator:\r
29  * <ul><li>getTitleInstance() returns a BreakIterator that locates boundaries\r
30  * between title breaks.\r
31  * <li>getSentenceInstance() returns a BreakIterator that locates boundaries\r
32  * between sentences.  This is useful for triple-click selection, for example.\r
33  * <li>getWordInstance() returns a BreakIterator that locates boundaries between\r
34  * words.  This is useful for double-click selection or "find whole words" searches.\r
35  * This type of BreakIterator makes sure there is a boundary position at the\r
36  * beginning and end of each legal word.  (Numbers count as words, too.)  Whitespace\r
37  * and punctuation are kept separate from real words.\r
38  * <li>getLineInstance() returns a BreakIterator that locates positions where it is\r
39  * legal for a text editor to wrap lines.  This is similar to word breaking, but\r
40  * not the same: punctuation and whitespace are generally kept with words (you don't\r
41  * want a line to start with whitespace, for example), and some special characters\r
42  * can force a position to be considered a line-break position or prevent a position\r
43  * from being a line-break position.\r
44  * <li>getCharacterInstance() returns a BreakIterator that locates boundaries between\r
45  * logical characters.  Because of the structure of the Unicode encoding, a logical\r
46  * character may be stored internally as more than one Unicode code point.  (A with an\r
47  * umlaut may be stored as an a followed by a separate combining umlaut character,\r
48  * for example, but the user still thinks of it as one character.)  This iterator allows\r
49  * various processes (especially text editors) to treat as characters the units of text\r
50  * that a user would think of as characters, rather than the units of text that the\r
51  * computer sees as "characters".</ul>\r
52  *\r
53  * BreakIterator's interface follows an "iterator" model (hence the name), meaning it\r
54  * has a concept of a "current position" and methods like first(), last(), next(),\r
55  * and previous() that update the current position.  All BreakIterators uphold the\r
56  * following invariants:\r
57  * <ul><li>The beginning and end of the text are always treated as boundary positions.\r
58  * <li>The current position of the iterator is always a boundary position (random-\r
59  * access methods move the iterator to the nearest boundary position before or\r
60  * after the specified position, not _to_ the specified position).\r
61  * <li>DONE is used as a flag to indicate when iteration has stopped.  DONE is only\r
62  * returned when the current position is the end of the text and the user calls next(),\r
63  * or when the current position is the beginning of the text and the user calls\r
64  * previous().\r
65  * <li>Break positions are numbered by the positions of the characters that follow\r
66  * them.  Thus, under normal circumstances, the position before the first character\r
67  * is 0, the position after the first character is 1, and the position after the\r
68  * last character is 1 plus the length of the string.\r
69  * <li>The client can change the position of an iterator, or the text it analyzes,\r
70  * at will, but cannot change the behavior.  If the user wants different behavior, he\r
71  * must instantiate a new iterator.</ul>\r
72  *\r
73  * BreakIterator accesses the text it analyzes through a CharacterIterator, which makes\r
74  * it possible to use BreakIterator to analyze text in any text-storage vehicle that\r
75  * provides a CharacterIterator interface.\r
76  *\r
77  * <b>Note:</b>  Some types of BreakIterator can take a long time to create, and\r
78  * instances of BreakIterator are not currently cached by the system.  For\r
79  * optimal performance, keep instances of BreakIterator around as long as makes\r
80  * sense.  For example, when word-wrapping a document, don't create and destroy a\r
81  * new BreakIterator for each line.  Create one break iterator for the whole document\r
82  * (or whatever stretch of text you're wrapping) and use it to do the whole job of\r
83  * wrapping the text.\r
84  *\r
85   * <P>\r
86  * <strong>Examples</strong>:<P>\r
87  * Creating and using text boundaries\r
88  * <blockquote>\r
89  * <pre>\r
90  * public static void main(String args[]) {\r
91  *      if (args.length == 1) {\r
92  *          String stringToExamine = args[0];\r
93  *          //print each word in order\r
94  *          BreakIterator boundary = BreakIterator.getWordInstance();\r
95  *          boundary.setText(stringToExamine);\r
96  *          printEachForward(boundary, stringToExamine);\r
97  *          //print each sentence in reverse order\r
98  *          boundary = BreakIterator.getSentenceInstance(Locale.US);\r
99  *          boundary.setText(stringToExamine);\r
100  *          printEachBackward(boundary, stringToExamine);\r
101  *          printFirst(boundary, stringToExamine);\r
102  *          printLast(boundary, stringToExamine);\r
103  *      }\r
104  * }\r
105  * </pre>\r
106  * </blockquote>\r
107  *\r
108  * Print each element in order\r
109  * <blockquote>\r
110  * <pre>\r
111  * public static void printEachForward(BreakIterator boundary, String source) {\r
112  *     int start = boundary.first();\r
113  *     for (int end = boundary.next();\r
114  *          end != BreakIterator.DONE;\r
115  *          start = end, end = boundary.next()) {\r
116  *          System.out.println(source.substring(start,end));\r
117  *     }\r
118  * }\r
119  * </pre>\r
120  * </blockquote>\r
121  *\r
122  * Print each element in reverse order\r
123  * <blockquote>\r
124  * <pre>\r
125  * public static void printEachBackward(BreakIterator boundary, String source) {\r
126  *     int end = boundary.last();\r
127  *     for (int start = boundary.previous();\r
128  *          start != BreakIterator.DONE;\r
129  *          end = start, start = boundary.previous()) {\r
130  *         System.out.println(source.substring(start,end));\r
131  *     }\r
132  * }\r
133  * </pre>\r
134  * </blockquote>\r
135  *\r
136  * Print first element\r
137  * <blockquote>\r
138  * <pre>\r
139  * public static void printFirst(BreakIterator boundary, String source) {\r
140  *     int start = boundary.first();\r
141  *     int end = boundary.next();\r
142  *     System.out.println(source.substring(start,end));\r
143  * }\r
144  * </pre>\r
145  * </blockquote>\r
146  *\r
147  * Print last element\r
148  * <blockquote>\r
149  * <pre>\r
150  * public static void printLast(BreakIterator boundary, String source) {\r
151  *     int end = boundary.last();\r
152  *     int start = boundary.previous();\r
153  *     System.out.println(source.substring(start,end));\r
154  * }\r
155  * </pre>\r
156  * </blockquote>\r
157  *\r
158  * Print the element at a specified position\r
159  * <blockquote>\r
160  * <pre>\r
161  * public static void printAt(BreakIterator boundary, int pos, String source) {\r
162  *     int end = boundary.following(pos);\r
163  *     int start = boundary.previous();\r
164  *     System.out.println(source.substring(start,end));\r
165  * }\r
166  * </pre>\r
167  * </blockquote>\r
168  *\r
169  * Find the next word\r
170  * <blockquote>\r
171  * <pre>\r
172  * public static int nextWordStartAfter(int pos, String text) {\r
173  *     BreakIterator wb = BreakIterator.getWordInstance();\r
174  *     wb.setText(text);\r
175  *     int last = wb.following(pos);\r
176  *     int current = wb.next();\r
177  *     while (current != BreakIterator.DONE) {\r
178  *         for (int p = last; p < current; p++) {\r
179  *             if (Character.isLetter(text.charAt(p)))\r
180  *                 return last;\r
181  *         }\r
182  *         last = current;\r
183  *         current = wb.next();\r
184  *     }\r
185  *     return BreakIterator.DONE;\r
186  * }\r
187  * </pre>\r
188  * (The iterator returned by BreakIterator.getWordInstance() is unique in that\r
189  * the break positions it returns don't represent both the start and end of the\r
190  * thing being iterated over.  That is, a sentence-break iterator returns breaks\r
191  * that each represent the end of one sentence and the beginning of the next.\r
192  * With the word-break iterator, the characters between two boundaries might be a\r
193  * word, or they might be the punctuation or whitespace between two words.  The\r
194  * above code uses a simple heuristic to determine which boundary is the beginning\r
195  * of a word: If the characters between this boundary and the next boundary\r
196  * include at least one letter (this can be an alphabetical letter, a CJK ideograph,\r
197  * a Hangul syllable, a Kana character, etc.), then the text between this boundary\r
198  * and the next is a word; otherwise, it's the material between words.)\r
199  * </blockquote>\r
200  *\r
201  * @see CharacterIterator\r
202  * @stable ICU 2.0\r
203  *\r
204  */\r
205 \r
206 public abstract class BreakIterator implements Cloneable\r
207 {\r
208 \r
209     private static final boolean DEBUG = ICUDebug.enabled("breakiterator");\r
210 \r
211     /**\r
212      * Default constructor.  There is no state that is carried by this abstract\r
213      * base class.\r
214      * @stable ICU 2.0\r
215      */\r
216     protected BreakIterator()\r
217     {\r
218     }\r
219 \r
220     /**\r
221      * Clone method.  Creates another BreakIterator with the same behavior and\r
222      * current state as this one.\r
223      * @return The clone.\r
224      * @stable ICU 2.0\r
225      */\r
226     public Object clone()\r
227     {\r
228         try {\r
229             return super.clone();\r
230         }\r
231         catch (CloneNotSupportedException e) {\r
232             ///CLOVER:OFF\r
233             throw new IllegalStateException();\r
234             ///CLOVER:ON\r
235         }\r
236     }\r
237 \r
238     /**\r
239      * DONE is returned by previous() and next() after all valid\r
240      * boundaries have been returned.\r
241      * @stable ICU 2.0\r
242      */\r
243     public static final int DONE = -1;\r
244 \r
245     /**\r
246      * Return the first boundary position.  This is always the beginning\r
247      * index of the text this iterator iterates over.  For example, if\r
248      * the iterator iterates over a whole string, this function will\r
249      * always return 0.  This function also updates the iteration position\r
250      * to point to the beginning of the text.\r
251      * @return The character offset of the beginning of the stretch of text\r
252      * being broken.\r
253      * @stable ICU 2.0\r
254      */\r
255     public abstract int first();\r
256 \r
257     /**\r
258      * Return the last boundary position.  This is always the "past-the-end"\r
259      * index of the text this iterator iterates over.  For example, if the\r
260      * iterator iterates over a whole string (call it "text"), this function\r
261      * will always return text.length().  This function also updated the\r
262      * iteration position to point to the end of the text.\r
263      * @return The character offset of the end of the stretch of text\r
264      * being broken.\r
265      * @stable ICU 2.0\r
266      */\r
267     public abstract int last();\r
268 \r
269     /**\r
270      * Advances the specified number of steps forward in the text (a negative\r
271      * number, therefore, advances backwards).  If this causes the iterator\r
272      * to advance off either end of the text, this function returns DONE;\r
273      * otherwise, this function returns the position of the appropriate\r
274      * boundary.  Calling this function is equivalent to calling next() or\r
275      * previous() n times.\r
276      * @param n The number of boundaries to advance over (if positive, moves\r
277      * forward; if negative, moves backwards).\r
278      * @return The position of the boundary n boundaries from the current\r
279      * iteration position, or DONE if moving n boundaries causes the iterator\r
280      * to advance off either end of the text.\r
281      * @stable ICU 2.0\r
282      */\r
283     public abstract int next(int n);\r
284 \r
285     /**\r
286      * Advances the iterator forward one boundary.  The current iteration\r
287      * position is updated to point to the next boundary position after the\r
288      * current position, and this is also the value that is returned.  If\r
289      * the current position is equal to the value returned by last(), or to\r
290      * DONE, this function returns DONE and sets the current position to\r
291      * DONE.\r
292      * @return The position of the first boundary position following the\r
293      * iteration position.\r
294      * @stable ICU 2.0\r
295      */\r
296     public abstract int next();\r
297 \r
298     /**\r
299      * Advances the iterator backward one boundary.  The current iteration\r
300      * position is updated to point to the last boundary position before\r
301      * the current position, and this is also the value that is returned.  If\r
302      * the current position is equal to the value returned by first(), or to\r
303      * DONE, this function returns DONE and sets the current position to\r
304      * DONE.\r
305      * @return The position of the last boundary position preceding the\r
306      * iteration position.\r
307      * @stable ICU 2.0\r
308      */\r
309     public abstract int previous();\r
310 \r
311     /**\r
312      * Sets the iterator's current iteration position to be the first\r
313      * boundary position following the specified position.  (Whether the\r
314      * specified position is itself a boundary position or not doesn't\r
315      * matter-- this function always moves the iteration position to the\r
316      * first boundary after the specified position.)  If the specified\r
317      * position is the past-the-end position, returns DONE.\r
318      * @param offset The character position to start searching from.\r
319      * @return The position of the first boundary position following\r
320      * "offset" (whether or not "offset" itself is a boundary position),\r
321      * or DONE if "offset" is the past-the-end offset.\r
322      * @stable ICU 2.0\r
323      */\r
324     public abstract int following(int offset);\r
325 \r
326     /**\r
327      * Sets the iterator's current iteration position to be the last\r
328      * boundary position preceding the specified position.  (Whether the\r
329      * specified position is itself a boundary position or not doesn't\r
330      * matter-- this function always moves the iteration position to the\r
331      * last boundary before the specified position.)  If the specified\r
332      * position is the starting position, returns DONE.\r
333      * @param offset The character position to start searching from.\r
334      * @return The position of the last boundary position preceding\r
335      * "offset" (whether of not "offset" itself is a boundary position),\r
336      * or DONE if "offset" is the starting offset of the iterator.\r
337      * @stable ICU 2.0\r
338      */\r
339     public int preceding(int offset) {\r
340         // NOTE:  This implementation is here solely because we can't add new\r
341         // abstract methods to an existing class.  There is almost ALWAYS a\r
342         // better, faster way to do this.\r
343         int pos = following(offset);\r
344         while (pos >= offset && pos != DONE)\r
345             pos = previous();\r
346         return pos;\r
347     }\r
348 \r
349     /**\r
350      * Return true if the specfied position is a boundary position.  If the\r
351      * function returns true, the current iteration position is set to the\r
352      * specified position; if the function returns false, the current\r
353      * iteration position is set as though following() had been called.\r
354      * @param offset the offset to check.\r
355      * @return True if "offset" is a boundary position.\r
356      * @stable ICU 2.0\r
357      */\r
358     public boolean isBoundary(int offset) {\r
359         // Again, this is the default implementation, which is provided solely because\r
360         // we couldn't add a new abstract method to an existing class.  The real\r
361         // implementations will usually need to do a little more work.\r
362         if (offset == 0) {\r
363             return true;\r
364         }\r
365         else\r
366             return following(offset - 1) == offset;\r
367     }\r
368 \r
369     /**\r
370      * Return the iterator's current position.\r
371      * @return The iterator's current position.\r
372      * @stable ICU 2.0\r
373      */\r
374     public abstract int current();\r
375 \r
376     /**\r
377      * Returns a CharacterIterator over the text being analyzed.\r
378      * For at least some subclasses of BreakIterator, this is a reference\r
379      * to the <b>actual iterator being used</b> by the BreakIterator,\r
380      * and therefore, this function's return value should be treated as\r
381      * <tt>const</tt>.  No guarantees are made about the current position\r
382      * of this iterator when it is returned.  If you need to move that\r
383      * position to examine the text, clone this function's return value first.\r
384      * @return A CharacterIterator over the text being analyzed.\r
385      * @stable ICU 2.0\r
386      */\r
387     public abstract CharacterIterator getText();\r
388 \r
389     /**\r
390      * Sets the iterator to analyze a new piece of text.  The new\r
391      * piece of text is passed in as a String, and the current\r
392      * iteration position is reset to the beginning of the string.\r
393      * (The old text is dropped.)\r
394      * @param newText A String containing the text to analyze with\r
395      * this BreakIterator.\r
396      * @stable ICU 2.0\r
397      */\r
398     public void setText(String newText)\r
399     {\r
400         setText(new StringCharacterIterator(newText));\r
401     }\r
402 \r
403     /**\r
404      * Sets the iterator to analyze a new piece of text.  The\r
405      * BreakIterator is passed a CharacterIterator through which\r
406      * it will access the text itself.  The current iteration\r
407      * position is reset to the CharacterIterator's start index.\r
408      * (The old iterator is dropped.)\r
409      * @param newText A CharacterIterator referring to the text\r
410      * to analyze with this BreakIterator (the iterator's current\r
411      * position is ignored, but its other state is significant).\r
412      * @stable ICU 2.0\r
413      */\r
414     public abstract void setText(CharacterIterator newText);\r
415 \r
416     /**\r
417      * {@icu}\r
418      * @stable ICU 2.4\r
419      */\r
420     public static final int KIND_CHARACTER = 0;\r
421     /**\r
422      * {@icu}\r
423      * @stable ICU 2.4\r
424      */\r
425     public static final int KIND_WORD = 1;\r
426     /** \r
427      * {@icu}\r
428      * @stable ICU 2.4\r
429      */\r
430     public static final int KIND_LINE = 2;\r
431     /** \r
432      * {@icu}\r
433      * @stable ICU 2.4\r
434      */\r
435     public static final int KIND_SENTENCE = 3;\r
436     /** \r
437      * {@icu}\r
438      * @stable ICU 2.4\r
439      */\r
440     public static final int KIND_TITLE = 4;\r
441 \r
442     /**\r
443      * @since ICU 2.8\r
444      */\r
445     private static final int KIND_COUNT = 5;\r
446 \r
447     private static final SoftReference<?>[] iterCache = new SoftReference<?>[5];\r
448 \r
449     /**\r
450      * Returns a new instance of BreakIterator that locates word boundaries.\r
451      * This function assumes that the text being analyzed is in the default\r
452      * locale's language.\r
453      * @return An instance of BreakIterator that locates word boundaries.\r
454      * @stable ICU 2.0\r
455      */\r
456     public static BreakIterator getWordInstance()\r
457     {\r
458         return getWordInstance(ULocale.getDefault());\r
459     }\r
460 \r
461     /**\r
462      * Returns a new instance of BreakIterator that locates word boundaries.\r
463      * @param where A locale specifying the language of the text to be\r
464      * analyzed.\r
465      * @return An instance of BreakIterator that locates word boundaries.\r
466      * @stable ICU 2.0\r
467      */\r
468     public static BreakIterator getWordInstance(Locale where)\r
469     {\r
470         return getBreakInstance(ULocale.forLocale(where), KIND_WORD);\r
471     }\r
472 \r
473     /**\r
474      * {@icu} Returns a new instance of BreakIterator that locates word boundaries.\r
475      * @param where A locale specifying the language of the text to be\r
476      * analyzed.\r
477      * @return An instance of BreakIterator that locates word boundaries.\r
478      * @stable ICU 3.2\r
479      */\r
480     public static BreakIterator getWordInstance(ULocale where)\r
481     {\r
482         return getBreakInstance(where, KIND_WORD);\r
483     }\r
484 \r
485     /**\r
486      * Returns a new instance of BreakIterator that locates legal line-\r
487      * wrapping positions.  This function assumes the text being broken\r
488      * is in the default locale's language.\r
489      * @return A new instance of BreakIterator that locates legal\r
490      * line-wrapping positions.\r
491      * @stable ICU 2.0\r
492      */\r
493     public static BreakIterator getLineInstance()\r
494     {\r
495         return getLineInstance(ULocale.getDefault());\r
496     }\r
497 \r
498     /**\r
499      * Returns a new instance of BreakIterator that locates legal line-\r
500      * wrapping positions.\r
501      * @param where A Locale specifying the language of the text being broken.\r
502      * @return A new instance of BreakIterator that locates legal\r
503      * line-wrapping positions.\r
504      * @stable ICU 2.0\r
505      */\r
506     public static BreakIterator getLineInstance(Locale where)\r
507     {\r
508         return getBreakInstance(ULocale.forLocale(where), KIND_LINE);\r
509     }\r
510 \r
511     /**\r
512      * {@icu} Returns a new instance of BreakIterator that locates legal line-\r
513      * wrapping positions.\r
514      * @param where A Locale specifying the language of the text being broken.\r
515      * @return A new instance of BreakIterator that locates legal\r
516      * line-wrapping positions.\r
517      * @stable ICU 3.2\r
518      */\r
519     public static BreakIterator getLineInstance(ULocale where)\r
520     {\r
521         return getBreakInstance(where, KIND_LINE);\r
522     }\r
523 \r
524     /**\r
525      * Returns a new instance of BreakIterator that locates logical-character\r
526      * boundaries.  This function assumes that the text being analyzed is\r
527      * in the default locale's language.\r
528      * @return A new instance of BreakIterator that locates logical-character\r
529      * boundaries.\r
530      * @stable ICU 2.0\r
531      */\r
532     public static BreakIterator getCharacterInstance()\r
533     {\r
534         return getCharacterInstance(ULocale.getDefault());\r
535     }\r
536 \r
537     /**\r
538      * Returns a new instance of BreakIterator that locates logical-character\r
539      * boundaries.\r
540      * @param where A Locale specifying the language of the text being analyzed.\r
541      * @return A new instance of BreakIterator that locates logical-character\r
542      * boundaries.\r
543      * @stable ICU 2.0\r
544      */\r
545     public static BreakIterator getCharacterInstance(Locale where)\r
546     {\r
547         return getBreakInstance(ULocale.forLocale(where), KIND_CHARACTER);\r
548     }\r
549 \r
550     /**\r
551      * {@icu} Returns a new instance of BreakIterator that locates logical-character\r
552      * boundaries.\r
553      * @param where A Locale specifying the language of the text being analyzed.\r
554      * @return A new instance of BreakIterator that locates logical-character\r
555      * boundaries.\r
556      * @stable ICU 3.2\r
557      */\r
558     public static BreakIterator getCharacterInstance(ULocale where)\r
559     {\r
560         return getBreakInstance(where, KIND_CHARACTER);\r
561     }\r
562 \r
563     /**\r
564      * Returns a new instance of BreakIterator that locates sentence boundaries.\r
565      * This function assumes the text being analyzed is in the default locale's\r
566      * language.\r
567      * @return A new instance of BreakIterator that locates sentence boundaries.\r
568      * @stable ICU 2.0\r
569      */\r
570     public static BreakIterator getSentenceInstance()\r
571     {\r
572         return getSentenceInstance(ULocale.getDefault());\r
573     }\r
574 \r
575     /**\r
576      * Returns a new instance of BreakIterator that locates sentence boundaries.\r
577      * @param where A Locale specifying the language of the text being analyzed.\r
578      * @return A new instance of BreakIterator that locates sentence boundaries.\r
579      * @stable ICU 2.0\r
580      */\r
581     public static BreakIterator getSentenceInstance(Locale where)\r
582     {\r
583         return getBreakInstance(ULocale.forLocale(where), KIND_SENTENCE);\r
584     }\r
585 \r
586     /**\r
587      * {@icu} Returns a new instance of BreakIterator that locates sentence boundaries.\r
588      * @param where A Locale specifying the language of the text being analyzed.\r
589      * @return A new instance of BreakIterator that locates sentence boundaries.\r
590      * @stable ICU 3.2\r
591      */\r
592     public static BreakIterator getSentenceInstance(ULocale where)\r
593     {\r
594         return getBreakInstance(where, KIND_SENTENCE);\r
595     }\r
596 \r
597     /**\r
598      * {@icu} Returns a new instance of BreakIterator that locates title boundaries.\r
599      * This function assumes the text being analyzed is in the default locale's\r
600      * language. The iterator returned locates title boundaries as described for\r
601      * Unicode 3.2 only. For Unicode 4.0 and above title boundary iteration,\r
602      * please use a word boundary iterator. {@link #getWordInstance}\r
603      * @return A new instance of BreakIterator that locates title boundaries.\r
604      * @stable ICU 2.0\r
605      */\r
606     public static BreakIterator getTitleInstance()\r
607     {\r
608         return getTitleInstance(ULocale.getDefault());\r
609     }\r
610 \r
611     /**\r
612      * {@icu} Returns a new instance of BreakIterator that locates title boundaries.\r
613      * The iterator returned locates title boundaries as described for\r
614      * Unicode 3.2 only. For Unicode 4.0 and above title boundary iteration,\r
615      * please use Word Boundary iterator.{@link #getWordInstance}\r
616      * @param where A Locale specifying the language of the text being analyzed.\r
617      * @return A new instance of BreakIterator that locates title boundaries.\r
618      * @stable ICU 2.0\r
619      */\r
620     public static BreakIterator getTitleInstance(Locale where)\r
621     {\r
622         return getBreakInstance(ULocale.forLocale(where), KIND_TITLE);\r
623     }\r
624 \r
625     /**\r
626      * {@icu} Returns a new instance of BreakIterator that locates title boundaries.\r
627      * The iterator returned locates title boundaries as described for\r
628      * Unicode 3.2 only. For Unicode 4.0 and above title boundary iteration,\r
629      * please use Word Boundary iterator.{@link #getWordInstance}\r
630      * @param where A Locale specifying the language of the text being analyzed.\r
631      * @return A new instance of BreakIterator that locates title boundaries.\r
632      * @stable ICU 3.2\r
633 s     */\r
634     public static BreakIterator getTitleInstance(ULocale where)\r
635     {\r
636         return getBreakInstance(where, KIND_TITLE);\r
637     }\r
638 \r
639     /**\r
640      * {@icu} Registers a new break iterator of the indicated kind, to use in the given\r
641      * locale.  Clones of the iterator will be returned if a request for a break iterator\r
642      * of the given kind matches or falls back to this locale.\r
643      * @param iter the BreakIterator instance to adopt.\r
644      * @param locale the Locale for which this instance is to be registered\r
645      * @param kind the type of iterator for which this instance is to be registered\r
646      * @return a registry key that can be used to unregister this instance\r
647      * @stable ICU 2.4\r
648      */\r
649     public static Object registerInstance(BreakIterator iter, Locale locale, int kind) {\r
650         return registerInstance(iter, ULocale.forLocale(locale), kind);\r
651     }\r
652 \r
653     /**\r
654      * {@icu} Registers a new break iterator of the indicated kind, to use in the given\r
655      * locale.  Clones of the iterator will be returned if a request for a break iterator\r
656      * of the given kind matches or falls back to this locale.\r
657      * @param iter the BreakIterator instance to adopt.\r
658      * @param locale the Locale for which this instance is to be registered\r
659      * @param kind the type of iterator for which this instance is to be registered\r
660      * @return a registry key that can be used to unregister this instance\r
661      * @stable ICU 3.2\r
662      */\r
663     public static Object registerInstance(BreakIterator iter, ULocale locale, int kind) {\r
664         // If the registered object matches the one in the cache, then\r
665         // flush the cached object.\r
666         if (iterCache[kind] != null) {\r
667             BreakIteratorCache cache = (BreakIteratorCache) iterCache[kind].get();\r
668             if (cache != null) {\r
669                 if (cache.getLocale().equals(locale)) {\r
670                     iterCache[kind] = null;\r
671                 }\r
672             }\r
673         }\r
674         return getShim().registerInstance(iter, locale, kind);\r
675     }\r
676 \r
677     /**\r
678      * {@icu} Unregisters a previously-registered BreakIterator using the key returned\r
679      * from the register call.  Key becomes invalid after this call and should not be used\r
680      * again.\r
681      * @param key the registry key returned by a previous call to registerInstance\r
682      * @return true if the iterator for the key was successfully unregistered\r
683      * @stable ICU 2.4\r
684      */\r
685     public static boolean unregister(Object key) {\r
686         if (key == null) {\r
687             throw new IllegalArgumentException("registry key must not be null");\r
688         }\r
689         // TODO: we don't do code coverage for the following lines\r
690         // because in getBreakInstance we always instantiate the shim,\r
691         // and test execution is such that we always instantiate a\r
692         // breakiterator before we get to the break iterator tests.\r
693         // this is for modularization, and we could remove the\r
694         // dependencies in getBreakInstance by rewriting part of the\r
695         // LocaleData code, or perhaps by accepting it into the\r
696         // module.\r
697         ///CLOVER:OFF\r
698         if (shim != null) {\r
699             // Unfortunately, we don't know what is being unregistered\r
700             // -- what `kind' and what locale -- so we flush all\r
701             // caches.  This is safe but inefficient if people are\r
702             // actively registering and unregistering.\r
703             for (int kind=0; kind<KIND_COUNT; ++kind) {\r
704                 iterCache[kind] = null;\r
705             }\r
706             return shim.unregister(key);\r
707         }\r
708         return false;\r
709         ///CLOVER:ON\r
710     }\r
711 \r
712     // end of registration\r
713 \r
714     /**\r
715      * Returns a particular kind of BreakIterator for a locale.\r
716      * Avoids writing a switch statement with getXYZInstance(where) calls.\r
717      * @internal\r
718      * @deprecated This API is ICU internal only.\r
719      */\r
720     public static BreakIterator getBreakInstance(ULocale where, int kind) {\r
721 \r
722         if (iterCache[kind] != null) {\r
723             BreakIteratorCache cache = (BreakIteratorCache)iterCache[kind].get();\r
724             if (cache != null) {\r
725                 if (cache.getLocale().equals(where)) {\r
726                     return cache.createBreakInstance();\r
727                 }\r
728             }\r
729         }\r
730 \r
731         // sigh, all to avoid linking in ICULocaleData...\r
732         BreakIterator result = getShim().createBreakIterator(where, kind);\r
733 \r
734         BreakIteratorCache cache = new BreakIteratorCache(where, result);\r
735         iterCache[kind] = new SoftReference<BreakIteratorCache>(cache);\r
736         return result;\r
737     }\r
738 \r
739 \r
740     /**\r
741      * Returns a list of locales for which BreakIterators can be used.\r
742      * @return An array of Locales.  All of the locales in the array can\r
743      * be used when creating a BreakIterator.\r
744      * @stable ICU 2.6\r
745      */\r
746     public static synchronized Locale[] getAvailableLocales()\r
747     {\r
748         // to avoid linking ICULocaleData\r
749         return getShim().getAvailableLocales();\r
750     }\r
751 \r
752     /**\r
753      * {@icu} Returns a list of locales for which BreakIterators can be used.\r
754      * @return An array of Locales.  All of the locales in the array can\r
755      * be used when creating a BreakIterator.\r
756      * @draft ICU 3.2 (retain)\r
757      * @provisional This API might change or be removed in a future release.\r
758      */\r
759     public static synchronized ULocale[] getAvailableULocales()\r
760     {\r
761         // to avoid linking ICULocaleData\r
762         return getShim().getAvailableULocales();\r
763     }\r
764 \r
765     private static final class BreakIteratorCache {\r
766 \r
767         private BreakIterator iter;\r
768         private ULocale where;\r
769 \r
770         BreakIteratorCache(ULocale where, BreakIterator iter) {\r
771             this.where = where;\r
772             this.iter = (BreakIterator) iter.clone();\r
773         }\r
774 \r
775         ULocale getLocale() {\r
776             return where;\r
777         }\r
778 \r
779         BreakIterator createBreakInstance() {\r
780             return (BreakIterator) iter.clone();\r
781         }\r
782     }\r
783 \r
784     static abstract class BreakIteratorServiceShim {\r
785         public abstract Object registerInstance(BreakIterator iter, ULocale l, int k);\r
786         public abstract boolean unregister(Object key);\r
787         public abstract Locale[] getAvailableLocales();\r
788         public abstract ULocale[] getAvailableULocales();\r
789         public abstract BreakIterator createBreakIterator(ULocale l, int k);\r
790     }\r
791 \r
792     private static BreakIteratorServiceShim shim;\r
793     private static BreakIteratorServiceShim getShim() {\r
794         // Note: this instantiation is safe on loose-memory-model configurations\r
795         // despite lack of synchronization, since the shim instance has no state--\r
796         // it's all in the class init.  The worst problem is we might instantiate\r
797         // two shim instances, but they'll share the same state so that's ok.\r
798         if (shim == null) {\r
799             try {\r
800                 Class<?> cls = Class.forName("com.ibm.icu.text.BreakIteratorFactory");\r
801                 shim = (BreakIteratorServiceShim)cls.newInstance();\r
802             }\r
803             catch (MissingResourceException e)\r
804             {\r
805                 throw e;\r
806             }\r
807             catch (Exception e) {\r
808                 ///CLOVER:OFF\r
809                 if(DEBUG){\r
810                     e.printStackTrace();\r
811                 }\r
812                 throw new RuntimeException(e.getMessage());\r
813                 ///CLOVER:ON\r
814             }\r
815         }\r
816         return shim;\r
817     }\r
818 \r
819     // -------- BEGIN ULocale boilerplate --------\r
820 \r
821     /**\r
822      * {@icu} Returns the locale that was used to create this object, or null.\r
823      * This may may differ from the locale requested at the time of\r
824      * this object's creation.  For example, if an object is created\r
825      * for locale <tt>en_US_CALIFORNIA</tt>, the actual data may be\r
826      * drawn from <tt>en</tt> (the <i>actual</i> locale), and\r
827      * <tt>en_US</tt> may be the most specific locale that exists (the\r
828      * <i>valid</i> locale).\r
829      *\r
830      * <p>Note: The <i>actual</i> locale is returned correctly, but the <i>valid</i>\r
831      * locale is not, in most cases.\r
832      * @param type type of information requested, either {@link\r
833      * com.ibm.icu.util.ULocale#VALID_LOCALE} or {@link\r
834      * com.ibm.icu.util.ULocale#ACTUAL_LOCALE}.\r
835      * @return the information specified by <i>type</i>, or null if\r
836      * this object was not constructed from locale data.\r
837      * @see com.ibm.icu.util.ULocale\r
838      * @see com.ibm.icu.util.ULocale#VALID_LOCALE\r
839      * @see com.ibm.icu.util.ULocale#ACTUAL_LOCALE\r
840      * @draft ICU 2.8 (retain)\r
841      * @provisional This API might change or be removed in a future release.\r
842      */\r
843     public final ULocale getLocale(ULocale.Type type) {\r
844         return type == ULocale.ACTUAL_LOCALE ?\r
845             this.actualLocale : this.validLocale;\r
846     }\r
847 \r
848     /**\r
849      * Set information about the locales that were used to create this\r
850      * object.  If the object was not constructed from locale data,\r
851      * both arguments should be set to null.  Otherwise, neither\r
852      * should be null.  The actual locale must be at the same level or\r
853      * less specific than the valid locale.  This method is intended\r
854      * for use by factories or other entities that create objects of\r
855      * this class.\r
856      * @param valid the most specific locale containing any resource\r
857      * data, or null\r
858      * @param actual the locale containing data used to construct this\r
859      * object, or null\r
860      * @see com.ibm.icu.util.ULocale\r
861      * @see com.ibm.icu.util.ULocale#VALID_LOCALE\r
862      * @see com.ibm.icu.util.ULocale#ACTUAL_LOCALE\r
863      */\r
864     final void setLocale(ULocale valid, ULocale actual) {\r
865         // Change the following to an assertion later\r
866         if ((valid == null) != (actual == null)) {\r
867             ///CLOVER:OFF\r
868             throw new IllegalArgumentException();\r
869             ///CLOVER:ON\r
870         }\r
871         // Another check we could do is that the actual locale is at\r
872         // the same level or less specific than the valid locale.\r
873         this.validLocale = valid;\r
874         this.actualLocale = actual;\r
875     }\r
876 \r
877     /**\r
878      * The most specific locale containing any resource data, or null.\r
879      * @see com.ibm.icu.util.ULocale\r
880      */\r
881     private ULocale validLocale;\r
882 \r
883     /**\r
884      * The locale containing data used to construct this object, or\r
885      * null.\r
886      * @see com.ibm.icu.util.ULocale\r
887      */\r
888     private ULocale actualLocale;\r
889 \r
890     // -------- END ULocale boilerplate --------\r
891 }\r