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

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

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

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

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

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

    
673
      return rev;
674
  }//getLatestRevisionNumber
675
   
676
}
(26-26/65)