1 /* 2 ******************************************************************************* 3 * Copyright (C) 2002-2015, International Business Machines Corporation and 4 * others. All Rights Reserved. 5 ******************************************************************************* 6 */ 7 8 package com.ibm.icu.text; 9 10 import java.io.IOException; 11 import java.nio.ByteBuffer; 12 import java.util.Locale; 13 import java.util.MissingResourceException; 14 15 import com.ibm.icu.impl.Assert; 16 import com.ibm.icu.impl.ICUBinary; 17 import com.ibm.icu.impl.ICUData; 18 import com.ibm.icu.impl.ICULocaleService; 19 import com.ibm.icu.impl.ICUResourceBundle; 20 import com.ibm.icu.impl.ICUService; 21 import com.ibm.icu.impl.ICUService.Factory; 22 import com.ibm.icu.util.ULocale; 23 24 /** 25 * @author Ram 26 * 27 * To change this generated comment edit the template variable "typecomment": 28 * Window>Preferences>Java>Templates. 29 * To enable and disable the creation of type comments go to 30 * Window>Preferences>Java>Code Generation. 31 */ 32 final class BreakIteratorFactory extends BreakIterator.BreakIteratorServiceShim { 33 registerInstance(BreakIterator iter, ULocale locale, int kind)34 public Object registerInstance(BreakIterator iter, ULocale locale, int kind) { 35 iter.setText(new java.text.StringCharacterIterator("")); 36 return service.registerObject(iter, locale, kind); 37 } 38 unregister(Object key)39 public boolean unregister(Object key) { 40 if (service.isDefault()) { 41 return false; 42 } 43 return service.unregisterFactory((Factory)key); 44 } 45 getAvailableLocales()46 public Locale[] getAvailableLocales() { 47 if (service == null) { 48 return ICUResourceBundle.getAvailableLocales(); 49 } else { 50 return service.getAvailableLocales(); 51 } 52 } 53 getAvailableULocales()54 public ULocale[] getAvailableULocales() { 55 if (service == null) { 56 return ICUResourceBundle.getAvailableULocales(); 57 } else { 58 return service.getAvailableULocales(); 59 } 60 } 61 createBreakIterator(ULocale locale, int kind)62 public BreakIterator createBreakIterator(ULocale locale, int kind) { 63 // TODO: convert to ULocale when service switches over 64 if (service.isDefault()) { 65 return createBreakInstance(locale, kind); 66 } 67 ULocale[] actualLoc = new ULocale[1]; 68 BreakIterator iter = (BreakIterator)service.get(locale, kind, actualLoc); 69 iter.setLocale(actualLoc[0], actualLoc[0]); // services make no distinction between actual & valid 70 return iter; 71 } 72 73 private static class BFService extends ICULocaleService { BFService()74 BFService() { 75 super("BreakIterator"); 76 77 class RBBreakIteratorFactory extends ICUResourceBundleFactory { 78 protected Object handleCreate(ULocale loc, int kind, ICUService srvc) { 79 return createBreakInstance(loc, kind); 80 } 81 } 82 registerFactory(new RBBreakIteratorFactory()); 83 84 markDefault(); 85 } 86 87 /** 88 * createBreakInstance() returns an appropriate BreakIterator for any locale. 89 * It falls back to root if there is no specific data. 90 * 91 * <p>Without this override, the service code would fall back to the default locale 92 * which is not desirable for an algorithm with a good Unicode default, 93 * like break iteration. 94 */ 95 @Override validateFallbackLocale()96 public String validateFallbackLocale() { 97 return ""; 98 } 99 } 100 static final ICULocaleService service = new BFService(); 101 102 103 /** KIND_NAMES are the resource key to be used to fetch the name of the 104 * pre-compiled break rules. The resource bundle name is "boundaries". 105 * The value for each key will be the rules to be used for the 106 * specified locale - "word" -> "word_th" for Thai, for example. 107 */ 108 private static final String[] KIND_NAMES = { 109 "grapheme", "word", "line", "sentence", "title" 110 }; 111 112 createBreakInstance(ULocale locale, int kind)113 private static BreakIterator createBreakInstance(ULocale locale, int kind) { 114 115 RuleBasedBreakIterator iter = null; 116 ICUResourceBundle rb = (ICUResourceBundle)ICUResourceBundle. 117 getBundleInstance(ICUResourceBundle.ICU_BRKITR_BASE_NAME, locale, 118 ICUResourceBundle.OpenType.LOCALE_ROOT); 119 120 // 121 // Get the binary rules. 122 // 123 ByteBuffer bytes = null; 124 String typeKeyExt = null; 125 if (kind == BreakIterator.KIND_LINE) { 126 String lbKeyValue = locale.getKeywordValue("lb"); 127 if ( lbKeyValue != null && (lbKeyValue.equals("strict") || lbKeyValue.equals("normal") || lbKeyValue.equals("loose")) ) { 128 typeKeyExt = "_" + lbKeyValue; 129 } 130 } 131 try { 132 String typeKey = (typeKeyExt == null)? KIND_NAMES[kind]: KIND_NAMES[kind] + typeKeyExt; 133 String brkfname = rb.getStringWithFallback("boundaries/" + typeKey); 134 String rulesFileName = ICUData.ICU_BRKITR_NAME+ '/' + brkfname; 135 bytes = ICUBinary.getData(rulesFileName); 136 } 137 catch (Exception e) { 138 throw new MissingResourceException(e.toString(),"",""); 139 } 140 141 // 142 // Create a normal RuleBasedBreakIterator. 143 // 144 try { 145 iter = RuleBasedBreakIterator.getInstanceFromCompiledRules(bytes); 146 } 147 catch (IOException e) { 148 // Shouldn't be possible to get here. 149 // If it happens, the compiled rules are probably corrupted in some way. 150 Assert.fail(e); 151 } 152 // TODO: Determine valid and actual locale correctly. 153 ULocale uloc = ULocale.forLocale(rb.getLocale()); 154 iter.setLocale(uloc, uloc); 155 iter.setBreakType(kind); 156 157 return iter; 158 159 } 160 161 } 162