123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581 |
- /*
- * Copyright 1999-2006 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /* $Id$ */
-
- package org.apache.fop.tools.anttasks;
-
- // Ant
- import org.apache.tools.ant.BuildException;
- import org.apache.tools.ant.DirectoryScanner;
- import org.apache.tools.ant.Project;
- import org.apache.tools.ant.Task;
- import org.apache.tools.ant.types.FileSet;
- import org.apache.tools.ant.util.GlobPatternMapper;
-
- // Java
- import java.io.BufferedOutputStream;
- import java.io.File;
- import java.io.IOException;
- import java.io.OutputStream;
- import java.net.MalformedURLException;
- import java.util.List;
-
- // FOP
- import org.apache.fop.apps.FOPException;
- import org.apache.fop.apps.FOUserAgent;
- import org.apache.fop.apps.FopFactory;
- import org.apache.fop.apps.MimeConstants;
- import org.apache.fop.cli.InputHandler;
-
- import org.apache.avalon.framework.configuration.Configuration;
- import org.apache.avalon.framework.configuration.ConfigurationException;
- import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
- import org.apache.commons.logging.impl.SimpleLog;
- import org.apache.commons.logging.Log;
- import org.xml.sax.SAXException;
-
- /**
- * Wrapper for FOP which allows it to be accessed from within an Ant task.
- * Accepts the inputs:
- * <ul>
- * <li>fofile -> formatting objects file to be transformed</li>
- * <li>format -> MIME type of the format to generate ex. "application/pdf"</li>
- * <li>outfile -> output filename</li>
- * <li>baseDir -> directory to work from</li>
- * <li>relativebase -> (true | false) control whether to use each FO's
- * directory as base directory. false uses the baseDir parameter.</li>
- * <li>userconfig -> file with user configuration (same as the "-c" command
- * line option)</li>
- * <li>messagelevel -> (error | warn | info | verbose | debug) level to output
- * non-error messages</li>
- * <li>logFiles -> Controls whether the names of the files that are processed
- * are logged or not</li>
- * </ul>
- */
- public class Fop extends Task {
-
- private File foFile;
- private List filesets = new java.util.ArrayList();
- private File outFile;
- private File outDir;
- private String format; //MIME type
- private File baseDir;
- private File userConfig;
- private int messageType = Project.MSG_VERBOSE;
- private boolean logFiles = true;
- private boolean force = false;
- private boolean relativebase = false;
-
- /**
- * Sets the filename for the userconfig.xml.
- * @param userConfig Configuration to use
- */
- public void setUserconfig(File userConfig) {
- this.userConfig = userConfig;
- }
-
- /**
- * Returns the file for the userconfig.xml.
- * @return the userconfig.xml file
- */
- public File getUserconfig() {
- return this.userConfig;
- }
-
- /**
- * Sets the input XSL-FO file.
- * @param foFile input XSL-FO file
- */
- public void setFofile(File foFile) {
- this.foFile = foFile;
- }
-
- /**
- * Gets the input XSL-FO file.
- * @return input XSL-FO file
- */
- public File getFofile() {
- return foFile;
- }
-
- /**
- * Adds a set of XSL-FO files (nested fileset attribute).
- * @param set a fileset
- */
- public void addFileset(FileSet set) {
- filesets.add(set);
- }
-
- /**
- * Returns the current list of filesets.
- * @return the filesets
- */
- public List getFilesets() {
- return this.filesets;
- }
-
- /**
- * Set whether to include files (external-graphics, instream-foreign-object)
- * from a path relative to the .fo file (true) or the working directory (false, default)
- * only useful for filesets
- *
- * @param relbase true if paths are relative to file.
- */
- public void setRelativebase(boolean relbase) {
- this.relativebase = relbase;
- }
-
- /**
- * Gets the relative base attribute
- * @return the relative base attribute
- */
- public boolean getRelativebase() {
- return relativebase;
- }
-
- /**
- * Set whether to check dependencies, or to always generate;
- * optional, default is false.
- *
- * @param force true if always generate.
- */
- public void setForce(boolean force) {
- this.force = force;
- }
-
- /**
- * Gets the force attribute
- * @return the force attribute
- */
- public boolean getForce() {
- return force;
- }
-
- /**
- * Sets the output file.
- * @param outFile File to output to
- */
- public void setOutfile(File outFile) {
- this.outFile = outFile;
- }
-
- /**
- * Gets the output file.
- * @return the output file
- */
- public File getOutfile() {
- return this.outFile;
- }
-
- /**
- * Sets the output directory.
- * @param outDir Directory to output to
- */
- public void setOutdir(File outDir) {
- this.outDir = outDir;
- }
-
- /**
- * Gets the output directory.
- * @return the output directory
- */
- public File getOutdir() {
- return this.outDir;
- }
-
- /**
- * Sets output format (MIME type).
- * @param format the output format
- */
- public void setFormat(String format) {
- this.format = format;
- }
-
- /**
- * Gets the output format (MIME type).
- * @return the output format
- */
- public String getFormat() {
- return this.format;
- }
-
- /**
- * Sets the message level to be used while processing.
- * @param messageLevel (error | warn| info | verbose | debug)
- */
- public void setMessagelevel(String messageLevel) {
- if (messageLevel.equalsIgnoreCase("info")) {
- messageType = Project.MSG_INFO;
- } else if (messageLevel.equalsIgnoreCase("verbose")) {
- messageType = Project.MSG_VERBOSE;
- } else if (messageLevel.equalsIgnoreCase("debug")) {
- messageType = Project.MSG_DEBUG;
- } else if (messageLevel.equalsIgnoreCase("err")
- || messageLevel.equalsIgnoreCase("error")) {
- messageType = Project.MSG_ERR;
- } else if (messageLevel.equalsIgnoreCase("warn")) {
- messageType = Project.MSG_WARN;
- } else {
- log("messagelevel set to unknown value \"" + messageLevel
- + "\"", Project.MSG_ERR);
- throw new BuildException("unknown messagelevel");
- }
- }
-
- /**
- * Returns the message type corresponding to Project.MSG_*
- * representing the current message level.
- * @see org.apache.tools.ant.Project
- */
- public int getMessageType() {
- return messageType;
- }
-
- /**
- * Sets the base directory for single FO file (non-fileset) usage
- * @param baseDir File to use as a working directory
- */
- public void setBasedir(File baseDir) {
- this.baseDir = baseDir;
- }
-
- /**
- * Gets the base directory.
- * @return the base directory
- */
- public File getBasedir() {
- return (baseDir != null) ? baseDir : getProject().resolveFile(".");
- }
-
- /**
- * Controls whether the filenames of the files that are processed are logged
- * or not.
- * @param logFiles True if the feature should be enabled
- */
- public void setLogFiles(boolean logFiles) {
- this.logFiles = logFiles;
- }
-
- /**
- * Returns True if the filename of each file processed should be logged.
- * @return True if the filenames should be logged.
- */
- public boolean getLogFiles() {
- return this.logFiles;
- }
-
- /**
- * @see org.apache.tools.ant.Task#execute()
- */
- public void execute() throws BuildException {
- int logLevel = SimpleLog.LOG_LEVEL_INFO;
- switch (getMessageType()) {
- case Project.MSG_DEBUG : logLevel = SimpleLog.LOG_LEVEL_DEBUG; break;
- case Project.MSG_INFO : logLevel = SimpleLog.LOG_LEVEL_INFO; break;
- case Project.MSG_WARN : logLevel = SimpleLog.LOG_LEVEL_WARN; break;
- case Project.MSG_ERR : logLevel = SimpleLog.LOG_LEVEL_ERROR; break;
- case Project.MSG_VERBOSE: logLevel = SimpleLog.LOG_LEVEL_DEBUG; break;
- default: logLevel = SimpleLog.LOG_LEVEL_INFO;
- }
- SimpleLog logger = new SimpleLog("FOP/Anttask");
- logger.setLevel(logLevel);
- try {
- FOPTaskStarter starter = new FOPTaskStarter(this);
- starter.setLogger(logger);
- starter.run();
- } catch (FOPException ex) {
- throw new BuildException(ex);
- }
-
- }
-
- }
-
- class FOPTaskStarter {
-
- // configure fopFactory as desired
- private FopFactory fopFactory = FopFactory.newInstance();
-
- private Fop task;
- private String baseURL = null;
-
- /**
- * logging instance
- */
- protected Log logger = null;
-
-
- /**
- * Sets the Commons-Logging instance for this class
- * @param logger The Commons-Logging instance
- */
- public void setLogger(Log logger) {
- this.logger = logger;
- }
-
- /**
- * Returns the Commons-Logging instance for this class
- * @return The Commons-Logging instance
- */
- protected Log getLogger() {
- return logger;
- }
-
- FOPTaskStarter(Fop task) throws FOPException {
- this.task = task;
- }
-
- private static final String[][] SHORT_NAMES = {
- {"pdf", MimeConstants.MIME_PDF},
- {"ps", MimeConstants.MIME_POSTSCRIPT},
- {"mif", MimeConstants.MIME_MIF},
- {"rtf", MimeConstants.MIME_RTF},
- {"pcl", MimeConstants.MIME_PCL},
- {"txt", MimeConstants.MIME_PLAIN_TEXT},
- {"at", MimeConstants.MIME_FOP_AREA_TREE},
- {"xml", MimeConstants.MIME_FOP_AREA_TREE},
- {"tiff", MimeConstants.MIME_TIFF},
- {"tif", MimeConstants.MIME_TIFF},
- {"png", MimeConstants.MIME_PNG}
- };
-
- private String normalizeOutputFormat(String format) {
- for (int i = 0; i < SHORT_NAMES.length; i++) {
- if (SHORT_NAMES[i][0].equals(format)) {
- return SHORT_NAMES[i][1];
- }
- }
- return format; //no change
- }
-
- private static final String[][] EXTENSIONS = {
- {MimeConstants.MIME_FOP_AREA_TREE, ".at.xml"},
- {MimeConstants.MIME_FOP_AWT_PREVIEW, null},
- {MimeConstants.MIME_FOP_PRINT, null},
- {MimeConstants.MIME_PDF, ".pdf"},
- {MimeConstants.MIME_POSTSCRIPT, ".ps"},
- {MimeConstants.MIME_PCL, ".pcl"},
- {MimeConstants.MIME_PCL_ALT, ".pcl"},
- {MimeConstants.MIME_PLAIN_TEXT, ".txt"},
- {MimeConstants.MIME_RTF, ".rtf"},
- {MimeConstants.MIME_RTF_ALT1, ".rtf"},
- {MimeConstants.MIME_RTF_ALT2, ".rtf"},
- {MimeConstants.MIME_MIF, ".mif"},
- {MimeConstants.MIME_SVG, ".svg"},
- {MimeConstants.MIME_PNG, ".png"},
- {MimeConstants.MIME_JPEG, ".jpg"},
- {MimeConstants.MIME_TIFF, ".tif"},
- {MimeConstants.MIME_XSL_FO, ".fo"}
- };
-
- private String determineExtension(String outputFormat) {
- for (int i = 0; i < EXTENSIONS.length; i++) {
- if (EXTENSIONS[i][0].equals(outputFormat)) {
- String ext = EXTENSIONS[i][1];
- if (ext == null) {
- throw new RuntimeException("Output format '"
- + outputFormat + "' does not produce a file.");
- } else {
- return ext;
- }
- }
- }
- return ".unk"; //unknown
- }
-
- private File replaceExtension(File file, String expectedExt,
- String newExt) {
- String name = file.getName();
- if (name.toLowerCase().endsWith(expectedExt)) {
- name = name.substring(0, name.length() - expectedExt.length());
- }
- name = name.concat(newExt);
- return new File(file.getParentFile(), name);
- }
-
- /**
- * @see org.apache.fop.apps.Starter#run()
- */
- public void run() throws FOPException {
- //Setup configuration
- Configuration userConfig = null;
- if (task.getUserconfig() != null) {
- if (task.getUserconfig() != null) {
- DefaultConfigurationBuilder configBuilder = new DefaultConfigurationBuilder();
- try {
- userConfig = configBuilder.buildFromFile(task.getUserconfig());
- } catch (SAXException e) {
- throw new FOPException(e);
- } catch (ConfigurationException e) {
- throw new FOPException(e);
- } catch (IOException e) {
- throw new FOPException(e);
- }
- }
- }
-
- //Set base directory
- if (task.getBasedir() != null) {
- try {
- this.baseURL = task.getBasedir().toURL().toExternalForm();
- } catch (MalformedURLException mfue) {
- logger.error("Error creating base URL from base directory", mfue);
- }
- } else {
- try {
- if (task.getFofile() != null) {
- this.baseURL = task.getFofile().getParentFile().toURL().
- toExternalForm();
- }
- } catch (MalformedURLException mfue) {
- logger.error("Error creating base URL from XSL-FO input file", mfue);
- }
- }
-
- task.log("Using base URL: " + baseURL, Project.MSG_DEBUG);
-
- String outputFormat = normalizeOutputFormat(task.getFormat());
- String newExtension = determineExtension(outputFormat);
-
- // actioncount = # of fofiles actually processed through FOP
- int actioncount = 0;
- // skippedcount = # of fofiles which haven't changed (force = "false")
- int skippedcount = 0;
-
- // deal with single source file
- if (task.getFofile() != null) {
- if (task.getFofile().exists()) {
- File outf = task.getOutfile();
- if (outf == null) {
- throw new BuildException("outfile is required when fofile is used");
- }
- if (task.getOutdir() != null) {
- outf = new File(task.getOutdir(), outf.getName());
- }
- // Render if "force" flag is set OR
- // OR output file doesn't exist OR
- // output file is older than input file
- if (task.getForce() || !outf.exists()
- || (task.getFofile().lastModified() > outf.lastModified() )) {
- render(task.getFofile(), outf, outputFormat, userConfig);
- actioncount++;
- } else if (outf.exists()
- && (task.getFofile().lastModified() <= outf.lastModified() )) {
- skippedcount++;
- }
- }
- }
-
- GlobPatternMapper mapper = new GlobPatternMapper();
- mapper.setFrom("*.fo");
- mapper.setTo("*" + newExtension);
-
- // deal with the filesets
- for (int i = 0; i < task.getFilesets().size(); i++) {
- FileSet fs = (FileSet) task.getFilesets().get(i);
- DirectoryScanner ds = fs.getDirectoryScanner(task.getProject());
- String[] files = ds.getIncludedFiles();
-
- for (int j = 0; j < files.length; j++) {
- File f = new File(fs.getDir(task.getProject()), files[j]);
-
- File outf = null;
- if (task.getOutdir() != null && files[j].endsWith(".fo")) {
- String[] sa = mapper.mapFileName(files[j]);
- outf = new File(task.getOutdir(), sa[0]);
- } else {
- outf = replaceExtension(f, ".fo", newExtension);
- if (task.getOutdir() != null) {
- outf = new File(task.getOutdir(), outf.getName());
- }
- }
-
- try {
- if (task.getRelativebase()) {
- this.baseURL = f.getParentFile().toURL().
- toExternalForm();
- }
- if (this.baseURL == null) {
- this.baseURL = fs.getDir(task.getProject()).toURL().
- toExternalForm();
- }
-
- } catch (Exception e) {
- task.log("Error setting base URL", Project.MSG_DEBUG);
- }
-
- // Render if "force" flag is set OR
- // OR output file doesn't exist OR
- // output file is older than input file
- if (task.getForce() || !outf.exists()
- || (f.lastModified() > outf.lastModified() )) {
- render(f, outf, outputFormat, userConfig);
- actioncount++;
- } else if (outf.exists() && (f.lastModified() <= outf.lastModified() )) {
- skippedcount++;
- }
- }
- }
-
- if (actioncount + skippedcount == 0) {
- task.log("No files processed. No files were selected by the filesets "
- + "and no fofile was set." , Project.MSG_WARN);
- } else if (skippedcount > 0) {
- task.log(skippedcount + " xslfo file(s) skipped (no change found"
- + " since last generation; set force=\"true\" to override)."
- , Project.MSG_INFO);
- }
- }
-
- private void render(File foFile, File outFile,
- String outputFormat, Configuration userConfig) throws FOPException {
- InputHandler inputHandler = new InputHandler(foFile);
-
- OutputStream out = null;
- try {
- out = new java.io.FileOutputStream(outFile);
- out = new BufferedOutputStream(out);
- } catch (Exception ex) {
- throw new BuildException("Failed to open " + outFile, ex);
- }
-
- if (task.getLogFiles()) {
- task.log(foFile + " -> " + outFile, Project.MSG_INFO);
- }
-
- boolean success = false;
- try {
- FOUserAgent userAgent = fopFactory.newFOUserAgent();
- userAgent.setBaseURL(this.baseURL);
- inputHandler.renderTo(userAgent, outputFormat, out);
- success = true;
- } catch (Exception ex) {
- throw new BuildException(ex);
- } finally {
- try {
- out.close();
- } catch (IOException ioe) {
- logger.error("Error closing output file", ioe);
- }
- if (!success) {
- outFile.delete();
- }
- }
- }
-
- }
|