001    package com.thaiopensource.relaxng.util;
002    
003    import com.thaiopensource.util.PropertyMapBuilder;
004    import com.thaiopensource.validate.Flag;
005    import com.thaiopensource.validate.SchemaReader;
006    import com.thaiopensource.validate.ValidationDriver;
007    import com.thaiopensource.validate.schematron.SchematronProperty;
008    import com.thaiopensource.validate.rng.CompactSchemaReader;
009    import com.thaiopensource.validate.rng.RngProperty;
010    import com.thaiopensource.xml.sax.ErrorHandlerImpl;
011    import org.apache.tools.ant.BuildException;
012    import org.apache.tools.ant.DirectoryScanner;
013    import org.apache.tools.ant.Project;
014    import org.apache.tools.ant.Task;
015    import org.apache.tools.ant.types.FileSet;
016    import org.xml.sax.SAXException;
017    import org.xml.sax.SAXParseException;
018    
019    import java.io.File;
020    import java.io.IOException;
021    import java.util.Vector;
022    
023    
024    /**
025     * Ant task to validate XML files using RELAX NG or other schema languages.
026     */
027    
028    public class JingTask extends Task {
029    
030      private File schemaFile;
031      private File src;
032      private final Vector filesets = new Vector();
033      private PropertyMapBuilder properties = new PropertyMapBuilder();
034      private boolean failOnError = true;
035      private SchemaReader schemaReader = null;
036    
037      private class LogErrorHandler extends ErrorHandlerImpl {
038        int logLevel = Project.MSG_ERR;
039    
040        public void warning(SAXParseException e) throws SAXParseException {
041          logLevel = Project.MSG_WARN;
042          super.warning(e);
043        }
044    
045        public void error(SAXParseException e) {
046          logLevel = Project.MSG_ERR;
047          super.error(e);
048        }
049    
050        public void printException(Throwable e) {
051          logLevel = Project.MSG_ERR;
052          super.printException(e);
053        }
054    
055        public void print(String message) {
056          log(message, logLevel);
057        }
058      }
059    
060      public JingTask() {
061        RngProperty.CHECK_ID_IDREF.add(properties);
062      }
063    
064      public void execute() throws BuildException {
065        if (schemaFile == null)
066          throw new BuildException("There must be an rngFile or schemaFile attribute",
067                                   location);
068        if (src == null && filesets.size() == 0)
069          throw new BuildException("There must be a file attribute or a fileset child element",
070                                   location);
071    
072        ErrorHandlerImpl eh = new LogErrorHandler();
073    
074        boolean hadError = false;
075    
076        try {
077          ValidationDriver driver = new ValidationDriver(properties.toPropertyMap(), schemaReader);
078          if (!driver.loadSchema(ValidationDriver.fileInputSource(schemaFile)))
079            hadError = true;
080          else {
081            if (src != null) {
082              if (!driver.validate(ValidationDriver.fileInputSource(src)))
083                hadError = true;
084            }
085            for (int i = 0; i < filesets.size(); i++) {
086              FileSet fs = (FileSet)filesets.elementAt(i);
087              DirectoryScanner ds = fs.getDirectoryScanner(project);
088              File dir = fs.getDir(project);
089              String[] srcs = ds.getIncludedFiles();
090              for (int j = 0; j < srcs.length; j++) {
091                if (!driver.validate(ValidationDriver.fileInputSource(new File(dir, srcs[j]))))
092                  hadError = true;
093              }
094            }
095          }
096        }
097        catch (SAXException e) {
098          hadError = true;
099          eh.printException(e);
100        }
101        catch (IOException e) {
102          hadError = true;
103          eh.printException(e);
104        }
105        if (hadError && failOnError)
106          throw new BuildException("Validation failed, messages should have been provided.", location);
107      }
108    
109      /**
110       * Handles the <code>rngfile</code> attribute.
111       *
112       * @param rngFilename the attribute value
113       */
114      public void setRngfile(String rngFilename) {
115        schemaFile = project.resolveFile(rngFilename);
116      }
117    
118      /**
119       * Handles the <code>schemafile</code> attribute.
120       *
121       * @param schemaFilename the attribute value
122       */
123      public void setSchemafile(String schemaFilename) {
124        schemaFile = project.resolveFile(schemaFilename);
125      }
126    
127      public void setFile(File file) {
128        this.src = file;
129      }
130    
131      /**
132       * Handles the <code>checkid</code> attribute.
133       *
134       * @param checkid the attribute value converted to a boolean
135       */
136      public void setCheckid(boolean checkid) {
137        properties.put(RngProperty.CHECK_ID_IDREF,
138                       checkid ? Flag.PRESENT : null);
139      }
140    
141      /**
142       * Handles the <code>compactsyntax</code> attribute.
143       *
144       * @param compactsyntax the attribute value converted to a boolean
145       */
146      public void setCompactsyntax(boolean compactsyntax) {
147        schemaReader = compactsyntax ? CompactSchemaReader.getInstance() : null;
148      }
149    
150      /**
151       * Handles the <code>feasible</code> attribute.
152       *
153       * @param feasible the attribute value converted to a boolean
154       */
155      public void setFeasible(boolean feasible) {
156        properties.put(RngProperty.FEASIBLE, feasible ? Flag.PRESENT : null);
157      }
158    
159      /**
160       * Handles the phase attribute.
161       *
162       * @param phase the attribute value
163       */
164      public void setPhase(String phase) {
165        SchematronProperty.PHASE.put(properties, phase);
166      }
167    
168      /**
169       * Handles the <code>failonerror</code> attribute.
170       *
171       * @param failOnError the attribute value converted to a boolean
172       */
173      public void setFailonerror(boolean failOnError) {
174        this.failOnError = failOnError;
175      }
176    
177      public void addFileset(FileSet set) {
178        filesets.addElement(set);
179      }
180    
181    }