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
 * 
11
 *   '$Author: jones $'
12
 *     '$Date: 2000-06-29 16:27:08 -0700 (Thu, 29 Jun 2000) $'
13
 * '$Revision: 243 $'
14
 */
15
package edu.ucsb.nceas.metacat;
16

    
17

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

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

    
30
import com.arbortext.catalog.*;
31

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

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

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

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

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

    
234
    /**
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
        
244
    /**
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

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

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

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

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

    
290
    //
291
    // Data
292
    //
293

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

    
299
    /**
300
     * Constructor
301
     */
302
    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
    }
308

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

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

    
332
/**
333
 * '$Log$
334
 * '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
 * '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
 */
(16-16/25)