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.

Fop.java 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. /*
  2. * $Id: Fop.java,v 1.24 2003/03/07 10:09:30 jeremias Exp $
  3. * ============================================================================
  4. * The Apache Software License, Version 1.1
  5. * ============================================================================
  6. *
  7. * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
  8. *
  9. * Redistribution and use in source and binary forms, with or without modifica-
  10. * tion, are permitted provided that the following conditions are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright notice,
  13. * this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright notice,
  16. * this list of conditions and the following disclaimer in the documentation
  17. * and/or other materials provided with the distribution.
  18. *
  19. * 3. The end-user documentation included with the redistribution, if any, must
  20. * include the following acknowledgment: "This product includes software
  21. * developed by the Apache Software Foundation (http://www.apache.org/)."
  22. * Alternately, this acknowledgment may appear in the software itself, if
  23. * and wherever such third-party acknowledgments normally appear.
  24. *
  25. * 4. The names "FOP" and "Apache Software Foundation" must not be used to
  26. * endorse or promote products derived from this software without prior
  27. * written permission. For written permission, please contact
  28. * apache@apache.org.
  29. *
  30. * 5. Products derived from this software may not be called "Apache", nor may
  31. * "Apache" appear in their name, without prior written permission of the
  32. * Apache Software Foundation.
  33. *
  34. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
  35. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  36. * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  37. * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  38. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
  39. * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  40. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  41. * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  42. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  43. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  44. * ============================================================================
  45. *
  46. * This software consists of voluntary contributions made by many individuals
  47. * on behalf of the Apache Software Foundation and was originally created by
  48. * James Tauber <jtauber@jtauber.com>. For more information on the Apache
  49. * Software Foundation, please see <http://www.apache.org/>.
  50. */
  51. package org.apache.fop.tools.anttasks;
  52. // Ant
  53. import org.apache.tools.ant.BuildException;
  54. import org.apache.tools.ant.DirectoryScanner;
  55. import org.apache.tools.ant.Project;
  56. import org.apache.tools.ant.Task;
  57. import org.apache.tools.ant.types.FileSet;
  58. import org.apache.tools.ant.util.GlobPatternMapper;
  59. // Java
  60. import java.io.File;
  61. import java.io.IOException;
  62. import java.io.OutputStream;
  63. import java.net.MalformedURLException;
  64. import java.util.List;
  65. // FOP
  66. import org.apache.fop.apps.Starter;
  67. import org.apache.fop.apps.InputHandler;
  68. import org.apache.fop.apps.FOInputHandler;
  69. import org.apache.fop.apps.Driver;
  70. import org.apache.fop.apps.FOPException;
  71. import org.apache.fop.fo.FOUserAgent;
  72. // Avalon
  73. import org.apache.avalon.framework.logger.ConsoleLogger;
  74. import org.apache.avalon.framework.logger.Logger;
  75. /**
  76. * Wrapper for FOP which allows it to be accessed from within an Ant task.
  77. * Accepts the inputs:
  78. * <ul>
  79. * <li>fofile -> formatting objects file to be transformed</li>
  80. * <li>format -> MIME type of the format to generate ex. "application/pdf"</li>
  81. * <li>outfile -> output filename</li>
  82. * <li>baseDir -> directory to work from</li>
  83. * <li>userconfig -> file with user configuration (same as the "-c" command
  84. * line option)</li>
  85. * <li>messagelevel -> (error | warn | info | verbose | debug) level to output
  86. * non-error messages</li>
  87. * <li>logFiles -> Controls whether the names of the files that are processed
  88. * are logged or not</li>
  89. * </ul>
  90. */
  91. public class Fop extends Task {
  92. private File foFile;
  93. private List filesets = new java.util.ArrayList();
  94. private File outFile;
  95. private File outDir;
  96. private String format; //MIME type
  97. private File baseDir;
  98. private File userConfig;
  99. private int messageType = Project.MSG_VERBOSE;
  100. private boolean logFiles = true;
  101. /**
  102. * Sets the filename for the userconfig.xml.
  103. * @param userConfig Configuration to use
  104. */
  105. public void setUserconfig(File userConfig) {
  106. this.userConfig = userConfig;
  107. }
  108. /**
  109. * Returns the file for the userconfig.xml.
  110. * @return the userconfig.xml file
  111. */
  112. public File getUserconfig() {
  113. return this.userConfig;
  114. }
  115. /**
  116. * Sets the input XSL-FO file.
  117. * @param foFile input XSL-FO file
  118. */
  119. public void setFofile(File foFile) {
  120. this.foFile = foFile;
  121. }
  122. /**
  123. * Gets the input XSL-FO file.
  124. * @return input XSL-FO file
  125. */
  126. public File getFofile() {
  127. return foFile;
  128. }
  129. /**
  130. * Adds a set of XSL-FO files (nested fileset attribute).
  131. * @param set a fileset
  132. */
  133. public void addFileset(FileSet set) {
  134. filesets.add(set);
  135. }
  136. /**
  137. * Returns the current list of filesets.
  138. * @return the filesets
  139. */
  140. public List getFilesets() {
  141. return this.filesets;
  142. }
  143. /**
  144. * Sets the output file.
  145. * @param outFile File to output to
  146. */
  147. public void setOutfile(File outFile) {
  148. this.outFile = outFile;
  149. }
  150. /**
  151. * Gets the output file.
  152. * @return the output file
  153. */
  154. public File getOutfile() {
  155. return this.outFile;
  156. }
  157. /**
  158. * Sets the output directory.
  159. * @param outDir Directory to output to
  160. */
  161. public void setOutdir(File outDir) {
  162. this.outDir = outDir;
  163. }
  164. /**
  165. * Gets the output directory.
  166. * @return the output directory
  167. */
  168. public File getOutdir() {
  169. return this.outDir;
  170. }
  171. /**
  172. * Sets output format (MIME type).
  173. * @param format the output format
  174. */
  175. public void setFormat(String format) {
  176. this.format = format;
  177. }
  178. /**
  179. * Gets the output format (MIME type).
  180. * @return the output format
  181. */
  182. public String getFormat() {
  183. return this.format;
  184. }
  185. /**
  186. * Sets the message level to be used while processing.
  187. * @param messageLevel (error | warn| info | verbose | debug)
  188. */
  189. public void setMessagelevel(String messageLevel) {
  190. if (messageLevel.equalsIgnoreCase("info")) {
  191. messageType = Project.MSG_INFO;
  192. } else if (messageLevel.equalsIgnoreCase("verbose")) {
  193. messageType = Project.MSG_VERBOSE;
  194. } else if (messageLevel.equalsIgnoreCase("debug")) {
  195. messageType = Project.MSG_DEBUG;
  196. } else if (messageLevel.equalsIgnoreCase("err")
  197. || messageLevel.equalsIgnoreCase("error")) {
  198. messageType = Project.MSG_ERR;
  199. } else if (messageLevel.equalsIgnoreCase("warn")) {
  200. messageType = Project.MSG_WARN;
  201. } else {
  202. log("messagelevel set to unknown value \"" + messageLevel
  203. + "\"", Project.MSG_ERR);
  204. throw new BuildException("unknown messagelevel");
  205. }
  206. }
  207. /**
  208. * Returns the message type corresponding to Project.MSG_*
  209. * representing the current message level.
  210. * @see org.apache.tools.ant.Project
  211. */
  212. public int getMessageType() {
  213. return messageType;
  214. }
  215. /**
  216. * Sets the base directory; currently ignored.
  217. * @param baseDir File to use as a working directory
  218. */
  219. public void setBasedir(File baseDir) {
  220. this.baseDir = baseDir;
  221. }
  222. /**
  223. * Gets the base directory.
  224. * @return the base directory
  225. */
  226. public File getBasedir() {
  227. return (baseDir != null) ? baseDir : getProject().resolveFile(".");
  228. }
  229. /**
  230. * Controls whether the filenames of the files that are processed are logged
  231. * or not.
  232. * @param logFiles True if the feature should be enabled
  233. */
  234. public void setLogFiles(boolean logFiles) {
  235. this.logFiles = logFiles;
  236. }
  237. /**
  238. * Returns True if the filename of each file processed should be logged.
  239. * @return True if the filenames should be logged.
  240. */
  241. public boolean getLogFiles() {
  242. return this.logFiles;
  243. }
  244. /**
  245. * @see org.apache.tools.ant.Task#execute()
  246. */
  247. public void execute() throws BuildException {
  248. int logLevel = ConsoleLogger.LEVEL_INFO;
  249. switch (getMessageType()) {
  250. case Project.MSG_DEBUG : logLevel = ConsoleLogger.LEVEL_DEBUG; break;
  251. case Project.MSG_INFO : logLevel = ConsoleLogger.LEVEL_INFO; break;
  252. case Project.MSG_WARN : logLevel = ConsoleLogger.LEVEL_WARN; break;
  253. case Project.MSG_ERR : logLevel = ConsoleLogger.LEVEL_ERROR; break;
  254. case Project.MSG_VERBOSE: logLevel = ConsoleLogger.LEVEL_DEBUG; break;
  255. }
  256. Logger log = new ConsoleLogger(logLevel);
  257. try {
  258. Starter starter = new FOPTaskStarter(this);
  259. starter.enableLogging(log);
  260. starter.run();
  261. } catch (FOPException ex) {
  262. throw new BuildException(ex);
  263. }
  264. }
  265. }
  266. class FOPTaskStarter extends Starter {
  267. private Fop task;
  268. private String baseURL = null;
  269. FOPTaskStarter(Fop task) throws FOPException {
  270. this.task = task;
  271. }
  272. private int determineRenderer(String format) {
  273. if ((format == null)
  274. || format.equalsIgnoreCase("application/pdf")
  275. || format.equalsIgnoreCase("pdf")) {
  276. return Driver.RENDER_PDF;
  277. } else if (format.equalsIgnoreCase("application/postscript")
  278. || format.equalsIgnoreCase("ps")) {
  279. return Driver.RENDER_PS;
  280. } else if (format.equalsIgnoreCase("application/vnd.mif")
  281. || format.equalsIgnoreCase("mif")) {
  282. return Driver.RENDER_MIF;
  283. } else if (format.equalsIgnoreCase("application/msword")
  284. || format.equalsIgnoreCase("application/rtf")
  285. || format.equalsIgnoreCase("rtf")) {
  286. return Driver.RENDER_RTF;
  287. } else if (format.equalsIgnoreCase("application/vnd.hp-PCL")
  288. || format.equalsIgnoreCase("pcl")) {
  289. return Driver.RENDER_PCL;
  290. } else if (format.equalsIgnoreCase("text/plain")
  291. || format.equalsIgnoreCase("txt")) {
  292. return Driver.RENDER_TXT;
  293. } else if (format.equalsIgnoreCase("text/xml")
  294. || format.equalsIgnoreCase("at")
  295. || format.equalsIgnoreCase("xml")) {
  296. return Driver.RENDER_XML;
  297. } else {
  298. String err = "Couldn't determine renderer to use: " + format;
  299. throw new BuildException(err);
  300. }
  301. }
  302. private String determineExtension(int renderer) {
  303. switch (renderer) {
  304. case Driver.RENDER_PDF:
  305. return ".pdf";
  306. case Driver.RENDER_PS:
  307. return ".ps";
  308. case Driver.RENDER_MIF:
  309. return ".mif";
  310. case Driver.RENDER_RTF:
  311. return ".rtf";
  312. case Driver.RENDER_PCL:
  313. return ".pcl";
  314. case Driver.RENDER_TXT:
  315. return ".txt";
  316. case Driver.RENDER_XML:
  317. return ".xml";
  318. default:
  319. String err = "Unknown renderer: " + renderer;
  320. throw new BuildException(err);
  321. }
  322. }
  323. private File replaceExtension(File file, String expectedExt,
  324. String newExt) {
  325. String name = file.getName();
  326. if (name.toLowerCase().endsWith(expectedExt)) {
  327. name = name.substring(0, name.length() - expectedExt.length());
  328. }
  329. name = name.concat(newExt);
  330. return new File(file.getParentFile(), name);
  331. }
  332. /**
  333. * @see org.apache.fop.apps.Starter#run()
  334. */
  335. public void run() throws FOPException {
  336. //Setup configuration
  337. if (task.getUserconfig() != null) {
  338. /**@todo implement me */
  339. }
  340. //Set base directory
  341. if (task.getBasedir() != null) {
  342. try {
  343. this.baseURL = task.getBasedir().toURL().toExternalForm();
  344. } catch (MalformedURLException mfue) {
  345. getLogger().error("Error creating base URL from base directory", mfue);
  346. }
  347. } else {
  348. try {
  349. if (task.getFofile() != null) {
  350. this.baseURL = task.getFofile().getParentFile().toURL().
  351. toExternalForm();
  352. }
  353. } catch (MalformedURLException mfue) {
  354. getLogger().error("Error creating base URL from XSL-FO input file", mfue);
  355. }
  356. }
  357. task.log("Using base URL: " + baseURL, Project.MSG_DEBUG);
  358. int rint = determineRenderer(task.getFormat());
  359. String newExtension = determineExtension(rint);
  360. int actioncount = 0;
  361. // deal with single source file
  362. if (task.getFofile() != null) {
  363. if (task.getFofile().exists()) {
  364. File outf = task.getOutfile();
  365. if (outf == null) {
  366. throw new BuildException("outfile is required when fofile is used");
  367. }
  368. if (task.getOutdir() != null) {
  369. outf = new File(task.getOutdir(), outf.getName());
  370. }
  371. render(task.getFofile(), outf, rint);
  372. actioncount++;
  373. }
  374. }
  375. GlobPatternMapper mapper = new GlobPatternMapper();
  376. mapper.setFrom("*.fo");
  377. mapper.setTo("*" + newExtension);
  378. // deal with the filesets
  379. for (int i = 0; i < task.getFilesets().size(); i++) {
  380. FileSet fs = (FileSet) task.getFilesets().get(i);
  381. DirectoryScanner ds = fs.getDirectoryScanner(task.getProject());
  382. String[] files = ds.getIncludedFiles();
  383. for (int j = 0; j < files.length; j++) {
  384. File f = new File(fs.getDir(task.getProject()), files[j]);
  385. File outf = null;
  386. if (task.getOutdir() != null && files[j].endsWith(".fo")) {
  387. String[] sa = mapper.mapFileName(files[j]);
  388. outf = new File(task.getOutdir(), sa[0]);
  389. } else {
  390. outf = replaceExtension(f, ".fo", newExtension);
  391. if (task.getOutdir() != null) {
  392. outf = new File(task.getOutdir(), outf.getName());
  393. }
  394. }
  395. try {
  396. if (this.baseURL == null) {
  397. this.baseURL = fs.getDir(task.getProject()).toURL().
  398. toExternalForm();
  399. }
  400. } catch (Exception e) {
  401. task.log("Error setting base URL", Project.MSG_DEBUG);
  402. }
  403. render(f, outf, rint);
  404. actioncount++;
  405. }
  406. }
  407. if (actioncount == 0) {
  408. task.log("No files processed. No files were selected by the filesets "
  409. + "and no fofile was set." , Project.MSG_WARN);
  410. }
  411. }
  412. private void render(File foFile, File outFile,
  413. int renderer) throws FOPException {
  414. InputHandler inputHandler = new FOInputHandler(foFile);
  415. OutputStream out = null;
  416. try {
  417. out = new java.io.FileOutputStream(outFile);
  418. } catch (Exception ex) {
  419. throw new BuildException("Failed to open " + outFile, ex);
  420. }
  421. if (task.getLogFiles()) {
  422. task.log(foFile + " -> " + outFile, Project.MSG_INFO);
  423. }
  424. try {
  425. Driver driver = new Driver();
  426. setupLogger(driver);
  427. FOUserAgent userAgent = new FOUserAgent();
  428. userAgent.setBaseURL(this.baseURL);
  429. userAgent.enableLogging(getLogger());
  430. driver.setUserAgent(userAgent);
  431. driver.setRenderer(renderer);
  432. driver.setOutputStream(out);
  433. driver.render(inputHandler);
  434. } catch (Exception ex) {
  435. throw new BuildException(ex);
  436. } finally {
  437. try {
  438. out.close();
  439. } catch (IOException ioe) {
  440. getLogger().error("Error closing output file", ioe);
  441. }
  442. }
  443. }
  444. }