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: 2005-11-16 17:27:26 -0800 (Wed, 16 Nov 2005) $'
14
 * '$Revision: 2752 $'
15
 *
16
 * This program is free software; you can redistribute it and/or modify
17
 * it under the terms of the GNU General Public License as published by
18
 * the Free Software Foundation; either version 2 of the License, or
19
 * (at your option) any later version.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 * GNU General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU General Public License
27
 * along with this program; if not, write to the Free Software
28
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29
 */
30
package edu.ucsb.nceas.metacat;
31

    
32

    
33
import java.net.URL;
34
import java.net.MalformedURLException;
35
import java.util.*;
36
import java.io.*;
37
import java.lang.reflect.*;
38
import java.sql.*;
39

    
40
import org.w3c.dom.*;
41
import org.xml.sax.*;
42
import org.xml.sax.XMLReader;
43
import org.xml.sax.helpers.XMLReaderFactory;
44

    
45
import com.arbortext.catalog.*;
46

    
47
/**
48
 * Name: DBValidate.java
49
 *       Purpose: A Class that validates XML documents
50
 * 			   This class is designed to be parser independent
51
 *    			   i.e. it uses only org.xml.sax classes
52
 * 			   It is tied to SAX 2.0 methods
53
 *     Copyright: 2000 Regents of the University of California and the
54
 *                National Center for Ecological Analysis and Synthesis
55
 *                April 28, 2000
56
 *    Authors: Dan Higgins, Matt Jones
57
 */
58
public class DBValidate {
59
    
60
  static int WARNING = 0;
61
  static int ERROR=1;
62
  static int FATAL_ERROR=2;
63

    
64
  XMLReader parser;
65
  ErrorStorer ef;
66
  String xml_doc; // document to be parsed
67
  public boolean alreadyHandle = false;
68
    
69
  /** Construct a new validation object */
70
  public DBValidate() {
71
    alreadyHandle = false;
72
    try {
73
      // Get an instance of the parser
74
      String parserName = MetaCatUtil.getOption("saxparser");
75
      parser = XMLReaderFactory.createXMLReader(parserName);
76
      parser.setFeature("http://xml.org/sax/features/validation",true);
77
      //parser.setValidationMode(true);     // Oracle
78
    } catch (Exception e) {
79
      System.err.println("Could not create parser in DBValidate.DBValidate");
80
    }
81
  }
82
    
83
  /** Construct a new validation object using an OASIS catalog file */
84
  public DBValidate(String xmlcatalogfile)  {
85
    this();
86

    
87
    CatalogEntityResolver cer = new CatalogEntityResolver();
88
    try {
89
      Catalog myCatalog = new Catalog();
90
      myCatalog.loadSystemCatalogs();
91
      myCatalog.parseCatalog(xmlcatalogfile);
92
      cer.setCatalog(myCatalog);
93
    } catch (Exception e) {
94
      System.out.println("Problem creating Catalog in DBValidate.DBValidate");
95
    }
96

    
97
    parser.setEntityResolver(cer);
98
  }
99

    
100
  /** Construct a new validation object using a database entity resolver */
101
  public DBValidate(DBConnection conn) {
102
    this();
103

    
104
    DBEntityResolver dbresolver = new DBEntityResolver(conn);
105
    parser.setEntityResolver(dbresolver);
106
  }
107

    
108
  /** 
109
   * validate an xml document against its DTD
110
   *
111
   * @param doc the filename of the document to validate
112
   */
113
  public boolean validate(String doc) {
114
    xml_doc = doc;    
115
    ef = new ErrorStorer();
116
    ef.resetErrors();
117
    parser.setErrorHandler(ef);
118
    try {
119
      parser.parse((createURL(xml_doc)).toString());
120
    } catch (IOException e) {
121
      System.out.println("IOException:Could not parse :" + xml_doc +
122
                         " from DBValidate.validate");
123
      ParseError eip = null;
124
      eip = new ParseError("",0,0,
125
                "IOException:Could not parse :"+xml_doc);
126
      if (ef.errorNodes == null)  ef.errorNodes = new Vector();
127
      ef.errorNodes.addElement(eip);
128
        
129
    } catch (Exception e) {} 
130

    
131
    
132
    
133
    if (ef != null && ef.getErrorNodes()!=null && 
134
      ef.getErrorNodes().size() > 0 ) {
135
      return false; 
136
    } else {
137
      return true;
138
    }
139
  }
140
    
141
  /** 
142
   * validate an xml document against its DTD
143
   *
144
   * @param xmldoc the String containing the xml document to validate
145
   */
146
  public boolean validateString(String xmldoc) {
147
    // string is actual XML here, NOT URL or file name    
148
    ef = new ErrorStorer();
149
    ef.resetErrors();
150
    parser.setErrorHandler(ef);
151
      
152
    InputSource is = new InputSource(new StringReader(xmldoc));
153
    try 
154
    {
155
      
156
      parser.parse(is);
157
     
158
    }
159
    catch (SAXParseException e) 
160
    {
161
      System.out.println("SAXParseException Error in DBValidate.validateString"
162
                         +e.getMessage());
163
      ef.error(e);
164
    }
165
    catch (SAXException saxe)
166
    {
167
      System.out.println("SAXException error in validateString: "
168
                          +saxe.getMessage());
169
      ef.otherError(saxe, null);
170
      
171
    }
172
    catch (IOException ioe)
173
    {
174
      System.out.println("IOExcption error in validateString "
175
                          +ioe.getMessage());
176
      ef.otherError(ioe, null);
177
    }
178

    
179
    if (ef != null && ef.getErrorNodes()!=null && 
180
      ef.getErrorNodes().size() > 0 ) {
181
      return false; 
182
    } else {
183
      return true;
184
    }
185
  }
186
    
187
  /** provide a list of errors from the validation process */
188
  public String returnErrors() {
189
    StringBuffer errorstring = new StringBuffer();
190
    errorstring.append("<?xml version=\"1.0\" ?>\n");
191
    if (ef != null && ef.getErrorNodes()!=null && 
192
        ef.getErrorNodes().size() > 0 ) {
193
      Vector errors = ef.getErrorNodes();
194
      errorstring.append("<validationerrors>\n");
195
      for (Enumeration e = errors.elements() ; e.hasMoreElements() ;) {
196
        errorstring.append(
197
                      ((ParseError)(e.nextElement())).toXML());
198
      }
199
      errorstring.append("</validationerrors>\n");
200
    } else {
201
      errorstring.append("<valid />\n");
202
    }
203
    return errorstring.toString();
204
  }
205
              
206
  /** Create a URL object from either a URL string or a plain file name. */
207
  private URL createURL(String name) throws Exception {
208
    try {
209
      URL u = new URL(name);
210
      return u;
211
    } catch (MalformedURLException ex) {
212
    }
213
    URL u = new URL("file:" + new File(name).getAbsolutePath());
214
    return u;
215
  }    
216

    
217
  /** 
218
   * main method for testing 
219
   * <p>
220
   * Usage: java DBValidate <xmlfile or URL>
221
   */
222
  public static void main(String[] args) {
223

    
224
    if (args.length != 1) {
225
      System.out.println("Usage: java DBValidate <xmlfile or URL>");
226
      System.exit(0);
227
    }
228

    
229
    String doc = args[0];
230

    
231
    MetaCatUtil util = new MetaCatUtil();
232
    DBConnection conn = null;
233
    int serailNumber = -1;
234
    try {
235
      conn = DBConnectionPool.getDBConnection("DBValidate.main");
236
      serailNumber = conn.getCheckOutSerialNumber();
237
  
238
      DBValidate gxv = new DBValidate(conn);
239
      if (gxv.validate(doc)) {
240
        System.out.print(gxv.returnErrors());
241
      } else {
242
        System.out.print(gxv.returnErrors());
243
      }
244
    } catch (SQLException e) {
245
      System.out.println("<error>Couldn't open database connection.</error>");
246
    } 
247
    finally
248
    {
249
      DBConnectionPool.returnDBConnection(conn, serailNumber);
250
    }//finally
251
  }
252

    
253
    
254
  /**
255
   * ErrorStorer has been revised here to simply create a Vector of 
256
   * ParseError objects
257
   *
258
   */
259
  class ErrorStorer implements ErrorHandler {
260

    
261
    //
262
    // Data
263
    //
264
    Vector errorNodes = null;
265
        
266
    /**
267
     * Constructor
268
     */
269
    public ErrorStorer() {
270
    }
271

    
272
    /**
273
     * The client is is allowed to get a reference to the Hashtable,
274
     * and so could corrupt it, or add to it...
275
     */
276
    public Vector getErrorNodes() {
277
        return errorNodes;
278
    }
279

    
280
    /**
281
     * The ParseError object for the node key is returned.
282
     * If the node doesn't have errors, null is returned.
283
     */
284
    public Object getError() {
285
        if (errorNodes == null)
286
            return null;
287
        return errorNodes;
288
    }
289
        
290
    /**
291
     * Reset the error storage.
292
     */
293
    public void resetErrors() {
294
        if (errorNodes != null)
295
        errorNodes.removeAllElements();
296
    }
297
    
298
    /***/
299
    public void warning(SAXParseException ex) {
300
        
301
        handleError(ex, WARNING);
302
        
303
    }
304

    
305
    public void error(SAXParseException ex) {
306
      
307
        handleError(ex, ERROR);
308
       
309
    }
310

    
311
    public void fatalError(SAXParseException ex){
312
      
313
        handleError(ex, FATAL_ERROR);
314
        
315
    }
316
    
317
    public void otherError(Exception ex, String fileName)
318
    {
319
      if (!alreadyHandle)
320
      {
321
        if (errorNodes == null) 
322
        {
323
          errorNodes = new Vector();
324
        }
325
      
326
        ParseError error = new ParseError(fileName, ex.getMessage());
327
        errorNodes.addElement(error);
328
       
329
      }
330
    }
331
        
332
    private void handleError(SAXParseException ex, int type) {
333
     
334
      if (errorNodes == null) {
335
        errorNodes = new Vector();
336
      }
337
      
338
      ParseError eip = null;
339
      
340
      eip = new ParseError(ex.getSystemId(), ex.getLineNumber(),
341
                           ex.getColumnNumber(), ex.getMessage());
342
      
343
      // put it in the Hashtable.
344
      errorNodes.addElement(eip);
345
      alreadyHandle = true;
346
      
347
    }
348
        
349
  }
350
    
351
  /**
352
   * The ParseError class wraps up all the error info from
353
   * the ErrorStorer's error method.
354
   *
355
   * @see ErrorStorer
356
   */
357
  class ParseError extends Object {
358

    
359
    //
360
    // Data
361
    //
362

    
363
    String fileName;
364
    int lineNo;
365
    int charOffset;
366
    String msg;
367

    
368
    /**
369
     * Constructor
370
     */
371
    public ParseError(String fileName, int lineNo, int charOffset, String msg) {
372
      this.fileName=fileName;
373
      this.lineNo=lineNo;
374
      this.charOffset=charOffset;
375
      this.msg=msg;
376
    }
377
    public ParseError(String fileName, String msg) {
378
      this.fileName=fileName;
379
      this.msg=msg;
380
    }
381
    //
382
    // Getters...
383
    //
384
    public String getFileName() { return fileName; }
385
    public int getLineNo() { return lineNo; }
386
    public int getCharOffset() { return charOffset;}
387
    public String getMsg() { return msg; }
388
    public void setMsg(String s) { msg = s; }
389

    
390
    /** Return the error message as an xml fragment */
391
    public String toXML() {
392
      StringBuffer err = new StringBuffer();
393
      err.append("<error>\n");
394
      err.append("<filename>").append(getFileName()).append("</filename>\n");
395
      err.append("<line>").append(getLineNo()).append("</line>\n");
396
      err.append("<offset>").append(getCharOffset()).append("</offset>\n");
397
      err.append("<message>").append(getMsg()).append("</message>\n");
398
      err.append("</error>\n");
399
      return err.toString();
400
    }
401
  }
402
}
(28-28/65)