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-10 11:06:55 -0700 (Mon, 10 Oct 2005) $'
14
 * '$Revision: 2663 $'
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
            ") AS subQueryResult" +
361
            " GROUP BY docid"
362
            );
363

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

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

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

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

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

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

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

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

    
675
      return rev;
676
  }//getLatestRevisionNumber
677
   
678
}
(27-27/63)