1/**
2*******************************************************************************
3* Copyright (C) 1996-2005, International Business Machines Corporation and    *
4* others. All Rights Reserved.                                                *
5*******************************************************************************
6*
7*
8*******************************************************************************
9*/
10
11package com.ibm.icu4jni.text;
12
13import java.util.Locale;
14import java.text.CharacterIterator;
15import java.text.ParseException;
16import com.ibm.icu4jni.common.ErrorCode;
17
18/**
19* Concrete implementation class for Collation.
20* <p>
21* The collation table is composed of a list of collation rules, where each
22* rule is of three forms:
23* <pre>
24*    < modifier >
25*    < relation > < text-argument >
26*    < reset > < text-argument >
27* </pre>
28* <p>
29* <code>RuleBasedCollator</code> has the following restrictions for efficiency
30* (other subclasses may be used for more complex languages) :
31* <ol>
32* <li> If a French secondary ordering is specified it applies to the whole
33*      collator object.
34* <li> All non-mentioned Unicode characters are at the end of the collation
35*      order.
36* <li> If a character is not located in the RuleBasedCollator, the default
37*      Unicode Collation Algorithm (UCA) rulebased table is automatically
38*      searched as a backup.
39* </ol>
40*
41* The following demonstrates how to create your own collation rules:
42* <UL Type=disc>
43*    <LI><strong>Text-Argument</strong>: A text-argument is any sequence of
44*        characters, excluding special characters (that is, common whitespace
45*        characters [0009-000D, 0020] and rule syntax characters [0021-002F,
46*        003A-0040, 005B-0060, 007B-007E]). If those characters are desired,
47*        you can put them in single quotes (e.g. ampersand => '&'). Note that
48*        unquoted white space characters are ignored; e.g. <code>b c</code> is
49*        treated as <code>bc</code>.
50*    <LI><strong>Modifier</strong>: There is a single modifier which is used
51*        to specify that all accents (secondary differences) are backwards.
52*        <p>'@' : Indicates that accents are sorted backwards, as in French.
53*    <LI><strong>Relation</strong>: The relations are the following:
54*        <UL Type=square>
55*            <LI>'<' : Greater, as a letter difference (primary)
56*            <LI>';' : Greater, as an accent difference (secondary)
57*            <LI>',' : Greater, as a case difference (tertiary)
58*            <LI>'=' : Equal
59*        </UL>
60*    <LI><strong>Reset</strong>: There is a single reset which is used
61*        primarily for contractions and expansions, but which can also be used
62*        to add a modification at the end of a set of rules.
63*        <p>'&' : Indicates that the next rule follows the position to where
64*            the reset text-argument would be sorted.
65* </UL>
66*
67* <p>
68* This sounds more complicated than it is in practice. For example, the
69* following are equivalent ways of expressing the same thing:
70* <blockquote>
71* <pre>
72* a < b < c
73* a < b & b < c
74* a < c & a < b
75* </pre>
76* </blockquote>
77* Notice that the order is important, as the subsequent item goes immediately
78* after the text-argument. The following are not equivalent:
79* <blockquote>
80* <pre>
81* a < b & a < c
82* a < c & a < b
83* </pre>
84* </blockquote>
85* Either the text-argument must already be present in the sequence, or some
86* initial substring of the text-argument must be present. (e.g. "a < b & ae <
87* e" is valid since "a" is present in the sequence before "ae" is reset). In
88* this latter case, "ae" is not entered and treated as a single character;
89* instead, "e" is sorted as if it were expanded to two characters: "a"
90* followed by an "e". This difference appears in natural languages: in
91* traditional Spanish "ch" is treated as though it contracts to a single
92* character (expressed as "c < ch < d"), while in traditional German a-umlaut
93* is treated as though it expanded to two characters (expressed as "a,A < b,B
94* ... & ae;? & AE;?"). [? and ? are, of course, the escape sequences for
95* a-umlaut.]
96* <p>
97* <strong>Ignorable Characters</strong>
98* <p>
99* For ignorable characters, the first rule must start with a relation (the
100* examples we have used above are really fragments; "a < b" really should be
101* "< a < b"). If, however, the first relation is not "<", then all the all
102* text-arguments up to the first "<" are ignorable. For example, ", - < a < b"
103* makes "-" an ignorable character, as we saw earlier in the word
104* "black-birds". In the samples for different languages, you see that most
105* accents are ignorable.
106*
107* <p><strong>Normalization and Accents</strong>
108* <p>
109* <code>RuleBasedCollator</code> automatically processes its rule table to
110* include both pre-composed and combining-character versions of accented
111* characters. Even if the provided rule string contains only base characters
112* and separate combining accent characters, the pre-composed accented
113* characters matching all canonical combinations of characters from the rule
114* string will be entered in the table.
115* <p>
116* This allows you to use a RuleBasedCollator to compare accented strings even
117* when the collator is set to NO_DECOMPOSITION. However, if the strings to be
118* collated contain combining sequences that may not be in canonical order, you
119* should set the collator to CANONICAL_DECOMPOSITION to enable sorting of
120* combining sequences.
121* For more information, see
122* <A HREF="http://www.aw.com/devpress">The Unicode Standard, Version 3.0</A>.)
123*
124* <p><strong>Errors</strong>
125* <p>
126* The following are errors:
127* <UL Type=disc>
128*     <LI>A text-argument contains unquoted punctuation symbols
129*        (e.g. "a < b-c < d").
130*     <LI>A relation or reset character not followed by a text-argument
131*        (e.g. "a < , b").
132*     <LI>A reset where the text-argument (or an initial substring of the
133*         text-argument) is not already in the sequence or allocated in the
134*         default UCA table.
135*         (e.g. "a < b & e < f")
136* </UL>
137* If you produce one of these errors, a <code>RuleBasedCollator</code> throws
138* a <code>ParseException</code>.
139*
140* <p><strong>Examples</strong>
141* <p>Simple:     "< a < b < c < d"
142* <p>Norwegian:  "< a,A< b,B< c,C< d,D< e,E< f,F< g,G< h,H< i,I< j,J
143*                 < k,K< l,L< m,M< n,N< o,O< p,P< q,Q< r,R< s,S< t,T
144*                < u,U< v,V< w,W< x,X< y,Y< z,Z
145*                 < ?=a?,?=A?
146*                 ;aa,AA< ?,?< ?,?"
147*
148* <p>
149* Normally, to create a rule-based Collator object, you will use
150* <code>Collator</code>'s factory method <code>getInstance</code>.
151* However, to create a rule-based Collator object with specialized rules
152* tailored to your needs, you construct the <code>RuleBasedCollator</code>
153* with the rules contained in a <code>String</code> object. For example:
154* <blockquote>
155* <pre>
156* String Simple = "< a < b < c < d";
157* RuleBasedCollator mySimple = new RuleBasedCollator(Simple);
158* </pre>
159* </blockquote>
160* Or:
161* <blockquote>
162* <pre>
163* String Norwegian = "< a,A< b,B< c,C< d,D< e,E< f,F< g,G< h,H< i,I< j,J" +
164*                 "< k,K< l,L< m,M< n,N< o,O< p,P< q,Q< r,R< s,S< t,T" +
165*                 "< u,U< v,V< w,W< x,X< y,Y< z,Z" +
166*                 "< ?=a?,?=A?" +
167*                 ";aa,AA< ?,?< ?,?";
168* RuleBasedCollator myNorwegian = new RuleBasedCollator(Norwegian);
169* </pre>
170* </blockquote>
171*
172* <p>
173* Combining <code>Collator</code>s is as simple as concatenating strings.
174* Here's an example that combines two <code>Collator</code>s from two
175* different locales:
176* <blockquote>
177* <pre>
178* // Create an en_US Collator object
179* RuleBasedCollator en_USCollator = (RuleBasedCollator)
180*     Collator.getInstance(new Locale("en", "US", ""));
181* // Create a da_DK Collator object
182* RuleBasedCollator da_DKCollator = (RuleBasedCollator)
183*     Collator.getInstance(new Locale("da", "DK", ""));
184* // Combine the two
185* // First, get the collation rules from en_USCollator
186* String en_USRules = en_USCollator.getRules();
187* // Second, get the collation rules from da_DKCollator
188* String da_DKRules = da_DKCollator.getRules();
189* RuleBasedCollator newCollator =
190*     new RuleBasedCollator(en_USRules + da_DKRules);
191* // newCollator has the combined rules
192* </pre>
193* </blockquote>
194*
195* <p>
196* Another more interesting example would be to make changes on an existing
197* table to create a new <code>Collator</code> object.  For example, add
198* "& C < ch, cH, Ch, CH" to the <code>en_USCollator</code> object to create
199* your own:
200* <blockquote>
201* <pre>
202* // Create a new Collator object with additional rules
203* String addRules = "& C < ch, cH, Ch, CH";
204* RuleBasedCollator myCollator =
205*     new RuleBasedCollator(en_USCollator + addRules);
206* // myCollator contains the new rules
207* </pre>
208* </blockquote>
209*
210* <p>
211* The following example demonstrates how to change the order of
212* non-spacing accents,
213* <blockquote>
214* <pre>
215* // old rule
216* String oldRules = "=?;?;?"    // main accents Diaeresis 00A8, Macron 00AF
217*                               // Acute 00BF
218*                 + "< a , A ; ae, AE ; ? , ?"
219*                 + "< b , B < c, C < e, E & C < d, D";
220* // change the order of accent characters
221* String addOn = "& ?;?;?;"; // Acute 00BF, Macron 00AF, Diaeresis 00A8
222* RuleBasedCollator myCollator = new RuleBasedCollator(oldRules + addOn);
223* </pre>
224* </blockquote>
225*
226* <p>
227* The last example shows how to put new primary ordering in before the
228* default setting. For example, in Japanese <code>Collator</code>, you
229* can either sort English characters before or after Japanese characters,
230* <blockquote>
231* <pre>
232* // get en_US Collator rules
233* RuleBasedCollator en_USCollator =
234*                      (RuleBasedCollator)Collator.getInstance(Locale.US);
235* // add a few Japanese character to sort before English characters
236* // suppose the last character before the first base letter 'a' in
237* // the English collation rule is ?
238* String jaString = "& \\u30A2 , \\u30FC < \\u30C8";
239* RuleBasedCollator myJapaneseCollator = new
240*     RuleBasedCollator(en_USCollator.getRules() + jaString);
241* </pre>
242* </blockquote>
243* <P>
244* @author syn wee quek
245* @stable ICU 2.4
246*/
247
248public final class RuleBasedCollator extends Collator
249{
250  // public constructors ------------------------------------------
251
252  /**
253  * RuleBasedCollator constructor. This takes the table rules and builds a
254  * collation table out of them. Please see RuleBasedCollator class
255  * description for more details on the collation rule syntax.
256  * @param rules the collation rules to build the collation table from.
257  * @exception ParseException thrown if rules are empty or a Runtime error
258  *            if collator can not be created.
259  * @stable ICU 2.4
260  */
261  public RuleBasedCollator(String rules) throws ParseException
262  {
263    // BEGIN android-changed
264    if (rules == null) {
265      throw new NullPointerException();
266    }
267    // if (rules.length() == 0)
268    //   throw new ParseException("Build rules empty.", 0);
269    // END android-changed
270    m_collator_ = NativeCollation.openCollatorFromRules(rules,
271                              CollationAttribute.VALUE_OFF,
272                              CollationAttribute.VALUE_DEFAULT_STRENGTH);
273  }
274
275  /**
276  * RuleBasedCollator constructor. This takes the table rules and builds a
277  * collation table out of them. Please see RuleBasedCollator class
278  * description for more details on the collation rule syntax.
279  * @param rules the collation rules to build the collation table from.
280  * @param strength collation strength
281  * @exception ParseException thrown if rules are empty or a Runtime error
282  *            if collator can not be created.
283  * @see #PRIMARY
284  * @see #SECONDARY
285  * @see #TERTIARY
286  * @see #QUATERNARY
287  * @see #IDENTICAL
288  * @stable ICU 2.4
289  */
290  public RuleBasedCollator(String rules, int strength) throws ParseException
291  {
292    // BEGIN android-changed
293    if (rules == null) {
294      throw new NullPointerException();
295    }
296    // if (rules.length() == 0)
297    //   throw new ParseException("Build rules empty.", 0);
298    // END android-changed
299    if (!CollationAttribute.checkStrength(strength))
300      throw ErrorCode.getException(ErrorCode.U_ILLEGAL_ARGUMENT_ERROR);
301
302    m_collator_ = NativeCollation.openCollatorFromRules(rules,
303                                CollationAttribute.VALUE_OFF,
304                                strength);
305  }
306
307  /**
308  * RuleBasedCollator constructor. This takes the table rules and builds a
309  * collation table out of them. Please see RuleBasedCollator class
310  * description for more details on the collation rule syntax.
311  * <p>Note API change starting from release 2.4. Prior to release 2.4, the
312  * normalizationmode argument values are from the class
313  * com.ibm.icu4jni.text.Normalization. In 2.4,
314  * the valid normalizationmode arguments for this API are
315  * CollationAttribute.VALUE_ON and CollationAttribute.VALUE_OFF.
316  * </p>
317  * @param rules the collation rules to build the collation table from.
318  * @param strength collation strength
319  * @param normalizationmode normalization mode
320  * @exception IllegalArgumentException thrown when constructor error occurs
321  * @see #PRIMARY
322  * @see #SECONDARY
323  * @see #TERTIARY
324  * @see #QUATERNARY
325  * @see #IDENTICAL
326  * @see #CANONICAL_DECOMPOSITION
327  * @see #NO_DECOMPOSITION
328  * @stable ICU 2.4
329  */
330  public RuleBasedCollator(String rules, int normalizationmode, int strength)
331  {
332    // BEGIN android-added
333    if (rules == null) {
334      throw new NullPointerException();
335    }
336    // END android-added
337    if (!CollationAttribute.checkStrength(strength) ||
338        !CollationAttribute.checkNormalization(normalizationmode)) {
339      throw ErrorCode.getException(ErrorCode.U_ILLEGAL_ARGUMENT_ERROR);
340    }
341
342    m_collator_ = NativeCollation.openCollatorFromRules(rules,
343                                          normalizationmode, strength);
344  }
345
346  // public methods -----------------------------------------------
347
348  /**
349  * Makes a complete copy of the current object.
350  * @return a copy of this object if data clone is a success, otherwise null
351  * @stable ICU 2.4
352  */
353  public Object clone()
354  {
355    RuleBasedCollator result = null;
356    int collatoraddress = NativeCollation.safeClone(m_collator_);
357    result = new RuleBasedCollator(collatoraddress);
358    return (Collator)result;
359  }
360
361  /**
362  * The comparison function compares the character data stored in two
363  * different strings. Returns information about whether a string is less
364  * than, greater than or equal to another string.
365  * <p>Example of use:
366  * <br>
367  * <code>
368  *   Collator myCollation = Collator.createInstance(Locale::US);
369  *   myCollation.setStrength(CollationAttribute.VALUE_PRIMARY);
370  *   // result would be Collator.RESULT_EQUAL ("abc" == "ABC")
371  *   // (no primary difference between "abc" and "ABC")
372  *   int result = myCollation.compare("abc", "ABC",3);
373  *   myCollation.setStrength(CollationAttribute.VALUE_TERTIARY);
374  *   // result would be Collation::LESS (abc" &lt;&lt;&lt; "ABC")
375  *   // (with tertiary difference between "abc" and "ABC")
376  *   int result = myCollation.compare("abc", "ABC",3);
377  * </code>
378  * @param source The source string.
379  * @param target The target string.
380  * @return result of the comparison, Collator.RESULT_EQUAL,
381  *         Collator.RESULT_GREATER or Collator.RESULT_LESS
382  * @stable ICU 2.4
383  */
384  public int compare(String source, String target)
385  {
386    return NativeCollation.compare(m_collator_, source, target);
387  }
388
389  /**
390  * Get the normalization mode for this object.
391  * The normalization mode influences how strings are compared.
392  * @see #CANONICAL_DECOMPOSITION
393  * @see #NO_DECOMPOSITION
394  * @stable ICU 2.4
395  */
396  public int getDecomposition()
397  {
398    return NativeCollation.getNormalization(m_collator_);
399  }
400
401  /**
402  * <p>Sets the decomposition mode of the Collator object on or off.
403  * If the decomposition mode is set to on, string would be decomposed into
404  * NFD format where necessary before sorting.</p>
405  * </p>
406  * @param decompositionmode the new decomposition mode
407  * @see #CANONICAL_DECOMPOSITION
408  * @see #NO_DECOMPOSITION
409  * @stable ICU 2.4
410  */
411  public void setDecomposition(int decompositionmode)
412  {
413    if (!CollationAttribute.checkNormalization(decompositionmode))
414      throw ErrorCode.getException(ErrorCode.U_ILLEGAL_ARGUMENT_ERROR);
415    NativeCollation.setAttribute(m_collator_,
416                                 CollationAttribute.NORMALIZATION_MODE,
417                                 decompositionmode);
418  }
419
420  /**
421  * Determines the minimum strength that will be use in comparison or
422  * transformation.
423  * <p>
424  * E.g. with strength == CollationAttribute.VALUE_SECONDARY, the tertiary difference
425  * is ignored
426  * </p>
427  * <p>
428  * E.g. with strength == PRIMARY, the secondary and tertiary difference are
429  * ignored.
430  * </p>
431  * @return the current comparison level.
432  * @see #PRIMARY
433  * @see #SECONDARY
434  * @see #TERTIARY
435  * @see #QUATERNARY
436  * @see #IDENTICAL
437  * @stable ICU 2.4
438  */
439  public int getStrength()
440  {
441    return NativeCollation.getAttribute(m_collator_,
442                                        CollationAttribute.STRENGTH);
443  }
444
445  /**
446  * Sets the minimum strength to be used in comparison or transformation.
447  * <p>Example of use:
448  * <br>
449  * <code>
450  * Collator myCollation = Collator.createInstance(Locale::US);
451  * myCollation.setStrength(PRIMARY);
452  * // result will be "abc" == "ABC"
453  * // tertiary differences will be ignored
454  * int result = myCollation->compare("abc", "ABC");
455  * </code>
456  * @param strength the new comparison level.
457  * @exception IllegalArgumentException when argument does not belong to any collation strength
458  *            mode or error occurs while setting data.
459  * @see #PRIMARY
460  * @see #SECONDARY
461  * @see #TERTIARY
462  * @see #QUATERNARY
463  * @see #IDENTICAL
464  * @stable ICU 2.4
465  */
466  public void setStrength(int strength)
467  {
468    if (!CollationAttribute.checkStrength(strength))
469      throw ErrorCode.getException(ErrorCode.U_ILLEGAL_ARGUMENT_ERROR);
470    NativeCollation.setAttribute(m_collator_, CollationAttribute.STRENGTH,
471                                 strength);
472  }
473
474  /**
475  * Sets the attribute to be used in comparison or transformation.
476  * <p>Example of use:
477  * <br>
478  * <code>
479  *  Collator myCollation = Collator.createInstance(Locale::US);
480  *  myCollation.setAttribute(CollationAttribute.CASE_LEVEL,
481  *                           CollationAttribute.VALUE_ON);
482  *  int result = myCollation->compare("\\u30C3\\u30CF",
483  *                                    "\\u30C4\\u30CF");
484  * // result will be Collator.RESULT_LESS.
485  * </code>
486  * @param type the attribute to be set from CollationAttribute
487  * @param value attribute value from CollationAttribute
488  * @stable ICU 2.4
489  */
490  public void setAttribute(int type, int value)
491  {
492    if (!CollationAttribute.checkAttribute(type, value))
493      throw ErrorCode.getException(ErrorCode.U_ILLEGAL_ARGUMENT_ERROR);
494    NativeCollation.setAttribute(m_collator_, type, value);
495  }
496
497  /**
498  * Gets the attribute to be used in comparison or transformation.
499  * @param type the attribute to be set from CollationAttribute
500  * @return value attribute value from CollationAttribute
501  * @stable ICU 2.4
502  */
503  public int getAttribute(int type)
504  {
505    if (!CollationAttribute.checkType(type))
506      throw ErrorCode.getException(ErrorCode.U_ILLEGAL_ARGUMENT_ERROR);
507    return NativeCollation.getAttribute(m_collator_, type);
508  }
509
510  /**
511  * Get the sort key as an CollationKey object from the argument string.
512  * To retrieve sort key in terms of byte arrays, use the method as below<br>
513  * <br>
514  * <code>
515  * Collator collator = Collator.getInstance();
516  * byte[] array = collator.getSortKey(source);
517  * </code><br>
518  * Byte array result are zero-terminated and can be compared using
519  * java.util.Arrays.equals();
520  * @param source string to be processed.
521  * @return the sort key
522  * @stable ICU 2.4
523  */
524  public CollationKey getCollationKey(String source)
525  {
526    // BEGIN android-removed
527    // return new CollationKey(NativeCollation.getSortKey(m_collator_, source));
528    // END android-removed
529    // BEGIN android-added
530    if(source == null) {
531        return null;
532    }
533    byte[] key = NativeCollation.getSortKey(m_collator_, source);
534    if(key == null) {
535      return null;
536    }
537    return new CollationKey(key);
538    // END android-added
539  }
540
541  /**
542  * Get a sort key for the argument string
543  * Sort keys may be compared using java.util.Arrays.equals
544  * @param source string for key to be generated
545  * @return sort key
546  * @stable ICU 2.4
547  */
548  public byte[] getSortKey(String source)
549  {
550    return NativeCollation.getSortKey(m_collator_, source);
551  }
552
553  /**
554  * Get the collation rules of this Collation object
555  * The rules will follow the rule syntax.
556  * @return collation rules.
557  * @stable ICU 2.4
558  */
559  public String getRules()
560  {
561    return NativeCollation.getRules(m_collator_);
562  }
563
564  /**
565  * Create a CollationElementIterator object that will iterator over the
566  * elements in a string, using the collation rules defined in this
567  * RuleBasedCollator
568  * @param source string to iterate over
569  * @return address of C collationelement
570  * @exception IllegalArgumentException thrown when error occurs
571  * @stable ICU 2.4
572  */
573  public CollationElementIterator getCollationElementIterator(String source)
574  {
575    CollationElementIterator result = new CollationElementIterator(
576         NativeCollation.getCollationElementIterator(m_collator_, source));
577    // result.setOwnCollationElementIterator(true);
578    return result;
579  }
580
581  // BEGIN android-added
582  /**
583  * Create a CollationElementIterator object that will iterator over the
584  * elements in a string, using the collation rules defined in this
585  * RuleBasedCollator
586  * @param source string to iterate over
587  * @return address of C collationelement
588  * @exception IllegalArgumentException thrown when error occurs
589  * @stable ICU 2.4
590  */
591  public CollationElementIterator getCollationElementIterator(
592          CharacterIterator source)
593  {
594    CollationElementIterator result = new CollationElementIterator(
595         NativeCollation.getCollationElementIterator(m_collator_,
596                 source.toString()));
597    // result.setOwnCollationElementIterator(true);
598    return result;
599  }
600  // END android-added
601
602  /**
603  * Returns a hash of this collation object
604  * Note this method is not complete, it only returns 0 at the moment.
605  * @return hash of this collation object
606  * @stable ICU 2.4
607  */
608  public int hashCode()
609  {
610    // since rules do not change once it is created, we can cache the hash
611    if (m_hashcode_ == 0) {
612      m_hashcode_ = NativeCollation.hashCode(m_collator_);
613      if (m_hashcode_ == 0)
614        m_hashcode_ = 1;
615    }
616    return m_hashcode_;
617  }
618
619  /**
620  * Checks if argument object is equals to this object.
621  * @param target object
622  * @return true if source is equivalent to target, false otherwise
623  * @stable ICU 2.4
624  */
625  public boolean equals(Object target)
626  {
627    if (this == target)
628      return true;
629    if (target == null)
630      return false;
631    if (getClass() != target.getClass())
632      return false;
633
634    RuleBasedCollator tgtcoll = (RuleBasedCollator)target;
635    return getRules().equals(tgtcoll.getRules()) &&
636           getStrength() == tgtcoll.getStrength() &&
637           getDecomposition() == tgtcoll.getDecomposition();
638  }
639
640  // package constructor ----------------------------------------
641
642  /**
643  * RuleBasedCollator default constructor. This constructor takes the default
644  * locale. The only caller of this class should be Collator.getInstance().
645  * Current implementation createInstance() returns a RuleBasedCollator(Locale)
646  * instance. The RuleBasedCollator will be created in the following order,
647  * <ul>
648  * <li> Data from argument locale resource bundle if found, otherwise
649  * <li> Data from parent locale resource bundle of arguemtn locale if found,
650  *      otherwise
651  * <li> Data from built-in default collation rules if found, other
652  * <li> null is returned
653  * </ul>
654  */
655  RuleBasedCollator()
656  {
657    m_collator_ = NativeCollation.openCollator();
658  }
659
660  /**
661  * RuleBasedCollator constructor. This constructor takes a locale. The
662  * only caller of this class should be Collator.createInstance().
663  * Current implementation createInstance() returns a RuleBasedCollator(Locale)
664  * instance. The RuleBasedCollator will be created in the following order,
665  * <ul>
666  * <li> Data from argument locale resource bundle if found, otherwise
667  * <li> Data from parent locale resource bundle of arguemtn locale if found,
668  *      otherwise
669  * <li> Data from built-in default collation rules if found, other
670  * <li> null is returned
671  * </ul>
672  * @param locale locale used
673  */
674  RuleBasedCollator(Locale locale)
675  {
676    if (locale == null) {
677      m_collator_ = NativeCollation.openCollator();
678    }
679    else {
680      m_collator_ = NativeCollation.openCollator(locale.toString());
681    }
682  }
683
684  // protected methods --------------------------------------------
685
686  /**
687  * Garbage collection.
688  * Close C collator and reclaim memory.
689  */
690  protected void finalize()
691  {
692    NativeCollation.closeCollator(m_collator_);
693  }
694
695  // private data members -----------------------------------------
696
697  /**
698  * C collator
699  */
700  private int m_collator_;
701
702  /**
703  * Hash code for rules
704  */
705  private int m_hashcode_ = 0;
706
707  // private constructor -----------------------------------------
708
709  /**
710  * Private use constructor.
711  * Does not create any instance of the C collator. Accepts argument as the
712  * C collator for new instance.
713  * @param collatoraddress address of C collator
714  */
715  private RuleBasedCollator(int collatoraddress)
716  {
717    m_collator_ = collatoraddress;
718  }
719}
720