Project

General

Profile

1
/**
2
 *  '$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
 *    Release: @release@
11
 * 
12
 *   '$Author: jones $'
13
 *     '$Date: 2000-08-14 13:53:34 -0700 (Mon, 14 Aug 2000) $'
14
 * '$Revision: 349 $'
15
 */
16
package edu.ucsb.nceas.metacat;
17

    
18

    
19
import java.net.URL;
20
import java.net.MalformedURLException;
21
import java.util.*;
22
import java.io.*;
23
import java.lang.reflect.*;
24
import java.sql.*;
25

    
26
import org.w3c.dom.*;
27
import org.xml.sax.*;
28
import org.xml.sax.XMLReader;
29
import org.xml.sax.helpers.XMLReaderFactory;
30

    
31
import com.arbortext.catalog.*;
32

    
33
/**
34
 * Name: DBValidate.java
35
 *       Purpose: A Class that validates XML documents
36
 * 			   This class is designed to be parser independent
37
 *    			   i.e. it uses only org.xml.sax classes
38
 * 			   It is tied to SAX 2.0 methods
39
 *     Copyright: 2000 Regents of the University of California and the
40
 *                National Center for Ecological Analysis and Synthesis
41
 *                April 28, 2000
42
 *    Authors: Dan Higgins, Matt Jones
43
 */
44
public class DBValidate {
45
    
46
  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
    
54
  /** 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
    }
65
  }
66
    
67
  /** Construct a new validation object using an OASIS catalog file */
68
  public DBValidate(String parserName, String xmlcatalogfile)  {
69
    this(parserName);
70

    
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
  /** 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
  /** 
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
      eip = new ParseError("",0,0,
106
                "IOException:Could not parse :"+xml_doc);
107
      if (ef.errorNodes == null)  ef.errorNodes = new Vector();
108
      ef.errorNodes.addElement(eip);
109
        
110
    } catch (Exception e) {} 
111

    
112
      // {System.out.println("Exception parsing:Could not parse :"+xml_doc);} 
113
    
114
    if (ef != null && ef.getErrorNodes()!=null && 
115
      ef.getErrorNodes().size() > 0 ) {
116
      return false; 
117
    } else {
118
      return true;
119
    }
120
  }
121
    
122
  /** 
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
    // string is actual XML here, NOT URL or file name    
129
    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

    
139
    if (ef != null && ef.getErrorNodes()!=null && 
140
      ef.getErrorNodes().size() > 0 ) {
141
      return false; 
142
    } else {
143
      return true;
144
    }
145
  }
146
    
147
  /** provide a list of errors from the validation process */
148
  public String returnErrors() {
149
    StringBuffer errorstring = new StringBuffer();
150
    errorstring.append("<?xml version=\"1.0\" ?>\n");
151
    if (ef != null && ef.getErrorNodes()!=null && 
152
        ef.getErrorNodes().size() > 0 ) {
153
      Vector errors = ef.getErrorNodes();
154
      errorstring.append("<validationerrors>\n");
155
      for (Enumeration e = errors.elements() ; e.hasMoreElements() ;) {
156
        errorstring.append(
157
                      ((ParseError)(e.nextElement())).toXML());
158
      }
159
      errorstring.append("</validationerrors>\n");
160
    } else {
161
      errorstring.append("<valid />\n");
162
    }
163
    return errorstring.toString();
164
  }
165
              
166
  /** 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
    MetaCatUtil util = new MetaCatUtil();
192
    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
    }
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
    //
217
    // Data
218
    //
219
    Vector errorNodes = null;
220
        
221
    /**
222
     * Constructor
223
     */
224
    public ErrorStorer() {
225
    }
226

    
227
    /**
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

    
235
    /**
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
        
245
    /**
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

    
258
    public void error(SAXParseException ex) {
259
        handleError(ex, ERROR);
260
    }
261

    
262
    public void fatalError(SAXParseException ex) throws SAXException {
263
        handleError(ex, FATAL_ERROR);
264
    }
265
        
266
    private void handleError(SAXParseException ex, int type) {
267
      // System.out.println("!!! handleError: "+ex.getMessage());
268

    
269
      if (errorNodes == null) {
270
        errorNodes = new Vector();
271
      }
272

    
273
      ParseError eip = null;
274
      eip = new ParseError(ex.getSystemId(), ex.getLineNumber(),
275
                           ex.getColumnNumber(), ex.getMessage());
276
        
277
      // put it in the Hashtable.
278
      errorNodes.addElement(eip);
279
    }
280
        
281
  }
282
    
283
  /**
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

    
291
    //
292
    // Data
293
    //
294

    
295
    String fileName;
296
    int lineNo;
297
    int charOffset;
298
    String msg;
299

    
300
    /**
301
     * Constructor
302
     */
303
    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
    }
309

    
310
    //
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

    
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
  }
331
}
332

    
333
/**
334
 * '$Log$
335
 * '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
 * '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
 * '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
 */
(14-14/27)