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