Project

General

Profile

1 168 jones
/**
2 203 jones
 *  '$RCSfile$'
3
 *    Purpose: A Class that validates XML documents
4
 *             This class is designed to be 'parser independent
5
 *             i.e. it uses only org.xml.sax classes
6
 *             It is tied to SAX 2.0 methods
7
 *  Copyright: 2000 Regents of the University of California and the
8
 *             National Center for Ecological Analysis and Synthesis
9
 *    Authors: Dan Higgins, Matt Jones
10 349 jones
 *    Release: @release@
11 168 jones
 *
12 203 jones
 *   '$Author$'
13
 *     '$Date$'
14
 * '$Revision$'
15 669 jones
 *
16
 * This program is free software; you can redistribute it and/or modify
17
 * it under the terms of the GNU General Public License as published by
18
 * the Free Software Foundation; either version 2 of the License, or
19
 * (at your option) any later version.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 * GNU General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU General Public License
27
 * along with this program; if not, write to the Free Software
28
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29 168 jones
 */
30 69 higgins
package edu.ucsb.nceas.metacat;
31
32
33 66 higgins
import java.net.URL;
34
import java.net.MalformedURLException;
35
import java.util.*;
36
import java.io.*;
37
import java.lang.reflect.*;
38 243 jones
import java.sql.*;
39 66 higgins
40
import org.w3c.dom.*;
41
import org.xml.sax.*;
42 185 jones
import org.xml.sax.XMLReader;
43
import org.xml.sax.helpers.XMLReaderFactory;
44 66 higgins
45
import com.arbortext.catalog.*;
46
47
/**
48 185 jones
 * Name: DBValidate.java
49 66 higgins
 *       Purpose: A Class that validates XML documents
50 185 jones
 * 			   This class is designed to be parser independent
51 66 higgins
 *    			   i.e. it uses only org.xml.sax classes
52 185 jones
 * 			   It is tied to SAX 2.0 methods
53 66 higgins
 *     Copyright: 2000 Regents of the University of California and the
54
 *                National Center for Ecological Analysis and Synthesis
55
 *                April 28, 2000
56 243 jones
 *    Authors: Dan Higgins, Matt Jones
57 66 higgins
 */
58 185 jones
public class DBValidate {
59 66 higgins
60 185 jones
  static int WARNING = 0;
61
  static int ERROR=1;
62
  static int FATAL_ERROR=2;
63
64
  XMLReader parser;
65
  ErrorStorer ef;
66
  String xml_doc; // document to be parsed
67 66 higgins
68 185 jones
  /** Construct a new validation object */
69
  public DBValidate(String parserName) {
70
71
    try {
72
      // Get an instance of the parser
73
      parser = XMLReaderFactory.createXMLReader(parserName);
74
      parser.setFeature("http://xml.org/sax/features/validation",true);
75
      //parser.setValidationMode(true);     // Oracle
76
    } catch (Exception e) {
77 675 berkley
      System.err.println("Could not create parser in DBValidate.DBValidate");
78 66 higgins
    }
79 185 jones
  }
80 66 higgins
81 243 jones
  /** Construct a new validation object using an OASIS catalog file */
82 185 jones
  public DBValidate(String parserName, String xmlcatalogfile)  {
83 243 jones
    this(parserName);
84 185 jones
85
    CatalogEntityResolver cer = new CatalogEntityResolver();
86
    try {
87
      Catalog myCatalog = new Catalog();
88
      myCatalog.loadSystemCatalogs();
89
      myCatalog.parseCatalog(xmlcatalogfile);
90
      cer.setCatalog(myCatalog);
91 675 berkley
    } catch (Exception e) {
92
      System.out.println("Problem creating Catalog in DBValidate.DBValidate");
93
    }
94 185 jones
95
    parser.setEntityResolver(cer);
96
  }
97
98 243 jones
  /** Construct a new validation object using a database entity resolver */
99
  public DBValidate(String parserName, Connection conn) {
100
    this(parserName);
101
102
    DBEntityResolver dbresolver = new DBEntityResolver(conn);
103
    parser.setEntityResolver(dbresolver);
104
  }
105
106 185 jones
  /**
107
   * validate an xml document against its DTD
108
   *
109
   * @param doc the filename of the document to validate
110
   */
111
  public boolean validate(String doc) {
112
    xml_doc = doc;
113
    ef = new ErrorStorer();
114
    ef.resetErrors();
115
    parser.setErrorHandler(ef);
116
    try {
117
      parser.parse((createURL(xml_doc)).toString());
118
    } catch (IOException e) {
119 675 berkley
      System.out.println("IOException:Could not parse :" + xml_doc +
120
                         " from DBValidate.validate");
121 185 jones
      ParseError eip = null;
122 243 jones
      eip = new ParseError("",0,0,
123 185 jones
                "IOException:Could not parse :"+xml_doc);
124
      if (ef.errorNodes == null)  ef.errorNodes = new Vector();
125
      ef.errorNodes.addElement(eip);
126 66 higgins
127 185 jones
    } catch (Exception e) {}
128
129
      // {System.out.println("Exception parsing:Could not parse :"+xml_doc);}
130 66 higgins
131 185 jones
    if (ef != null && ef.getErrorNodes()!=null &&
132
      ef.getErrorNodes().size() > 0 ) {
133
      return false;
134
    } else {
135
      return true;
136 66 higgins
    }
137 185 jones
  }
138 66 higgins
139 185 jones
  /**
140
   * validate an xml document against its DTD
141
   *
142
   * @param xmldoc the String containing the xml document to validate
143
   */
144
  public boolean validateString(String xmldoc) {
145 66 higgins
    // string is actual XML here, NOT URL or file name
146 185 jones
    ef = new ErrorStorer();
147
    ef.resetErrors();
148
    parser.setErrorHandler(ef);
149
150
    InputSource is = new InputSource(new StringReader(xmldoc));
151
    try {
152
      parser.parse(is);
153
    }
154 675 berkley
    catch (Exception e) {
155
      System.out.println("Error in parsing in DBValidate.validateString");
156
    }
157 66 higgins
158 185 jones
    if (ef != null && ef.getErrorNodes()!=null &&
159
      ef.getErrorNodes().size() > 0 ) {
160
      return false;
161
    } else {
162
      return true;
163 66 higgins
    }
164 185 jones
  }
165 66 higgins
166 243 jones
  /** provide a list of errors from the validation process */
167 185 jones
  public String returnErrors() {
168 243 jones
    StringBuffer errorstring = new StringBuffer();
169
    errorstring.append("<?xml version=\"1.0\" ?>\n");
170 185 jones
    if (ef != null && ef.getErrorNodes()!=null &&
171
        ef.getErrorNodes().size() > 0 ) {
172
      Vector errors = ef.getErrorNodes();
173 243 jones
      errorstring.append("<validationerrors>\n");
174 185 jones
      for (Enumeration e = errors.elements() ; e.hasMoreElements() ;) {
175 243 jones
        errorstring.append(
176
                      ((ParseError)(e.nextElement())).toXML());
177 185 jones
      }
178 243 jones
      errorstring.append("</validationerrors>\n");
179 185 jones
    } else {
180 243 jones
      errorstring.append("<valid />\n");
181 66 higgins
    }
182 243 jones
    return errorstring.toString();
183 185 jones
  }
184 66 higgins
185 185 jones
  /** Create a URL object from either a URL string or a plain file name. */
186
  private URL createURL(String name) throws Exception {
187
    try {
188
      URL u = new URL(name);
189
      return u;
190
    } catch (MalformedURLException ex) {
191
    }
192
    URL u = new URL("file:" + new File(name).getAbsolutePath());
193
    return u;
194
  }
195
196
  /**
197
   * main method for testing
198
   * <p>
199
   * Usage: java DBValidate <xmlfile or URL>
200
   */
201
  public static void main(String[] args) {
202
203
    if (args.length != 1) {
204
      System.out.println("Usage: java DBValidate <xmlfile or URL>");
205
      System.exit(0);
206
    }
207
208
    String doc = args[0];
209
210 203 jones
    MetaCatUtil util = new MetaCatUtil();
211 243 jones
    try {
212
      Connection conn = util.openDBConnection();
213
214
      DBValidate gxv = new DBValidate(util.getOption("saxparser"), conn);
215
      if (gxv.validate(doc)) {
216
        System.out.print(gxv.returnErrors());
217
      } else {
218
        System.out.print(gxv.returnErrors());
219
      }
220
    } catch (SQLException e) {
221
      System.out.println("<error>Couldn't open database connection.</error>");
222
    } catch (ClassNotFoundException e) {
223
      System.out.println("<error>Couldn't open database connection.</error>");
224 185 jones
    }
225
  }
226
227
228
  /**
229
   * ErrorStorer has been revised here to simply create a Vector of
230
   * ParseError objects
231
   *
232
   */
233
  class ErrorStorer implements ErrorHandler {
234
235 66 higgins
    //
236 185 jones
    // Data
237 66 higgins
    //
238 185 jones
    Vector errorNodes = null;
239
240 66 higgins
    /**
241 185 jones
     * Constructor
242 66 higgins
     */
243 185 jones
    public ErrorStorer() {
244
    }
245 66 higgins
246 185 jones
    /**
247
     * The client is is allowed to get a reference to the Hashtable,
248
     * and so could corrupt it, or add to it...
249
     */
250
    public Vector getErrorNodes() {
251
        return errorNodes;
252
    }
253 66 higgins
254 185 jones
    /**
255
     * The ParseError object for the node key is returned.
256
     * If the node doesn't have errors, null is returned.
257
     */
258
    public Object getError() {
259
        if (errorNodes == null)
260
            return null;
261
        return errorNodes;
262
    }
263 66 higgins
264 185 jones
    /**
265
     * Reset the error storage.
266
     */
267
    public void resetErrors() {
268
        if (errorNodes != null)
269
        errorNodes.removeAllElements();
270
    }
271
272
    /***/
273
    public void warning(SAXParseException ex) {
274
        handleError(ex, WARNING);
275
    }
276 66 higgins
277 185 jones
    public void error(SAXParseException ex) {
278
        handleError(ex, ERROR);
279
    }
280 66 higgins
281 185 jones
    public void fatalError(SAXParseException ex) throws SAXException {
282
        handleError(ex, FATAL_ERROR);
283
    }
284 66 higgins
285 185 jones
    private void handleError(SAXParseException ex, int type) {
286
      // System.out.println("!!! handleError: "+ex.getMessage());
287 66 higgins
288 185 jones
      if (errorNodes == null) {
289
        errorNodes = new Vector();
290
      }
291 243 jones
292 185 jones
      ParseError eip = null;
293 243 jones
      eip = new ParseError(ex.getSystemId(), ex.getLineNumber(),
294
                           ex.getColumnNumber(), ex.getMessage());
295 66 higgins
296 185 jones
      // put it in the Hashtable.
297
      errorNodes.addElement(eip);
298
    }
299 66 higgins
300 185 jones
  }
301 66 higgins
302 185 jones
  /**
303
   * The ParseError class wraps up all the error info from
304
   * the ErrorStorer's error method.
305
   *
306
   * @see ErrorStorer
307
   */
308
  class ParseError extends Object {
309 66 higgins
310 185 jones
    //
311
    // Data
312
    //
313 66 higgins
314 185 jones
    String fileName;
315
    int lineNo;
316
    int charOffset;
317
    String msg;
318 66 higgins
319 185 jones
    /**
320
     * Constructor
321
     */
322 243 jones
    public ParseError(String fileName, int lineNo, int charOffset, String msg) {
323
      this.fileName=fileName;
324
      this.lineNo=lineNo;
325
      this.charOffset=charOffset;
326
      this.msg=msg;
327 185 jones
    }
328 66 higgins
329 185 jones
    //
330
    // Getters...
331
    //
332
    public String getFileName() { return fileName; }
333
    public int getLineNo() { return lineNo; }
334
    public int getCharOffset() { return charOffset;}
335
    public String getMsg() { return msg; }
336
    public void setMsg(String s) { msg = s; }
337 243 jones
338
    /** Return the error message as an xml fragment */
339
    public String toXML() {
340
      StringBuffer err = new StringBuffer();
341
      err.append("<error>\n");
342
      err.append("<filename>").append(getFileName()).append("</filename>\n");
343
      err.append("<line>").append(getLineNo()).append("</line>\n");
344
      err.append("<offset>").append(getCharOffset()).append("</offset>\n");
345
      err.append("<message>").append(getMsg()).append("</message>\n");
346
      err.append("</error>\n");
347
      return err.toString();
348
    }
349 185 jones
  }
350 80 jones
}