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

    
30
package edu.ucsb.nceas.metacat;
31

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

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

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

    
48
import org.apache.log4j.Logger;
49

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

    
55
  //private Connection	conn = null;
56
  private static Logger logMetacat = Logger.getLogger(DBUtil.class);
57

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

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

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

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

    
123
    Vector doctypeList = new Vector();
124
    DBConnection dbConn = null;
125
    int serialNumber = -1;
126
    PreparedStatement pstmt = null;
127
    try {
128

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

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

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

    
162
    return formatToXML(doctypeList, "doctype");
163
  }
164

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

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

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

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

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

    
244
  /**
245
   * format the DataGuide ResultSet to XML
246
   */
247
  private String formatToXML(Vector resultset) {
248
  
249
    String currPath = null;
250
    String currElement = null;
251
    String prevElement = null;
252
    StringBuffer result = new StringBuffer();
253
    Enumeration rs = resultset.elements(); 
254
    Stack st = new Stack();
255
    int i = 0;
256

    
257
    result.append("<?xml version=\"1.0\"?>\n");
258
    result.append("<resultset>\n"); 
259
    
260
    while (rs.hasMoreElements()) {
261
        currPath = (String)rs.nextElement();
262
        while ( !In(prevElement, currPath) ) {
263
            currElement = (String)st.pop();
264
            result.append(pad(" ",i--) + "</" + currElement + ">\n");
265
            if ( st.empty() ) 
266
                prevElement = null;
267
            else    
268
                prevElement = (String)st.peek();
269
        }    
270
        currElement = getElementFromPath(currPath);
271
        st.push(currElement);
272
        result.append(pad(" ",++i) + "<" + currElement + ">\n");
273
        prevElement = currElement;
274
    }
275
    while ( !st.empty() ) {
276
        prevElement = (String)st.pop();
277
        result.append(pad(" ",i--) + "</" + prevElement + ">\n");
278
    }    
279
    result.append("</resultset>\n"); 
280

    
281
    return result.toString();
282
  }
283

    
284
  /**
285
   * check if element is in path like /elem1/elem2/elemn3
286
   */
287
  private boolean In(String element, String path) {
288
    
289
    if ( element == null ) return true;
290
    return ( path.indexOf(element) != -1 );
291
  }
292

    
293
  /**
294
   * get last element from path like /elem1/elem2/elemn3
295
   */
296
  private String getElementFromPath(String path) {
297
    
298
    return ( path.substring(path.lastIndexOf("/")+1) );
299
  }
300

    
301
  /**
302
   * repeates the str n-times
303
   */
304
  private String pad(String str, int n) {
305
    
306
    String result = "";
307
    for ( int i = 0; i < n; i++ )
308
        result = result.concat(str);
309
        
310
    return result;    
311
  }
312

    
313
  /**
314
   * format the ResultSet to XML
315
   */
316
  private String formatToXML(Vector resultset, String tag) {
317
  
318
    String val = null;
319
    StringBuffer result = new StringBuffer();
320
    Enumeration rs = resultset.elements(); 
321

    
322
    result.append("<?xml version=\"1.0\"?>\n");
323
    result.append("<resultset>\n"); 
324
    while (rs.hasMoreElements()) {
325
        val = (String)rs.nextElement();
326
        result.append("   <" + tag + ">" + val + "</" + tag + ">\n");
327
    }
328
    result.append("</resultset>\n"); 
329
    
330
    return result.toString();
331
  }
332

    
333
  /**
334
   * get the lastest Accession Number from a particular scope
335
   */
336
  public String getMaxDocid(String scope)
337
        throws SQLException  {
338

    
339
    String accnum = null;
340
    String sep = MetaCatUtil.getOption("accNumSeparator");
341
    PreparedStatement pstmt = null;
342
    DBConnection dbConn = null;
343
    int serialNumber = -1;
344
    try {
345
        dbConn=DBConnectionPool.
346
                  getDBConnection("DBUtil.getMaxDocid");
347
        serialNumber=dbConn.getCheckOutSerialNumber();
348
        pstmt =
349
        dbConn.prepareStatement(
350
            "SELECT docid, max(rev) FROM " +
351
            "( " +
352
                "SELECT docid, rev " + 
353
                "FROM xml_documents " +
354
                "WHERE docid LIKE ? " +
355
            "UNION " + 
356
                "SELECT docid, rev " + 
357
                "FROM xml_revisions " +
358
                "WHERE docid LIKE ?" +
359
            ") subquery GROUP BY docid"
360
            );
361

    
362
      pstmt.setString(1,scope + sep + "%");
363
      pstmt.setString(2,scope + sep + "%");
364
      pstmt.execute();
365
      ResultSet rs = pstmt.getResultSet();
366
      
367
      long max = 0;
368
      String temp = null;
369
      
370
      while(rs.next()){
371
    	  temp = rs.getString(1);
372
    	  if(temp != null){
373
    		  temp = temp.substring(temp.indexOf(scope) + scope.length() + 1);
374
    		  try {
375
    			  long localid = Long.parseLong(temp);
376
    			  if (localid > max) {
377
    				  max = localid;
378
    				  accnum = rs.getString(1) + sep + rs.getString(2);
379
    			  }
380
    		  } catch (NumberFormatException nfe){
381
    			  // ignore the exception as it is possible that the  
382
    			  // localid in the identifier is not an integer 
383
    		  }
384
    	  }
385
      }
386
      
387
      pstmt.close();
388

    
389
    } catch (SQLException e) {
390
      throw new SQLException("DBUtil.getMaxDocid(). " + e.getMessage());
391
    }
392
    finally
393
    {
394
      try
395
      {
396
        pstmt.close();
397
      }//try
398
      finally
399
      {
400
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
401
      }//finally
402
    }//finally
403

    
404
    return accnum;
405
  }
406
  
407
  /**
408
   * get the lastest Accession Number from a particular scope
409
   */
410
  public Vector getAllDocids(String scope)
411
        throws SQLException  {
412
    Vector resultVector = new Vector();
413
    String accnum = null;
414
    String sep = MetaCatUtil.getOption("accNumSeparator");
415
    PreparedStatement pstmt = null;
416
    DBConnection dbConn = null;
417
    int serialNumber = -1;
418
    try 
419
    {
420
      dbConn=DBConnectionPool.
421
                getDBConnection("DBUtil.getAllDocids");
422
      serialNumber=dbConn.getCheckOutSerialNumber();
423
      StringBuffer sb = new StringBuffer();
424
      
425
      sb.append("SELECT docid, rev FROM " +
426
                "( " +
427
                "SELECT docid, rev " + 
428
                "FROM xml_documents ");
429
      if(scope != null)
430
      {
431
        sb.append("WHERE docid LIKE ? ");
432
      }
433
      sb.append("UNION " + 
434
                "SELECT docid, rev " + 
435
                "FROM xml_revisions ");
436
      if(scope != null)
437
      {
438
        sb.append("WHERE docid LIKE ?");
439
      }
440
      sb.append(") subquery GROUP BY docid, rev");
441
      pstmt = dbConn.prepareStatement(sb.toString());
442

    
443
      if(scope != null)
444
      {
445
        pstmt.setString(1,scope + sep + "%");
446
        pstmt.setString(2,scope + sep + "%");
447
      }
448
      pstmt.execute();
449
      ResultSet rs = pstmt.getResultSet();
450
      
451
      long max = 0;
452
      String id = null;
453
      String rev = null;
454
      while(rs.next()){
455
    	  id = rs.getString(1);
456
        rev = rs.getString(2);
457
    	  if(id != null){
458
    		  //temp = temp.substring(id.indexOf(scope) + scope.length() + 1);
459
          resultVector.addElement(id + sep + rev);
460
        }
461
      }
462
      
463
      pstmt.close();
464

    
465
    } catch (SQLException e) {
466
      throw new SQLException("DBUtil.getAllDocids(). " + e.getMessage());
467
    }
468
    finally
469
    {
470
      try
471
      {
472
        pstmt.close();
473
      }//try
474
      finally
475
      {
476
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
477
      }//finally
478
    }//finally
479

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

    
673
          pStmt = dbConn
674
                  .prepareStatement("SELECT rev FROM xml_revisions WHERE docid='"
675
                          + docIdWithoutRev + "'");
676
          pStmt.execute();
677

    
678
          ResultSet rs = pStmt.getResultSet();
679
          boolean hasRow = rs.next();
680
          while (hasRow) {
681
              rev = rs.getInt(1);
682
              logMetacat.warn("rev "+ rev +" is added to list");
683
              list.add(new Integer(rev));
684
              hasRow = rs.next();
685
              
686
          }
687
          pStmt.close();
688
      }//try
689
      finally {
690
          try {
691
              pStmt.close();
692
          } catch (Exception ee) {
693
        	  logMetacat.error("Error in DocumentImpl."
694
                      + "getLatestRevisionNumber: " + ee.getMessage());
695
          } finally {
696
              DBConnectionPool.returnDBConnection(dbConn, serialNumber);
697
          }
698
      }//finally
699

    
700
      return list;
701
  }//getLatestRevisionNumber
702
  
703
  /**
704
   * Get last revision number from database for a docid If couldn't find an
705
   * entry, -1 will return The return value is integer because we want compare
706
   * it to there new one
707
   *
708
   * @param docid
709
   *            <sitecode>. <uniqueid>part of Accession Number
710
   */
711
  public static int getLatestRevisionInDocumentTable(String docIdWithoutRev) throws SQLException
712
  {
713
      int rev = 1;
714
      PreparedStatement pStmt = null;
715
      DBConnection dbConn = null;
716
      int serialNumber = -1;
717
      try {
718
          //check out DBConnection
719
          dbConn = DBConnectionPool
720
                  .getDBConnection("DBUtil.getLatestRevisionInDocumentTable");
721
          serialNumber = dbConn.getCheckOutSerialNumber();
722

    
723
          pStmt = dbConn
724
                  .prepareStatement("SELECT rev FROM xml_documents WHERE docid='"
725
                          + docIdWithoutRev + "'");
726
          pStmt.execute();
727

    
728
          ResultSet rs = pStmt.getResultSet();
729
          boolean hasRow = rs.next();
730
          if (hasRow) {
731
              rev = rs.getInt(1);
732
              pStmt.close();
733
          } else {
734
              rev = -1;
735
              pStmt.close();
736
          }
737
      }//try
738
      finally {
739
          try {
740
              pStmt.close();
741
          } catch (Exception ee) {
742
        	  logMetacat.error("Error in DBUtil."
743
                      + "getLatestRevisionInDocumentTable: " + ee.getMessage());
744
          } finally {
745
              DBConnectionPool.returnDBConnection(dbConn, serialNumber);
746
          }
747
      }//finally
748

    
749
      return rev;
750
  }//getLatestRevisionNumber
751
   
752
}
(26-26/65)