Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that represents an XML document
4
 *  Copyright: 2000 Regents of the University of California and the
5
 *             National Center for Ecological Analysis and Synthesis
6
 *    Authors: Matt Jones
7
 *    Release: @release@
8
 *
9
 *   '$Author: jones $'
10
 *     '$Date: 2001-07-19 01:52:43 -0700 (Thu, 19 Jul 2001) $'
11
 * '$Revision: 798 $'
12
 *
13
 * This program is free software; you can redistribute it and/or modify
14
 * it under the terms of the GNU General Public License as published by
15
 * the Free Software Foundation; either version 2 of the License, or
16
 * (at your option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU General Public License
24
 * along with this program; if not, write to the Free Software
25
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
 */
27

    
28
package edu.ucsb.nceas.metacat;
29

    
30
import java.sql.*;
31
import java.io.File;
32
import java.io.FileReader;
33
import java.io.IOException;
34
import java.io.PrintWriter;
35
import java.io.Reader;
36
import java.io.StringWriter;
37
import java.io.Writer;
38
import java.io.InputStreamReader;
39

    
40
import java.text.SimpleDateFormat;
41

    
42
import java.util.Date;
43
import java.util.Iterator;
44
import java.util.Stack;
45
import java.util.TreeSet;
46
import java.util.Enumeration;
47

    
48
import org.xml.sax.AttributeList;
49
import org.xml.sax.ContentHandler;
50
import org.xml.sax.DTDHandler;
51
import org.xml.sax.EntityResolver;
52
import org.xml.sax.ErrorHandler;
53
import org.xml.sax.InputSource;
54
import org.xml.sax.XMLReader;
55
import org.xml.sax.SAXException;
56
import org.xml.sax.SAXParseException;
57
import org.xml.sax.helpers.XMLReaderFactory;
58

    
59
import java.net.URL;
60

    
61
import edu.ucsb.nceas.dbadapter.AbstractDatabase;
62

    
63
/**
64
 * A class that represents an XML document. It can be created with a simple
65
 * document identifier from a database connection.  It also will write an
66
 * XML text document to a database connection using SAX.
67
 */
68
public class DocumentImpl {
69

    
70
  static final int ALL = 1;
71
  static final int WRITE = 2;
72
  static final int READ = 4;
73
  private static final AbstractDatabase dbAdapter = MetaCatUtil.dbAdapter;
74

    
75
  private Connection conn = null;
76
  private String docid = null;
77
  private String docname = null;
78
  private String doctype = null;
79
// DOCTITLE attr cleared from the db
80
//  private String doctitle = null;
81
  private String createdate = null;
82
  private String updatedate = null;
83
  private String system_id = null;
84
  private String userowner = null;
85
  private String userupdated = null;
86
  private int rev;
87
  private int serverlocation;
88
  private String publicaccess; 
89
  private long rootnodeid;
90
  private ElementNode rootNode = null;
91
  private TreeSet nodeRecordList = null;
92
  
93
  /**
94
   * Constructor used from DBQuery.findDocuments();
95
   * used with getDocumentInfo() to get document info from xml_documents
96
   *
97
   * @param conn the database connection from which to read the document
98
   */
99
  public DocumentImpl(Connection conn) throws McdbException 
100
  {
101
    this.conn = conn;
102
  }
103

    
104
  /**
105
   * Constructor, creates document from database connection, used 
106
   * for reading the document
107
   *
108
   * @param conn the database connection from which to read the document
109
   * @param docid the identifier of the document to be created
110
   */
111
  public DocumentImpl(Connection conn, String docid) throws McdbException 
112
  {
113
    try { 
114
      this.conn = conn;
115
      this.docid = docid;
116
      
117
      // NOT NEEDED
118
      //DocumentIdentifier id = new DocumentIdentifier(docid);
119
  
120
      // Look up the document information
121
      getDocumentInfo(docid);
122
      
123
      // Download all of the document nodes using a single SQL query
124
      // The sort order of the records is determined by the NodeComparator
125
      // class, and needs to represent a depth-first traversal for the
126
      // toXml() method to work properly
127
      nodeRecordList = getNodeRecordList(rootnodeid);
128
  
129
    } catch (McdbException ex) {
130
      throw ex;
131
    } catch (Throwable t) {
132
      throw new McdbException("Error reading document from " +
133
                              "DocumentImpl.DocumentImpl: " + docid);
134
    }
135
  }
136

    
137
  /** 
138
   * Construct a new document instance, writing the contents to the database.
139
   * This method is called from DBSAXHandler because we need to know the
140
   * root element name for documents without a DOCTYPE before creating it.
141
   *
142
   * @param conn the JDBC Connection to which all information is written
143
   * @param rootnodeid - sequence id of the root node in the document
144
   * @param docname - the name of DTD, i.e. the name immediately following 
145
   *        the DOCTYPE keyword ( should be the root element name ) or
146
   *        the root element name if no DOCTYPE declaration provided
147
   *        (Oracle's and IBM parsers are not aware if it is not the 
148
   *        root element name)
149
   * @param doctype - Public ID of the DTD, i.e. the name immediately 
150
   *                  following the PUBLIC keyword in DOCTYPE declaration or
151
   *                  the docname if no Public ID provided or
152
   *                  null if no DOCTYPE declaration provided
153
   * @param docid the docid to use for the INSERT OR UPDATE
154
   * @param action the action to be performed (INSERT OR UPDATE)
155
   * @param user the user that owns the document
156
   * @param pub flag for public "read" access on document
157
   * @param serverCode the serverid from xml_replication on which this document
158
   *        resides.
159
   *
160
   */
161
  public DocumentImpl(Connection conn, long rootnodeid, String docname, 
162
                      String doctype, String docid, String action, String user,
163
                      String pub, String catalogid, int serverCode)
164
                      throws SQLException, Exception
165
  {
166
    this.conn = conn;
167
    this.rootnodeid = rootnodeid;
168
    this.docname = docname;
169
    this.doctype = doctype;
170
    this.docid = docid;
171
    writeDocumentToDB(action, user, pub, catalogid, serverCode);
172
  }
173
  
174
  /**
175
   * Register a document that resides on the filesystem with the database.
176
   * (ie, just an entry in xml_documents, nothing in xml_nodes).
177
   * Creates a reference to a filesystem document (used for non-xml data files).
178
   *
179
   * @param conn the JDBC Connection to which all information is written
180
   * @param docname - the name of DTD, i.e. the name immediately following 
181
   *        the DOCTYPE keyword ( should be the root element name ) or
182
   *        the root element name if no DOCTYPE declaration provided
183
   *        (Oracle's and IBM parsers are not aware if it is not the 
184
   *        root element name)
185
   * @param doctype - Public ID of the DTD, i.e. the name immediately 
186
   *                  following the PUBLIC keyword in DOCTYPE declaration or
187
   *                  the docname if no Public ID provided or
188
   *                  null if no DOCTYPE declaration provided
189
   * @param accnum the accession number to use for the INSERT OR UPDATE, which 
190
   *               includes a revision number for this revision of the document 
191
   *               (e.g., knb.1.1)
192
   * @param user the user that owns the document
193
   * @param serverCode the serverid from xml_replication on which this document
194
   *        resides.
195
   */
196
  public static void registerDocument(
197
                     String docname, String doctype, String accnum, 
198
                     String user, int serverCode)
199
                     throws SQLException, AccessionNumberException, Exception
200
  {
201
    Connection dbconn = null;
202
    MetaCatUtil util = new MetaCatUtil();
203

    
204
    try {
205
      dbconn = util.openDBConnection();
206

    
207
      AccessionNumber ac = new AccessionNumber(dbconn, accnum, "insert");
208
      String docid = ac.getDocid();
209
      String rev = ac.getRev();
210
  
211
      SimpleDateFormat formatter = new SimpleDateFormat ("yy-MM-dd HH:mm:ss");
212
      Date localtime = new Date();
213
      String dateString = formatter.format(localtime);
214
  
215
      String sqlDateString = "to_date('" + dateString + "', 'YY-MM-DD HH24:MI:SS')";
216
  
217
      StringBuffer sql = new StringBuffer();
218
      sql.append("insert into xml_documents (docid, docname, doctype, ");
219
      sql.append("user_owner, user_updated, server_location, rev, date_created");
220
      sql.append(", date_updated, public_access) values ('");
221
      sql.append(docid).append("','");
222
      sql.append(docname).append("','");
223
      sql.append(doctype).append("','");
224
      sql.append(user).append("','");
225
      sql.append(user).append("','");
226
      sql.append(serverCode).append("','");
227
      sql.append(rev).append("',");
228
      sql.append(sqlDateString).append(",");
229
      sql.append(sqlDateString).append(",");
230
      sql.append("'0')");
231
      //System.out.println("sql: " + sql.toString());
232

    
233
      PreparedStatement pstmt = dbconn.prepareStatement(sql.toString());
234
      pstmt.execute();
235
      pstmt.close();
236
      dbconn.close();
237
    } finally {
238
      util.returnConnection(dbconn);
239
    }    
240
  }
241

    
242
  /**
243
   * get the document name
244
   */
245
  public String getDocname() {
246
    return docname;
247
  }
248

    
249
  /**
250
   * get the document type (which is the PublicID)
251
   */
252
  public String getDoctype() {
253
    return doctype;
254
  }
255

    
256
  /**
257
   * get the system identifier
258
   */
259
  public String getSystemID() {
260
    return system_id;
261
  }
262

    
263
  /**
264
   * get the root node identifier
265
   */
266
  public long getRootNodeID() {
267
    return rootnodeid;
268
  }
269
  
270
  /**
271
   * get the creation date
272
   */
273
  public String getCreateDate() {
274
    return createdate;
275
  }
276
  
277
  /**
278
   * get the update date
279
   */
280
  public String getUpdateDate() {
281
    return updatedate;
282
  }
283

    
284
  /** 
285
   * Get the document identifier (docid)
286
   */
287
  public String getDocID() {
288
    return docid;
289
  }
290
  
291
// DOCTITLE attr cleared from the db
292
//  /**
293
//   *get the document title
294
//   */
295
//  public String getDocTitle() {
296
//    return doctitle;
297
//  }
298
  
299
  public String getUserowner() {
300
    return userowner;
301
  }
302
  
303
  public String getUserupdated() {
304
    return userupdated;
305
  }
306
  
307
  public int getServerlocation() {
308
    return serverlocation;
309
  }
310
  
311
  public String getPublicaccess() {
312
    return publicaccess;
313
  }
314
  
315
  public int getRev() {
316
    return rev;
317
  }
318

    
319
  /**
320
   * Print a string representation of the XML document
321
   */
322
  public String toString()
323
  {
324
    StringWriter docwriter = new StringWriter();
325
    this.toXml(docwriter);
326
    String document = docwriter.toString();
327
    return document;
328
  }
329

    
330
  /**
331
   * Get a text representation of the XML document as a string
332
   * This older algorithm uses a recursive tree of Objects to represent the
333
   * nodes of the tree.  Each object is passed the data for the document 
334
   * and searches all of the document data to find its children nodes and
335
   * recursively build.  Thus, because each node reads the whole document,
336
   * this algorithm is extremely slow for larger documents, and the time
337
   * to completion is O(N^N) wrt the number of nodes.  See toXml() for a
338
   * better algorithm.
339
   */
340
  public String readUsingSlowAlgorithm()
341
  {
342
    StringBuffer doc = new StringBuffer();
343

    
344
    // Create the elements from the downloaded data in the TreeSet
345
    rootNode = new ElementNode(nodeRecordList, rootnodeid);
346

    
347
    // Append the resulting document to the StringBuffer and return it
348
    doc.append("<?xml version=\"1.0\"?>\n");
349
      
350
    if (docname != null) {
351
      if ((doctype != null) && (system_id != null)) {
352
        doc.append("<!DOCTYPE " + docname + " PUBLIC \"" + doctype + 
353
                   "\" \"" + system_id + "\">\n");
354
      } else {
355
        doc.append("<!DOCTYPE " + docname + ">\n");
356
      }
357
    }
358
    doc.append(rootNode.toString());
359
  
360
    return (doc.toString());
361
  }
362

    
363
  /**
364
   * Print a text representation of the XML document to a Writer
365
   *
366
   * @param pw the Writer to which we print the document
367
   */
368
  public void toXml(Writer pw)
369
  {
370
    PrintWriter out = null;
371
    if (pw instanceof PrintWriter) {
372
      out = (PrintWriter)pw;
373
    } else {
374
      out = new PrintWriter(pw);
375
    }
376

    
377
    MetaCatUtil util = new MetaCatUtil();
378
    
379
    Stack openElements = new Stack();
380
    boolean atRootElement = true;
381
    boolean previousNodeWasElement = false;
382

    
383
    // Step through all of the node records we were given
384
    Iterator it = nodeRecordList.iterator();
385
    while (it.hasNext()) {
386
      NodeRecord currentNode = (NodeRecord)it.next();
387
      //util.debugMessage("[Got Node ID: " + currentNode.nodeid +
388
                          //" (" + currentNode.parentnodeid +
389
                          //", " + currentNode.nodeindex + 
390
                          //", " + currentNode.nodetype + 
391
                          //", " + currentNode.nodename + 
392
                          //", " + currentNode.nodedata + ")]");
393

    
394
      // Print the end tag for the previous node if needed
395
      //
396
      // This is determined by inspecting the parent nodeid for the
397
      // currentNode.  If it is the same as the nodeid of the last element
398
      // that was pushed onto the stack, then we are still in that previous
399
      // parent element, and we do nothing.  However, if it differs, then we
400
      // have returned to a level above the previous parent, so we go into
401
      // a loop and pop off nodes and print out their end tags until we get
402
      // the node on the stack to match the currentNode parentnodeid
403
      //
404
      // So, this of course means that we rely on the list of elements
405
      // having been sorted in a depth first traversal of the nodes, which
406
      // is handled by the NodeComparator class used by the TreeSet
407
      if (!atRootElement) {
408
        NodeRecord currentElement = (NodeRecord)openElements.peek();
409
        if ( currentNode.parentnodeid != currentElement.nodeid ) {
410
          while ( currentNode.parentnodeid != currentElement.nodeid ) {
411
            currentElement = (NodeRecord)openElements.pop();
412
            util.debugMessage("\n POPPED: " + currentElement.nodename);
413
            if (previousNodeWasElement) {
414
              out.print(">");
415
              previousNodeWasElement = false;
416
            }  
417
            out.print("</" + currentElement.nodename + ">" );
418
            currentElement = (NodeRecord)openElements.peek();
419
          }
420
        }
421
      }
422

    
423
      // Handle the DOCUMENT node
424
      if (currentNode.nodetype.equals("DOCUMENT")) {
425
        out.println("<?xml version=\"1.0\"?>");
426
      
427
        if (docname != null) {
428
          if ((doctype != null) && (system_id != null)) {
429
            out.println("<!DOCTYPE " + docname + " PUBLIC \"" + doctype + 
430
                       "\" \"" + system_id + "\">");
431
          } else {
432
            out.println("<!DOCTYPE " + docname + ">");
433
          }
434
        }
435

    
436
      // Handle the ELEMENT nodes
437
      } else if (currentNode.nodetype.equals("ELEMENT")) {
438
        if (atRootElement) {
439
          atRootElement = false;
440
        } else {
441
          if (previousNodeWasElement) {
442
            out.print(">");
443
          }
444
        }
445
        openElements.push(currentNode);
446
        util.debugMessage("\n PUSHED: " + currentNode.nodename);
447
        previousNodeWasElement = true;
448
        out.print("<" + currentNode.nodename);
449

    
450
      // Handle the ATTRIBUTE nodes
451
      } else if (currentNode.nodetype.equals("ATTRIBUTE")) {
452
        out.print(" " + currentNode.nodename + "=\""
453
                 + currentNode.nodedata + "\"");
454
      } else if (currentNode.nodetype.equals("TEXT")) {
455
        if (previousNodeWasElement) {
456
          out.print(">");
457
        }
458
        out.print(currentNode.nodedata);
459
        previousNodeWasElement = false;
460

    
461
      // Handle the COMMENT nodes
462
      } else if (currentNode.nodetype.equals("COMMENT")) {
463
        if (previousNodeWasElement) {
464
          out.print(">");
465
        }
466
        out.print("<!--" + currentNode.nodedata + "-->");
467
        previousNodeWasElement = false;
468

    
469
      // Handle the PI nodes
470
      } else if (currentNode.nodetype.equals("PI")) {
471
        if (previousNodeWasElement) {
472
          out.print(">");
473
        }
474
        out.print("<?" + currentNode.nodename + " " +
475
                        currentNode.nodedata + "?>");
476
        previousNodeWasElement = false;
477

    
478
      // Handle any other node type (do nothing)
479
      } else {
480
        // Any other types of nodes are not handled.
481
        // Probably should throw an exception here to indicate this
482
      }
483
      out.flush();
484
    }
485

    
486
    // Print the final end tag for the root element
487
    while(!openElements.empty())
488
    {
489
      NodeRecord currentElement = (NodeRecord)openElements.pop();
490
      util.debugMessage("\n POPPED: " + currentElement.nodename);
491
      out.print("</" + currentElement.nodename + ">" );
492
    }
493
    out.flush();
494
  }
495
  
496
  private boolean isRevisionOnly(DocumentIdentifier docid) throws Exception
497
  {
498
    //System.out.println("inRevisionOnly");
499
    PreparedStatement pstmt;
500
    String rev = docid.getRev();
501
    String newid = docid.getIdentifier();
502
    pstmt = conn.prepareStatement("select rev from xml_documents " +
503
                                  "where docid like '" + newid + "'");
504
    pstmt.execute();
505
    ResultSet rs = pstmt.getResultSet();
506
    boolean tablehasrows = rs.next();
507
    if(rev.equals("newest") || rev.equals("all"))
508
    {
509
      return false;
510
    }
511
    
512
    if(tablehasrows)
513
    {
514
      int r = rs.getInt(1);
515
      pstmt.close();
516
      if(new Integer(rev).intValue() == r)
517
      { //the current revision in in xml_documents
518
        //System.out.println("returning false");
519
        return false;
520
      }
521
      else if(new Integer(rev).intValue() < r)
522
      { //the current revision is in xml_revisions.
523
        //System.out.println("returning true");
524
        return true;
525
      }
526
      else if(new Integer(rev).intValue() > r)
527
      { //error, rev cannot be greater than r
528
        throw new Exception("requested revision cannot be greater than " +
529
                            "the latest revision number.");
530
      }
531
    }
532
    throw new Exception("the requested docid '" + docid.toString() + 
533
                        "' does not exist");
534
  }
535

    
536
  public void getDocumentInfo(String docid) throws McdbException, 
537
                                                    AccessionNumberException
538
  {
539
    getDocumentInfo(new DocumentIdentifier(docid));
540
  }
541
  
542
  /**
543
   * Look up the document type information from the database
544
   *
545
   * @param docid the id of the document to look up
546
   */
547
  private void getDocumentInfo(DocumentIdentifier docid) throws McdbException 
548
  {
549
    PreparedStatement pstmt;
550
    String table = "xml_documents";
551
    
552
    try
553
    {
554
      if(isRevisionOnly(docid))
555
      { //pull the document from xml_revisions instead of from xml_documents;
556
        table = "xml_revisions";
557
      }
558
    }
559
    catch(Exception e)
560
    {
561
      System.out.println("error in DocumentImpl.getDocumentInfo: " + 
562
                          e.getMessage());
563
    }
564
    
565
    //deal with the key words here.
566
    
567
    if(docid.getRev().equals("all"))
568
    {
569
      
570
    }
571
    
572
    try {
573
      StringBuffer sql = new StringBuffer();
574
// DOCTITLE attr cleared from the db
575
//      sql.append("SELECT docname, doctype, rootnodeid, doctitle, ");
576
      sql.append("SELECT docname, doctype, rootnodeid, ");
577
      sql.append("date_created, date_updated, user_owner, user_updated, ");
578
      sql.append("server_location, public_access, rev");
579
      sql.append(" FROM ").append(table);
580
      sql.append(" WHERE docid LIKE '").append(docid.getIdentifier());
581
      sql.append("' and rev like '").append(docid.getRev()).append("'");
582
      //System.out.println(sql.toString());
583
      pstmt =
584
        conn.prepareStatement(sql.toString());
585
      // Bind the values to the query
586
      //pstmt.setString(1, docid.getIdentifier());
587
      //pstmt.setString(2, docid.getRev());
588

    
589
      pstmt.execute();
590
      ResultSet rs = pstmt.getResultSet();
591
      boolean tableHasRows = rs.next();
592
      if (tableHasRows) {
593
        this.docname        = rs.getString(1);
594
        this.doctype        = rs.getString(2);
595
        this.rootnodeid     = rs.getLong(3);
596
// DOCTITLE attr cleared from the db
597
//        this.doctitle       = rs.getString(4);
598
        this.createdate     = rs.getString(4);
599
        this.updatedate     = rs.getString(5);
600
        this.userowner      = rs.getString(6);
601
        this.userupdated    = rs.getString(7);
602
        this.serverlocation = rs.getInt(8);
603
        this.publicaccess   = rs.getString(9);
604
        this.rev            = rs.getInt(10);
605
      } 
606

    
607
      if (this.doctype != null) {
608
        pstmt =
609
          conn.prepareStatement("SELECT system_id " +
610
                                  "FROM xml_catalog " +
611
                                 "WHERE public_id = ?");
612
        // Bind the values to the query
613
        pstmt.setString(1, doctype);
614
  
615
        pstmt.execute();
616
        rs = pstmt.getResultSet();
617
        tableHasRows = rs.next();
618
        if (tableHasRows) {
619
          this.system_id  = rs.getString(1);
620
        } 
621
        //pstmt.close();
622
      }
623
    } catch (SQLException e) {
624
      System.out.println("error in DocumentImpl.getDocumentInfo: " + 
625
                          e.getMessage());
626
      e.printStackTrace(System.out);
627
      throw new McdbException("Error accessing database connection in " +
628
                              "DocumentImpl.getDocumentInfo: ", e);
629
    }
630

    
631
    if (this.docname == null) {
632
      throw new McdbDocNotFoundException("Document not found: " + docid);
633
    }
634
  }
635

    
636
  /**
637
   * Look up the node data from the database
638
   *
639
   * @param rootnodeid the id of the root node of the node tree to look up
640
   */
641
  private TreeSet getNodeRecordList(long rootnodeid) throws McdbException 
642
  {
643
    PreparedStatement pstmt;
644
    TreeSet nodeRecordList = new TreeSet(new NodeComparator());
645
    long nodeid = 0;
646
    long parentnodeid = 0;
647
    long nodeindex = 0;
648
    String nodetype = null;
649
    String nodename = null;
650
    String nodedata = null;
651

    
652
    try {
653
      pstmt =
654
      conn.prepareStatement("SELECT nodeid,parentnodeid,nodeindex, " +
655
           "nodetype,nodename,"+               
656
           "replace(" +
657
           "replace(" +
658
           "replace(nodedata,'&','&amp;') " +
659
           ",'<','&lt;') " +
660
           ",'>','&gt;') " +
661
           "FROM xml_nodes WHERE rootnodeid = ?");
662

    
663
      // Bind the values to the query
664
      pstmt.setLong(1, rootnodeid);
665

    
666
      pstmt.execute();
667
      ResultSet rs = pstmt.getResultSet();
668
      boolean tableHasRows = rs.next();
669
      while (tableHasRows) {
670
        nodeid = rs.getLong(1);
671
        parentnodeid = rs.getLong(2);
672
        nodeindex = rs.getLong(3);
673
        nodetype = rs.getString(4);
674
        nodename = rs.getString(5);
675
        nodedata = rs.getString(6);
676

    
677
        // add the data to the node record list hashtable
678
        NodeRecord currentRecord = new NodeRecord(nodeid, parentnodeid, 
679
                                   nodeindex, nodetype, nodename, nodedata);
680
        nodeRecordList.add(currentRecord);
681

    
682
        // Advance to the next node
683
        tableHasRows = rs.next();
684
      } 
685
      pstmt.close();
686

    
687
    } catch (SQLException e) {
688
      throw new McdbException("Error accessing database connection from " +
689
                              "DocumentImpl.getNodeRecordList ", e);
690
    }
691

    
692
    if (nodeRecordList != null) {
693
      return nodeRecordList;
694
    } else {
695
      throw new McdbException("Error getting node data: " + docid);
696
    }
697
  }
698
  
699
// NOT USED ANY MORE
700
//  /** creates SQL code and inserts new document into DB connection 
701
//   default serverCode of 1*/
702
//  private void writeDocumentToDB(String action, String user)
703
//               throws SQLException, Exception
704
//  {
705
//    writeDocumentToDB(action, user, null, 1);
706
//  }
707

    
708
 /** creates SQL code and inserts new document into DB connection */
709
  private void writeDocumentToDB(String action, String user, String pub, 
710
                                 String catalogid, int serverCode) 
711
               throws SQLException, Exception {
712

    
713
    String sysdate = dbAdapter.getDateTimeFunction();
714

    
715
    try {
716
      PreparedStatement pstmt = null;
717

    
718
      if (action.equals("INSERT")) {
719
        //AccessionNumber ac = new AccessionNumber();
720
        //this.docid = ac.generate(docid, "INSERT");
721
        pstmt = conn.prepareStatement(
722
                "INSERT INTO xml_documents " +
723
                "(docid, rootnodeid, docname, doctype, " + 
724
                "user_owner, user_updated, date_created, date_updated, " + 
725
                "public_access, catalog_id, server_location) " +
726
                "VALUES (?, ?, ?, ?, ?, ?, " + sysdate + ", " + sysdate + 
727
                ", ?, ?, ?)");
728
        //note that the server_location is set to 1. 
729
        //this means that "localhost" in the xml_replication table must
730
        //always be the first entry!!!!!
731
        
732
        // Bind the values to the query
733
        pstmt.setString(1, this.docid);
734
        pstmt.setLong(2, rootnodeid);
735
        pstmt.setString(3, docname);
736
        pstmt.setString(4, doctype);
737
        pstmt.setString(5, user);
738
        pstmt.setString(6, user);
739
        if ( pub == null ) {
740
          pstmt.setString(7, null);
741
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
742
          pstmt.setInt(7, 1);
743
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
744
          pstmt.setInt(7, 0);
745
        }
746
        pstmt.setString(8, catalogid);
747
        pstmt.setInt(9, serverCode);
748
      } else if (action.equals("UPDATE")) {
749

    
750
        // Save the old document entry in a backup table
751
        DocumentImpl.archiveDocRevision( conn, docid, user );
752
        DocumentImpl thisdoc = new DocumentImpl(conn, docid);
753
        int thisrev = thisdoc.getRev();
754
        thisrev++;
755
        // Delete index for the old version of docid
756
        // The new index is inserting on the next calls to DBSAXNode
757
        pstmt = conn.prepareStatement(
758
                "DELETE FROM xml_index WHERE docid='" + this.docid + "'");
759
        pstmt.execute();
760
        //pstmt.close();
761

    
762
        // Update the new document to reflect the new node tree
763
        pstmt = conn.prepareStatement(
764
            "UPDATE xml_documents " +
765
            "SET rootnodeid = ?, docname = ?, doctype = ?, " +
766
            "user_updated = ?, date_updated = " + sysdate + ", " +
767
            "server_location = ?, rev = ?, public_access = ?, catalog_id = ? " +
768
            "WHERE docid = ?");
769
        // Bind the values to the query
770
        pstmt.setLong(1, rootnodeid);
771
        pstmt.setString(2, docname);
772
        pstmt.setString(3, doctype);
773
        pstmt.setString(4, user);
774
        pstmt.setInt(5, serverCode);
775
        pstmt.setInt(6, thisrev);
776
        if ( pub == null ) {
777
          pstmt.setString(7, null);
778
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
779
          pstmt .setInt(7, 1);
780
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
781
          pstmt.setInt(7, 0);
782
        }
783
        pstmt.setString(8, catalogid);
784
        pstmt.setString(9, this.docid);
785

    
786
      } else {
787
        System.err.println("Action not supported: " + action);
788
      }
789

    
790
      // Do the insertion
791
      pstmt.execute();
792
      pstmt.close();
793

    
794
    } catch (SQLException sqle) {
795
      throw sqle;
796
    } catch (Exception e) {
797
      throw e;
798
    }
799
  }
800

    
801
  /**
802
   * Write an XML file to the database, given a filename
803
   *
804
   * @param conn the JDBC connection to the database
805
   * @param filename the filename to be loaded into the database
806
   * @param pub flag for public "read" access on document
807
   * @param dtdfilename the dtd to be uploaded on server's file system
808
   * @param action the action to be performed (INSERT OR UPDATE)
809
   * @param docid the docid to use for the INSERT OR UPDATE
810
   * @param user the user that owns the document
811
   * @param group the group to which user belongs
812
   */
813
  public static String write(Connection conn,String filename,
814
                             String pub, String dtdfilename,
815
                             String action, String docid, String user,
816
                             String group )
817
                throws Exception {
818
                  
819
    Reader dtd = null;
820
    if ( dtdfilename != null ) {
821
      dtd = new FileReader(new File(dtdfilename).toString());
822
    }
823
    return write ( conn, new FileReader(new File(filename).toString()),
824
                   pub, dtd, action, docid, user, group, false);
825
  }
826

    
827
  public static String write(Connection conn,Reader xml,String pub,Reader dtd,
828
                             String action, String docid, String user,
829
                             String group, boolean validate)
830
                throws Exception {
831
    return write(conn,xml,pub,dtd,action,docid,user,group,1,false,validate);
832
  }
833

    
834
  public static String write(Connection conn, Reader xml, String pub,
835
                             String action, String docid, String user,
836
                             String group )
837
                throws Exception {
838
    if(action.equals("UPDATE"))
839
    {//if the document is being updated then use the servercode from the 
840
     //originally inserted document.
841
      DocumentImpl doc = new DocumentImpl(conn, docid);
842
      int servercode = doc.getServerlocation();
843
      return write(conn, xml, pub, action, docid, user, group, servercode);
844
    }
845
    else
846
    {//if the file is being inserted then the servercode is always 1
847
      return write(conn, xml, pub, action, docid, user, group, 1);
848
    }
849
  }
850
  
851
  public static String write( Connection conn, Reader xml,
852
                              String action, String docid, String user,
853
                              String group, int serverCode )
854
                throws Exception
855
  {
856
    return write(conn,xml,null,action,docid,user,group,serverCode);
857
  }
858
  
859
  public static String write( Connection conn, Reader xml, String pub,
860
                              String action, String docid, String user,
861
                              String group, int serverCode) 
862
                throws Exception
863
  {
864
    return write(conn,xml,pub,null,action,docid,user,group,
865
                 serverCode,false,false);
866
  }
867
  
868
  public static String write( Connection conn, Reader xml, String pub,
869
                              String action, String docid, String user,
870
                              String group, int serverCode, boolean override)
871
                throws Exception
872
  {
873
    return write(conn,xml,pub,null,action,docid,user,group,
874
                 serverCode,override,false);
875
  }
876
  
877
  /**
878
   * Write an XML file to the database, given a Reader
879
   *
880
   * @param conn the JDBC connection to the database
881
   * @param xml the xml stream to be loaded into the database
882
   * @param pub flag for public "read" access on xml document
883
   * @param dtd the dtd to be uploaded on server's file system
884
   * @param action the action to be performed (INSERT or UPDATE)
885
   * @param accnum the docid + rev# to use on INSERT or UPDATE
886
   * @param user the user that owns the document
887
   * @param group the group to which user belongs
888
   * @param serverCode the serverid from xml_replication on which this document
889
   *        resides.
890
   * @param override flag to stop insert replication checking.
891
   *        if override = true then a document not belonging to the local server
892
   *        will not be checked upon update for a file lock.
893
   *        if override = false then a document not from this server, upon 
894
   *        update will be locked and version checked.
895
   */
896

    
897
  public static String write( Connection conn,Reader xml,String pub,Reader dtd,
898
                              String action, String accnum, String user,
899
                              String group, int serverCode, boolean override,
900
                              boolean validate)
901
                throws Exception
902
  {
903
//    int rev = 1;
904
//    String docid = null;
905
//    MetaCatUtil util = new MetaCatUtil();
906
//    String sep = util.getOption("accNumSeparator");
907
/*    
908
    if ( accnum != null ) {
909
      // check the correctness of accnum;
910
      // split accnum in docid and rev in order to
911
      // preserve the current implementation of processing and storing,
912
      // but show the whole accnum to the client.
913
      DocumentIdentifier id = new DocumentIdentifier(accnum);
914
      docid = id.getIdentifier();
915
      rev = (new Integer(id.getRev())).intValue();
916
      sep = id.getSeparator();
917
    }
918
*/    
919
    // OLD
920
    // Determine if the docid,rev are OK for INSERT or UPDATE
921
    // Generate new docid on INSERT, if one is not provided.
922
    //AccessionNumber ac = new AccessionNumber(conn);
923
    //docid = ac.generate(docid, java.lang.String.valueOf(rev), action); 
924
    
925
    // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
926
    AccessionNumber ac = new AccessionNumber(conn, accnum, action);
927
    String docid = ac.getDocid();
928
    String rev = ac.getRev();
929
    
930
    MetaCatUtil.debugMessage("action: " + action + " servercode: " + 
931
                             serverCode + " override: " + override);
932
                        
933
    if((serverCode != 1 && action.equals("UPDATE")) && !override)
934
    { //if this document being written is not a resident of this server then
935
      //we need to try to get a lock from it's resident server.  If the
936
      //resident server will not give a lock then we send the user a message
937
      //saying that he/she needs to download a new copy of the file and
938
      //merge the differences manually.
939
      int istreamInt; 
940
      char istreamChar;
941
      DocumentIdentifier id = new DocumentIdentifier(accnum);
942
      String updaterev = id.getRev();
943
      String server = MetacatReplication.getServer(serverCode);
944
      MetacatReplication.replLog("attempting to lock " + accnum);
945
      URL u = new URL("http://" + server + "?action=getlock&updaterev=" + 
946
                      updaterev + "&docid=" + docid);
947
      System.out.println("sending message: " + u.toString());
948
      String serverResStr = MetacatReplication.getURLContent(u);
949
      String openingtag = serverResStr.substring(0, serverResStr.indexOf(">")+1);
950
      
951
      if(openingtag.equals("<lockgranted>"))
952
      {//the lock was granted go ahead with the insert
953
        try 
954
        {
955
          MetacatReplication.replLog("lock granted for " + accnum + " from " +
956
                                      server);
957
          XMLReader parser = initializeParser(conn, action, docid, validate,
958
                                              user, group, pub, serverCode, dtd);
959
          conn.setAutoCommit(false);
960
          parser.parse(new InputSource(xml)); 
961
          conn.commit();
962
          conn.setAutoCommit(true);
963
        } 
964
        catch (Exception e) 
965
        {
966
          conn.rollback();
967
          conn.setAutoCommit(true);
968
          throw e;
969
        }
970
                
971
        //after inserting the document locally, tell the document's home server
972
        //to come get a copy from here.
973
        ForceReplicationHandler frh = new ForceReplicationHandler(docid);
974
        
975
        // OLD
976
        //rev++;
977
        //return (docid + sep + rev);
978
        return (accnum);
979
      }
980

    
981
      else if(openingtag.equals("<filelocked>"))
982
      {//the file is currently locked by another user
983
       //notify our user to wait a few minutes, check out a new copy and try
984
       //again.
985
        //System.out.println("file locked");
986
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
987
                                   server + " reason: file already locked");
988
        throw new Exception("The file specified is already locked by another " +
989
                            "user.  Please wait 30 seconds, checkout the " +
990
                            "newer document, merge your changes and try " +
991
                            "again.");
992
      }
993
      else if(openingtag.equals("<outdatedfile>"))
994
      {//our file is outdated.  notify our user to check out a new copy of the
995
       //file and merge his version with the new version.
996
        //System.out.println("outdated file");
997
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
998
                                    server + " reason: local file outdated");
999
        throw new Exception("The file you are trying to update is an outdated" +
1000
                            " version.  Please checkout the newest document, " +
1001
                            "merge your changes and try again.");
1002
      }
1003
    }
1004
    
1005
    if ( action.equals("UPDATE") ) {
1006
      // check for 'write' permission for 'user' to update this document
1007

    
1008
      if ( !hasPermission(conn, user, group, docid) ) {
1009
        throw new Exception("User " + user + 
1010
              " does not have permission to update XML Document #" + accnum);
1011
      }          
1012
      //rev++;
1013
    }
1014

    
1015
    try 
1016
    { 
1017
      XMLReader parser = initializeParser(conn, action, docid, validate,
1018
                                          user, group, pub, serverCode, dtd);
1019
      conn.setAutoCommit(false);
1020
      parser.parse(new InputSource(xml));
1021
      conn.commit();
1022
      conn.setAutoCommit(true);
1023
    } 
1024
    catch (Exception e) 
1025
    {
1026
      conn.rollback();
1027
      conn.setAutoCommit(true);
1028
      throw e;
1029
    }
1030
    
1031
    //force replicate out the new document to each server in our server list.
1032
    if(serverCode == 1)
1033
    { //start the thread to replicate this new document out to the other servers
1034
      ForceReplicationHandler frh = new ForceReplicationHandler(docid, action);
1035
    }
1036
      
1037
    //return (docid + sep + rev);
1038
    return(accnum);
1039
  }
1040

    
1041
  /**
1042
   * Delete an XML file from the database (actually, just make it a revision
1043
   * in the xml_revisions table)
1044
   *
1045
   * @param docid the ID of the document to be deleted from the database
1046
   */
1047
  public static void delete( Connection conn, String accnum,
1048
                                 String user, String group )
1049
                throws Exception 
1050
  {
1051
    // OLD
1052
    //DocumentIdentifier id = new DocumentIdentifier(accnum);
1053
    //String docid = id.getIdentifier();
1054
    //String rev = id.getRev();
1055
    
1056
    // OLD
1057
    // Determine if the docid,rev are OK for DELETE
1058
    //AccessionNumber ac = new AccessionNumber(conn);
1059
    //docid = ac.generate(docid, rev, "DELETE");
1060

    
1061
    // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1062
    AccessionNumber ac = new AccessionNumber(conn, accnum, "DELETE");
1063
    String docid = ac.getDocid();
1064
    String rev = ac.getRev();
1065
    
1066

    
1067
    // check for 'write' permission for 'user' to delete this document
1068
    if ( !hasPermission(conn, user, group, docid) ) {
1069
      throw new Exception("User " + user + 
1070
              " does not have permission to delete XML Document #" + accnum);
1071
    }
1072

    
1073
    conn.setAutoCommit(false);
1074
    // Copy the record to the xml_revisions table
1075
    DocumentImpl.archiveDocRevision( conn, docid, user );
1076

    
1077
    // Now delete it from the xml_documents table
1078
    
1079
    Statement stmt = conn.createStatement();
1080
    stmt.execute("DELETE FROM xml_index WHERE docid = '" + docid + "'");
1081
    //stmt.execute("DELETE FROM xml_access WHERE docid = '" + docid + "'");
1082
    stmt.execute("DELETE FROM xml_access WHERE accessfileid = '" + docid + "'");
1083
    stmt.execute("DELETE FROM xml_relation WHERE docid = '" + docid + "'");
1084
    stmt.execute("DELETE FROM xml_documents WHERE docid = '" + docid + "'");
1085
    stmt.close();
1086
    conn.commit();
1087
    conn.setAutoCommit(true);
1088
    //IF this is a package document:
1089
    //delete all of the relations that this document created.
1090
    //if the deleted document is a package document its relations should 
1091
    //no longer be active if it has been deleted from the system.
1092
    
1093
  }
1094

    
1095
  /** 
1096
    * Check for "WRITE" permission on @docid for @user and/or @group 
1097
    * from DB connection 
1098
    */
1099
  private static boolean hasPermission( Connection conn, String user,
1100
                                        String group, String docid) 
1101
                         throws SQLException 
1102
  {
1103
    // b' of the command line invocation
1104
    if ( (user == null) && (group == null) ) {
1105
      return true;
1106
    }
1107

    
1108
    // Check for WRITE permission on @docid for @user and/or @group
1109
    AccessControlList aclobj = new AccessControlList(conn);
1110
    boolean hasPermission = aclobj.hasPermission("WRITE",user,docid);
1111
    if ( !hasPermission && group != null ) {
1112
      hasPermission = aclobj.hasPermission("WRITE",group,docid);
1113
    }
1114
    
1115
    return hasPermission;
1116
  }
1117

    
1118
  /**
1119
   * Set up the parser handlers for writing the document to the database
1120
   */
1121
  private static XMLReader initializeParser(Connection conn, String action,
1122
                                   String docid, boolean validate, 
1123
                                   String user, String group, String pub, 
1124
                                   int serverCode, Reader dtd) 
1125
                           throws Exception 
1126
  {
1127
    XMLReader parser = null;
1128
    //
1129
    // Set up the SAX document handlers for parsing
1130
    //
1131
    try {
1132
      ContentHandler chandler = new DBSAXHandler(conn, action, docid,
1133
                                                 user, group, pub, serverCode);
1134
      EntityResolver eresolver= new DBEntityResolver(conn,
1135
                                                 (DBSAXHandler)chandler, dtd);
1136
      DTDHandler dtdhandler   = new DBDTDHandler(conn);
1137

    
1138
      // Get an instance of the parser
1139
      MetaCatUtil util = new MetaCatUtil();
1140
      String parserName = util.getOption("saxparser");
1141
      parser = XMLReaderFactory.createXMLReader(parserName);
1142

    
1143
      // Turn on validation
1144
      parser.setFeature("http://xml.org/sax/features/validation", validate);
1145
      // Turn off Including all external parameter entities
1146
      // (the external DTD subset also)
1147
      // Doesn't work well, probably the feature name is not correct
1148
      // parser.setFeature(
1149
      //  "http://xml.org/sax/features/external-parameter-entities", false);
1150
      
1151
      // Set Handlers in the parser
1152
      parser.setProperty("http://xml.org/sax/properties/declaration-handler",
1153
                         chandler);
1154
      parser.setProperty("http://xml.org/sax/properties/lexical-handler",
1155
                         chandler);
1156
      parser.setContentHandler((ContentHandler)chandler);
1157
      parser.setEntityResolver((EntityResolver)eresolver);
1158
      parser.setDTDHandler((DTDHandler)dtdhandler);
1159
      parser.setErrorHandler((ErrorHandler)chandler);
1160

    
1161
    } catch (Exception e) {
1162
      throw e;
1163
    }
1164

    
1165
    return parser;
1166
  }
1167

    
1168
  /** Save a document entry in the xml_revisions table */
1169
  private static void archiveDocRevision(Connection conn, String docid,
1170
                                         String user) 
1171
                                         throws SQLException {
1172
    String sysdate = dbAdapter.getDateTimeFunction();
1173
    
1174
    // create a record in xml_revisions table 
1175
    // for that document as selected from xml_documents
1176
    PreparedStatement pstmt = conn.prepareStatement(
1177
      "INSERT INTO xml_revisions " +
1178
        "(docid, rootnodeid, docname, doctype, " +
1179
        "user_owner, user_updated, date_created, date_updated, " +
1180
        "server_location, rev, public_access, catalog_id) " +
1181
      "SELECT ?, rootnodeid, docname, doctype, " + 
1182
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
1183
        "server_location, rev, public_access, catalog_id " +
1184
      "FROM xml_documents " +
1185
      "WHERE docid = ?");
1186
    // Bind the values to the query and execute it
1187
    pstmt.setString(1, docid);
1188
    pstmt.setString(2, user);
1189
    pstmt.setString(3, docid);
1190
    pstmt.execute();
1191
    pstmt.close();
1192

    
1193
  }
1194

    
1195
  /**
1196
   * the main routine used to test the DBWriter utility.
1197
   * <p>
1198
   * Usage: java DocumentImpl <-f filename -a action -d docid>
1199
   *
1200
   * @param filename the filename to be loaded into the database
1201
   * @param action the action to perform (READ, INSERT, UPDATE, DELETE)
1202
   * @param docid the id of the document to process
1203
   */
1204
  static public void main(String[] args) {
1205
     
1206
    try {
1207
      String filename    = null;
1208
      String dtdfilename = null;
1209
      String action      = null;
1210
      String docid       = null;
1211
      boolean showRuntime = false;
1212
      boolean useOldReadAlgorithm = false;
1213

    
1214
      // Parse the command line arguments
1215
      for ( int i=0 ; i < args.length; ++i ) {
1216
        if ( args[i].equals( "-f" ) ) {
1217
          filename =  args[++i];
1218
        } else if ( args[i].equals( "-r" ) ) {
1219
          dtdfilename =  args[++i];
1220
        } else if ( args[i].equals( "-a" ) ) {
1221
          action =  args[++i];
1222
        } else if ( args[i].equals( "-d" ) ) {
1223
          docid =  args[++i];
1224
        } else if ( args[i].equals( "-t" ) ) {
1225
          showRuntime = true;
1226
        } else if ( args[i].equals( "-old" ) ) {
1227
          useOldReadAlgorithm = true;
1228
        } else {
1229
          System.err.println
1230
            ( "   args[" +i+ "] '" +args[i]+ "' ignored." );
1231
        }
1232
      }
1233
      
1234
      // Check if the required arguments are provided
1235
      boolean argsAreValid = false;
1236
      if (action != null) {
1237
        if (action.equals("INSERT")) {
1238
          if (filename != null) {
1239
            argsAreValid = true;
1240
          } 
1241
        } else if (action.equals("UPDATE")) {
1242
          if ((filename != null) && (docid != null)) {
1243
            argsAreValid = true;
1244
          } 
1245
        } else if (action.equals("DELETE")) {
1246
          if (docid != null) {
1247
            argsAreValid = true;
1248
          } 
1249
        } else if (action.equals("READ")) {
1250
          if (docid != null) {
1251
            argsAreValid = true;
1252
          } 
1253
        } 
1254
      } 
1255

    
1256
      // Print usage message if the arguments are not valid
1257
      if (!argsAreValid) {
1258
        System.err.println("Wrong number of arguments!!!");
1259
        System.err.println(
1260
          "USAGE: java DocumentImpl [-t] <-a INSERT> [-d docid] <-f filename> "+
1261
          "[-r dtdfilename]");
1262
        System.err.println(
1263
          "   OR: java DocumentImpl [-t] <-a UPDATE -d docid -f filename> " +
1264
          "[-r dtdfilename]");
1265
        System.err.println(
1266
          "   OR: java DocumentImpl [-t] <-a DELETE -d docid>");
1267
        System.err.println(
1268
          "   OR: java DocumentImpl [-t] [-old] <-a READ -d docid>");
1269
        return;
1270
      }
1271
      
1272
      // Time the request if asked for
1273
      double startTime = System.currentTimeMillis();
1274
      
1275
      // Open a connection to the database
1276
      MetaCatUtil util = new MetaCatUtil();
1277
      Connection dbconn = util.openDBConnection();
1278

    
1279
      double connTime = System.currentTimeMillis();
1280
      // Execute the action requested (READ, INSERT, UPDATE, DELETE)
1281
      if (action.equals("READ")) {
1282
          DocumentImpl xmldoc = new DocumentImpl( dbconn, docid );
1283
          if (useOldReadAlgorithm) {
1284
            System.out.println(xmldoc.readUsingSlowAlgorithm());
1285
          } else {
1286
            xmldoc.toXml(new PrintWriter(System.out));
1287
          }
1288
      } else if (action.equals("DELETE")) {
1289
        DocumentImpl.delete(dbconn, docid, null, null);
1290
        System.out.println("Document deleted: " + docid);
1291
      } else {
1292
        String newdocid = DocumentImpl.write(dbconn, filename, null,
1293
                                             dtdfilename, action, docid,
1294
                                             null, null);
1295
        if ((docid != null) && (!docid.equals(newdocid))) {
1296
          if (action.equals("INSERT")) {
1297
            System.out.println("New document ID generated!!! ");
1298
          } else if (action.equals("UPDATE")) {
1299
            System.out.println("ERROR: Couldn't update document!!! ");
1300
          }
1301
        } else if ((docid == null) && (action.equals("UPDATE"))) {
1302
          System.out.println("ERROR: Couldn't update document!!! ");
1303
        }
1304
        System.out.println("Document processing finished for: " + filename
1305
              + " (" + newdocid + ")");
1306
      }
1307

    
1308
      double stopTime = System.currentTimeMillis();
1309
      double dbOpenTime = (connTime - startTime)/1000;
1310
      double insertTime = (stopTime - connTime)/1000;
1311
      double executionTime = (stopTime - startTime)/1000;
1312
      if (showRuntime) {
1313
        System.out.println("\n\nTotal Execution time was: " + 
1314
                           executionTime + " seconds.");
1315
        System.out.println("Time to open DB connection was: " + dbOpenTime + 
1316
                           " seconds.");
1317
        System.out.println("Time to insert document was: " + insertTime +
1318
                           " seconds.");
1319
      }
1320
      dbconn.close();
1321
    } catch (McdbException me) {
1322
      me.toXml(new PrintWriter(System.err));
1323
    } catch (AccessionNumberException ane) {
1324
      System.out.println(ane.getMessage());
1325
    } catch (Exception e) {
1326
      System.err.println("EXCEPTION HANDLING REQUIRED");
1327
      System.err.println(e.getMessage());
1328
      e.printStackTrace(System.err);
1329
    }
1330
  }
1331
}
(26-26/43)