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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  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. // SAX
  60. import org.xml.sax.XMLReader;
  61. // Java
  62. import java.io.File;
  63. import java.io.IOException;
  64. import java.io.OutputStream;
  65. import java.net.MalformedURLException;
  66. import java.util.List;
  67. // FOP
  68. import org.apache.fop.apps.Starter;
  69. import org.apache.fop.apps.InputHandler;
  70. import org.apache.fop.apps.FOInputHandler;
  71. import org.apache.fop.apps.Session;
  72. import org.apache.fop.apps.FOPException;
  73. import org.apache.fop.fo.FOUserAgent;
  74. // Avalon
  75. import org.apache.avalon.framework.logger.ConsoleLogger;
  76. import org.apache.avalon.framework.logger.Logger;
  77. /**
  78. * Wrapper for FOP which allows it to be accessed from within an Ant task.
  79. * Accepts the inputs:
  80. * <ul>
  81. * <li>fofile -> formatting objects file to be transformed</li>
  82. * <li>format -> MIME type of the format to generate ex. "application/pdf"</li>
  83. * <li>outfile -> output filename</li>
  84. * <li>baseDir -> directory to work from</li>
  85. * <li>userconfig -> file with user configuration (same as the "-c" command
  86. * line option)</li>
  87. * <li>messagelevel -> (error | warn | info | verbose | debug) level to output
  88. * non-error messages</li>
  89. * <li>logFiles -> Controls whether the names of the files that are processed
  90. * are logged or not</li>
  91. * </ul>
  92. */
  93. public class Fop extends Task {
  94. private File foFile;
  95. private List filesets = new java.util.ArrayList();
  96. private File outFile;
  97. private File outDir;
  98. private String format; //MIME type
  99. private File baseDir;
  100. private File userConfig;
  101. private int messageType = Project.MSG_VERBOSE;
  102. private boolean logFiles = true;
  103. /**
  104. * Sets the filename for the userconfig.xml.
  105. * @param userConfig Configuration to use
  106. */
  107. public void setUserconfig(File userConfig) {
  108. this.userConfig = userConfig;
  109. }
  110. /**
  111. * Returns the file for the userconfig.xml.
  112. * @return the userconfig.xml file
  113. */
  114. public File getUserconfig() {
  115. return this.userConfig;
  116. }
  117. /**
  118. * Sets the input XSL-FO file.
  119. * @param foFile input XSL-FO file
  120. */
  121. public void setFofile(File foFile) {
  122. this.foFile = foFile;
  123. }
  124. /**
  125. * Gets the input XSL-FO file.
  126. * @return input XSL-FO file
  127. */
  128. public File getFofile() {
  129. return foFile;
  130. }
  131. /**
  132. * Adds a set of XSL-FO files (nested fileset attribute).
  133. * @param set a fileset
  134. */
  135. public void addFileset(FileSet set) {
  136. filesets.add(set);
  137. }
  138. /**
  139. * Returns the current list of filesets.
  140. * @return the filesets
  141. */
  142. public List getFilesets() {
  143. return this.filesets;
  144. }
  145. /**
  146. * Sets the output file.
  147. * @param outFile File to output to
  148. */
  149. public void setOutfile(File outFile) {
  150. this.outFile = outFile;
  151. }
  152. /**
  153. * Gets the output file.
  154. * @return the output file
  155. */
  156. public File getOutfile() {
  157. return this.outFile;
  158. }
  159. /**
  160. * Sets the output directory.
  161. * @param outDir Directory to output to
  162. */
  163. public void setOutdir(File outDir) {
  164. this.outDir = outDir;
  165. }
  166. /**
  167. * Gets the output directory.
  168. * @return the output directory
  169. */
  170. public File getOutdir() {
  171. return this.outDir;
  172. }
  173. /**
  174. * Sets output format (MIME type).
  175. * @param format the output format
  176. */
  177. public void setFormat(String format) {
  178. this.format = format;
  179. }
  180. /**
  181. * Gets the output format (MIME type).
  182. * @return the output format
  183. */
  184. public String getFormat() {
  185. return this.format;
  186. }
  187. /**
  188. * Sets the message level to be used while processing.
  189. * @param messageLevel (error | warn| info | verbose | debug)
  190. */
  191. public void setMessagelevel(String messageLevel) {
  192. if (messageLevel.equalsIgnoreCase("info")) {
  193. messageType = Project.MSG_INFO;
  194. } else if (messageLevel.equalsIgnoreCase("verbose")) {
  195. messageType = Project.MSG_VERBOSE;
  196. } else if (messageLevel.equalsIgnoreCase("debug")) {
  197. messageType = Project.MSG_DEBUG;
  198. } else if (messageLevel.equalsIgnoreCase("err")
  199. || messageLevel.equalsIgnoreCase("error")) {
  200. messageType = Project.MSG_ERR;
  201. } else if (messageLevel.equalsIgnoreCase("warn")) {
  202. messageType = Project.MSG_WARN;
  203. } else {
  204. log("messagelevel set to unknown value \"" + messageLevel
  205. + "\"", Project.MSG_ERR);
  206. throw new BuildException("unknown messagelevel");
  207. }
  208. }
  209. /**
  210. * Returns the message type corresponding to Project.MSG_*
  211. * representing the current message level.
  212. * @see org.apache.tools.ant.Project
  213. */
  214. public int getMessageType() {
  215. return messageType;
  216. }
  217. /**
  218. * Sets the base directory; currently ignored.
  219. * @param baseDir File to use as a working directory
  220. */
  221. public void setBasedir(File baseDir) {
  222. this.baseDir = baseDir;
  223. }
  224. /**
  225. * Gets the base directory.
  226. * @return the base directory
  227. */
  228. public File getBasedir() {
  229. return (baseDir != null) ? baseDir : getProject().resolveFile(".");
  230. }
  231. /**
  232. * Controls whether the filenames of the files that are processed are logged
  233. * or not.
  234. * @param logFiles True if the feature should be enabled
  235. */
  236. public void setLogFiles(boolean logFiles) {
  237. this.logFiles = logFiles;
  238. }
  239. /**
  240. * Returns True if the filename of each file processed should be logged.
  241. * @return True if the filenames should be logged.
  242. */
  243. public boolean getLogFiles() {
  244. return this.logFiles;
  245. }
  246. /**
  247. * @see org.apache.tools.ant.Task#execute()
  248. */
  249. public void execute() throws BuildException {
  250. int logLevel = ConsoleLogger.LEVEL_INFO;
  251. switch (getMessageType()) {
  252. case Project.MSG_DEBUG : logLevel = ConsoleLogger.LEVEL_DEBUG; break;
  253. case Project.MSG_INFO : logLevel = ConsoleLogger.LEVEL_INFO; break;
  254. case Project.MSG_WARN : logLevel = ConsoleLogger.LEVEL_WARN; break;
  255. case Project.MSG_ERR : logLevel = ConsoleLogger.LEVEL_ERROR; break;
  256. case Project.MSG_VERBOSE: logLevel = ConsoleLogger.LEVEL_DEBUG; break;
  257. }
  258. Logger log = new ConsoleLogger(logLevel);
  259. try {
  260. Starter starter = new FOPTaskStarter(this);
  261. starter.enableLogging(log);
  262. starter.run();
  263. } catch (FOPException ex) {
  264. throw new BuildException(ex);
  265. }
  266. }
  267. }
  268. class FOPTaskStarter extends Starter {
  269. private Fop task;
  270. private String baseURL = null;
  271. FOPTaskStarter(Fop task) throws FOPException {
  272. this.task = task;
  273. }
  274. private int determineRenderer(String format) {
  275. if ((format == null)
  276. || format.equalsIgnoreCase("application/pdf")
  277. || format.equalsIgnoreCase("pdf")) {
  278. return Session.RENDER_PDF;
  279. } else if (format.equalsIgnoreCase("application/postscript")
  280. || format.equalsIgnoreCase("ps")) {
  281. return Session.RENDER_PS;
  282. } else if (format.equalsIgnoreCase("application/vnd.mif")
  283. || format.equalsIgnoreCase("mif")) {
  284. return Session.RENDER_MIF;
  285. } else if (format.equalsIgnoreCase("application/msword")
  286. || format.equalsIgnoreCase("application/rtf")
  287. || format.equalsIgnoreCase("rtf")) {
  288. return Session.RENDER_RTF;
  289. } else if (format.equalsIgnoreCase("application/vnd.hp-PCL")
  290. || format.equalsIgnoreCase("pcl")) {
  291. return Session.RENDER_PCL;
  292. } else if (format.equalsIgnoreCase("text/plain")
  293. || format.equalsIgnoreCase("txt")) {
  294. return Session.RENDER_TXT;
  295. } else if (format.equalsIgnoreCase("text/xml")
  296. || format.equalsIgnoreCase("at")
  297. || format.equalsIgnoreCase("xml")) {
  298. return Session.RENDER_XML;
  299. } else {
  300. String err = "Couldn't determine renderer to use: " + format;
  301. throw new BuildException(err);
  302. }
  303. }
  304. private String determineExtension(int renderer) {
  305. switch (renderer) {
  306. case Session.RENDER_PDF:
  307. return ".pdf";
  308. case Session.RENDER_PS:
  309. return ".ps";
  310. case Session.RENDER_MIF:
  311. return ".mif";
  312. case Session.RENDER_RTF:
  313. return ".rtf";
  314. case Session.RENDER_PCL:
  315. return ".pcl";
  316. case Session.RENDER_TXT:
  317. return ".txt";
  318. case Session.RENDER_XML:
  319. return ".xml";
  320. default:
  321. String err = "Unknown renderer: " + renderer;
  322. throw new BuildException(err);
  323. }
  324. }
  325. private File replaceExtension(File file, String expectedExt,
  326. String newExt) {
  327. String name = file.getName();
  328. if (name.toLowerCase().endsWith(expectedExt)) {
  329. name = name.substring(0, name.length() - expectedExt.length());
  330. }
  331. name = name.concat(newExt);
  332. return new File(file.getParentFile(), name);
  333. }
  334. /**
  335. * @see org.apache.fop.apps.Starter#run()
  336. */
  337. public void run() throws FOPException {
  338. //Setup configuration
  339. if (task.getUserconfig() != null) {
  340. /**@todo implement me */
  341. }
  342. //Set base directory
  343. if (task.getBasedir() != null) {
  344. try {
  345. this.baseURL = task.getBasedir().toURL().toExternalForm();
  346. } catch (MalformedURLException mfue) {
  347. getLogger().error("Error creating base URL from base directory", mfue);
  348. }
  349. } else {
  350. try {
  351. if (task.getFofile() != null) {
  352. this.baseURL = task.getFofile().getParentFile().toURL().
  353. toExternalForm();
  354. }
  355. } catch (MalformedURLException mfue) {
  356. getLogger().error("Error creating base URL from XSL-FO input file", mfue);
  357. }
  358. }
  359. task.log("Using base URL: " + baseURL, Project.MSG_DEBUG);
  360. int rint = determineRenderer(task.getFormat());
  361. String newExtension = determineExtension(rint);
  362. int actioncount = 0;
  363. // deal with single source file
  364. if (task.getFofile() != null) {
  365. if (task.getFofile().exists()) {
  366. File outf = task.getOutfile();
  367. if (outf == null) {
  368. throw new BuildException("outfile is required when fofile is used");
  369. }
  370. if (task.getOutdir() != null) {
  371. outf = new File(task.getOutdir(), outf.getName());
  372. }
  373. render(task.getFofile(), outf, rint);
  374. actioncount++;
  375. }
  376. }
  377. GlobPatternMapper mapper = new GlobPatternMapper();
  378. mapper.setFrom("*.fo");
  379. mapper.setTo("*" + newExtension);
  380. // deal with the filesets
  381. for (int i = 0; i < task.getFilesets().size(); i++) {
  382. FileSet fs = (FileSet) task.getFilesets().get(i);
  383. DirectoryScanner ds = fs.getDirectoryScanner(task.getProject());
  384. String[] files = ds.getIncludedFiles();
  385. for (int j = 0; j < files.length; j++) {
  386. File f = new File(fs.getDir(task.getProject()), files[j]);
  387. File outf = null;
  388. if (task.getOutdir() != null && files[j].endsWith(".fo")) {
  389. String[] sa = mapper.mapFileName(files[j]);
  390. outf = new File(task.getOutdir(), sa[0]);
  391. } else {
  392. outf = replaceExtension(f, ".fo", newExtension);
  393. if (task.getOutdir() != null) {
  394. outf = new File(task.getOutdir(), outf.getName());
  395. }
  396. }
  397. try {
  398. if (this.baseURL == null) {
  399. this.baseURL = fs.getDir(task.getProject()).toURL().
  400. toExternalForm();
  401. }
  402. } catch (Exception e) {
  403. task.log("Error setting base URL", Project.MSG_DEBUG);
  404. }
  405. render(f, outf, rint);
  406. actioncount++;
  407. }
  408. }
  409. if (actioncount == 0) {
  410. task.log("No files processed. No files were selected by the filesets "
  411. + "and no fofile was set." , Project.MSG_WARN);
  412. }
  413. }
  414. private void render(File foFile, File outFile,
  415. int renderer) throws FOPException {
  416. InputHandler inputHandler = new FOInputHandler(foFile);
  417. XMLReader parser = inputHandler.getParser();
  418. setParserFeatures(parser);
  419. OutputStream out = null;
  420. try {
  421. out = new java.io.FileOutputStream(outFile);
  422. } catch (Exception ex) {
  423. throw new BuildException("Failed to open " + outFile, ex);
  424. }
  425. if (task.getLogFiles()) {
  426. task.log(foFile + " -> " + outFile, Project.MSG_INFO);
  427. }
  428. try {
  429. Session session = new Session();
  430. setupLogger(session);
  431. session.initialize();
  432. FOUserAgent userAgent = new FOUserAgent();
  433. userAgent.setBaseURL(this.baseURL);
  434. userAgent.enableLogging(getLogger());
  435. session.setUserAgent(userAgent);
  436. session.setRenderer(renderer);
  437. session.setOutputStream(out);
  438. session.render(parser, inputHandler.getInputSource());
  439. } catch (Exception ex) {
  440. throw new BuildException(ex);
  441. } finally {
  442. try {
  443. out.close();
  444. } catch (IOException ioe) {
  445. getLogger().error("Error closing output file", ioe);
  446. }
  447. }
  448. }
  449. }