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 1343 tao
  public boolean alreadyHandle = false;
68 66 higgins
69 185 jones
  /** Construct a new validation object */
70
  public DBValidate(String parserName) {
71 1343 tao
    alreadyHandle = false;
72 185 jones
    try {
73
      // Get an instance of the parser
74
      parser = XMLReaderFactory.createXMLReader(parserName);
75
      parser.setFeature("http://xml.org/sax/features/validation",true);
76
      //parser.setValidationMode(true);     // Oracle
77
    } catch (Exception e) {
78 675 berkley
      System.err.println("Could not create parser in DBValidate.DBValidate");
79 66 higgins
    }
80 185 jones
  }
81 66 higgins
82 243 jones
  /** Construct a new validation object using an OASIS catalog file */
83 185 jones
  public DBValidate(String parserName, String xmlcatalogfile)  {
84 243 jones
    this(parserName);
85 185 jones
86
    CatalogEntityResolver cer = new CatalogEntityResolver();
87
    try {
88
      Catalog myCatalog = new Catalog();
89
      myCatalog.loadSystemCatalogs();
90
      myCatalog.parseCatalog(xmlcatalogfile);
91
      cer.setCatalog(myCatalog);
92 675 berkley
    } catch (Exception e) {
93
      System.out.println("Problem creating Catalog in DBValidate.DBValidate");
94
    }
95 185 jones
96
    parser.setEntityResolver(cer);
97
  }
98
99 243 jones
  /** Construct a new validation object using a database entity resolver */
100 1217 tao
  public DBValidate(String parserName, DBConnection conn) {
101 243 jones
    this(parserName);
102
103
    DBEntityResolver dbresolver = new DBEntityResolver(conn);
104
    parser.setEntityResolver(dbresolver);
105
  }
106
107 185 jones
  /**
108
   * validate an xml document against its DTD
109
   *
110
   * @param doc the filename of the document to validate
111
   */
112
  public boolean validate(String doc) {
113
    xml_doc = doc;
114
    ef = new ErrorStorer();
115
    ef.resetErrors();
116
    parser.setErrorHandler(ef);
117
    try {
118
      parser.parse((createURL(xml_doc)).toString());
119
    } catch (IOException e) {
120 675 berkley
      System.out.println("IOException:Could not parse :" + xml_doc +
121
                         " from DBValidate.validate");
122 185 jones
      ParseError eip = null;
123 243 jones
      eip = new ParseError("",0,0,
124 185 jones
                "IOException:Could not parse :"+xml_doc);
125
      if (ef.errorNodes == null)  ef.errorNodes = new Vector();
126
      ef.errorNodes.addElement(eip);
127 66 higgins
128 185 jones
    } catch (Exception e) {}
129
130 66 higgins
131 1343 tao
132 185 jones
    if (ef != null && ef.getErrorNodes()!=null &&
133
      ef.getErrorNodes().size() > 0 ) {
134
      return false;
135
    } else {
136
      return true;
137 66 higgins
    }
138 185 jones
  }
139 66 higgins
140 185 jones
  /**
141
   * validate an xml document against its DTD
142
   *
143
   * @param xmldoc the String containing the xml document to validate
144
   */
145
  public boolean validateString(String xmldoc) {
146 66 higgins
    // string is actual XML here, NOT URL or file name
147 185 jones
    ef = new ErrorStorer();
148
    ef.resetErrors();
149
    parser.setErrorHandler(ef);
150
151
    InputSource is = new InputSource(new StringReader(xmldoc));
152 1343 tao
    try
153
    {
154
155 185 jones
      parser.parse(is);
156 1343 tao
157 185 jones
    }
158 1343 tao
    catch (SAXParseException e)
159
    {
160
      System.out.println("SAXParseException Error in DBValidate.validateString"
161
                         +e.getMessage());
162
      ef.error(e);
163 675 berkley
    }
164 1343 tao
    catch (SAXException saxe)
165
    {
166
      System.out.println("SAXException error in validateString: "
167
                          +saxe.getMessage());
168
      ef.otherError(saxe, null);
169
170
    }
171
    catch (IOException ioe)
172
    {
173
      System.out.println("IOExcption error in validateString "
174
                          +ioe.getMessage());
175
      ef.otherError(ioe, null);
176
    }
177 66 higgins
178 185 jones
    if (ef != null && ef.getErrorNodes()!=null &&
179
      ef.getErrorNodes().size() > 0 ) {
180
      return false;
181
    } else {
182
      return true;
183 66 higgins
    }
184 185 jones
  }
185 66 higgins
186 243 jones
  /** provide a list of errors from the validation process */
187 185 jones
  public String returnErrors() {
188 243 jones
    StringBuffer errorstring = new StringBuffer();
189
    errorstring.append("<?xml version=\"1.0\" ?>\n");
190 185 jones
    if (ef != null && ef.getErrorNodes()!=null &&
191
        ef.getErrorNodes().size() > 0 ) {
192
      Vector errors = ef.getErrorNodes();
193 243 jones
      errorstring.append("<validationerrors>\n");
194 185 jones
      for (Enumeration e = errors.elements() ; e.hasMoreElements() ;) {
195 243 jones
        errorstring.append(
196
                      ((ParseError)(e.nextElement())).toXML());
197 185 jones
      }
198 243 jones
      errorstring.append("</validationerrors>\n");
199 185 jones
    } else {
200 243 jones
      errorstring.append("<valid />\n");
201 66 higgins
    }
202 243 jones
    return errorstring.toString();
203 185 jones
  }
204 66 higgins
205 185 jones
  /** Create a URL object from either a URL string or a plain file name. */
206
  private URL createURL(String name) throws Exception {
207
    try {
208
      URL u = new URL(name);
209
      return u;
210
    } catch (MalformedURLException ex) {
211
    }
212
    URL u = new URL("file:" + new File(name).getAbsolutePath());
213
    return u;
214
  }
215
216
  /**
217
   * main method for testing
218
   * <p>
219
   * Usage: java DBValidate <xmlfile or URL>
220
   */
221
  public static void main(String[] args) {
222
223
    if (args.length != 1) {
224
      System.out.println("Usage: java DBValidate <xmlfile or URL>");
225
      System.exit(0);
226
    }
227
228
    String doc = args[0];
229
230 203 jones
    MetaCatUtil util = new MetaCatUtil();
231 1217 tao
    DBConnection conn = null;
232
    int serailNumber = -1;
233 243 jones
    try {
234 1217 tao
      conn = DBConnectionPool.getDBConnection("DBValidate.main");
235
      serailNumber = conn.getCheckOutSerialNumber();
236 243 jones
237
      DBValidate gxv = new DBValidate(util.getOption("saxparser"), conn);
238
      if (gxv.validate(doc)) {
239
        System.out.print(gxv.returnErrors());
240
      } else {
241
        System.out.print(gxv.returnErrors());
242
      }
243
    } catch (SQLException e) {
244
      System.out.println("<error>Couldn't open database connection.</error>");
245 1217 tao
    }
246
    finally
247
    {
248
      DBConnectionPool.returnDBConnection(conn, serailNumber);
249
    }//finally
250 185 jones
  }
251
252
253
  /**
254
   * ErrorStorer has been revised here to simply create a Vector of
255
   * ParseError objects
256
   *
257
   */
258
  class ErrorStorer implements ErrorHandler {
259
260 66 higgins
    //
261 185 jones
    // Data
262 66 higgins
    //
263 185 jones
    Vector errorNodes = null;
264
265 66 higgins
    /**
266 185 jones
     * Constructor
267 66 higgins
     */
268 185 jones
    public ErrorStorer() {
269
    }
270 66 higgins
271 185 jones
    /**
272
     * The client is is allowed to get a reference to the Hashtable,
273
     * and so could corrupt it, or add to it...
274
     */
275
    public Vector getErrorNodes() {
276
        return errorNodes;
277
    }
278 66 higgins
279 185 jones
    /**
280
     * The ParseError object for the node key is returned.
281
     * If the node doesn't have errors, null is returned.
282
     */
283
    public Object getError() {
284
        if (errorNodes == null)
285
            return null;
286
        return errorNodes;
287
    }
288 66 higgins
289 185 jones
    /**
290
     * Reset the error storage.
291
     */
292
    public void resetErrors() {
293
        if (errorNodes != null)
294
        errorNodes.removeAllElements();
295
    }
296
297
    /***/
298
    public void warning(SAXParseException ex) {
299 1343 tao
300 185 jones
        handleError(ex, WARNING);
301 1343 tao
302 185 jones
    }
303 66 higgins
304 185 jones
    public void error(SAXParseException ex) {
305 1343 tao
306 185 jones
        handleError(ex, ERROR);
307 1343 tao
308 185 jones
    }
309 66 higgins
310 1343 tao
    public void fatalError(SAXParseException ex){
311
312 185 jones
        handleError(ex, FATAL_ERROR);
313 1343 tao
314 185 jones
    }
315 1343 tao
316
    public void otherError(Exception ex, String fileName)
317
    {
318
      if (!alreadyHandle)
319
      {
320
        if (errorNodes == null)
321
        {
322
          errorNodes = new Vector();
323
        }
324
325
        ParseError error = new ParseError(fileName, ex.getMessage());
326
        errorNodes.addElement(error);
327
328
      }
329
    }
330 66 higgins
331 185 jones
    private void handleError(SAXParseException ex, int type) {
332 1343 tao
333 185 jones
      if (errorNodes == null) {
334
        errorNodes = new Vector();
335
      }
336 1343 tao
337 185 jones
      ParseError eip = null;
338 1343 tao
339 243 jones
      eip = new ParseError(ex.getSystemId(), ex.getLineNumber(),
340
                           ex.getColumnNumber(), ex.getMessage());
341 1343 tao
342 185 jones
      // put it in the Hashtable.
343
      errorNodes.addElement(eip);
344 1343 tao
      alreadyHandle = true;
345
346 185 jones
    }
347 66 higgins
348 185 jones
  }
349 66 higgins
350 185 jones
  /**
351
   * The ParseError class wraps up all the error info from
352
   * the ErrorStorer's error method.
353
   *
354
   * @see ErrorStorer
355
   */
356
  class ParseError extends Object {
357 66 higgins
358 185 jones
    //
359
    // Data
360
    //
361 66 higgins
362 185 jones
    String fileName;
363
    int lineNo;
364
    int charOffset;
365
    String msg;
366 66 higgins
367 185 jones
    /**
368
     * Constructor
369
     */
370 243 jones
    public ParseError(String fileName, int lineNo, int charOffset, String msg) {
371
      this.fileName=fileName;
372
      this.lineNo=lineNo;
373
      this.charOffset=charOffset;
374
      this.msg=msg;
375 185 jones
    }
376 1343 tao
    public ParseError(String fileName, String msg) {
377
      this.fileName=fileName;
378
      this.msg=msg;
379
    }
380 185 jones
    //
381
    // Getters...
382
    //
383
    public String getFileName() { return fileName; }
384
    public int getLineNo() { return lineNo; }
385
    public int getCharOffset() { return charOffset;}
386
    public String getMsg() { return msg; }
387
    public void setMsg(String s) { msg = s; }
388 243 jones
389
    /** Return the error message as an xml fragment */
390
    public String toXML() {
391
      StringBuffer err = new StringBuffer();
392
      err.append("<error>\n");
393
      err.append("<filename>").append(getFileName()).append("</filename>\n");
394
      err.append("<line>").append(getLineNo()).append("</line>\n");
395
      err.append("<offset>").append(getCharOffset()).append("</offset>\n");
396
      err.append("<message>").append(getMsg()).append("</message>\n");
397
      err.append("</error>\n");
398
      return err.toString();
399
    }
400 185 jones
  }
401 80 jones
}