View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.text;
18  
19  import static org.junit.Assert.assertEquals;
20  import static org.junit.Assert.assertFalse;
21  import static org.junit.Assert.assertTrue;
22  
23  import java.text.DateFormat;
24  import java.text.FieldPosition;
25  import java.text.Format;
26  import java.text.MessageFormat;
27  import java.text.NumberFormat;
28  import java.text.ParsePosition;
29  import java.util.Arrays;
30  import java.util.Calendar;
31  import java.util.Collections;
32  import java.util.HashMap;
33  import java.util.HashSet;
34  import java.util.Locale;
35  import java.util.Map;
36  
37  import org.junit.Before;
38  import org.junit.Test;
39  
40  /**
41   * Test case for {@link ExtendedMessageFormat}.
42   */
43  public class ExtendedMessageFormatTest {
44  
45      private final Map<String, FormatFactory> registry = new HashMap<>();
46  
47      @Before
48      public void setUp() {
49          registry.put("lower", new LowerCaseFormatFactory());
50          registry.put("upper", new UpperCaseFormatFactory());
51      }
52  
53      /**
54       * Test extended formats.
55       */
56      @Test
57      public void testExtendedFormats() {
58          final String pattern = "Lower: {0,lower} Upper: {1,upper}";
59          final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
60          assertEquals("TOPATTERN", pattern, emf.toPattern());
61          assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"foo", "bar"}));
62          assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"Foo", "Bar"}));
63          assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"FOO", "BAR"}));
64          assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"FOO", "bar"}));
65          assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"foo", "BAR"}));
66      }
67  
68      /**
69       * Test Bug LANG-477 - out of memory error with escaped quote
70       */
71      @Test
72      public void testEscapedQuote_LANG_477() {
73          final String pattern = "it''s a {0,lower} 'test'!";
74          final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
75          assertEquals("it's a dummy test!", emf.format(new Object[] {"DUMMY"}));
76      }
77  
78      /**
79       * Test Bug LANG-917 - IndexOutOfBoundsException and/or infinite loop when using a choice pattern
80       */
81      @Test
82      public void testEmbeddedPatternInChoice() {
83          final String pattern = "Hi {0,lower}, got {1,choice,0#none|1#one|1<{1,number}}, {2,upper}!";
84          final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
85          assertEquals(emf.format(new Object[] {"there", 3, "great"}), "Hi there, got 3, GREAT!");
86      }
87  
88      /**
89       * Test Bug LANG-948 - Exception while using ExtendedMessageFormat and escaping braces
90       */
91      @Test
92      public void testEscapedBraces_LANG_948() {
93          // message without placeholder because braces are escaped by quotes
94          final String pattern = "Message without placeholders '{}'";
95          final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
96          assertEquals("Message without placeholders {}", emf.format(new Object[] {"DUMMY"}));
97  
98          // message with placeholder because quotes are escaped by quotes
99          final String pattern2 = "Message with placeholder ''{0}''";
100         final ExtendedMessageFormat emf2 = new ExtendedMessageFormat(pattern2, registry);
101         assertEquals("Message with placeholder 'DUMMY'", emf2.format(new Object[] {"DUMMY"}));
102     }
103 
104     /**
105      * Test Bug TEXT-106 - Exception while using ExtendedMessageFormat and choice format element with quote just
106      * before brace end
107      */
108     @Test
109     public void testChoiceQuoteJustBeforeBraceEnd_TEXT_106() {
110         final String pattern2 = "Choice format element with quote just before brace end ''{0,choice,0#0|0<'1'}''";
111         final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern2, registry);
112         assertEquals("Choice format element with quote just before brace end '0'", emf.format(new Object[] {0}));
113         assertEquals("Choice format element with quote just before brace end '1'", emf.format(new Object[] {1}));
114     }
115 
116     /**
117      * Test extended and built in formats.
118      */
119     @Test
120     public void testExtendedAndBuiltInFormats() {
121         final Calendar cal = Calendar.getInstance();
122         cal.set(2007, Calendar.JANUARY, 23, 18, 33, 5);
123         final Object[] args = new Object[] {"John Doe", cal.getTime(), Double.valueOf("12345.67")};
124         final String builtinsPattern = "DOB: {1,date,short} Salary: {2,number,currency}";
125         final String extendedPattern = "Name: {0,upper} ";
126         final String pattern = extendedPattern + builtinsPattern;
127 
128         final HashSet<Locale> testLocales = new HashSet<>();
129         testLocales.addAll(Arrays.asList(DateFormat.getAvailableLocales()));
130         testLocales.retainAll(Arrays.asList(NumberFormat.getAvailableLocales()));
131         testLocales.add(null);
132 
133         for (final Locale locale : testLocales) {
134             final MessageFormat builtins = createMessageFormat(builtinsPattern, locale);
135             final String expectedPattern = extendedPattern + builtins.toPattern();
136             DateFormat df = null;
137             NumberFormat nf = null;
138             ExtendedMessageFormat emf = null;
139             if (locale == null) {
140                 df = DateFormat.getDateInstance(DateFormat.SHORT);
141                 nf = NumberFormat.getCurrencyInstance();
142                 emf = new ExtendedMessageFormat(pattern, registry);
143             } else {
144                 df = DateFormat.getDateInstance(DateFormat.SHORT, locale);
145                 nf = NumberFormat.getCurrencyInstance(locale);
146                 emf = new ExtendedMessageFormat(pattern, locale, registry);
147             }
148             final StringBuilder expected = new StringBuilder();
149             expected.append("Name: ");
150             expected.append(args[0].toString().toUpperCase(Locale.ROOT));
151             expected.append(" DOB: ");
152             expected.append(df.format(args[1]));
153             expected.append(" Salary: ");
154             expected.append(nf.format(args[2]));
155             assertEquals("pattern comparison for locale " + locale, expectedPattern, emf.toPattern());
156             assertEquals(String.valueOf(locale), expected.toString(), emf.format(args));
157         }
158     }
159 
160 //    /**
161 //     * Test extended formats with choice format.
162 //     *
163 //     * NOTE: FAILING - currently sub-formats not supported
164 //     */
165 //    public void testExtendedWithChoiceFormat() {
166 //        String pattern = "Choice: {0,choice,1.0#{1,lower}|2.0#{1,upper}}";
167 //        ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
168 //        assertPatterns(null, pattern, emf.toPattern());
169 //        try {
170 //            assertEquals("one", emf.format(new Object[] {Integer.valueOf(1), "ONE"}));
171 //            assertEquals("TWO", emf.format(new Object[] {Integer.valueOf(2), "two"}));
172 //        } catch (IllegalArgumentException e) {
173 //            // currently sub-formats not supported
174 //        }
175 //    }
176 
177 //    /**
178 //     * Test mixed extended and built-in formats with choice format.
179 //     *
180 //     * NOTE: FAILING - currently sub-formats not supported
181 //     */
182 //    public void testExtendedAndBuiltInWithChoiceFormat() {
183 //        String pattern = "Choice: {0,choice,1.0#{0} {1,lower} {2,number}|2.0#{0} {1,upper} {2,number,currency}}";
184 //        Object[] lowArgs  = new Object[] {Integer.valueOf(1), "Low",  Double.valueOf("1234.56")};
185 //        Object[] highArgs = new Object[] {Integer.valueOf(2), "High", Double.valueOf("9876.54")};
186 //        Locale[] availableLocales = ChoiceFormat.getAvailableLocales();
187 //        Locale[] testLocales = new Locale[availableLocales.length + 1];
188 //        testLocales[0] = null;
189 //        System.arraycopy(availableLocales, 0, testLocales, 1, availableLocales.length);
190 //        for (int i = 0; i < testLocales.length; i++) {
191 //            NumberFormat nf = null;
192 //            NumberFormat cf = null;
193 //            ExtendedMessageFormat emf = null;
194 //            if (testLocales[i] == null) {
195 //                nf = NumberFormat.getNumberInstance();
196 //                cf = NumberFormat.getCurrencyInstance();
197 //                emf = new ExtendedMessageFormat(pattern, registry);
198 //            } else {
199 //                nf = NumberFormat.getNumberInstance(testLocales[i]);
200 //                cf = NumberFormat.getCurrencyInstance(testLocales[i]);
201 //                emf = new ExtendedMessageFormat(pattern, testLocales[i], registry);
202 //            }
203 //            assertPatterns(null, pattern, emf.toPattern());
204 //            try {
205 //                String lowExpected = lowArgs[0] + " low "    + nf.format(lowArgs[2]);
206 //                String highExpected = highArgs[0] + " HIGH "  + cf.format(highArgs[2]);
207 //                assertEquals(lowExpected,  emf.format(lowArgs));
208 //                assertEquals(highExpected, emf.format(highArgs));
209 //            } catch (IllegalArgumentException e) {
210 //                // currently sub-formats not supported
211 //            }
212 //        }
213 //    }
214 
215     /**
216      * Test the built in choice format.
217      */
218     @Test
219     public void testBuiltInChoiceFormat() {
220         final Object[] values = new Number[] {1, Double.valueOf("2.2"), Double.valueOf("1234.5")};
221         String choicePattern = null;
222         final Locale[] availableLocales = NumberFormat.getAvailableLocales();
223 
224         choicePattern = "{0,choice,1#One|2#Two|3#Many {0,number}}";
225         for (final Object value : values) {
226             checkBuiltInFormat(value + ": " + choicePattern, new Object[] {value}, availableLocales);
227         }
228 
229         choicePattern = "{0,choice,1#''One''|2#\"Two\"|3#''{Many}'' {0,number}}";
230         for (final Object value : values) {
231             checkBuiltInFormat(value + ": " + choicePattern, new Object[] {value}, availableLocales);
232         }
233     }
234 
235     /**
236      * Test the built in date/time formats
237      */
238     @Test
239     public void testBuiltInDateTimeFormat() {
240         final Calendar cal = Calendar.getInstance();
241         cal.set(2007, Calendar.JANUARY, 23, 18, 33, 5);
242         final Object[] args = new Object[] {cal.getTime()};
243         final Locale[] availableLocales = DateFormat.getAvailableLocales();
244 
245         checkBuiltInFormat("1: {0,date,short}",    args, availableLocales);
246         checkBuiltInFormat("2: {0,date,medium}",   args, availableLocales);
247         checkBuiltInFormat("3: {0,date,long}",     args, availableLocales);
248         checkBuiltInFormat("4: {0,date,full}",     args, availableLocales);
249         checkBuiltInFormat("5: {0,date,d MMM yy}", args, availableLocales);
250         checkBuiltInFormat("6: {0,time,short}",    args, availableLocales);
251         checkBuiltInFormat("7: {0,time,medium}",   args, availableLocales);
252         checkBuiltInFormat("8: {0,time,long}",     args, availableLocales);
253         checkBuiltInFormat("9: {0,time,full}",     args, availableLocales);
254         checkBuiltInFormat("10: {0,time,HH:mm}",   args, availableLocales);
255         checkBuiltInFormat("11: {0,date}",         args, availableLocales);
256         checkBuiltInFormat("12: {0,time}",         args, availableLocales);
257     }
258 
259     @Test
260     public void testOverriddenBuiltinFormat() {
261         final Calendar cal = Calendar.getInstance();
262         cal.set(2007, Calendar.JANUARY, 23);
263         final Object[] args = new Object[] {cal.getTime()};
264         final Locale[] availableLocales = DateFormat.getAvailableLocales();
265         final Map<String, ? extends FormatFactory> dateRegistry =
266                 Collections.singletonMap("date", new OverrideShortDateFormatFactory());
267 
268         //check the non-overridden builtins:
269         checkBuiltInFormat("1: {0,date}", dateRegistry,          args, availableLocales);
270         checkBuiltInFormat("2: {0,date,medium}", dateRegistry,   args, availableLocales);
271         checkBuiltInFormat("3: {0,date,long}", dateRegistry,     args, availableLocales);
272         checkBuiltInFormat("4: {0,date,full}", dateRegistry,     args, availableLocales);
273         checkBuiltInFormat("5: {0,date,d MMM yy}", dateRegistry, args, availableLocales);
274 
275         //check the overridden format:
276         for (int i = -1; i < availableLocales.length; i++) {
277             final Locale locale = i < 0 ? null : availableLocales[i];
278             final MessageFormat dateDefault = createMessageFormat("{0,date}", locale);
279             final String pattern = "{0,date,short}";
280             final ExtendedMessageFormat dateShort = new ExtendedMessageFormat(pattern, locale, dateRegistry);
281             assertEquals("overridden date,short format", dateDefault.format(args), dateShort.format(args));
282             assertEquals("overridden date,short pattern", pattern, dateShort.toPattern());
283         }
284     }
285 
286     /**
287      * Test the built in number formats.
288      */
289     @Test
290     public void testBuiltInNumberFormat() {
291         final Object[] args = new Object[] {Double.valueOf("6543.21")};
292         final Locale[] availableLocales = NumberFormat.getAvailableLocales();
293         checkBuiltInFormat("1: {0,number}",            args, availableLocales);
294         checkBuiltInFormat("2: {0,number,integer}",    args, availableLocales);
295         checkBuiltInFormat("3: {0,number,currency}",   args, availableLocales);
296         checkBuiltInFormat("4: {0,number,percent}",    args, availableLocales);
297         checkBuiltInFormat("5: {0,number,00000.000}",  args, availableLocales);
298     }
299 
300     /**
301      * Test equals() and hashcode.
302      */
303     @Test
304     public void testEqualsHashcode() {
305         final Map<String, ? extends FormatFactory> fmtRegistry =
306                 Collections.singletonMap("testfmt", new LowerCaseFormatFactory());
307         final Map<String, ? extends FormatFactory> otherRegitry =
308                 Collections.singletonMap("testfmt", new UpperCaseFormatFactory());
309 
310         final String pattern = "Pattern: {0,testfmt}";
311         final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, Locale.US, fmtRegistry);
312 
313         ExtendedMessageFormat other = null;
314 
315         // Same object
316         assertTrue("same, equals()",   emf.equals(emf));
317         assertTrue("same, hashcode()", emf.hashCode() == emf.hashCode());
318 
319         assertFalse("null, equals", emf.equals(null));
320 
321         // Equal Object
322         other = new ExtendedMessageFormat(pattern, Locale.US, fmtRegistry);
323         assertTrue("equal, equals()",   emf.equals(other));
324         assertTrue("equal, hashcode()", emf.hashCode() == other.hashCode());
325 
326         // Different Class
327         other = new OtherExtendedMessageFormat(pattern, Locale.US, fmtRegistry);
328         assertFalse("class, equals()",  emf.equals(other));
329         assertTrue("class, hashcode()", emf.hashCode() == other.hashCode()); // same hashcode
330 
331         // Different pattern
332         other = new ExtendedMessageFormat("X" + pattern, Locale.US, fmtRegistry);
333         assertFalse("pattern, equals()",   emf.equals(other));
334         assertFalse("pattern, hashcode()", emf.hashCode() == other.hashCode());
335 
336         // Different registry
337         other = new ExtendedMessageFormat(pattern, Locale.US, otherRegitry);
338         assertFalse("registry, equals()",   emf.equals(other));
339         assertFalse("registry, hashcode()", emf.hashCode() == other.hashCode());
340 
341         // Different Locale
342         other = new ExtendedMessageFormat(pattern, Locale.FRANCE, fmtRegistry);
343         assertFalse("locale, equals()",  emf.equals(other));
344         assertTrue("locale, hashcode()", emf.hashCode() == other.hashCode()); // same hashcode
345     }
346 
347     /**
348      * Test a built in format for the specified Locales, plus <code>null</code> Locale.
349      * @param pattern MessageFormat pattern
350      * @param args MessageFormat arguments
351      * @param locales to test
352      */
353     private void checkBuiltInFormat(final String pattern, final Object[] args, final Locale[] locales) {
354         checkBuiltInFormat(pattern, null, args, locales);
355     }
356 
357     /**
358      * Test a built in format for the specified Locales, plus <code>null</code> Locale.
359      * @param pattern MessageFormat pattern
360      * @param fmtRegistry FormatFactory registry to use
361      * @param args MessageFormat arguments
362      * @param locales to test
363      */
364     private void checkBuiltInFormat(final String pattern, final Map<String, ?> fmtRegistry, final Object[] args,
365             final Locale[] locales) {
366         checkBuiltInFormat(pattern, fmtRegistry, args, (Locale) null);
367         for (final Locale locale : locales) {
368             checkBuiltInFormat(pattern, fmtRegistry, args, locale);
369         }
370     }
371 
372     /**
373      * Create an ExtendedMessageFormat for the specified pattern and locale and check the
374      * formated output matches the expected result for the parameters.
375      * @param pattern string
376      * @param registryUnused map (currently unused)
377      * @param args Object[]
378      * @param locale Locale
379      */
380     private void checkBuiltInFormat(final String pattern, final Map<String, ?> registryUnused, final Object[] args,
381             final Locale locale) {
382         final StringBuilder buffer = new StringBuilder();
383         buffer.append("Pattern=[");
384         buffer.append(pattern);
385         buffer.append("], locale=[");
386         buffer.append(locale);
387         buffer.append("]");
388         final MessageFormat mf = createMessageFormat(pattern, locale);
389         // System.out.println(buffer + ", result=[" + mf.format(args) +"]");
390         ExtendedMessageFormat emf = null;
391         if (locale == null) {
392             emf = new ExtendedMessageFormat(pattern);
393         } else {
394             emf = new ExtendedMessageFormat(pattern, locale);
395         }
396         assertEquals("format "    + buffer.toString(), mf.format(args), emf.format(args));
397         assertEquals("toPattern " + buffer.toString(), mf.toPattern(), emf.toPattern());
398     }
399 
400     /**
401      * Replace MessageFormat(String, Locale) constructor (not available until JDK 1.4).
402      * @param pattern string
403      * @param locale Locale
404      * @return MessageFormat
405      */
406     private MessageFormat createMessageFormat(final String pattern, final Locale locale) {
407         final MessageFormat result = new MessageFormat(pattern);
408         if (locale != null) {
409             result.setLocale(locale);
410             result.applyPattern(pattern);
411         }
412         return result;
413     }
414 
415     @Test(expected = UnsupportedOperationException.class)
416     public void testSetFormatIsUnsupported() {
417         final ExtendedMessageFormat emf = new ExtendedMessageFormat("");
418         emf.setFormat(0, new LowerCaseFormat());
419     }
420 
421     @Test(expected = UnsupportedOperationException.class)
422     public void testSetFormatByArgumentIndexIsUnsupported() {
423         final ExtendedMessageFormat emf = new ExtendedMessageFormat("");
424         emf.setFormatByArgumentIndex(0, new LowerCaseFormat());
425     }
426 
427     @Test(expected = UnsupportedOperationException.class)
428     public void testSetFormatsIsUnsupported() {
429         final ExtendedMessageFormat emf = new ExtendedMessageFormat("");
430         emf.setFormats(new Format[]{new LowerCaseFormat(), new UpperCaseFormat()});
431     }
432 
433     @Test(expected = UnsupportedOperationException.class)
434     public void testSetFormatsByArgumentIndex() {
435         final ExtendedMessageFormat emf = new ExtendedMessageFormat("");
436         emf.setFormatsByArgumentIndex(new Format[]{new LowerCaseFormat(), new UpperCaseFormat()});
437     }
438 
439     @Test(expected = IllegalArgumentException.class)
440     public void testFailsToCreateExtendedMessageFormatTakingTwoArgumentsThrowsIllegalArgumentExceptionOne() {
441         new ExtendedMessageFormat("agdXdkR;T1{9 ^,LzXf?", new HashMap<String, FormatFactory>());
442     }
443 
444     @Test(expected = IllegalArgumentException.class)
445     public void testFailsToCreateExtendedMessageFormatTakingTwoArgumentsThrowsIllegalArgumentExceptionTwo() {
446         new ExtendedMessageFormat("a5XdkR;T1{9 ,LzXf?", new HashMap<String, FormatFactory>());
447     }
448 
449     @Test(expected = IllegalArgumentException.class)
450     public void testFailsToCreateExtendedMessageFormatTakingTwoArgumentsThrowsIllegalArgumentExceptionThree() {
451         new ExtendedMessageFormat("9jLh_D9{ ", new HashMap<String, FormatFactory>());
452     }
453 
454     @Test(expected = IllegalArgumentException.class)
455     public void testFailsToCreateExtendedMessageFormatTakingTwoArgumentsThrowsIllegalArgumentExceptionFour() {
456         new ExtendedMessageFormat("RD,nXhM{}{", new HashMap<String, FormatFactory>());
457     }
458 
459     @Test(expected = IllegalArgumentException.class)
460     public void testFailsToCreateExtendedMessageFormatTakingTwoArgumentsThrowsIllegalArgumentExceptionFive() {
461         new ExtendedMessageFormat("j/[_D9{0,\"&'+0o", new HashMap<String, FormatFactory>());
462     }
463 
464     @Test
465     public void testCreatesExtendedMessageFormatTakingString() {
466         final ExtendedMessageFormat extendedMessageFormat =
467                 new ExtendedMessageFormat("Unterminated format element at position ");
468         final Map<String, FormatFactory> map = new HashMap<>();
469         final ExtendedMessageFormat extendedMessageFormatTwo =
470                 new ExtendedMessageFormat("Unterminated format element at position ", map);
471 
472         assertEquals("Unterminated format element at position ", extendedMessageFormatTwo.toPattern());
473         assertFalse(extendedMessageFormat.equals(extendedMessageFormatTwo));
474     }
475 
476     // ------------------------ Test Formats ------------------------
477 
478     /**
479      * {@link Format} implementation which converts to lower case.
480      */
481     private static class LowerCaseFormat extends Format {
482         private static final long serialVersionUID = 1L;
483 
484         @Override
485         public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) {
486             return toAppendTo.append(((String) obj).toLowerCase(Locale.ROOT));
487         }
488 
489         @Override
490         public Object parseObject(final String source, final ParsePosition pos) {
491             throw new UnsupportedOperationException();
492         }
493     }
494 
495     /**
496      * {@link Format} implementation which converts to upper case.
497      */
498     private static class UpperCaseFormat extends Format {
499         private static final long serialVersionUID = 1L;
500 
501         @Override
502         public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) {
503             return toAppendTo.append(((String) obj).toUpperCase(Locale.ROOT));
504         }
505 
506         @Override
507         public Object parseObject(final String source, final ParsePosition pos) {
508             throw new UnsupportedOperationException();
509         }
510     }
511 
512 
513     // ------------------------ Test Format Factories ---------------
514     /**
515      * {@link FormatFactory} implementation for lower case format.
516      */
517     private static class LowerCaseFormatFactory implements FormatFactory {
518         private static final Format LOWER_INSTANCE = new LowerCaseFormat();
519         @Override
520         public Format getFormat(final String name, final String arguments, final Locale locale) {
521             return LOWER_INSTANCE;
522         }
523     }
524     /**
525      * {@link FormatFactory} implementation for upper case format.
526      */
527     private static class UpperCaseFormatFactory implements FormatFactory {
528         private static final Format UPPER_INSTANCE = new UpperCaseFormat();
529         @Override
530         public Format getFormat(final String name, final String arguments, final Locale locale) {
531             return UPPER_INSTANCE;
532         }
533     }
534     /**
535      * {@link FormatFactory} implementation to override date format "short" to "default".
536      */
537     private static class OverrideShortDateFormatFactory implements FormatFactory {
538         @Override
539         public Format getFormat(final String name, final String arguments, final Locale locale) {
540             return !"short".equals(arguments) ? null
541                     : locale == null ? DateFormat
542                             .getDateInstance(DateFormat.DEFAULT) : DateFormat
543                             .getDateInstance(DateFormat.DEFAULT, locale);
544         }
545     }
546 
547     /**
548      * Alternative ExtendedMessageFormat impl.
549      */
550     private static class OtherExtendedMessageFormat extends ExtendedMessageFormat {
551         private static final long serialVersionUID = 1L;
552 
553         OtherExtendedMessageFormat(final String pattern, final Locale locale,
554                 final Map<String, ? extends FormatFactory> registry) {
555             super(pattern, locale, registry);
556         }
557     }
558 
559 }