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: sgarg $'
13
 *     '$Date: 2005-10-27 16:46:57 -0700 (Thu, 27 Oct 2005) $'
14
 * '$Revision: 2698 $'
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
import org.apache.log4j.Logger;
50

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
282
    return result.toString();
283
  }
284

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

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

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

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

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

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

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

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

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

    
405
    return accnum;
406
  }
407
  
408
  /**
409
   * To a given docid, found a dataset docid which conatains the the given doicd
410
   * This will be done by searching xml_relation table
411
   * If couldn't find, null will be return
412
   * @param givenDocId, the docid which we want to find
413
   */
414
  public static String findDataSetDocIdForGivenDocument(String givenDocId)
415
  {
416
    // Prepared statement for sql
417
    PreparedStatement pStmt = null;
418
    // Result set
419
    ResultSet resultSet = null;
420
    // String to store the data set docid
421
    String dataSetDocId = null;
422
    // DBConnection will be checkout
423
    DBConnection dbConn = null;
424
    int serialNumber = -1;
425
    // String to store the sql command
426
    String sqlCommand = null;
427
    try
428
    {
429
      // Checkout DBConnection from pool
430
      dbConn=DBConnectionPool.
431
                  getDBConnection("DBUtil.findDataSetDocIdForGivenDocument");
432
      serialNumber=dbConn.getCheckOutSerialNumber();
433
      // Sql command to chose a docid from xm_relation table
434
      sqlCommand = "select docid from xml_relation where object like ? or " 
435
                                                    + "subject like ?";
436
      // Prepared statement
437
      pStmt = dbConn.prepareStatement(sqlCommand);
438
      // Bind variable
439
      pStmt.setString(1, givenDocId);
440
      pStmt.setString(2, givenDocId);
441
      // Excute prepared statement
442
      pStmt.execute();
443
      // Get result set
444
      resultSet = pStmt.getResultSet();
445
      
446
      // There has record
447
      if (resultSet.next())
448
      {
449
        // Put the docid into dataSetDocid
450
        dataSetDocId = resultSet.getString(1);
451
        return dataSetDocId;
452
      }//if
453
      else
454
      {
455
        // No record in xml_relation table for given doicd, null returned
456
        return dataSetDocId;
457
      }//else
458
    
459
    }//try
460
    catch ( SQLException e)
461
    {
462
      // Print out excepition
463
      logMetacat.error("Error in DBUil.findDataSEtDocIdForGivenDocument"
464
                                +e.getMessage());
465
      // return null
466
      return dataSetDocId;
467
     
468
    }//catch
469
    finally
470
    {
471
      try
472
      {
473
        // Close result set
474
        resultSet.close();
475
        // Close preparedStatement
476
        pStmt.close();
477
      }//try
478
      catch ( SQLException e)
479
      {
480
        // Print out excepition
481
    	  logMetacat.error("Error in DBUil.findDataSetDocIdForGivenDoc"
482
                                + e.getMessage());
483
     
484
      }//catch
485
      finally
486
      {
487
        // Return DBConnection to the pool
488
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
489
      }//finally
490
    }//finally
491
        
492
  }//findDataSetDocIdForGivenDocument
493
  
494
  /**
495
   * Method to get current revision and doctype for a given docid
496
   * The output will look like "rev;doctype"
497
   * @param givenDocId, the docid which we want 
498
   */
499
  public String getCurrentRevisionAndDocTypeForGivenDocument(String givenDocId)
500
                                                 throws SQLException
501
  {
502
    // DBConection for JDBC
503
    DBConnection dbConn = null;
504
    int serialNumber = -1;
505
    // Prepared Statement
506
    PreparedStatement pstmt = null;
507
    // String to store a docid without rev
508
    String docIdWithoutRevision = null;
509
    // SQL comand
510
    String sqlCommand = null;
511
    // Resulst set
512
    ResultSet rs = null;
513
    // String to store the revision
514
    String revision = null;
515
    // String to store the doctype
516
    String docType = null;
517
    
518
    // Get docid without rev
519
    docIdWithoutRevision = MetaCatUtil.getDocIdFromString(givenDocId);
520
    // SQL comand is:
521
    sqlCommand = "select rev, doctype from xml_documents where docid like ?";
522
    
523
    try
524
    {
525
      // Check out the connection
526
      dbConn=DBConnectionPool.
527
         getDBConnection("DBUtil.getCurrentRevisionAndDocTypeForGivenDocument");
528
      serialNumber=dbConn.getCheckOutSerialNumber();
529
      
530
      // Prepare the sql command
531
      pstmt = dbConn.prepareStatement(sqlCommand);
532
      // Bin vairable
533
      pstmt.setString(1, docIdWithoutRevision);
534
      // Excute the prepared statement
535
      pstmt.execute();
536
      // Get result set
537
      rs = pstmt.getResultSet();
538
      // If there is some record
539
      if (rs.next())
540
      {
541
        revision = rs.getString(1);
542
        docType = rs.getString(2);
543
      }//if
544
      else
545
      {
546
        // No record, throw a exception
547
        throw new 
548
              SQLException("There is not record for given docid:"+givenDocId);
549
      }//else
550
        
551
    }
552
    finally
553
    {
554
      try
555
      {
556
        // Close result set
557
        rs.close();
558
        // Close preparedStatement
559
        pstmt.close();
560
      }//try
561
      catch ( SQLException e)
562
      {
563
        // Print out excepition
564
    	  logMetacat.error("Error in DBUil.getCurrentRevisionAndDocType"
565
                                + e.getMessage());
566
     
567
      }//catch
568
      finally
569
      {
570
        // Return DBConnection to the pool
571
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
572
      }//finally
573
    }
574
    return revision+";"+docType;
575
  }//getCurrentRevisionAndDocTypeForGivenDocument
576
  
577
  /**
578
   * Method to return a rev list in xml_revision for given docid.
579
   * @param docId
580
   * @return is a vector which contains Integer object
581
   * @throws SQLException
582
   */
583
  public static Vector getRevListFromRevisionTable(String docId) throws SQLException
584
  {
585
      Vector list = new Vector();
586
      int rev = 1;
587
      PreparedStatement pStmt = null;
588
      DBConnection dbConn = null;
589
      int serialNumber = -1;
590
      // get rid of rev
591
      docId = MetaCatUtil.getDocIdFromString(docId);
592
      try {
593
          //check out DBConnection
594
          dbConn = DBConnectionPool
595
                  .getDBConnection("getRevListFromRevisionTable");
596
          serialNumber = dbConn.getCheckOutSerialNumber();
597

    
598
          pStmt = dbConn
599
                  .prepareStatement("SELECT rev FROM xml_revisions WHERE docid='"
600
                          + docId + "'");
601
          pStmt.execute();
602

    
603
          ResultSet rs = pStmt.getResultSet();
604
          boolean hasRow = rs.next();
605
          while (hasRow) {
606
              rev = rs.getInt(1);
607
              logMetacat.warn("rev "+ rev +" is added to list");
608
              list.add(new Integer(rev));
609
              hasRow = rs.next();
610
              
611
          }
612
          pStmt.close();
613
      }//try
614
      finally {
615
          try {
616
              pStmt.close();
617
          } catch (Exception ee) {
618
        	  logMetacat.error("Error in DocumentImpl."
619
                      + "getLatestRevisionNumber: " + ee.getMessage());
620
          } finally {
621
              DBConnectionPool.returnDBConnection(dbConn, serialNumber);
622
          }
623
      }//finally
624

    
625
      return list;
626
  }//getLatestRevisionNumber
627
  
628
  /**
629
   * Get last revision number from database for a docid If couldn't find an
630
   * entry, -1 will return The return value is integer because we want compare
631
   * it to there new one
632
   *
633
   * @param docid
634
   *            <sitecode>. <uniqueid>part of Accession Number
635
   */
636
  public static int getLatestRevisionInDocumentTable(String docIdWithoutRev) throws SQLException
637
  {
638
      int rev = 1;
639
      PreparedStatement pStmt = null;
640
      DBConnection dbConn = null;
641
      int serialNumber = -1;
642
      try {
643
          //check out DBConnection
644
          dbConn = DBConnectionPool
645
                  .getDBConnection("DBUtil.getLatestRevisionInDocumentTable");
646
          serialNumber = dbConn.getCheckOutSerialNumber();
647

    
648
          pStmt = dbConn
649
                  .prepareStatement("SELECT rev FROM xml_documents WHERE docid='"
650
                          + docIdWithoutRev + "'");
651
          pStmt.execute();
652

    
653
          ResultSet rs = pStmt.getResultSet();
654
          boolean hasRow = rs.next();
655
          if (hasRow) {
656
              rev = rs.getInt(1);
657
              pStmt.close();
658
          } else {
659
              rev = -1;
660
              pStmt.close();
661
          }
662
      }//try
663
      finally {
664
          try {
665
              pStmt.close();
666
          } catch (Exception ee) {
667
        	  logMetacat.error("Error in DBUtil."
668
                      + "getLatestRevisionInDocumentTable: " + ee.getMessage());
669
          } finally {
670
              DBConnectionPool.returnDBConnection(dbConn, serialNumber);
671
          }
672
      }//finally
673

    
674
      return rev;
675
  }//getLatestRevisionNumber
676
   
677
}
(27-27/65)