Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that implements a metadata catalog as a java Servlet
4
 *  Copyright: 2000 Regents of the University of California and the
5
 *             National Center for Ecological Analysis and Synthesis
6
 *    Authors: Matt Jones, Dan Higgins
7
 *
8
 *   '$Author: jones $'
9
 *     '$Date: 2000-06-26 21:31:07 -0700 (Mon, 26 Jun 2000) $'
10
 * '$Revision: 204 $'
11
 */
12

    
13
package edu.ucsb.nceas.metacat;
14

    
15
import java.io.PrintWriter;
16
import java.io.IOException;
17
import java.io.Reader;
18
import java.io.StringReader;
19
import java.io.BufferedReader;
20
import java.io.File;
21
import java.io.FileInputStream;
22
import java.util.Enumeration;
23
import java.util.Hashtable;
24
import java.util.ResourceBundle;
25
import java.util.PropertyResourceBundle;
26
import java.net.URL;
27
import java.net.MalformedURLException;
28
import java.sql.PreparedStatement;
29
import java.sql.ResultSet;
30
import java.sql.Connection;
31
import java.sql.SQLException;
32

    
33
import javax.servlet.ServletConfig;
34
import javax.servlet.ServletContext;
35
import javax.servlet.ServletException;
36
import javax.servlet.ServletInputStream;
37
import javax.servlet.http.HttpServlet;
38
import javax.servlet.http.HttpServletRequest;
39
import javax.servlet.http.HttpServletResponse;
40
import javax.servlet.http.HttpUtils;
41

    
42
import oracle.xml.parser.v2.XSLStylesheet;
43
import oracle.xml.parser.v2.XSLException;
44
import oracle.xml.parser.v2.XMLDocumentFragment;
45
import oracle.xml.parser.v2.XSLProcessor;
46

    
47
import org.xml.sax.SAXException;
48

    
49
/**
50
 * A metadata catalog server implemented as a Java Servlet
51
 *
52
 * <p>Valid parameters are:<br>
53
 * action=query -- query the values of all elements and attributes
54
 *                     and return a result set of nodes<br>
55
 * action=squery -- structured query (@see pathquery.dtd)
56
 * doctype -- document type list returned by the query (publicID)
57
 * qformat=xml -- display resultset from query in XML<br>
58
 * qformat=html -- display resultset from query in HTML<br>
59
 * action=getdocument -- display an XML document in XML or HTML<br>
60
 * docid=34 -- display the document with the document ID number 34<br>
61
 * action=putdocument -- load an XML document into the database store<br>
62
 * doctext -- XML text ofthe document to load into the database<br>
63
 * query -- actual query text (to go with 'action=query' or 'action=squery')<br>
64
 * action=validate -- vallidate the xml contained in validatetext<br>
65
 * valtext -- XML text to be validated
66
 * action=getdatadoc -- retreive a stored datadocument
67
 * datadoc -- data document name (id)
68
 */
69
public class MetaCatServlet extends HttpServlet {
70

    
71
  private ServletConfig		config = null;
72
  private ServletContext	context = null;
73
  private Connection 		conn = null;
74
  private DBQuery		queryobj = null;
75
  private DBReader		docreader = null;
76
  private DBTransform		dbt = null;
77
  private String 		resultStyleURL = null;
78
  private String 		xmlcatalogfile = null;
79
  private String 		saxparser = null;
80
  private String    		defaultdatapath = null; 
81
					// path to directory where data files 
82
					// that can be downloaded will be stored
83
  private String    		executescript  = null;  
84
					// script to get data file and put it 
85
                                    	// in defaultdocpath dir
86
  private PropertyResourceBundle options = null;
87

    
88
  private MetaCatUtil util = null;
89

    
90
  /**
91
   * Initialize the servlet by creating appropriate database connections
92
   */
93
  public void init( ServletConfig config ) throws ServletException {
94
    try {
95
      super.init( config );
96
      this.config = config;
97
      this.context = config.getServletContext();
98
      System.out.println("MetaCatServlet Initialize");
99

    
100
      util = new MetaCatUtil();
101

    
102
      // Get the configuration file information
103
      resultStyleURL = util.getOption("resultStyleURL");
104
      xmlcatalogfile = util.getOption("xmlcatalogfile");
105
      saxparser = util.getOption("saxparser");
106
      defaultdatapath = util.getOption("defaultdatapath");
107
      executescript = util.getOption("executescript");
108

    
109
      try {
110
        // Open a connection to the database
111
        conn = util.openDBConnection();
112

    
113
        queryobj = new DBQuery(conn,saxparser);
114
        docreader = new DBReader(conn);
115
        dbt = new DBTransform(conn);
116

    
117
      } catch (Exception e) {
118
        System.err.println("Error opening database connection");
119
      }
120
    } catch ( ServletException ex ) {
121
      throw ex;
122
    }
123
  }
124

    
125
  /** Handle "GET" method requests from HTTP clients */
126
  public void doGet (HttpServletRequest request, HttpServletResponse response)
127
    throws ServletException, IOException {
128

    
129
    // Process the data and send back the response
130
    handleGetOrPost(request, response);
131
  }
132

    
133
  /** Handle "POST" method requests from HTTP clients */
134
  public void doPost( HttpServletRequest request, HttpServletResponse response)
135
    throws ServletException, IOException {
136

    
137
    // Process the data and send back the response
138
    handleGetOrPost(request, response);
139
  }
140

    
141
  /**
142
   * Control servlet response depending on the action parameter specified
143
   */
144
  private void handleGetOrPost(HttpServletRequest request, 
145
    HttpServletResponse response) 
146
    throws ServletException, IOException {
147

    
148
    if (conn == null) {
149
      System.err.println("Connection to database lost.  Reopening...");
150
      try {
151
        // Open a connection to the database
152
        conn = util.openDBConnection();
153
  
154
        queryobj = new DBQuery(conn, saxparser);
155
        docreader = new DBReader(conn);
156
        dbt = new DBTransform(conn);
157
  
158
      } catch (Exception e) {
159
        System.err.println("Error opening database connection");
160
      }
161
    }
162

    
163
    // Get a handle to the output stream back to the client
164
    PrintWriter out = response.getWriter();
165
    //response.setContentType("text/html");
166
  
167
    String name = null;
168
    String[] value = null;
169
    String[] docid = new String[3];
170
    Hashtable params = new Hashtable();
171
    Enumeration paramlist = request.getParameterNames();
172
    while (paramlist.hasMoreElements()) {
173
      name = (String)paramlist.nextElement();
174
      value = request.getParameterValues(name);
175

    
176
      // Decode the docid and mouse click information
177
      if (name.endsWith(".y")) {
178
        docid[0] = name.substring(0,name.length()-2);
179
        //out.println("docid => " + docid[0]);
180
        params.put("docid", docid);
181
        name = "ypos";
182
      }
183
      if (name.endsWith(".x")) {
184
        name = "xpos";
185
      }
186

    
187
      //out.println(name + " => " + value[0]);
188
      params.put(name,value);
189
    }
190

    
191
    // Determine what type of request the user made
192
    // if the action parameter is set, use it as a default
193
    // but if the ypos param is set, calculate the action needed
194
    String action = ((String[])params.get("action"))[0];
195
    long ypos = 0;
196
    try {
197
      ypos = (new Long(((String[])params.get("ypos"))[0]).longValue());
198
      //out.println("<P>YPOS IS " + ypos);
199
      if (ypos <= 13) {
200
        action = "getdocument";
201
      } else if (ypos > 13 && ypos <= 27) {
202
        action = "validate";
203
      } else if (ypos > 27) {
204
        action = "transform";
205
      } else {
206
        action = "";
207
      }
208
    } catch (Exception npe) {
209
      //out.println("<P>Caught exception looking for Y value.");
210
    }
211

    
212
    if (action.equals("query") || action.equals("squery")) {
213
      handleQueryAction(out, params, response);
214
    } else if (action.equals("getdocument")) {
215
      try {
216
        handleGetDocumentAction(out, params, response);
217
      } catch (ClassNotFoundException e) {
218
        out.println(e.getMessage());
219
      } catch (SQLException se) {
220
        out.println(se.getMessage());
221
      }
222
    } else if (action.equals("insert") || action.equals("update")) {
223
      handleInsertOrUpdateAction(out, params, response);
224
    } else if (action.equals("delete")) {
225
      handleDeleteAction(out, params, response);
226
    } else if (action.equals("validate")) {
227
      handleValidateAction(out, params, response);  
228
    } else if (action.equals("getdatadoc")) {
229
      handleGetDataDocumentAction(out, params, response);  
230
    } else {
231
      out.println("Error: action not registered.  Please report this error.");
232
    }
233

    
234
    // Close the stream to the client
235
    out.close();
236
  }
237

    
238
  /** 
239
   * Handle the database query request and return a result set, possibly
240
   * transformed from XML into HTML
241
   */
242
  private void handleQueryAction(PrintWriter out, Hashtable params, 
243
               HttpServletResponse response) {
244
      String action = ((String[])params.get("action"))[0];
245
      String query = ((String[])params.get("query"))[0]; 
246
      Hashtable doclist = null;
247
      String[] doctypeArr = null;
248
      String doctype = null;
249
      Reader xmlquery = null;
250

    
251
      // Run the query if it is a structured query
252
      // or, if it is a free-text, simple query,
253
      // format it first as a structured query and then run it
254
      if (action.equals("query")) {
255
        doctypeArr = (String[])params.get("doctype");
256
        doctype = null;
257
        if (doctypeArr != null) {
258
          doctype = ((String[])params.get("doctype"))[0]; 
259
        }
260

    
261
        if (doctype != null) {
262
          xmlquery = new StringReader(DBQuery.createQuery(query,doctype));
263
        } else {
264
          xmlquery = new StringReader(DBQuery.createQuery(query));
265
        }
266
      } else if (action.equals("squery")) {
267
        xmlquery = new StringReader(query);
268
      } else {
269
        System.err.println("Error handling query -- illegal action value");
270
      }
271

    
272
      if (queryobj != null) {
273
          doclist = queryobj.findDocuments(xmlquery);
274
      } else {
275
        out.println("Query Object Init failed.");
276
        return;
277
      }
278
 
279
      // Create a buffer to hold the xml result
280
      StringBuffer resultset = new StringBuffer();
281
 
282
      // Print the resulting root nodes
283
      String docid;
284
      String document = null;
285
      resultset.append("<?xml version=\"1.0\"?>\n");
286
      //resultset.append("<!DOCTYPE resultset PUBLIC " +
287
      //               "\"-//NCEAS//resultset//EN\" \"resultset.dtd\">\n");
288
      resultset.append("<resultset>\n");
289
      resultset.append("  <query>" + query + "</query>");
290
      Enumeration doclistkeys = doclist.keys(); 
291
      while (doclistkeys.hasMoreElements()) {
292
        docid = (String)doclistkeys.nextElement();
293
        document = (String)doclist.get(docid);
294
        resultset.append("  <document>" + document + "</document>");
295
      }
296
      resultset.append("</resultset>");
297

    
298
      String qformat = ((String[])params.get("qformat"))[0]; 
299
      if (qformat.equals("xml")) {
300
        // set content type and other response header fields first
301
        response.setContentType("text/xml");
302
        out.println(resultset.toString());
303
      } else if (qformat.equals("html")) {
304
        // set content type and other response header fields first
305
        response.setContentType("text/html");
306
        //out.println("Converting to HTML...");
307
        XMLDocumentFragment htmldoc = null;
308
        try {
309
          XSLStylesheet style = new XSLStylesheet(
310
                                    new URL(resultStyleURL), null);
311
          htmldoc = (new XSLProcessor()).processXSL(style, 
312
                     (Reader)(new StringReader(resultset.toString())),null);
313
          htmldoc.print(out);
314
        } catch (Exception e) {
315
          out.println("Error transforming document:\n" + e.getMessage());
316
        }
317
      }
318
  }
319

    
320
  /** 
321
   * Handle the database getdocument request and return a XML document, 
322
   * possibly transformed from XML into HTML
323
   */
324
  private void handleGetDocumentAction(PrintWriter out, Hashtable params, 
325
               HttpServletResponse response) 
326
               throws ClassNotFoundException, IOException, SQLException {
327
    String docidstr = null;
328
    String docid = null;
329
    String doc = null;
330
    try {
331
      // Find the document id number
332
      docidstr = ((String[])params.get("docid"))[0]; 
333
      //docid = (new Long(docidstr)).longValue();
334
      docid = docidstr;
335

    
336
      // Get the document indicated fromthe db
337
      doc = docreader.readXMLDocument(docid);
338
    } catch (NullPointerException npe) {
339
      response.setContentType("text/html");
340
      out.println("Error getting document ID: " + docidstr +" (" + docid + ")");
341
    }
342

    
343
      // Return the document in XML or HTML format
344
      String qformat = ((String[])params.get("qformat"))[0]; 
345
      if (qformat.equals("xml")) {
346
        // set content type and other response header fields first
347
        response.setContentType("text/xml");
348
        out.println(doc);
349
      } else if (qformat.equals("html")) {
350
        // set content type and other response header fields first
351
        response.setContentType("text/html");
352

    
353
        // Look up the document type
354
        String sourcetype = docreader.getDoctypeInfo(docid).getDoctype();
355

    
356
        // Transform the document to the new doctype
357
        dbt.transformXMLDocument(doc, sourcetype, "-//W3C//HTML//EN", out);
358
      }
359
  }
360

    
361
  /** 
362
   * Handle the database putdocument request and write an XML document 
363
   * to the database connection
364
   */
365
  private void handleInsertOrUpdateAction(PrintWriter out, Hashtable params, 
366
               HttpServletResponse response) {
367

    
368
    try {
369
      // Get the document indicated
370
      String[] doctext = (String[])params.get("doctext");
371
      StringReader xml = null;
372
      try {
373
        xml = new StringReader(doctext[0]);
374

    
375
        String[] action = (String[])params.get("action");
376
        String[] docid = (String[])params.get("docid");
377
        String newdocid = null;
378

    
379
        String doAction = null;
380
        if (action[0].equals("insert")) {
381
          doAction = "INSERT";
382
        } else if (action[0].equals("update")) {
383
          doAction = "UPDATE";
384
        }
385

    
386
        // write the document to the database
387
        DBWriter dbw = new DBWriter(conn, saxparser);
388

    
389
        try {
390
          String accNumber = docid[0];
391
          if (accNumber.equals("")) {
392
            accNumber = null;
393
          }
394
          newdocid = dbw.write(xml, doAction, accNumber);  
395
        } catch (NullPointerException npe) {
396
          newdocid = dbw.write(xml, doAction, null);  
397
        }
398

    
399
        // set content type and other response header fields first
400
        response.setContentType("text/xml");
401
        out.println("<?xml version=\"1.0\"?>");
402
        out.println("<success>");
403
        out.println("<docid>" + newdocid + "</docid>"); 
404
        out.println("</success>");
405

    
406
      } catch (NullPointerException npe) {
407
        response.setContentType("text/xml");
408
        out.println("<?xml version=\"1.0\"?>");
409
        out.println("<error>");
410
        out.println(npe.getMessage()); 
411
        out.println("</error>");
412
      }
413
    } catch (Exception e) {
414
      response.setContentType("text/xml");
415
      out.println("<?xml version=\"1.0\"?>");
416
      out.println("<error>");
417
      out.println(e.getMessage()); 
418
      if (e instanceof SAXException) {
419
        Exception e2 = ((SAXException)e).getException();
420
        out.println("<error>");
421
        out.println(e2.getMessage()); 
422
        out.println("</error>");
423
      }
424
      //e.printStackTrace(out);
425
      out.println("</error>");
426
    }
427
  }
428

    
429
  /** 
430
   * Handle the database delete request and delete an XML document 
431
   * from the database connection
432
   */
433
  private void handleDeleteAction(PrintWriter out, Hashtable params, 
434
               HttpServletResponse response) {
435

    
436
    String[] docid = (String[])params.get("docid");
437

    
438
    // delete the document from the database
439
    try {
440
      DBWriter dbw = new DBWriter(conn, saxparser);
441
                                      // NOTE -- NEED TO TEST HERE
442
                                      // FOR EXISTENCE OF PARAM
443
                                      // BEFORE ACCESSING ARRAY
444
      try {
445
        dbw.delete(docid[0]);
446
        response.setContentType("text/xml");
447
        out.println("<?xml version=\"1.0\"?>");
448
        out.println("<success>");
449
        out.println("Document deleted."); 
450
        out.println("</success>");
451
      } catch (AccessionNumberException ane) {
452
        response.setContentType("text/xml");
453
        out.println("<?xml version=\"1.0\"?>");
454
        out.println("<error>");
455
        out.println("Error deleting document!!!");
456
        out.println(ane.getMessage()); 
457
        out.println("</error>");
458
      }
459
    } catch (Exception e) {
460
      response.setContentType("text/xml");
461
      out.println("<?xml version=\"1.0\"?>");
462
      out.println("<error>");
463
      out.println(e.getMessage()); 
464
      out.println("</error>");
465
    }
466
  }
467
  
468
  /** 
469
   * Handle the validtion request and return the results to the requestor
470
   */
471
  private void handleValidateAction(PrintWriter out, Hashtable params, 
472
               HttpServletResponse response) {
473

    
474
    // Get the document indicated
475
    String valtext = null;
476
    try {
477
      valtext = ((String[])params.get("valtext"))[0];
478
    } catch (Exception nullpe) {
479

    
480
      String docid = null;
481
      try {
482
        // Find the document id number
483
        docid = ((String[])params.get("docid"))[0]; 
484
  
485
        // Get the document indicated fromthe db
486
        valtext = docreader.readXMLDocument(docid);
487

    
488
      } catch (NullPointerException npe) {
489
        response.setContentType("text/html");
490
        out.println("Error getting document ID: " + docid );
491
      }
492
    }
493

    
494
    try {
495
      DBValidate valobj = new DBValidate(saxparser,xmlcatalogfile);
496
      boolean valid = valobj.validateString(valtext);
497

    
498
      // set content type and other response header fields first
499
      response.setContentType("text/html");
500
      out.println("<html>");
501
      out.println("<head><link rel=\"stylesheet\" type=\"text/css\" " +
502
                  "href=\"/xmltodb/rowcol.css\" /></head>");
503
      out.println("<body class=\"emlbody\">");
504
  
505
      if (valid) {
506
        out.println("The input XML is VALID!");
507
      } else {
508
        out.println("The input XML is NOT VALID<br />\n<pre>\n" 
509
                    + valobj.returnErrors() + "\n</pre>\n");
510
      } 
511
      out.println("</body></html>");
512
    } catch (NullPointerException npe2) {
513
      // set content type and other response header fields first
514
      response.setContentType("text/html");
515
      out.println("Error validating document."); 
516
    }
517
  }
518

    
519
  /** 
520
   * Handle the document request and return the results 
521
   * to the requestor
522
   */
523
  private void handleGetDataDocumentAction(PrintWriter out, Hashtable params, 
524
               HttpServletResponse response) {
525
      boolean error_flag = false;
526
      String error_message = "";
527
      // Get the document indicated
528
      String[] datadoc = (String[])params.get("datadoc");
529
      // defaultdatapath = "C:\\Temp\\";    // for testing only!!!
530
      // executescript = "test.bat";        // for testing only!!!
531
      
532
      // set content type and other response header fields first
533
      response.setContentType("application/octet-stream");
534
      if (defaultdatapath!=null) {
535
        if(!defaultdatapath.endsWith(System.getProperty("file.separator"))) {
536
          defaultdatapath=defaultdatapath+System.getProperty("file.separator");
537
        }
538
        System.out.println("Path= "+defaultdatapath+datadoc[0]);
539
        if (executescript!=null) {
540
          String command = null;
541
          File scriptfile = new File(executescript);
542
          if (scriptfile.exists()) {
543
            command=executescript+" "+datadoc[0]; // script includes path
544
        } else {     // look in defaultdatapath
545
            // on Win98 one MUST include the .bat extender
546
            command = defaultdatapath+executescript+" "+datadoc[0];  
547
        }
548
      System.out.println(command);
549
      try {
550
      Process proc = Runtime.getRuntime().exec(command);
551
      proc.waitFor();
552
      }
553
      catch (Exception eee) {
554
        System.out.println("Error running process!");
555
        error_flag = true;
556
        error_message = "Error running process!";}
557
      } // end executescript not null if
558
      File datafile = new File(defaultdatapath+datadoc[0]);
559
      try {
560
      FileInputStream fw = new FileInputStream(datafile);
561
      int x;
562
      while ((x = fw.read())!=-1) {
563
        out.write(x); }
564
        fw.close();
565
      } catch (Exception e) {
566
        System.out.println("Error in returning file\n"+e.getMessage());
567
        error_flag=true;
568
        error_message = error_message+"\nError in returning file\n"+
569
                        e.getMessage();
570
      }
571
    } // end defaultdatapath not null if
572
  }
573
}
574

    
575
/**
576
 * '$Log$
577
 * 'Revision 1.31  2000/06/26 10:35:05  jones
578
 * 'Merged in substantial changes to DBWriter and associated classes and to
579
 * 'the MetaCatServlet in order to accomodate the new UPDATE and DELETE
580
 * 'functions.  The command line tools and the parameters for the
581
 * 'servlet have changed substantially.
582
 * '
583
 * 'Revision 1.30.2.6  2000/06/26 10:18:06  jones
584
 * 'Partial fix for MetaCatServlet INSERT?UPDATE bug.  Only will work on
585
 * 'the first call to the servlet.  Subsequent calls fail.  Seems to be
586
 * 'related to exception handling.  Multiple successive DELETE actions
587
 * 'work fine.
588
 * '
589
 * 'Revision 1.30.2.5  2000/06/26 09:09:53  jones
590
 * 'Modified MetaCatServlet and associated files to handle the UPDATE
591
 * 'and DELETE actions for DBWriter.
592
 * '
593
 * 'Revision 1.30.2.4  2000/06/26 00:51:06  jones
594
 * 'If docid passed to DBWriter.write() is not unique, classes now generate
595
 * 'an AccessionNumberException containing the new docid generated as a
596
 * 'replacement.  The docid is then extracted from the exception and
597
 * 'returned to the calling application for user feedback or client processing.
598
 * '
599
 * 'Revision 1.30.2.3  2000/06/25 23:38:17  jones
600
 * 'Added RCSfile keyword
601
 * '
602
 * 'Revision 1.30.2.2  2000/06/25 23:34:18  jones
603
 * 'Changed documentation formatting, added log entries at bottom of source files
604
 * ''
605
 */
(17-17/20)