You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Hyphenator.java 9.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  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. /* $Id$ */
  18. package org.apache.fop.hyphenation;
  19. import java.io.BufferedInputStream;
  20. import java.io.IOException;
  21. import java.io.InputStream;
  22. import java.io.ObjectInputStream;
  23. import java.net.URISyntaxException;
  24. import java.util.Map;
  25. import org.xml.sax.InputSource;
  26. import org.apache.commons.io.IOUtils;
  27. import org.apache.commons.logging.Log;
  28. import org.apache.commons.logging.LogFactory;
  29. import org.apache.fop.ResourceEventProducer;
  30. import org.apache.fop.apps.FOUserAgent;
  31. import org.apache.fop.apps.io.InternalResourceResolver;
  32. import org.apache.fop.events.EventBroadcaster;
  33. /**
  34. * <p>This class is the main entry point to the hyphenation package.
  35. * You can use only the static methods or create an instance.</p>
  36. *
  37. * <p>This work was authored by Carlos Villegas (cav@uniscope.co.jp).</p>
  38. */
  39. public final class Hyphenator {
  40. /** logging instance */
  41. private static final Log log = LogFactory.getLog(Hyphenator.class);
  42. /** Enables a dump of statistics. Note: If activated content is sent to System.out! */
  43. private static boolean statisticsDump;
  44. public static final String HYPTYPE = Hyphenator.class.toString() + "HYP";
  45. public static final String XMLTYPE = Hyphenator.class.toString() + "XML";
  46. private Hyphenator() {
  47. }
  48. public static HyphenationTree getHyphenationTree(String lang, String country,
  49. InternalResourceResolver resourceResolver, Map hyphPatNames, FOUserAgent foUserAgent) {
  50. String llccKey = HyphenationTreeCache.constructLlccKey(lang, country);
  51. HyphenationTreeCache cache = foUserAgent.getHyphenationTreeCache();
  52. // See if there was an error finding this hyphenation tree before
  53. if (cache == null || cache.isMissing(llccKey)) {
  54. return null;
  55. }
  56. HyphenationTree hTree;
  57. // first try to find it in the cache
  58. hTree = cache.getHyphenationTree(lang, country);
  59. if (hTree != null) {
  60. return hTree;
  61. }
  62. String key = HyphenationTreeCache.constructUserKey(lang, country, hyphPatNames);
  63. if (key == null) {
  64. key = llccKey;
  65. }
  66. if (resourceResolver != null) {
  67. hTree = getUserHyphenationTree(key, resourceResolver);
  68. }
  69. if (hTree == null) {
  70. hTree = getFopHyphenationTree(key);
  71. }
  72. if (hTree == null && country != null && !country.equals("none")) {
  73. return getHyphenationTree(lang, null, resourceResolver, hyphPatNames, foUserAgent);
  74. }
  75. // put it into the pattern cache
  76. if (hTree != null) {
  77. cache.cache(llccKey, hTree);
  78. } else {
  79. EventBroadcaster eventBroadcaster = foUserAgent.getEventBroadcaster();
  80. if (eventBroadcaster == null) {
  81. log.error("Couldn't find hyphenation pattern " + llccKey);
  82. } else {
  83. ResourceEventProducer producer = ResourceEventProducer.Provider.get(eventBroadcaster);
  84. String name = key.replace(HYPTYPE, "").replace(XMLTYPE, "");
  85. producer.hyphenationNotFound(cache, name);
  86. }
  87. cache.noteMissing(llccKey);
  88. }
  89. return hTree;
  90. }
  91. private static InputStream getResourceStream(String key) {
  92. InputStream is = null;
  93. // Try to use Context Class Loader to load the properties file.
  94. try {
  95. java.lang.reflect.Method getCCL = Thread.class.getMethod(
  96. "getContextClassLoader", new Class[0]);
  97. if (getCCL != null) {
  98. ClassLoader contextClassLoader = (ClassLoader)getCCL.invoke(
  99. Thread.currentThread(),
  100. new Object[0]);
  101. is = contextClassLoader.getResourceAsStream("hyph/" + key
  102. + ".hyp");
  103. }
  104. } catch (NoSuchMethodException e) {
  105. //ignore, fallback further down
  106. } catch (IllegalAccessException e) {
  107. //ignore, fallback further down
  108. } catch (java.lang.reflect.InvocationTargetException e) {
  109. //ignore, fallback further down
  110. }
  111. if (is == null) {
  112. is = Hyphenator.class.getResourceAsStream("/hyph/" + key
  113. + ".hyp");
  114. }
  115. return is;
  116. }
  117. private static HyphenationTree readHyphenationTree(InputStream in) {
  118. HyphenationTree hTree = null;
  119. try {
  120. ObjectInputStream ois = new ObjectInputStream(in);
  121. hTree = (HyphenationTree)ois.readObject();
  122. } catch (IOException ioe) {
  123. log.error("I/O error while loading precompiled hyphenation pattern file", ioe);
  124. } catch (ClassNotFoundException cnfe) {
  125. log.error("Error while reading hyphenation object from file", cnfe);
  126. }
  127. return hTree;
  128. }
  129. /**
  130. * Returns a hyphenation tree. This method looks in the resources (getResourceStream) for
  131. * the hyphenation patterns.
  132. * @param key the language/country key
  133. * @return the hyphenation tree or null if it wasn't found in the resources
  134. */
  135. public static HyphenationTree getFopHyphenationTree(String key) {
  136. InputStream is = getResourceStream(key);
  137. if (is == null) {
  138. if (log.isDebugEnabled()) {
  139. log.debug("Couldn't find precompiled hyphenation pattern "
  140. + key + " in resources");
  141. }
  142. return null;
  143. }
  144. return readHyphenationTree(is);
  145. }
  146. /**
  147. * Load tree from serialized file or xml file
  148. * using configuration settings
  149. * @param key language key for the requested hyphenation file
  150. * @param resourceResolver resource resolver to find the hyphenation files
  151. * @return the requested HypenationTree or null if it is not available
  152. */
  153. public static HyphenationTree getUserHyphenationTree(String key,
  154. InternalResourceResolver resourceResolver) {
  155. HyphenationTree hTree = null;
  156. // I use here the following convention. The file name specified in
  157. // the configuration is taken as the base name. First we try
  158. // name + ".hyp" assuming a serialized HyphenationTree. If that fails
  159. // we try name + ".xml", assumming a raw hyphenation pattern file.
  160. // first try serialized object
  161. String name = key + ".hyp";
  162. if (key.endsWith(HYPTYPE)) {
  163. name = key.replace(HYPTYPE, "");
  164. }
  165. if (!key.endsWith(XMLTYPE)) {
  166. try {
  167. InputStream in = getHyphenationTreeStream(name, resourceResolver);
  168. try {
  169. hTree = readHyphenationTree(in);
  170. } finally {
  171. IOUtils.closeQuietly(in);
  172. }
  173. return hTree;
  174. } catch (IOException ioe) {
  175. if (log.isDebugEnabled()) {
  176. log.debug("I/O problem while trying to load " + name, ioe);
  177. }
  178. }
  179. }
  180. // try the raw XML file
  181. name = key + ".xml";
  182. if (key.endsWith(XMLTYPE)) {
  183. name = key.replace(XMLTYPE, "");
  184. }
  185. hTree = new HyphenationTree();
  186. try {
  187. InputStream in = getHyphenationTreeStream(name, resourceResolver);
  188. try {
  189. InputSource src = new InputSource(in);
  190. src.setSystemId(name);
  191. hTree.loadPatterns(src);
  192. } finally {
  193. IOUtils.closeQuietly(in);
  194. }
  195. if (statisticsDump) {
  196. System.out.println("Stats: ");
  197. hTree.printStats();
  198. }
  199. return hTree;
  200. } catch (HyphenationException ex) {
  201. log.error("Can't load user patterns from XML file " + name + ": " + ex.getMessage());
  202. return null;
  203. } catch (IOException ioe) {
  204. if (log.isDebugEnabled()) {
  205. log.debug("I/O problem while trying to load " + name, ioe);
  206. }
  207. return null;
  208. }
  209. }
  210. private static InputStream getHyphenationTreeStream(String name,
  211. InternalResourceResolver resourceResolver) throws IOException {
  212. try {
  213. return new BufferedInputStream(resourceResolver.getResource(name));
  214. } catch (URISyntaxException use) {
  215. log.debug("An exception was thrown while attempting to load " + name, use);
  216. }
  217. return null;
  218. }
  219. public static Hyphenation hyphenate(String lang, String country, InternalResourceResolver resourceResolver,
  220. Map hyphPatNames,
  221. String word,
  222. int leftMin, int rightMin, FOUserAgent foUserAgent) {
  223. HyphenationTree hTree = getHyphenationTree(lang, country, resourceResolver, hyphPatNames, foUserAgent);
  224. if (hTree == null) {
  225. return null;
  226. }
  227. return hTree.hyphenate(word, leftMin, rightMin);
  228. }
  229. }