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