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