\defclass{Texjava}

This Ant task invokes {\tt texjava.pl} to extract Java code from
\LaTeX{} files.  Given a list of files, it can invoke {\tt texjava.pl}
once for each, creating Java file that can be processed
with Ant.  The {\tt Texjava} task checks for depencies, avoiding
to run {\tt texjava.pl} for {\tt .tex} files with a more recent {\tt .java} file.
It acts like a proxy to {\tt texjava.pl} so all of its options are supported by
the task through attributes.  It is possible to set default values
for most of these attributes using system properties.
See the documentation of {\tt texjava.pl} for more detailed information
about the options.

Note: For this class to work, the Perl interpreter must be in the PATH environment variable.

\paragraph*{Supported system properties}
The system properties allows one to set default attributes
common to all {\tt texjava} task usage.  It reduces
the tedium of writing the {\tt texjava} calls and provides
an easier way to modify parameters later.

\noindent
{\tt texjava.html}

\noindent
{\tt texjava.images}

\noindent
{\tt texjava.savelatex}

\noindent
{\tt texjava.htmloutdir}

\noindent
{\tt texjava.texjava}

\begin{tab}
This property specifies the path to the {\tt texjava.pl} file,
including the name of the script.  Since no assumption can
be made about the current directory, it is recommended to
give an absolute path or a path relative to one's project base
directory.
If the path is not specified, {\tt tcode/texjava.pl} will be assumed.
This imply that one's project will have a {\tt tcode} directory
containing {\tt texjava.pl}.
\end{tab}

\paragraph*{Available attributes.}
Attributes are use to customize a single call to the
{\tt texjava} task.
They have precedence on system properties.

\noindent
{\tt html}

\noindent
{\tt images}

\noindent
{\tt savelatex}

\noindent
{\tt htmlonly}

\noindent
{\tt htmloutdir}

\noindent
{\tt master}

\noindent
{\tt texjava}

\begin{tab}
This specifies the path to the {\tt texjava.pl} script.
\end{tab}

\noindent
{\tt overviewtopackage}

\begin{tab}
Normally, any {\tt .tex} file is mapped to a corresponding {\tt .java}
for dependency checking and conversion.  If {\tt htmlonly} is {\tt true},
{\tt .tex} files will be mapped to {\tt .html} files.  This attribute, if set
to {\tt true}, will define a mapping from {\tt overview.tex} to
{\tt package.html}.  This allows one to generate package overviews
without converting them every time.
\end{tab}

\paragraph*{Nested elements}

Two nested elements are supported: file sets and file lists.
These elements allows one to construct the list of {\tt .tex} files
to be converted to {\tt .java} files.

\noindent
{\tt texfileset}

\begin{tab}
Corresponds to an Ant {\tt FileSet} element which should
only contain {\tt .tex} files.
A set can include files matching patterns.
\end{tab}

\noindent
{\tt texfilelist}

\begin{tab}
Corresponds to an Ant {\tt FileList} element which should
only contain {\tt .tex} files.
When making a file list, one must specify the names of each
individual files.
\end{tab}

\paragraph*{Example.}

For example, the compile target of Probdist uses the task to
create the Java files and compiles them.

\begin{verbatim}
<target name="probdist"
    description="Compiles probability distribution package">
   <texjava master="src/${pprobdist}/guideprobdist.tex">
      <texfilelist dir="src/${pprobdist}" 
         files="DiscreteDistribution.tex,ContinuousDistribution.tex"/>
      <texfileset dir="src/${pprobdist}" includes="*Dist.tex"/>
   </texjava>
   <javac srcdir="src" destdir="build" includes="${pprobdist}/*.java"/>
   <texjava overviewtopackage="yes" html="yes" htmlonly="yes"
                 master=''src/${pprobdist}/guideprobdist.tex">
      <texfilelist dir="src/${pprobdist}" files="overview.tex"/>
   </texjava>
</target>
\end{verbatim}

Here, the {\tt pprobdist} system property refers to the location of
the Probdist package,
i.e., {\tt umontreal/iro/lecuyer/probdist}.  This will generate
only the needed Java file and one is free to add classes
ending with the {\tt Dist} suffix without modifying the build file.

\bigskip\hrule\bigskip

\begin{code}
package umontreal.iro.lecuyer.tcode;\begin{hide}

import org.apache.tools.ant.util.*;
import org.apache.tools.ant.*;
import org.apache.tools.ant.taskdefs.Execute;
import org.apache.tools.ant.taskdefs.LogStreamHandler;
import org.apache.tools.ant.types.Commandline;
import org.apache.tools.ant.types.FileList;
import org.apache.tools.ant.types.FileSet;
import java.util.Enumeration;
import java.util.Vector;
import java.io.IOException;
import java.io.File;\end{hide}

public class Texjava extends Task\begin{hide} {
   // We want the task as Ant-friendly as possible, so
   // use built-in file sets and file lists.
   private Vector texFileSets = new Vector();
   private Vector texFileLists = new Vector();
   private File texjava;  // Location of texjava.pl
   private File masterFile = null;
   private File htmloutdir = null;
   private boolean html = false;
   private boolean htmlset = false;
   private boolean images = false;
   private boolean imagesset = false;
   private boolean savelatex = false;
   private boolean savelatexset = false;

   private boolean htmlonly = false;
   private String htmltitle;
   private boolean overviewtopackage = false;

   private File[] texjavaList;

   private Boolean getBoolProperty (String name) {
      String val = getProject().getProperty (name);
      if (val == null)
         return null;
      if (val.equalsIgnoreCase ("yes") || val.equalsIgnoreCase ("true") ||
          val.equals ("1"))
         return new Boolean (true);
      else if (val.equalsIgnoreCase ("no") || val.equalsIgnoreCase ("false") ||
               val.equals ("0"))
         return new Boolean (false);
      else
         return null;
   }\end{hide}

   public boolean getHtml()\begin{hide} {
      if (!htmlset) {
         Boolean b = getBoolProperty ("texjava.html");
         if (b != null) {
            html = b.booleanValue();
            htmlset = true;
         }
      }
      return html;
   }\end{hide}
\end{code}
\begin{tabb}  Returns {\tt true} if the task generates HTML contents.
\end{tabb}
\begin{code}

   public void setHtml (boolean html)\begin{hide} {
      this.html = html;
      htmlset = true;
   }\end{hide}
\end{code}
\begin{tabb}  If set to {\tt true}, HTML contents will be generated.
\end{tabb}
\begin{code}

   public boolean getImages()\begin{hide} {
      if (!imagesset) {
         Boolean b = getBoolProperty ("texjava.images");
         if (b != null) {
            images = b.booleanValue();
            imagesset = true;
         }
      }
      return images;
   }\end{hide}
\end{code}
\begin{tabb}   Returns {\tt true} if the image generation is activated.
\end{tabb}
\begin{code}

   public void setImages (boolean images)\begin{hide} {
      this.images = images;
      imagesset = true;
   }\end{hide}
\end{code}
\begin{tabb}  If set to {\tt true}, \latextohtml{} will generate
   images when converting the documentation.
\end{tabb}
\begin{code}

   public boolean getSavelatex()\begin{hide} {
      if (!savelatexset) {
         Boolean b = getBoolProperty ("texjava.savelatex");
         if (b != null) {
            html = b.booleanValue();
            savelatexset = true;
         }
      }
      return savelatex;
   }\end{hide}
\end{code}
\begin{tabb}  Returns {\tt true} if the \LaTeX{} contents
  is saved to allow reverting to \LaTeX{} using \emph{javatex}.
\end{tabb}
\begin{code}

   public void setSavelatex (boolean savelatex)\begin{hide} {
      this.savelatex = savelatex;
      savelatexset = true;
   }\end{hide}
\end{code}
\begin{tabb}  If set to {\tt true} the \LaTeX{} contents will
  be saved in the produced Java file.
\end{tabb}
\begin{code}

   public boolean getHtmlonly()\begin{hide} {
      return htmlonly;
   }\end{hide}
\end{code}
\begin{tabb}   Returns {\tt true} if only HTML code is to be produced.
\end{tabb}
\begin{code}

   public void setHtmlonly (boolean htmlonly)\begin{hide} {
      this.htmlonly = htmlonly;
   }\end{hide}
\end{code}
\begin{tabb}  If set to {\tt true}, only HTML code will be produced.
  No Java code and comments will appear.
\end{tabb}
\begin{code}

   public boolean getOverviewtopackage()\begin{hide} {
      return overviewtopackage;
   }\end{hide}
\end{code}
\begin{tabb}   Returns {\tt true} if {\tt package.html} will be
   created from {\tt overview.tex}.
\end{tabb}
\begin{code}

   public void setOverviewtopackage (boolean pack)\begin{hide} {
      overviewtopackage = pack;
   }\end{hide}
\end{code}
\begin{tabb}   If set to {\tt true}, a file named {\tt overview.tex} will
  be mapped to {\tt package.html} instead of {\tt overview.html}.
\end{tabb}
\begin{code}

   public File getMaster()\begin{hide} {
      return masterFile;
   }\end{hide}
\end{code}
\begin{tabb}  Gets the name of the master file.
\end{tabb}
\begin{code}

   public void setMaster (File masterFile)\begin{hide} {
      this.masterFile = masterFile;
   }\end{hide}
\end{code}
\begin{tabb}   Sets the name of the master file.
\end{tabb}
\begin{code}

   public File getHtmloutdir()\begin{hide} {
      if (htmloutdir == null)
         htmloutdir = getProject().resolveFile (getProject().getProperty ("texjava.htmloutdir"));
      return htmloutdir;
   }\end{hide}
\end{code}
\begin{tabb}  Gets the directory where the HTML files will be created.
\end{tabb}
\begin{code}

   public void setHtmloutdir (File htmloutdir)\begin{hide} {
      this.htmloutdir = htmloutdir;
   }\end{hide}
\end{code}
\begin{tabb}   Sets the directory where the HTML files will be created.
\end{tabb}
\begin{code}

   public String getHtmltitle()\begin{hide} {
      if (htmltitle == null)
         htmltitle = "";
      return htmltitle;
   }\end{hide}
\end{code}
\begin{tabb}  Gets the title of the HTML page.
\end{tabb}
\begin{code}

   public void setHtmltitle (String title)\begin{hide} {
      htmltitle = title;
   }\end{hide}
\end{code}
\begin{tabb}   Sets the title of the HTML page.
\end{tabb}
\begin{code}

   public File getTexjava()\begin{hide} {
      if (texjava == null) {
         String val = getProject().getProperty ("texjava.texjava");
         if (val != null)
            texjava = getProject().resolveFile (val);
      }
      if (texjava == null)
         texjava = new File (getProject().getBaseDir() + "/tcode", "texjava.pl");
      return texjava;
   }\end{hide}
\end{code}
\begin{tabb}   Returns the path to {\tt texjava.pl}.
\end{tabb}
\begin{code}

   public void setTexjava (File texjava)\begin{hide} {
      this.texjava = texjava;
   }\end{hide}
\end{code}
\begin{tabb}   Sets the path to {\tt texjava.pl}.
\end{tabb}
\begin{code}

   public void addTexfileset (FileSet fs)\begin{hide} {
      texFileSets.addElement (fs);
   }\end{hide}
\end{code}
\begin{tabb}   Adds a set of {\tt .tex} files to be converted to {\tt .java} files.
\end{tabb}
\begin{code}

   public void addTexfilelist (FileList fl)\begin{hide} {
      texFileLists.addElement (fl);
   }\end{hide}
\end{code}
\begin{tabb}   Adds a list of {\tt .tex} files to be converted to {\tt .java} files.
\end{tabb}
\begin{code}

   public void execute() throws BuildException\begin{hide} {
      resetFileLists();

      // Get all the files from the sets and lists and
      // fill in texjavaList with the files that need
      // to be processed.
      Enumeration enumTexFileSets = texFileSets.elements();
      while (enumTexFileSets.hasMoreElements()) {
         FileSet fs = (FileSet)enumTexFileSets.nextElement();
         DirectoryScanner ds = fs.getDirectoryScanner (getProject());
         String[] files = ds.getIncludedFiles();
         scanDir (fs.getDir (getProject()), files);
      }
      Enumeration enumTexFileLists = texFileLists.elements();
      while (enumTexFileLists.hasMoreElements()) {
         FileList fl = (FileList)enumTexFileLists.nextElement();
         String[] files = fl.getFiles (getProject());
         scanDir (fl.getDir (getProject()), files);
      }

      // Since texjava.pl can process one file at a time,
      // we need to run it for every file.
      GlobPatternMapper m = new GlobPatternMapper();
      m.setFrom ("*.tex");
      m.setTo (getHtmlonly() ? "*.html" : "*.java");
      if (texjavaList.length > 0 && !overviewtopackage)
         log ((htmlonly ? "Creating HTML contents from " :
               "Extracting Java code from ") + texjavaList.length +
              " TeX file" + (texjavaList.length == 1 ? "" : "s"));
      for (int i = 0; i < texjavaList.length; i++) {
         if (texjavaList[i] == null)
            continue;
         try {
            log ("Processing " + texjavaList[i].getAbsolutePath());
            Commandline cmd = new Commandline();
            // This could be replaced by an absolute
            // path to Perl interpreter which would have to
            // be determined or specified at runtime.
            cmd.setExecutable ("perl");
            // The first argument must be the name of the script
            cmd.createArgument().setFile (getTexjava());
            if (masterFile != null) {
               cmd.createArgument().setValue ("-master");
               cmd.createArgument().setFile (masterFile);
            }
            cmd.createArgument().setValue (getHtml() ? "-html" : "-nohtml");
            cmd.createArgument().setValue (getImages() ? "-images" : "-noimages");
            cmd.createArgument().setValue (getSavelatex() ? "-savelatex" : "-nosavelatex");
            if (getHtmloutdir() != null) {
               cmd.createArgument().setValue ("-htmloutdir");
               cmd.createArgument().setFile (htmloutdir);
            }
            if (getHtmlonly()) {
               cmd.createArgument().setValue ("-htmlonly");
               if (!getHtmltitle().equals ("")) {
                  cmd.createArgument().setValue ("-htmltitle");
                  cmd.createArgument().setValue (htmltitle);
               }
            }
            // Pass the TeX file
            cmd.createArgument().setFile (texjavaList[i]);
            // The .tex file must be converted to .java file
            String javaName = getOverviewtopackage()
               && texjavaList[i].getName().equals ("overview.tex")
               ? "package.html" : 
               m.mapFileName (texjavaList[i].getName())[0];
            cmd.createArgument().setFile (new File (texjavaList[i].getParentFile(), javaName));

            // We prefer to use Execute rather than JDK Runtime
            // because Execute is designed to face
            // portability issues and can redirect outputs
            // into Ant.
            Execute exe = new Execute
               (new LogStreamHandler
                (this, Project.MSG_VERBOSE, Project.MSG_WARN));
            exe.setAntRun (getProject());
            exe.setWorkingDirectory (getProject().getBaseDir());
            exe.setCommandline (cmd.getCommandline());
            exe.execute();
            if (exe.getExitValue() != 0)
               throw new BuildException
                  ("Error running texjava", getLocation());
         }
         catch (IOException e) {
            throw new BuildException
               ("Error running texjava", e, getLocation());
         }
      }
   }\end{hide}
\end{code}
\begin{tabb}   Executes the conversion task, using
the Ant {\tt exec} task to invoke {\tt texjava.pl} on each {\tt .tex} file.
\end{tabb}
\begin{code}\begin{hide}

   private void resetFileLists() {
      texjavaList = new File[0];
   }

   /*
    * Given a source directory and a list of .tex files,
    * scans the corresponding .java files in srcDir
    * to locate any outdated .java file that need to be
    * regenerated from its .tex file.
    */
   private void scanDir (File srcDir, String[] files) {
      GlobPatternMapper m = new GlobPatternMapper();
      m.setFrom ("*.tex");
      m.setTo (htmlonly ? "*.html" : "*.java");
      SourceFileScanner sfs = new SourceFileScanner (this);
      File[] newFiles = sfs.restrictAsFiles (files, srcDir, srcDir, m);
      if (overviewtopackage) {
         for (int i = 0; i < newFiles.length; i++) {
            if (newFiles[i].getName().equals ("overview.tex")) {
               long lastModifTex = newFiles[i].lastModified();
               File packagehtml = new File (newFiles[i].getParent(),
                                            "package.html");
               long lastModifHtml = packagehtml.lastModified();
               if (lastModifHtml >= lastModifTex)
                  newFiles[i] = null;
            }
         }
      }

      if (newFiles.length > 0) {
         File[] newTexjavaList = new File[texjavaList.length + newFiles.length];
         System.arraycopy (texjavaList, 0, newTexjavaList, 0, texjavaList.length);
         System.arraycopy (newFiles, 0, newTexjavaList, texjavaList.length, newFiles.length);
         texjavaList = newTexjavaList;
      }
   }
}\end{hide}
\end{code}
