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.

FOUserAgent.java 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. /*
  2. * Copyright 1999-2005 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /* $Id$ */
  17. package org.apache.fop.apps;
  18. // Java
  19. import java.io.File;
  20. import java.io.IOException;
  21. import java.net.URL;
  22. import java.net.MalformedURLException;
  23. import java.util.Date;
  24. import java.util.List;
  25. import java.util.Map;
  26. import javax.xml.transform.Source;
  27. import javax.xml.transform.TransformerException;
  28. import javax.xml.transform.URIResolver;
  29. // avalon configuration
  30. import org.apache.avalon.framework.configuration.Configuration;
  31. import org.apache.avalon.framework.configuration.ConfigurationException;
  32. // commons logging
  33. import org.apache.commons.logging.Log;
  34. import org.apache.commons.logging.LogFactory;
  35. // FOP
  36. import org.apache.fop.fo.ElementMapping;
  37. import org.apache.fop.fo.FOEventHandler;
  38. import org.apache.fop.layoutmgr.LayoutManagerMaker;
  39. import org.apache.fop.pdf.PDFEncryptionParams;
  40. import org.apache.fop.render.Renderer;
  41. import org.apache.fop.render.RendererFactory;
  42. import org.apache.fop.render.XMLHandlerRegistry;
  43. /**
  44. * The User Agent for fo.
  45. * This user agent is used by the processing to obtain user configurable
  46. * options.
  47. * <p>
  48. * Renderer specific extensions (that do not produce normal areas on
  49. * the output) will be done like so:
  50. * <br>
  51. * The extension will create an area, custom if necessary
  52. * <br>
  53. * this area will be added to the user agent with a key
  54. * <br>
  55. * the renderer will know keys for particular extensions
  56. * <br>
  57. * eg. bookmarks will be held in a special hierarchical area representing
  58. * the title and bookmark structure
  59. * <br>
  60. * These areas may contain resolvable areas that will be processed
  61. * with other resolvable areas
  62. */
  63. public class FOUserAgent {
  64. /** Defines the default resolution (72dpi) for FOP */
  65. public static final float DEFAULT_RESOLUTION = 72.0f; //dpi
  66. /** Defines the default resolution (72dpi) for FOP */
  67. public static final float DEFAULT_PX2MM = (25.4f / DEFAULT_RESOLUTION); //dpi (=25.4/dpi)
  68. /** Defines the default page-height */
  69. public static final String DEFAULT_PAGE_HEIGHT = "11in";
  70. /** Defines the default page-width */
  71. public static final String DEFAULT_PAGE_WIDTH = "8.26in";
  72. /** Factory for Renderers and FOEventHandlers */
  73. private RendererFactory rendererFactory = new RendererFactory();
  74. /** Registry for XML handlers */
  75. private XMLHandlerRegistry xmlHandlers = new XMLHandlerRegistry();
  76. private String baseURL;
  77. /** A user settable URI Resolver */
  78. private URIResolver uriResolver = null;
  79. /** Our default resolver if none is set */
  80. private URIResolver foURIResolver = new FOURIResolver();
  81. private PDFEncryptionParams pdfEncryptionParams;
  82. private float resolution = DEFAULT_RESOLUTION;
  83. private String pageHeight = DEFAULT_PAGE_HEIGHT;
  84. private String pageWidth = DEFAULT_PAGE_WIDTH;
  85. private Map rendererOptions = new java.util.HashMap();
  86. private File outputFile = null;
  87. private Renderer rendererOverride = null;
  88. private FOEventHandler foEventHandlerOverride = null;
  89. private LayoutManagerMaker lmMakerOverride = null;
  90. /* user configuration */
  91. private Configuration userConfig = null;
  92. private Log log = LogFactory.getLog("FOP");
  93. /* FOP has the ability, for some FO's, to continue processing even if the
  94. * input XSL violates that FO's content model. This is the default
  95. * behavior for FOP. However, this flag, if set, provides the user the
  96. * ability for FOP to halt on all content model violations if desired.
  97. */
  98. private boolean strictValidation = true;
  99. /* Additional fo.ElementMapping subclasses set by user */
  100. private List additionalElementMappings = null;
  101. /** Producer: Metadata element for the system/software that produces
  102. * the document. (Some renderers can store this in the document.)
  103. */
  104. protected String producer = "Apache FOP Version " + Fop.getVersion();
  105. /** Creator: Metadata element for the user that created the
  106. * document. (Some renderers can store this in the document.)
  107. */
  108. protected String creator = null;
  109. /** Creation Date: Override of the date the document was created.
  110. * (Some renderers can store this in the document.)
  111. */
  112. protected Date creationDate = null;
  113. /** Author of the content of the document. */
  114. protected String author = null;
  115. /** Title of the document. */
  116. protected String title = null;
  117. /** Set of keywords applicable to this document. */
  118. protected String keywords = null;
  119. /**
  120. * Add the element mapping with the given class name.
  121. * @param elementMapping the class name representing the element mapping.
  122. */
  123. public void addElementMapping(ElementMapping elementMapping) {
  124. if (additionalElementMappings == null) {
  125. additionalElementMappings = new java.util.ArrayList();
  126. }
  127. additionalElementMappings.add(elementMapping);
  128. }
  129. /**
  130. * Returns the List of user-added ElementMapping class names
  131. * @return List of Strings holding ElementMapping names.
  132. */
  133. public List getAdditionalElementMappings() {
  134. return additionalElementMappings;
  135. }
  136. /**
  137. * Sets an explicit renderer to use which overrides the one defined by the
  138. * render type setting.
  139. * @param renderer the Renderer instance to use
  140. */
  141. public void setRendererOverride(Renderer renderer) {
  142. this.rendererOverride = renderer;
  143. }
  144. /**
  145. * Returns the overriding Renderer instance, if any.
  146. * @return the overriding Renderer or null
  147. */
  148. public Renderer getRendererOverride() {
  149. return rendererOverride;
  150. }
  151. /**
  152. * Sets an explicit FOEventHandler instance which overrides the one
  153. * defined by the render type setting.
  154. * @param handler the FOEventHandler instance
  155. */
  156. public void setFOEventHandlerOverride(FOEventHandler handler) {
  157. this.foEventHandlerOverride = handler;
  158. }
  159. /**
  160. * Returns the overriding FOEventHandler instance, if any.
  161. * @return the overriding FOEventHandler or null
  162. */
  163. public FOEventHandler getFOEventHandlerOverride() {
  164. return this.foEventHandlerOverride;
  165. }
  166. /**
  167. * Activates strict XSL content model validation for FOP
  168. * Default is false (FOP will continue processing where it can)
  169. * @param validateStrictly true to turn on strict validation
  170. */
  171. public void setStrictValidation(boolean validateStrictly) {
  172. this.strictValidation = validateStrictly;
  173. }
  174. /**
  175. * Returns whether FOP is strictly validating input XSL
  176. * @return true of strict validation turned on, false otherwise
  177. */
  178. public boolean validateStrictly() {
  179. return strictValidation;
  180. }
  181. /**
  182. * Sets an explicit LayoutManagerMaker instance which overrides the one
  183. * defined by the AreaTreeHandler.
  184. * @param lmMaker the LayoutManagerMaker instance
  185. */
  186. public void setLayoutManagerMakerOverride(LayoutManagerMaker lmMaker) {
  187. this.lmMakerOverride = lmMaker;
  188. }
  189. /**
  190. * Returns the overriding LayoutManagerMaker instance, if any.
  191. * @return the overriding LayoutManagerMaker or null
  192. */
  193. public LayoutManagerMaker getLayoutManagerMakerOverride() {
  194. return this.lmMakerOverride;
  195. }
  196. /**
  197. * Sets the producer of the document.
  198. * @param producer source of document
  199. */
  200. public void setProducer(String producer) {
  201. this.producer = producer;
  202. }
  203. /**
  204. * Returns the producer of the document
  205. * @return producer name
  206. */
  207. public String getProducer() {
  208. return producer;
  209. }
  210. /**
  211. * Sets the creator of the document.
  212. * @param creator of document
  213. */
  214. public void setCreator(String creator) {
  215. this.creator = creator;
  216. }
  217. /**
  218. * Returns the creator of the document
  219. * @return creator name
  220. */
  221. public String getCreator() {
  222. return creator;
  223. }
  224. /**
  225. * Sets the creation date of the document.
  226. * @param creationDate date of document
  227. */
  228. public void setCreationDate(Date creationDate) {
  229. this.creationDate = creationDate;
  230. }
  231. /**
  232. * Returns the creation date of the document
  233. * @return creation date of document
  234. */
  235. public Date getCreationDate() {
  236. return creationDate;
  237. }
  238. /**
  239. * Sets the author of the document.
  240. * @param author of document
  241. */
  242. public void setAuthor(String author) {
  243. this.author = author;
  244. }
  245. /**
  246. * Returns the author of the document
  247. * @return author name
  248. */
  249. public String getAuthor() {
  250. return author;
  251. }
  252. /**
  253. * Sets the title of the document. This will override any title coming from
  254. * an fo:title element.
  255. * @param title of document
  256. */
  257. public void setTitle(String title) {
  258. this.title = title;
  259. }
  260. /**
  261. * Returns the title of the document
  262. * @return title name
  263. */
  264. public String getTitle() {
  265. return title;
  266. }
  267. /**
  268. * Sets the keywords for the document.
  269. * @param keywords for the document
  270. */
  271. public void setKeywords(String keywords) {
  272. this.keywords = keywords;
  273. }
  274. /**
  275. * Returns the keywords for the document
  276. * @return the keywords
  277. */
  278. public String getKeywords() {
  279. return keywords;
  280. }
  281. /**
  282. * Returns the renderer options
  283. * @return renderer options
  284. */
  285. public Map getRendererOptions() {
  286. return rendererOptions;
  287. }
  288. /**
  289. * Set the user configuration.
  290. * @param userConfig configuration
  291. */
  292. public void setUserConfig(Configuration userConfig) {
  293. this.userConfig = userConfig;
  294. try {
  295. initUserConfig();
  296. } catch (ConfigurationException cfge) {
  297. log.error("Error initializing User Agent configuration: "
  298. + cfge.getMessage());
  299. }
  300. }
  301. /**
  302. * Get the user configuration.
  303. * @return the user configuration
  304. */
  305. public Configuration getUserConfig() {
  306. return userConfig;
  307. }
  308. /**
  309. * Initializes user agent settings from the user configuration
  310. * file, if present: baseURL, resolution, default page size,...
  311. *
  312. * @throws ConfigurationException when there is an entry that
  313. * misses the required attribute
  314. */
  315. public void initUserConfig() throws ConfigurationException {
  316. log.info("Initializing User Agent Configuration");
  317. if (userConfig.getChild("base", false) != null) {
  318. try {
  319. String cfgBaseDir = userConfig.getChild("base").getValue(null);
  320. if (cfgBaseDir != null) {
  321. File dir = new File(cfgBaseDir);
  322. if (dir.isDirectory()) {
  323. cfgBaseDir = "file://" + dir.getCanonicalPath()
  324. + System.getProperty("file.separator");
  325. cfgBaseDir = cfgBaseDir.replace(
  326. System.getProperty("file.separator").charAt(0), '/');
  327. } else {
  328. //The next statement is for validation only
  329. new URL(cfgBaseDir);
  330. }
  331. }
  332. setBaseURL(cfgBaseDir);
  333. } catch (MalformedURLException mue) {
  334. log.error("Base URL in user config is malformed!");
  335. } catch (IOException ioe) {
  336. log.error("Error converting relative base directory to absolute URL.");
  337. }
  338. log.info("Base URL set to: " + baseURL);
  339. }
  340. if (userConfig.getChild("pixelToMillimeter", false) != null) {
  341. this.resolution = 25.4f / userConfig.getChild("pixelToMillimeter")
  342. .getAttributeAsFloat("value", DEFAULT_PX2MM);
  343. log.info("resolution set to: " + resolution
  344. + "dpi (px2mm=" + getPixelUnitToMillimeter() + ")");
  345. } else if (userConfig.getChild("resolution", false) != null) {
  346. this.resolution
  347. = 25.4f / userConfig.getChild("resolution").getValueAsFloat(DEFAULT_RESOLUTION);
  348. log.info("resolution set to: " + resolution
  349. + "dpi (px2mm=" + getPixelUnitToMillimeter() + ")");
  350. }
  351. Configuration pageConfig = userConfig.getChild("default-page-settings");
  352. if (pageConfig.getAttribute("height", null) != null) {
  353. setPageHeight(pageConfig.getAttribute("height"));
  354. log.info("Default page-height set to: " + pageHeight);
  355. }
  356. if (pageConfig.getAttribute("width", null) != null) {
  357. setPageWidth(pageConfig.getAttribute("width"));
  358. log.info("Default page-width set to: " + pageWidth);
  359. }
  360. }
  361. /**
  362. * Returns the configuration subtree for a specific renderer.
  363. * @param mimeType MIME type of the renderer
  364. * @return the requested configuration subtree, null if there's no configuration
  365. */
  366. public Configuration getUserRendererConfig (String mimeType) {
  367. if (userConfig == null || mimeType == null) {
  368. return null;
  369. }
  370. Configuration userRendererConfig = null;
  371. Configuration[] cfgs
  372. = userConfig.getChild("renderers").getChildren("renderer");
  373. for (int i = 0; i < cfgs.length; ++i) {
  374. Configuration cfg = cfgs[i];
  375. try {
  376. if (cfg.getAttribute("mime").equals(mimeType)) {
  377. userRendererConfig = cfg;
  378. break;
  379. }
  380. } catch (ConfigurationException e) {
  381. // silently pass over configurations without mime type
  382. }
  383. }
  384. log.debug((userRendererConfig == null ? "No u" : "U")
  385. + "ser configuration found for MIME type " + mimeType);
  386. return userRendererConfig;
  387. }
  388. /**
  389. * Sets the base URL.
  390. * @param baseURL base URL
  391. */
  392. public void setBaseURL(String baseURL) {
  393. this.baseURL = baseURL;
  394. }
  395. /**
  396. * Returns the base URL.
  397. * @return the base URL
  398. */
  399. public String getBaseURL() {
  400. return this.baseURL;
  401. }
  402. /**
  403. * Sets the URI Resolver.
  404. * @param uriResolver the new URI resolver
  405. */
  406. public void setURIResolver(URIResolver uriResolver) {
  407. this.uriResolver = uriResolver;
  408. }
  409. /**
  410. * Returns the URI Resolver.
  411. * @return the URI Resolver
  412. */
  413. public URIResolver getURIResolver() {
  414. return this.uriResolver;
  415. }
  416. /**
  417. * Returns the parameters for PDF encryption.
  418. * @return the PDF encryption parameters, null if not applicable
  419. */
  420. public PDFEncryptionParams getPDFEncryptionParams() {
  421. return pdfEncryptionParams;
  422. }
  423. /**
  424. * Sets the parameters for PDF encryption.
  425. * @param pdfEncryptionParams the PDF encryption parameters, null to
  426. * disable PDF encryption
  427. */
  428. public void setPDFEncryptionParams(PDFEncryptionParams pdfEncryptionParams) {
  429. this.pdfEncryptionParams = pdfEncryptionParams;
  430. }
  431. /**
  432. * Attempts to resolve the given URI.
  433. * Will use the configured resolver and if not successful fall back
  434. * to the default resolver.
  435. * @param uri URI to access
  436. * @return A {@link javax.xml.transform.Source} object, or null if the URI
  437. * cannot be resolved.
  438. * @see org.apache.fop.apps.FOURIResolver
  439. */
  440. public Source resolveURI(String uri) {
  441. Source source = null;
  442. if (uriResolver != null) {
  443. try {
  444. source = uriResolver.resolve(uri, getBaseURL());
  445. } catch (TransformerException te) {
  446. log.error("Attempt to resolve URI '" + uri + "' failed: ", te);
  447. }
  448. }
  449. if (source == null) {
  450. // URI Resolver not configured or returned null, use default resolver
  451. try {
  452. source = foURIResolver.resolve(uri, getBaseURL());
  453. } catch (TransformerException te) {
  454. log.error("Attempt to resolve URI '" + uri + "' failed: ", te);
  455. }
  456. }
  457. return source;
  458. }
  459. /**
  460. * Sets the output File.
  461. * @param f the output File
  462. */
  463. public void setOutputFile(File f) {
  464. this.outputFile = f;
  465. }
  466. /**
  467. * Gets the output File.
  468. * @return the output File
  469. */
  470. public File getOutputFile() {
  471. return outputFile;
  472. }
  473. /**
  474. * Returns the conversion factor from pixel units to millimeters. This
  475. * depends on the desired reolution.
  476. * @return float conversion factor
  477. */
  478. public float getPixelUnitToMillimeter() {
  479. return 25.4f / this.resolution;
  480. }
  481. /** @return the resolution for resolution-dependant output */
  482. public float getResolution() {
  483. return this.resolution;
  484. }
  485. /**
  486. * Sets the resolution in dpi.
  487. * @param dpi resolution in dpi
  488. */
  489. public void setResolution(int dpi) {
  490. this.resolution = dpi;
  491. }
  492. /**
  493. * Gets the default page-height to use as fallback,
  494. * in case page-height="auto"
  495. *
  496. * @return the page-height, as a String
  497. */
  498. public String getPageHeight() {
  499. return this.pageHeight;
  500. }
  501. /**
  502. * Sets the page-height to use as fallback, in case
  503. * page-height="auto"
  504. *
  505. * @param pageHeight page-height as a String
  506. */
  507. public void setPageHeight(String pageHeight) {
  508. this.pageHeight = pageHeight;
  509. }
  510. /**
  511. * Gets the default page-width to use as fallback,
  512. * in case page-width="auto"
  513. *
  514. * @return the page-width, as a String
  515. */
  516. public String getPageWidth() {
  517. return this.pageWidth;
  518. }
  519. /**
  520. * Sets the page-width to use as fallback, in case
  521. * page-width="auto"
  522. *
  523. * @param pageWidth page-width as a String
  524. */
  525. public void setPageWidth(String pageWidth) {
  526. this.pageWidth = pageWidth;
  527. }
  528. /**
  529. * If to create hot links to footnotes and before floats.
  530. * @return True if hot links should be created
  531. */
  532. /* TODO This method is never referenced!
  533. public boolean linkToFootnotes() {
  534. return true;
  535. }*/
  536. /**
  537. * @return the RendererFactory
  538. */
  539. public RendererFactory getRendererFactory() {
  540. return this.rendererFactory;
  541. }
  542. /**
  543. * @return the XML handler registry
  544. */
  545. public XMLHandlerRegistry getXMLHandlerRegistry() {
  546. return this.xmlHandlers;
  547. }
  548. }