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.

RendererFactory.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  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.render;
  19. import java.io.OutputStream;
  20. import java.util.Collections;
  21. import java.util.Iterator;
  22. import java.util.List;
  23. import java.util.Map;
  24. import org.apache.commons.logging.Log;
  25. import org.apache.commons.logging.LogFactory;
  26. import org.apache.xmlgraphics.util.Service;
  27. import org.apache.fop.apps.FOPException;
  28. import org.apache.fop.apps.FOUserAgent;
  29. import org.apache.fop.area.AreaTreeHandler;
  30. import org.apache.fop.fo.FOEventHandler;
  31. /**
  32. * Factory for FOEventHandlers and Renderers.
  33. */
  34. public class RendererFactory {
  35. /** the logger */
  36. private static Log log = LogFactory.getLog(RendererFactory.class);
  37. private Map rendererMakerMapping = new java.util.HashMap();
  38. private Map eventHandlerMakerMapping = new java.util.HashMap();
  39. /**
  40. * Main constructor.
  41. */
  42. public RendererFactory() {
  43. discoverRenderers();
  44. discoverFOEventHandlers();
  45. }
  46. /**
  47. * Add a new RendererMaker. If another maker has already been registered for a
  48. * particular MIME type, this call overwrites the existing one.
  49. * @param maker the RendererMaker
  50. */
  51. public void addRendererMaker(AbstractRendererMaker maker) {
  52. String[] mimes = maker.getSupportedMimeTypes();
  53. for (int i = 0; i < mimes.length; i++) {
  54. //This overrides any renderer previously set for a MIME type
  55. if (rendererMakerMapping.get(mimes[i]) != null) {
  56. log.trace("Overriding renderer for " + mimes[i]
  57. + " with " + maker.getClass().getName());
  58. }
  59. rendererMakerMapping.put(mimes[i], maker);
  60. }
  61. }
  62. /**
  63. * Add a new FOEventHandlerMaker. If another maker has already been registered for a
  64. * particular MIME type, this call overwrites the existing one.
  65. * @param maker the FOEventHandlerMaker
  66. */
  67. public void addFOEventHandlerMaker(AbstractFOEventHandlerMaker maker) {
  68. String[] mimes = maker.getSupportedMimeTypes();
  69. for (int i = 0; i < mimes.length; i++) {
  70. //This overrides any event handler previously set for a MIME type
  71. if (eventHandlerMakerMapping.get(mimes[i]) != null) {
  72. log.trace("Overriding FOEventHandler for " + mimes[i]
  73. + " with " + maker.getClass().getName());
  74. }
  75. eventHandlerMakerMapping.put(mimes[i], maker);
  76. }
  77. }
  78. /**
  79. * Add a new RendererMaker. If another maker has already been registered for a
  80. * particular MIME type, this call overwrites the existing one.
  81. * @param className the fully qualified class name of the RendererMaker
  82. */
  83. public void addRendererMaker(String className) {
  84. try {
  85. AbstractRendererMaker makerInstance
  86. = (AbstractRendererMaker)Class.forName(className).newInstance();
  87. addRendererMaker(makerInstance);
  88. } catch (ClassNotFoundException e) {
  89. throw new IllegalArgumentException("Could not find "
  90. + className);
  91. } catch (InstantiationException e) {
  92. throw new IllegalArgumentException("Could not instantiate "
  93. + className);
  94. } catch (IllegalAccessException e) {
  95. throw new IllegalArgumentException("Could not access "
  96. + className);
  97. } catch (ClassCastException e) {
  98. throw new IllegalArgumentException(className
  99. + " is not an "
  100. + AbstractRendererMaker.class.getName());
  101. }
  102. }
  103. /**
  104. * Add a new FOEventHandlerMaker. If another maker has already been registered for a
  105. * particular MIME type, this call overwrites the existing one.
  106. * @param className the fully qualified class name of the FOEventHandlerMaker
  107. */
  108. public void addFOEventHandlerMaker(String className) {
  109. try {
  110. AbstractFOEventHandlerMaker makerInstance
  111. = (AbstractFOEventHandlerMaker)Class.forName(className).newInstance();
  112. addFOEventHandlerMaker(makerInstance);
  113. } catch (ClassNotFoundException e) {
  114. throw new IllegalArgumentException("Could not find "
  115. + className);
  116. } catch (InstantiationException e) {
  117. throw new IllegalArgumentException("Could not instantiate "
  118. + className);
  119. } catch (IllegalAccessException e) {
  120. throw new IllegalArgumentException("Could not access "
  121. + className);
  122. } catch (ClassCastException e) {
  123. throw new IllegalArgumentException(className
  124. + " is not an "
  125. + AbstractFOEventHandlerMaker.class.getName());
  126. }
  127. }
  128. /**
  129. * Returns a RendererMaker which handles the given MIME type.
  130. * @param mime the requested output format
  131. * @return the requested RendererMaker or null if none is available
  132. */
  133. public AbstractRendererMaker getRendererMaker(String mime) {
  134. AbstractRendererMaker maker
  135. = (AbstractRendererMaker)rendererMakerMapping.get(mime);
  136. return maker;
  137. }
  138. /**
  139. * Returns a FOEventHandlerMaker which handles the given MIME type.
  140. * @param mime the requested output format
  141. * @return the requested FOEventHandlerMaker or null if none is available
  142. */
  143. public AbstractFOEventHandlerMaker getFOEventHandlerMaker(String mime) {
  144. AbstractFOEventHandlerMaker maker
  145. = (AbstractFOEventHandlerMaker)eventHandlerMakerMapping.get(mime);
  146. return maker;
  147. }
  148. /**
  149. * Creates a Renderer object based on render-type desired
  150. * @param userAgent the user agent for access to configuration
  151. * @param outputFormat the MIME type of the output format to use (ex. "application/pdf").
  152. * @return the new Renderer instance
  153. * @throws FOPException if the renderer cannot be properly constructed
  154. */
  155. public Renderer createRenderer(FOUserAgent userAgent, String outputFormat)
  156. throws FOPException {
  157. if (userAgent.getRendererOverride() != null) {
  158. return userAgent.getRendererOverride();
  159. } else {
  160. AbstractRendererMaker maker = getRendererMaker(outputFormat);
  161. if (maker == null) {
  162. throw new UnsupportedOperationException(
  163. "No renderer for the requested format available: " + outputFormat);
  164. }
  165. Renderer rend = maker.makeRenderer(userAgent);
  166. rend.setUserAgent(userAgent);
  167. RendererConfigurator configurator = maker.getConfigurator(userAgent);
  168. if (configurator != null) {
  169. configurator.configure(rend);
  170. }
  171. return rend;
  172. }
  173. }
  174. /**
  175. * Creates FOEventHandler instances based on the desired output.
  176. * @param userAgent the user agent for access to configuration
  177. * @param outputFormat the MIME type of the output format to use (ex. "application/pdf").
  178. * @param out the OutputStream where the output is written to (if applicable)
  179. * @return the newly constructed FOEventHandler
  180. * @throws FOPException if the FOEventHandler cannot be properly constructed
  181. */
  182. public FOEventHandler createFOEventHandler(FOUserAgent userAgent,
  183. String outputFormat, OutputStream out) throws FOPException {
  184. if (userAgent.getFOEventHandlerOverride() != null) {
  185. return userAgent.getFOEventHandlerOverride();
  186. } else {
  187. AbstractFOEventHandlerMaker maker = getFOEventHandlerMaker(outputFormat);
  188. if (maker == null) {
  189. AbstractRendererMaker rendMaker = getRendererMaker(outputFormat);
  190. if (rendMaker == null && userAgent.getRendererOverride() == null) {
  191. throw new UnsupportedOperationException(
  192. "Don't know how to handle \"" + outputFormat + "\" as an output format."
  193. + " Neither an FOEventHandler, nor a Renderer could be found"
  194. + " for this output format.");
  195. } else {
  196. if (out == null
  197. && userAgent.getRendererOverride() == null
  198. && rendMaker.needsOutputStream()) {
  199. throw new FOPException(
  200. "OutputStream has not been set");
  201. }
  202. //Found a Renderer so we need to construct an AreaTreeHandler.
  203. return new AreaTreeHandler(userAgent, outputFormat, out);
  204. }
  205. } else {
  206. return maker.makeFOEventHandler(userAgent, out);
  207. }
  208. }
  209. }
  210. /**
  211. * @return an array of all supported MIME types
  212. */
  213. public String[] listSupportedMimeTypes() {
  214. List lst = new java.util.ArrayList();
  215. Iterator iter = this.rendererMakerMapping.keySet().iterator();
  216. while (iter.hasNext()) {
  217. lst.add(((String)iter.next()));
  218. }
  219. iter = this.eventHandlerMakerMapping.keySet().iterator();
  220. while (iter.hasNext()) {
  221. lst.add(((String)iter.next()));
  222. }
  223. Collections.sort(lst);
  224. return (String[])lst.toArray(new String[lst.size()]);
  225. }
  226. /**
  227. * Discovers Renderer implementations through the classpath and dynamically
  228. * registers them.
  229. */
  230. private void discoverRenderers() {
  231. // add mappings from available services
  232. Iterator providers
  233. = Service.providers(Renderer.class);
  234. if (providers != null) {
  235. while (providers.hasNext()) {
  236. AbstractRendererMaker maker = (AbstractRendererMaker)providers.next();
  237. try {
  238. if (log.isDebugEnabled()) {
  239. log.debug("Dynamically adding maker for Renderer: "
  240. + maker.getClass().getName());
  241. }
  242. addRendererMaker(maker);
  243. } catch (IllegalArgumentException e) {
  244. log.error("Error while adding maker for Renderer", e);
  245. }
  246. }
  247. }
  248. }
  249. /**
  250. * Discovers FOEventHandler implementations through the classpath and dynamically
  251. * registers them.
  252. */
  253. private void discoverFOEventHandlers() {
  254. // add mappings from available services
  255. Iterator providers
  256. = Service.providers(FOEventHandler.class);
  257. if (providers != null) {
  258. while (providers.hasNext()) {
  259. AbstractFOEventHandlerMaker maker = (AbstractFOEventHandlerMaker)providers.next();
  260. try {
  261. if (log.isDebugEnabled()) {
  262. log.debug("Dynamically adding maker for FOEventHandler: "
  263. + maker.getClass().getName());
  264. }
  265. addFOEventHandlerMaker(maker);
  266. } catch (IllegalArgumentException e) {
  267. log.error("Error while adding maker for FOEventHandler", e);
  268. }
  269. }
  270. }
  271. }
  272. }