Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that implements utility methods like:
4
 *             1/ Reding all doctypes from db connection
5
 *             2/ Reading DTD or Schema file from Metacat catalog system
6
 *             3/ Reading Lore type Data Guide from db connection
7
 *  Copyright: 2000 Regents of the University of California and the
8
 *             National Center for Ecological Analysis and Synthesis
9
 *    Authors: Jivka Bojilova
10
 *    Release: @release@
11
 * 
12
 *   '$Author: tao $'
13
 *     '$Date: 2002-07-14 12:33:25 -0700 (Sun, 14 Jul 2002) $'
14
 * '$Revision: 1292 $'
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

    
31
package edu.ucsb.nceas.metacat;
32

    
33
import java.sql.Connection;
34
import java.sql.SQLException;
35
import java.sql.PreparedStatement;
36
import java.sql.ResultSet;
37

    
38
import java.io.BufferedInputStream;
39
import java.io.InputStream;
40
import java.io.IOException;
41
import java.net.URL;
42
import java.net.URLConnection;
43
import java.net.MalformedURLException;
44

    
45
import java.util.Enumeration;
46
import java.util.Vector;
47
import java.util.Stack;
48

    
49
/**
50
 * A suite of utility classes for quering DB
51
 */
52
public class DBUtil {
53

    
54
  //private Connection	conn = null;
55

    
56
  /**
57
   * main routine used for testing.
58
   * <p>
59
   * Usage: java DBUtil <-dt|-dg>
60
   *
61
   * @param -dt for selecting all doctypes
62
   *        -dg for selecting DataGuide
63
   */
64
  static public void main(String[] args) {
65
     
66
     if (args.length < 1)
67
     {
68
        System.err.println("Wrong number of arguments!!!");
69
        System.err.println(
70
        "USAGE: java DBUtil <-dt | -ds [doctype] | -dg [doctype] | -dl user>");
71
        return;
72
     } else {
73
        try {
74
                    
75
          // Open a connection to the database
76
          MetaCatUtil   util = new MetaCatUtil();
77
          //Connection dbconn = util.openDBConnection();
78

    
79
          DBUtil dbutil = new DBUtil();
80
          
81
          if ( args[0].equals("-dt") ) {
82
            String doctypes = dbutil.readDoctypes();
83
            System.out.println(doctypes);
84
          } else if ( args[0].equals("-dg") ) {
85
            String doctype = null;
86
            if ( args.length == 2 ) { doctype = args[1]; }
87
            String dataguide = dbutil.readDataGuide(doctype);
88
            System.out.println(dataguide);
89
          } else if ( args[0].equals("-ds") ) {
90
            String doctype = null;
91
            if ( args.length == 2 ) { doctype = args[1]; }
92
            String dtdschema = dbutil.readDTDSchema(doctype);
93
            System.out.println(dtdschema);
94
          } else if ( args[0].equals("-dl") ) {
95
            String scope = "";
96
            if ( args.length == 2 ) { scope = args[1]; }
97
            String docid = dbutil.getMaxDocid(scope);
98
            System.out.println(docid);
99
          } else {
100
            System.err.println(
101
            "USAGE: java DBUtil <-dt | -ds [doctype] | -dg [doctype]>");
102
          }  
103

    
104
        } catch (Exception e) {
105
          //System.err.println("error in DBUtil.main");
106
          //System.err.println(e.getMessage());
107
          e.printStackTrace(System.err);
108
        }
109
     }
110
  }
111
  
112
  /**
113
   * Construct an instance of the utility class
114
   */
115
  public DBUtil() {
116
    //this.conn = conn;
117
  }
118

    
119
  /**
120
   * read all doctypes from db connection in XML format
121
   * select all Public Id from xml_catalog table
122
   */
123
  public String readDoctypes()
124
        throws SQLException  {
125

    
126
    Vector doctypeList = new Vector();
127
    DBConnection dbConn = null;
128
    int serialNumber = -1;
129
    PreparedStatement pstmt = null;
130
    try {
131

    
132
      dbConn=DBConnectionPool.
133
                  getDBConnection("DBUtil.readDoctypes");
134
      serialNumber=dbConn.getCheckOutSerialNumber();
135
      pstmt =
136
        dbConn.prepareStatement("SELECT public_id FROM xml_catalog " +
137
                              "WHERE entry_type = 'DTD'");
138

    
139
      pstmt.execute();
140
      ResultSet rs = pstmt.getResultSet();
141
      boolean tableHasRows = rs.next();
142
      while (tableHasRows) {
143
           doctypeList.addElement(rs.getString(1));
144
           tableHasRows = rs.next();
145
      }
146
      
147
      pstmt.close();
148

    
149
    } catch (SQLException e) {
150
      throw new SQLException("DBUtil.readDoctypes(). " + e.getMessage());
151
    }
152
    finally
153
    {
154
      try
155
      {
156
        pstmt.close();
157
      }//try
158
      finally
159
      {
160
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
161
      }//finally
162
    }//finally
163
       
164

    
165
    return formatToXML(doctypeList, "doctype");
166
  }
167

    
168
  /**
169
   * read DTD or Schema file from Metacat's XML catalog system
170
   */
171
  public String readDTDSchema(String doctype)
172
        throws SQLException, MalformedURLException, IOException
173
  {
174
    String systemID = null;
175
    PreparedStatement pstmt = null;
176
    StringBuffer cbuff = new StringBuffer();
177
    DBConnection dbConn = null;
178
    int serialNumber = -1;
179
    // get doctype's System ID from db catalog
180
    try {
181
      
182
      dbConn=DBConnectionPool.
183
                  getDBConnection("DBUtil.readDTDSchema");
184
      serialNumber=dbConn.getCheckOutSerialNumber();
185
      pstmt = dbConn.prepareStatement("SELECT system_id " + 
186
                                    "FROM xml_catalog " +
187
                                    "WHERE entry_type in ('DTD','Schema') " +
188
                                    "AND public_id LIKE ?");
189
      pstmt.setString(1, doctype);
190
      pstmt.execute();
191
      ResultSet rs = pstmt.getResultSet();
192
      boolean hasRow = rs.next();
193
      if (hasRow) {
194
        systemID = rs.getString(1);
195
      } else {
196
        throw new SQLException("Non-registered doctype: " + doctype);
197
      }
198
      pstmt.close();
199

    
200
    } catch (SQLException e) {
201
      throw new SQLException("DBUtil.readDTD(). " + e.getMessage());
202
    }
203
    finally
204
    {
205
      try
206
      {
207
        pstmt.close();
208
      }//try
209
      finally
210
      {
211
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
212
      }//finally
213
    }//finally
214

    
215
    // read from URL stream as specified by the System ID.
216
    try {
217
      // open a connection to this URL and return an InputStream
218
      // for reading from that connection
219
      InputStream istream = new URL(systemID).openStream();
220
      // create a buffering character-input stream
221
      // that uses a default-sized input buffer
222
      BufferedInputStream in = new BufferedInputStream(istream);
223

    
224
      // read the input and write into the string buffer
225
	    int inputByte;
226
	    while ( (inputByte = in.read()) != -1 ) {
227
        cbuff.append((char)inputByte);
228
	    }
229

    
230
      // the input stream must be closed
231
	    in.close();
232
	    
233
    } catch (MalformedURLException e) {
234
      throw new MalformedURLException
235
      ("DBUtil.readDTD(). " + e.getMessage());
236
    } catch (IOException e) {
237
      throw new IOException
238
      ("DBUtil.readDTD(). " + e.getMessage());
239
    } catch (SecurityException e) {
240
      throw new IOException
241
      ("DBUtil.readDTD(). " + e.getMessage());
242
    }
243
    
244
   return cbuff.toString();
245
  }
246

    
247
  /**
248
   * read Data Guide for a given doctype from db connection in XML format
249
   * select all distinct absolute paths from xml_index table
250
   */
251
  public String readDataGuide( String doctype )
252
        throws SQLException  {
253

    
254
    Vector dataguide = new Vector();
255
    String path;
256
    PreparedStatement pstmt = null;
257
    DBConnection dbConn = null;
258
    int serialNumber = -1;
259
    
260
    try {
261
        dbConn=DBConnectionPool.
262
                  getDBConnection("DBUtil.readDataGuide");
263
        serialNumber=dbConn.getCheckOutSerialNumber();
264
        
265
        if ( doctype != null ) {
266
            pstmt = dbConn.prepareStatement("SELECT distinct path, nodeid " + 
267
                                          "FROM xml_index " +
268
                                          "WHERE path LIKE '/%' " + 
269
                                          "AND doctype LIKE ? " +
270
                                          "ORDER BY nodeid");
271
            pstmt.setString(1, doctype);
272
        } else {
273
            pstmt = 
274
            dbConn.prepareStatement("SELECT distinct path, doctype, nodeid " + 
275
                                          "FROM xml_index " +
276
                                          "WHERE path LIKE '/%' " + 
277
                                          "ORDER BY doctype, nodeid");
278
        }
279

    
280
        pstmt.execute();
281
        ResultSet rs = pstmt.getResultSet();
282
        boolean tableHasRows = rs.next();
283
        while (tableHasRows) {
284
            path = rs.getString(1);
285
            if ( dataguide.indexOf(path) == -1 ) {
286
                dataguide.addElement(path);
287
            }    
288
            tableHasRows = rs.next();
289
        }
290
      
291
        pstmt.close();
292

    
293
    } catch (SQLException e) {
294
      throw new SQLException("DBUtil.readDataGuide(). " + e.getMessage());
295
    }
296
    finally
297
    {
298
      try
299
      {
300
        pstmt.close();
301
      }//try
302
      finally
303
      {
304
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
305
      }//finally
306
    }//finally
307

    
308
    return formatToXML(dataguide);
309
  }
310

    
311
  /**
312
   * format the DataGuide ResultSet to XML
313
   */
314
  private String formatToXML(Vector resultset) {
315
  
316
    String currPath = null;
317
    String currElement = null;
318
    String prevElement = null;
319
    StringBuffer result = new StringBuffer();
320
    Enumeration rs = resultset.elements(); 
321
    Stack st = new Stack();
322
    int i = 0;
323

    
324
    result.append("<?xml version=\"1.0\"?>\n");
325
    result.append("<resultset>\n"); 
326
    
327
    while (rs.hasMoreElements()) {
328
        currPath = (String)rs.nextElement();
329
        while ( !In(prevElement, currPath) ) {
330
            currElement = (String)st.pop();
331
            result.append(pad(" ",i--) + "</" + currElement + ">\n");
332
            if ( st.empty() ) 
333
                prevElement = null;
334
            else    
335
                prevElement = (String)st.peek();
336
        }    
337
        currElement = getElementFromPath(currPath);
338
        st.push(currElement);
339
        result.append(pad(" ",++i) + "<" + currElement + ">\n");
340
        prevElement = currElement;
341
    }
342
    while ( !st.empty() ) {
343
        prevElement = (String)st.pop();
344
        result.append(pad(" ",i--) + "</" + prevElement + ">\n");
345
    }    
346
    result.append("</resultset>\n"); 
347

    
348
    return result.toString();
349
  }
350

    
351
  /**
352
   * check if element is in path like /elem1/elem2/elemn3
353
   */
354
  private boolean In(String element, String path) {
355
    
356
    if ( element == null ) return true;
357
    return ( path.indexOf(element) != -1 );
358
  }
359

    
360
  /**
361
   * get last element from path like /elem1/elem2/elemn3
362
   */
363
  private String getElementFromPath(String path) {
364
    
365
    return ( path.substring(path.lastIndexOf("/")+1) );
366
  }
367

    
368
  /**
369
   * repeates the str n-times
370
   */
371
  private String pad(String str, int n) {
372
    
373
    String result = "";
374
    for ( int i = 0; i < n; i++ )
375
        result = result.concat(str);
376
        
377
    return result;    
378
  }
379

    
380
  /**
381
   * format the ResultSet to XML
382
   */
383
  private String formatToXML(Vector resultset, String tag) {
384
  
385
    String val = null;
386
    StringBuffer result = new StringBuffer();
387
    Enumeration rs = resultset.elements(); 
388

    
389
    result.append("<?xml version=\"1.0\"?>\n");
390
    result.append("<resultset>\n"); 
391
    while (rs.hasMoreElements()) {
392
        val = (String)rs.nextElement();
393
        result.append("   <" + tag + ">" + val + "</" + tag + ">\n");
394
    }
395
    result.append("</resultset>\n"); 
396
    
397
    return result.toString();
398
  }
399

    
400
  /**
401
   * get the lastest Accession Number from a particular scope
402
   */
403
  public String getMaxDocid(String scope)
404
        throws SQLException  {
405

    
406
    String accnum = null;
407
    String sep = MetaCatUtil.getOption("accNumSeparator");
408
    PreparedStatement pstmt = null;
409
    DBConnection dbConn = null;
410
    int serialNumber = -1;
411
    try {
412
        dbConn=DBConnectionPool.
413
                  getDBConnection("DBUtil.getMaxDocid");
414
        serialNumber=dbConn.getCheckOutSerialNumber();
415
        pstmt =
416
        dbConn.prepareStatement(
417
            "SELECT docid, rev, acc FROM " +
418
            "( " +
419
            "SELECT docid, rev, acc FROM " +
420
                "(" +
421
                "SELECT docid, rev, " + 
422
                "SUBSTR(docid, INSTR(docid, '" + sep + "', 1)+1)+0 acc " +
423
                "FROM xml_documents " +
424
                "WHERE docid LIKE ? " +
425
                "ORDER BY acc DESC " +
426
                ") " +
427
            "WHERE rownum = 1 " +
428
            "UNION " + 
429
            "SELECT docid, rev, acc FROM " +
430
                "(" +
431
                "SELECT docid, rev, " + 
432
                "SUBSTR(docid, INSTR(docid, '" + sep + "', 1)+1)+0 acc " +
433
                "FROM xml_revisions " +
434
                "WHERE docid LIKE ? " +
435
                "ORDER BY acc DESC " +
436
                ") " +
437
            "WHERE rownum = 1 " +
438
            ") " +
439
            "ORDER BY acc DESC"
440
            );
441

    
442
      pstmt.setString(1,scope + sep + "%");
443
      pstmt.setString(2,scope + sep + "%");
444
      pstmt.execute();
445
      ResultSet rs = pstmt.getResultSet();
446
      boolean tableHasRows = rs.next(); 
447
      // 0, 1 or 2 possible num of rows
448
      // get the first one which is the max accnum
449
      if (tableHasRows) {
450
        accnum = rs.getString(1) + sep + rs.getString(2);
451
        //tableHasRows = rs.next();
452
      }
453
      
454
      pstmt.close();
455

    
456
    } catch (SQLException e) {
457
      throw new SQLException("DBUtil.getMaxDocid(). " + e.getMessage());
458
    }
459
    finally
460
    {
461
      try
462
      {
463
        pstmt.close();
464
      }//try
465
      finally
466
      {
467
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
468
      }//finally
469
    }//finally
470

    
471
    return accnum;
472
  }
473
  
474
  /**
475
   * To a given docid, found a dataset docid which conatains the the given doicd
476
   * This will be done by searching xml_relation table
477
   * If couldn't find, null will be return
478
   * @param givenDocId, the docid which we want to find
479
   */
480
  public static String findDataSetDocIdForGivenDocument(String givenDocId)
481
  {
482
    // Prepared statement for sql
483
    PreparedStatement pStmt = null;
484
    // Result set
485
    ResultSet resultSet = null;
486
    // String to store the data set docid
487
    String dataSetDocId = null;
488
    // DBConnection will be checkout
489
    DBConnection dbConn = null;
490
    int serialNumber = -1;
491
    // String to store the sql command
492
    String sqlCommand = null;
493
    try
494
    {
495
      // Checkout DBConnection from pool
496
      dbConn=DBConnectionPool.
497
                  getDBConnection("DBUtil.findDataSetDocIdForGivenDocument");
498
      serialNumber=dbConn.getCheckOutSerialNumber();
499
      // Sql command to chose a docid from xm_relation table
500
      sqlCommand = "select docid from xml_relation where object like ? or " 
501
                                                    + "subject like ?";
502
      // Prepared statement
503
      pStmt = dbConn.prepareStatement(sqlCommand);
504
      // Bind variable
505
      pStmt.setString(1, givenDocId);
506
      pStmt.setString(2, givenDocId);
507
      // Excute prepared statement
508
      pStmt.execute();
509
      // Get result set
510
      resultSet = pStmt.getResultSet();
511
      
512
      // There has record
513
      if (resultSet.next())
514
      {
515
        // Put the docid into dataSetDocid
516
        dataSetDocId = resultSet.getString(1);
517
        return dataSetDocId;
518
      }//if
519
      else
520
      {
521
        // No record in xml_relation table for given doicd, null returned
522
        return dataSetDocId;
523
      }//else
524
    
525
    }//try
526
    catch ( SQLException e)
527
    {
528
      // Print out excepition
529
      MetaCatUtil.debugMessage("Error in DBUil.findDataSEtDocIdForGivenDocument"
530
                                +e.getMessage(), 30);
531
      // return null
532
      return dataSetDocId;
533
     
534
    }//catch
535
    finally
536
    {
537
      try
538
      {
539
        // Close result set
540
        resultSet.close();
541
        // Close preparedStatement
542
        pStmt.close();
543
      }//try
544
      catch ( SQLException e)
545
      {
546
        // Print out excepition
547
        MetaCatUtil.debugMessage("Error in DBUil.findDataSetDocIdForGivenDoc"
548
                                + e.getMessage(), 30);
549
     
550
      }//catch
551
      finally
552
      {
553
        // Return DBConnection to the pool
554
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
555
      }//finally
556
    }//finally
557
        
558
  }//findDataSetDocIdForGivenDocument
559
  
560
  /**
561
   * Method to get current revision and doctype for a given docid
562
   * The output will look like "rev;doctype"
563
   * @param givenDocId, the docid which we want 
564
   */
565
  public String getCurrentRevisionAndDocTypeForGivenDocument(String givenDocId)
566
                                                 throws SQLException
567
  {
568
    // DBConection for JDBC
569
    DBConnection dbConn = null;
570
    int serialNumber = -1;
571
    // Prepared Statement
572
    PreparedStatement pstmt = null;
573
    // String to store a docid without rev
574
    String docIdWithoutRevision = null;
575
    // SQL comand
576
    String sqlCommand = null;
577
    // Resulst set
578
    ResultSet rs = null;
579
    // String to store the revision
580
    String revision = null;
581
    // String to store the doctype
582
    String docType = null;
583
    
584
    // Get docid without rev
585
    docIdWithoutRevision = MetaCatUtil.getDocIdFromString(givenDocId);
586
    // SQL comand is:
587
    sqlCommand = "select rev, doctype from xml_documents where docid like ?";
588
    
589
    try
590
    {
591
      // Check out the connection
592
      dbConn=DBConnectionPool.
593
         getDBConnection("DBUtil.getCurrentRevisionAndDocTypeForGivenDocument");
594
      serialNumber=dbConn.getCheckOutSerialNumber();
595
      
596
      // Prepare the sql command
597
      pstmt = dbConn.prepareStatement(sqlCommand);
598
      // Bin vairable
599
      pstmt.setString(1, docIdWithoutRevision);
600
      // Excute the prepared statement
601
      pstmt.execute();
602
      // Get result set
603
      rs = pstmt.getResultSet();
604
      // If there is some record
605
      if (rs.next())
606
      {
607
        revision = rs.getString(1);
608
        docType = rs.getString(2);
609
      }//if
610
      else
611
      {
612
        // No record, throw a exception
613
        throw new 
614
              SQLException("There is not record for given docid:"+givenDocId);
615
      }//else
616
        
617
    }
618
    finally
619
    {
620
      try
621
      {
622
        // Close result set
623
        rs.close();
624
        // Close preparedStatement
625
        pstmt.close();
626
      }//try
627
      catch ( SQLException e)
628
      {
629
        // Print out excepition
630
        MetaCatUtil.debugMessage("Error in DBUil.getCurrentRevisionAndDocType"
631
                                + e.getMessage(), 30);
632
     
633
      }//catch
634
      finally
635
      {
636
        // Return DBConnection to the pool
637
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
638
      }//finally
639
    }
640
    return revision+";"+docType;
641
  }//getCurrentRevisionAndDocTypeForGivenDocument
642
   
643
}
(22-22/46)