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: tao $'
10
 *     '$Date: 2002-02-26 08:30:38 -0800 (Tue, 26 Feb 2002) $'
11
 * '$Revision: 946 $'
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 to create a document and read the document information
95
   * from the database.  If readNodes is false, then the node data is not 
96
   * read at this time, but is deferred until it is needed (such as when a 
97
   * call to toXml() is made).  
98
   *
99
   * @param conn the database connection from which to read the document
100
   * @param docid the identifier of the document to be created
101
   * @param readNodes flag indicating whether the xmlnodes should be read
102
   */
103
  public DocumentImpl(Connection conn, String docid, boolean readNodes) 
104
         throws McdbException 
105
  {
106
    try {
107
      this.conn = conn;
108
      this.docid = docid;
109
      
110
      // Look up the document information
111
      getDocumentInfo(docid);
112

    
113
      if (readNodes) {
114
        // Download all of the document nodes using a single SQL query
115
        // The sort order of the records is determined by the NodeComparator
116
        // class, and needs to represent a depth-first traversal for the
117
        // toXml() method to work properly
118
        nodeRecordList = getNodeRecordList(rootnodeid);
119
      }
120
    
121
    } catch (McdbException ex) {
122
      throw ex;
123
    } catch (Throwable t) {
124
      throw new McdbException("Error reading document from " +
125
                              "DocumentImpl.DocumentImpl: " + docid);
126
    }
127
  }
128

    
129
  /**
130
   * Constructor, creates document from database connection, used 
131
   * for reading the document
132
   *
133
   * @param conn the database connection from which to read the document
134
   * @param docid the identifier of the document to be created
135
   */
136
  public DocumentImpl(Connection conn, String docid) throws McdbException 
137
  {
138
    this(conn, docid, true);
139
  }
140

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

    
208
    try {
209
      dbconn = util.openDBConnection();
210

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

    
238
      PreparedStatement pstmt = dbconn.prepareStatement(sql.toString());
239
      pstmt.execute();
240
      pstmt.close();
241
      dbconn.close();
242
    } finally {
243
      util.returnConnection(dbconn);
244
    }    
245
  }
246

    
247
  /**
248
   * get the document name
249
   */
250
  public String getDocname() {
251
    return docname;
252
  }
253

    
254
  /**
255
   * get the document type (which is the PublicID)
256
   */
257
  public String getDoctype() {
258
    return doctype;
259
  }
260

    
261
  /**
262
   * get the system identifier
263
   */
264
  public String getSystemID() {
265
    return system_id;
266
  }
267

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

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

    
324
  /**
325
   * Print a string representation of the XML document
326
   */
327
  public String toString()
328
  {
329
    StringWriter docwriter = new StringWriter();
330
    try {
331
      this.toXml(docwriter);
332
    } catch (McdbException mcdbe) {
333
      return null;
334
    }
335
    String document = docwriter.toString();
336
    return document;
337
  }
338

    
339
  /**
340
   * Get a text representation of the XML document as a string
341
   * This older algorithm uses a recursive tree of Objects to represent the
342
   * nodes of the tree.  Each object is passed the data for the document 
343
   * and searches all of the document data to find its children nodes and
344
   * recursively build.  Thus, because each node reads the whole document,
345
   * this algorithm is extremely slow for larger documents, and the time
346
   * to completion is O(N^N) wrt the number of nodes.  See toXml() for a
347
   * better algorithm.
348
   */
349
  public String readUsingSlowAlgorithm() throws McdbException
350
  {
351
    StringBuffer doc = new StringBuffer();
352

    
353
    // First, check that we have the needed node data, and get it if not
354
    if (nodeRecordList == null) {
355
      nodeRecordList = getNodeRecordList(rootnodeid);
356
    }
357

    
358
    // Create the elements from the downloaded data in the TreeSet
359
    rootNode = new ElementNode(nodeRecordList, rootnodeid);
360

    
361
    // Append the resulting document to the StringBuffer and return it
362
    doc.append("<?xml version=\"1.0\"?>\n");
363
      
364
    if (docname != null) {
365
      if ((doctype != null) && (system_id != null)) {
366
        doc.append("<!DOCTYPE " + docname + " PUBLIC \"" + doctype + 
367
                   "\" \"" + system_id + "\">\n");
368
      } else {
369
        doc.append("<!DOCTYPE " + docname + ">\n");
370
      }
371
    }
372
    doc.append(rootNode.toString());
373
  
374
    return (doc.toString());
375
  }
376

    
377
  /**
378
   * Print a text representation of the XML document to a Writer
379
   *
380
   * @param pw the Writer to which we print the document
381
   */
382
  public void toXml(Writer pw) throws McdbException
383
  {
384
    PrintWriter out = null;
385
    if (pw instanceof PrintWriter) {
386
      out = (PrintWriter)pw;
387
    } else {
388
      out = new PrintWriter(pw);
389
    }
390

    
391
    MetaCatUtil util = new MetaCatUtil();
392
    
393
    // First, check that we have the needed node data, and get it if not
394
    if (nodeRecordList == null) {
395
      nodeRecordList = getNodeRecordList(rootnodeid);
396
    }
397

    
398
    Stack openElements = new Stack();
399
    boolean atRootElement = true;
400
    boolean previousNodeWasElement = false;
401

    
402
    // Step through all of the node records we were given
403
    Iterator it = nodeRecordList.iterator();
404
    while (it.hasNext()) {
405
      NodeRecord currentNode = (NodeRecord)it.next();
406
      //util.debugMessage("[Got Node ID: " + currentNode.nodeid +
407
                          //" (" + currentNode.parentnodeid +
408
                          //", " + currentNode.nodeindex + 
409
                          //", " + currentNode.nodetype + 
410
                          //", " + currentNode.nodename + 
411
                          //", " + currentNode.nodedata + ")]");
412
      // Print the end tag for the previous node if needed
413
      //
414
      // This is determined by inspecting the parent nodeid for the
415
      // currentNode.  If it is the same as the nodeid of the last element
416
      // that was pushed onto the stack, then we are still in that previous
417
      // parent element, and we do nothing.  However, if it differs, then we
418
      // have returned to a level above the previous parent, so we go into
419
      // a loop and pop off nodes and print out their end tags until we get
420
      // the node on the stack to match the currentNode parentnodeid
421
      //
422
      // So, this of course means that we rely on the list of elements
423
      // having been sorted in a depth first traversal of the nodes, which
424
      // is handled by the NodeComparator class used by the TreeSet
425
      if (!atRootElement) {
426
        NodeRecord currentElement = (NodeRecord)openElements.peek();
427
        if ( currentNode.parentnodeid != currentElement.nodeid ) {
428
          while ( currentNode.parentnodeid != currentElement.nodeid ) {
429
            currentElement = (NodeRecord)openElements.pop();
430
            util.debugMessage("\n POPPED: " + currentElement.nodename);
431
            if (previousNodeWasElement) {
432
              out.print(">");
433
              previousNodeWasElement = false;
434
            }  
435
            if ( currentElement.nodeprefix != null ) {
436
              out.print("</" + currentElement.nodeprefix + ":" + 
437
                        currentElement.nodename + ">" );
438
            } else {
439
              out.print("</" + currentElement.nodename + ">" );
440
            }
441
            currentElement = (NodeRecord)openElements.peek();
442
          }
443
        }
444
      }
445

    
446
      // Handle the DOCUMENT node
447
      if (currentNode.nodetype.equals("DOCUMENT")) {
448
        out.println("<?xml version=\"1.0\"?>");
449
      
450
        if (docname != null) {
451
          if ((doctype != null) && (system_id != null)) {
452
            out.println("<!DOCTYPE " + docname + " PUBLIC \"" + doctype + 
453
                       "\" \"" + system_id + "\">");
454
          } else {
455
            out.println("<!DOCTYPE " + docname + ">");
456
          }
457
        }
458

    
459
      // Handle the ELEMENT nodes
460
      } else if (currentNode.nodetype.equals("ELEMENT")) {
461
        if (atRootElement) {
462
          atRootElement = false;
463
        } else {
464
          if (previousNodeWasElement) {
465
            out.print(">");
466
          }
467
        }
468
        openElements.push(currentNode);
469
        util.debugMessage("\n PUSHED: " + currentNode.nodename);
470
        previousNodeWasElement = true;
471
        if ( currentNode.nodeprefix != null ) {
472
          out.print("<" + currentNode.nodeprefix + ":" + currentNode.nodename);
473
        } else {
474
          out.print("<" + currentNode.nodename);
475
        }
476

    
477
      // Handle the ATTRIBUTE nodes
478
      } else if (currentNode.nodetype.equals("ATTRIBUTE")) {
479
        if ( currentNode.nodeprefix != null ) {
480
          out.print(" " + currentNode.nodeprefix + ":" + currentNode.nodename +
481
                    "=\"" + currentNode.nodedata + "\"");
482
        } else {
483
          out.print(" " + currentNode.nodename + "=\"" +
484
                    currentNode.nodedata + "\"");
485
        }
486

    
487
      // Handle the NAMESPACE nodes
488
      } else if (currentNode.nodetype.equals("NAMESPACE")) {
489
        out.print(" xmlns:" + currentNode.nodename + "=\""
490
                 + currentNode.nodedata + "\"");
491

    
492
      // Handle the TEXT nodes
493
      } else if (currentNode.nodetype.equals("TEXT")) {
494
        if (previousNodeWasElement) {
495
          out.print(">");
496
        }
497
        out.print(currentNode.nodedata);
498
        previousNodeWasElement = false;
499

    
500
      // Handle the COMMENT nodes
501
      } else if (currentNode.nodetype.equals("COMMENT")) {
502
        if (previousNodeWasElement) {
503
          out.print(">");
504
        }
505
        out.print("<!--" + currentNode.nodedata + "-->");
506
        previousNodeWasElement = false;
507

    
508
      // Handle the PI nodes
509
      } else if (currentNode.nodetype.equals("PI")) {
510
        if (previousNodeWasElement) {
511
          out.print(">");
512
        }
513
        out.print("<?" + currentNode.nodename + " " +
514
                        currentNode.nodedata + "?>");
515
        previousNodeWasElement = false;
516

    
517
      // Handle any other node type (do nothing)
518
      } else {
519
        // Any other types of nodes are not handled.
520
        // Probably should throw an exception here to indicate this
521
      }
522
      out.flush();
523
    }
524

    
525
    // Print the final end tag for the root element
526
    while(!openElements.empty())
527
    {
528
      NodeRecord currentElement = (NodeRecord)openElements.pop();
529
      util.debugMessage("\n POPPED: " + currentElement.nodename);
530
      if ( currentElement.nodeprefix != null ) {
531
        out.print("</" + currentElement.nodeprefix + ":" + 
532
                  currentElement.nodename + ">" );
533
      } else {
534
        out.print("</" + currentElement.nodename + ">" );
535
      }
536
    }
537
    out.flush();
538
  }
539
  
540
  private boolean isRevisionOnly(DocumentIdentifier docid) throws Exception
541
  {
542
    //System.out.println("inRevisionOnly");
543
    PreparedStatement pstmt;
544
    String rev = docid.getRev();
545
    String newid = docid.getIdentifier();
546
    pstmt = conn.prepareStatement("select rev from xml_documents " +
547
                                  "where docid like '" + newid + "'");
548
    pstmt.execute();
549
    ResultSet rs = pstmt.getResultSet();
550
    boolean tablehasrows = rs.next();
551
    if(rev.equals("newest") || rev.equals("all"))
552
    {
553
      return false;
554
    }
555
    
556
    if(tablehasrows)
557
    {
558
      int r = rs.getInt(1);
559
      pstmt.close();
560
      if(new Integer(rev).intValue() == r)
561
      { //the current revision in in xml_documents
562
        //System.out.println("returning false");
563
        return false;
564
      }
565
      else if(new Integer(rev).intValue() < r)
566
      { //the current revision is in xml_revisions.
567
        //System.out.println("returning true");
568
        return true;
569
      }
570
      else if(new Integer(rev).intValue() > r)
571
      { //error, rev cannot be greater than r
572
        throw new Exception("requested revision cannot be greater than " +
573
                            "the latest revision number.");
574
      }
575
    }
576
    throw new Exception("the requested docid '" + docid.toString() + 
577
                        "' does not exist");
578
  }
579

    
580
  private void getDocumentInfo(String docid) throws McdbException, 
581
                                                    AccessionNumberException
582
  {
583
    getDocumentInfo(new DocumentIdentifier(docid));
584
  }
585
  
586
  /**
587
   * Look up the document type information from the database
588
   *
589
   * @param docid the id of the document to look up
590
   */
591
  private void getDocumentInfo(DocumentIdentifier docid) throws McdbException 
592
  {
593
    PreparedStatement pstmt;
594
    String table = "xml_documents";
595
    
596
    try
597
    {
598
      if(isRevisionOnly(docid))
599
      { //pull the document from xml_revisions instead of from xml_documents;
600
        table = "xml_revisions";
601
      }
602
    }
603
    catch(Exception e)
604
    {
605
      System.out.println("error in DocumentImpl.getDocumentInfo: " + 
606
                          e.getMessage());
607
    }
608
    
609
    //deal with the key words here.
610
    
611
    if(docid.getRev().equals("all"))
612
    {
613
      
614
    }
615
    
616
    try {
617
      StringBuffer sql = new StringBuffer();
618
// DOCTITLE attr cleared from the db
619
//      sql.append("SELECT docname, doctype, rootnodeid, doctitle, ");
620
      sql.append("SELECT docname, doctype, rootnodeid, ");
621
      sql.append("date_created, date_updated, user_owner, user_updated, ");
622
      sql.append("server_location, public_access, rev");
623
      sql.append(" FROM ").append(table);
624
      sql.append(" WHERE docid LIKE '").append(docid.getIdentifier());
625
      sql.append("' and rev like '").append(docid.getRev()).append("'");
626
      //System.out.println(sql.toString());
627
      pstmt =
628
        conn.prepareStatement(sql.toString());
629
      // Bind the values to the query
630
      //pstmt.setString(1, docid.getIdentifier());
631
      //pstmt.setString(2, docid.getRev());
632

    
633
      pstmt.execute();
634
      ResultSet rs = pstmt.getResultSet();
635
      boolean tableHasRows = rs.next();
636
      if (tableHasRows) {
637
        this.docname        = rs.getString(1);
638
        this.doctype        = rs.getString(2);
639
        this.rootnodeid     = rs.getLong(3);
640
// DOCTITLE attr cleared from the db
641
//        this.doctitle       = rs.getString(4);
642
        this.createdate     = rs.getString(4);
643
        this.updatedate     = rs.getString(5);
644
        this.userowner      = rs.getString(6);
645
        this.userupdated    = rs.getString(7);
646
        this.serverlocation = rs.getInt(8);
647
        this.publicaccess   = rs.getString(9);
648
        this.rev            = rs.getInt(10);
649
      } 
650
      pstmt.close();
651
      if (this.doctype != null) {
652
        pstmt =
653
          conn.prepareStatement("SELECT system_id " +
654
                                  "FROM xml_catalog " +
655
                                 "WHERE public_id = ?");
656
        // Bind the values to the query
657
        pstmt.setString(1, doctype);
658
  
659
        pstmt.execute();
660
        rs = pstmt.getResultSet();
661
        tableHasRows = rs.next();
662
        if (tableHasRows) {
663
          this.system_id  = rs.getString(1);
664
        } 
665
        pstmt.close();
666
      }
667
    } catch (SQLException e) {
668
      System.out.println("error in DocumentImpl.getDocumentInfo: " + 
669
                          e.getMessage());
670
      e.printStackTrace(System.out);
671
      throw new McdbException("Error accessing database connection in " +
672
                              "DocumentImpl.getDocumentInfo: ", e);
673
    }
674

    
675
    if (this.docname == null) {
676
      throw new McdbDocNotFoundException("Document not found: " + docid);
677
    }
678
  }
679

    
680
  /**
681
   * Look up the node data from the database
682
   *
683
   * @param rootnodeid the id of the root node of the node tree to look up
684
   */
685
  private TreeSet getNodeRecordList(long rootnodeid) throws McdbException 
686
  {
687
    PreparedStatement pstmt;
688
    TreeSet nodeRecordList = new TreeSet(new NodeComparator());
689
    long nodeid = 0;
690
    long parentnodeid = 0;
691
    long nodeindex = 0;
692
    String nodetype = null;
693
    String nodename = null;
694
    String nodeprefix = null;
695
    String nodedata = null;
696
    String quotechar = dbAdapter.getStringDelimiter();
697

    
698
    try {
699
      pstmt =
700
      conn.prepareStatement("SELECT nodeid,parentnodeid,nodeindex, " +
701
           "nodetype,nodename,nodeprefix,nodedata " +               
702
           "FROM xml_nodes WHERE rootnodeid = ?");
703

    
704
      // Bind the values to the query
705
      pstmt.setLong(1, rootnodeid);
706

    
707
      pstmt.execute();
708
      ResultSet rs = pstmt.getResultSet();
709
      boolean tableHasRows = rs.next();
710
      while (tableHasRows) {
711
        nodeid = rs.getLong(1);
712
        parentnodeid = rs.getLong(2);
713
        nodeindex = rs.getLong(3);
714
        nodetype = rs.getString(4);
715
        nodename = rs.getString(5);
716
        nodeprefix = rs.getString(6);
717
        nodedata = rs.getString(7);
718
        nodedata = MetaCatUtil.normalize(nodedata);
719
        // add the data to the node record list hashtable
720
        NodeRecord currentRecord = new NodeRecord(nodeid,parentnodeid,nodeindex,
721
                                      nodetype, nodename, nodeprefix, nodedata);
722
        nodeRecordList.add(currentRecord);
723

    
724
        // Advance to the next node
725
        tableHasRows = rs.next();
726
      } 
727
      pstmt.close();
728

    
729
    } catch (SQLException e) {
730
      throw new McdbException("Error in DocumentImpl.getNodeRecordList " +
731
                              e.getMessage());
732
    }
733

    
734
    if (nodeRecordList != null) {
735
      return nodeRecordList;
736
    } else {
737
      throw new McdbException("Error getting node data: " + docid);
738
    }
739
  }
740
  
741
// NOT USED ANY MORE
742
//  /** creates SQL code and inserts new document into DB connection 
743
//   default serverCode of 1*/
744
//  private void writeDocumentToDB(String action, String user)
745
//               throws SQLException, Exception
746
//  {
747
//    writeDocumentToDB(action, user, null, 1);
748
//  }
749

    
750
 /** creates SQL code and inserts new document into DB connection */
751
  private void writeDocumentToDB(String action, String user, String pub, 
752
                                 String catalogid, int serverCode) 
753
               throws SQLException, Exception {
754

    
755
    String sysdate = dbAdapter.getDateTimeFunction();
756

    
757
    try {
758
      PreparedStatement pstmt = null;
759

    
760
      if (action.equals("INSERT")) {
761
        //AccessionNumber ac = new AccessionNumber();
762
        //this.docid = ac.generate(docid, "INSERT");
763
        pstmt = conn.prepareStatement(
764
                "INSERT INTO xml_documents " +
765
                "(docid, rootnodeid, docname, doctype, " + 
766
                "user_owner, user_updated, date_created, date_updated, " + 
767
                "public_access, catalog_id, server_location) " +
768
                "VALUES (?, ?, ?, ?, ?, ?, " + sysdate + ", " + sysdate + 
769
                ", ?, ?, ?)");
770
        //note that the server_location is set to 1. 
771
        //this means that "localhost" in the xml_replication table must
772
        //always be the first entry!!!!!
773
        
774
        // Bind the values to the query
775
        pstmt.setString(1, this.docid);
776
        pstmt.setLong(2, rootnodeid);
777
        pstmt.setString(3, docname);
778
        pstmt.setString(4, doctype);
779
        pstmt.setString(5, user);
780
        pstmt.setString(6, user);
781
        if ( pub == null ) {
782
          pstmt.setString(7, null);
783
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
784
          pstmt.setInt(7, 1);
785
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
786
          pstmt.setInt(7, 0);
787
        }
788
        pstmt.setString(8, catalogid);
789
        pstmt.setInt(9, serverCode);
790
      } else if (action.equals("UPDATE")) {
791

    
792
        // Save the old document entry in a backup table
793
        DocumentImpl.archiveDocRevision( conn, docid, user );
794
        DocumentImpl thisdoc = new DocumentImpl(conn, docid);
795
        int thisrev = thisdoc.getRev();
796
        thisrev++;
797
        // Delete index for the old version of docid
798
        // The new index is inserting on the next calls to DBSAXNode
799
        pstmt = conn.prepareStatement(
800
                "DELETE FROM xml_index WHERE docid='" + this.docid + "'");
801
        pstmt.execute();
802
        pstmt.close();
803

    
804
        // Update the new document to reflect the new node tree
805
        pstmt = conn.prepareStatement(
806
            "UPDATE xml_documents " +
807
            "SET rootnodeid = ?, docname = ?, doctype = ?, " +
808
            "user_updated = ?, date_updated = " + sysdate + ", " +
809
            "server_location = ?, rev = ?, public_access = ?, catalog_id = ? " +
810
            "WHERE docid = ?");
811
        // Bind the values to the query
812
        pstmt.setLong(1, rootnodeid);
813
        pstmt.setString(2, docname);
814
        pstmt.setString(3, doctype);
815
        pstmt.setString(4, user);
816
        pstmt.setInt(5, serverCode);
817
        pstmt.setInt(6, thisrev);
818
        if ( pub == null ) {
819
          pstmt.setString(7, null);
820
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
821
          pstmt .setInt(7, 1);
822
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
823
          pstmt.setInt(7, 0);
824
        }
825
        pstmt.setString(8, catalogid);
826
        pstmt.setString(9, this.docid);
827

    
828
      } else {
829
        System.err.println("Action not supported: " + action);
830
      }
831

    
832
      // Do the insertion
833
      pstmt.execute();
834
      pstmt.close();
835

    
836
    } catch (SQLException sqle) {
837
      throw sqle;
838
    } catch (Exception e) {
839
      throw e;
840
    }
841
  }
842

    
843
  /**
844
   * Write an XML file to the database, given a filename
845
   *
846
   * @param conn the JDBC connection to the database
847
   * @param filename the filename to be loaded into the database
848
   * @param pub flag for public "read" access on document
849
   * @param dtdfilename the dtd to be uploaded on server's file system
850
   * @param action the action to be performed (INSERT OR UPDATE)
851
   * @param docid the docid to use for the INSERT OR UPDATE
852
   * @param user the user that owns the document
853
   * @param groups the groups to which user belongs
854
   */
855
  public static String write(Connection conn,String filename,
856
                             String pub, String dtdfilename,
857
                             String action, String docid, String user,
858
                             String[] groups )
859
                throws Exception {
860
                  
861
    Reader dtd = null;
862
    if ( dtdfilename != null ) {
863
      dtd = new FileReader(new File(dtdfilename).toString());
864
    }
865
    return write ( conn, new FileReader(new File(filename).toString()),
866
                   pub, dtd, action, docid, user, groups, false);
867
  }
868

    
869
  public static String write(Connection conn,Reader xml,String pub,Reader dtd,
870
                             String action, String docid, String user,
871
                             String[] groups, boolean validate)
872
                throws Exception {
873
    return write(conn,xml,pub,dtd,action,docid,user,groups,1,false,validate);
874
  }
875

    
876
  public static String write(Connection conn, Reader xml, String pub,
877
                             String action, String docid, String user,
878
                             String[] groups )
879
                throws Exception {
880
    if(action.equals("UPDATE"))
881
    {//if the document is being updated then use the servercode from the 
882
     //originally inserted document.
883
      DocumentImpl doc = new DocumentImpl(conn, docid);
884
      int servercode = doc.getServerlocation();
885
      return write(conn, xml, pub, action, docid, user, groups, servercode);
886
    }
887
    else
888
    {//if the file is being inserted then the servercode is always 1
889
      return write(conn, xml, pub, action, docid, user, groups, 1);
890
    }
891
  }
892
  
893
  public static String write( Connection conn, Reader xml,
894
                              String action, String docid, String user,
895
                              String[] groups, int serverCode )
896
                throws Exception
897
  {
898
    return write(conn,xml,null,action,docid,user,groups,serverCode);
899
  }
900
  
901
  public static String write( Connection conn, Reader xml, String pub,
902
                              String action, String docid, String user,
903
                              String[] groups, int serverCode) 
904
                throws Exception
905
  {
906
    return write(conn,xml,pub,null,action,docid,user,groups,
907
                 serverCode,false,false);
908
  }
909
  
910
  public static String write( Connection conn, Reader xml, String pub,
911
                              String action, String docid, String user,
912
                              String[] groups, int serverCode, boolean override)
913
                throws Exception
914
  {
915
    return write(conn,xml,pub,null,action,docid,user,groups,
916
                 serverCode,override,false);
917
  }
918
  
919
  /**
920
   * Write an XML file to the database, given a Reader
921
   *
922
   * @param conn the JDBC connection to the database
923
   * @param xml the xml stream to be loaded into the database
924
   * @param pub flag for public "read" access on xml document
925
   * @param dtd the dtd to be uploaded on server's file system
926
   * @param action the action to be performed (INSERT or UPDATE)
927
   * @param accnum the docid + rev# to use on INSERT or UPDATE
928
   * @param user the user that owns the document
929
   * @param groups the groups to which user belongs
930
   * @param serverCode the serverid from xml_replication on which this document
931
   *        resides.
932
   * @param override flag to stop insert replication checking.
933
   *        if override = true then a document not belonging to the local server
934
   *        will not be checked upon update for a file lock.
935
   *        if override = false then a document not from this server, upon 
936
   *        update will be locked and version checked.
937
   */
938

    
939
  public static String write( Connection conn,Reader xml,String pub,Reader dtd,
940
                              String action, String accnum, String user,
941
                              String[] groups, int serverCode, boolean override,
942
                              boolean validate)
943
                throws Exception
944
  {
945
    // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
946
    AccessionNumber ac = new AccessionNumber(conn, accnum, action);
947
    String docid = ac.getDocid();
948
    String rev = ac.getRev();
949
    
950
    MetaCatUtil.debugMessage("action: " + action + " servercode: " + 
951
                             serverCode + " override: " + override);
952
                        
953
    if((serverCode != 1 && action.equals("UPDATE")) && !override)
954
    { //if this document being written is not a resident of this server then
955
      //we need to try to get a lock from it's resident server.  If the
956
      //resident server will not give a lock then we send the user a message
957
      //saying that he/she needs to download a new copy of the file and
958
      //merge the differences manually.
959
      int istreamInt; 
960
      char istreamChar;
961
      DocumentIdentifier id = new DocumentIdentifier(accnum);
962
      String updaterev = id.getRev();
963
      String server = MetacatReplication.getServer(serverCode);
964
      MetacatReplication.replLog("attempting to lock " + accnum);
965
      URL u = new URL("https://" + server + "?action=getlock&updaterev=" + 
966
                      updaterev + "&docid=" + docid);
967
      System.out.println("sending message: " + u.toString());
968
      String serverResStr = MetacatReplication.getURLContent(u);
969
      String openingtag =serverResStr.substring(0, serverResStr.indexOf(">")+1);
970
      
971
      if(openingtag.equals("<lockgranted>"))
972
      {//the lock was granted go ahead with the insert
973
        try 
974
        {
975
          MetacatReplication.replLog("lock granted for " + accnum + " from " +
976
                                      server);
977
          XMLReader parser = initializeParser(conn, action, docid, validate,
978
                                            user, groups, pub, serverCode, dtd);
979
          conn.setAutoCommit(false);
980
          parser.parse(new InputSource(xml)); 
981
          conn.commit();
982
          conn.setAutoCommit(true);
983
        } 
984
        catch (Exception e) 
985
        {
986
          conn.rollback();
987
          conn.setAutoCommit(true);
988
          throw e;
989
        }
990
                
991
        //after inserting the document locally, tell the document's home server
992
        //to come get a copy from here.
993
        ForceReplicationHandler frh = new ForceReplicationHandler(accnum);
994
        
995
        return (accnum);
996
      }
997

    
998
      else if(openingtag.equals("<filelocked>"))
999
      {//the file is currently locked by another user
1000
       //notify our user to wait a few minutes, check out a new copy and try
1001
       //again.
1002
        //System.out.println("file locked");
1003
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1004
                                   server + " reason: file already locked");
1005
        throw new Exception("The file specified is already locked by another " +
1006
                            "user.  Please wait 30 seconds, checkout the " +
1007
                            "newer document, merge your changes and try " +
1008
                            "again.");
1009
      }
1010
      else if(openingtag.equals("<outdatedfile>"))
1011
      {//our file is outdated.  notify our user to check out a new copy of the
1012
       //file and merge his version with the new version.
1013
        //System.out.println("outdated file");
1014
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1015
                                    server + " reason: local file outdated");
1016
        throw new Exception("The file you are trying to update is an outdated" +
1017
                            " version.  Please checkout the newest document, " +
1018
                            "merge your changes and try again.");
1019
      }
1020
    }
1021
    
1022
    if ( action.equals("UPDATE") ) {
1023
      // check for 'write' permission for 'user' to update this document
1024

    
1025
      if ( !hasPermission(conn, user, groups, docid) ) {
1026
        throw new Exception("User " + user + 
1027
              " does not have permission to update XML Document #" + accnum);
1028
      }          
1029
    }
1030

    
1031
    try 
1032
    { 
1033
      XMLReader parser = initializeParser(conn, action, docid, validate,
1034
                                          user, groups, pub, serverCode, dtd);
1035
      conn.setAutoCommit(false);
1036
      parser.parse(new InputSource(xml));
1037
      conn.commit();
1038
      conn.setAutoCommit(true);
1039
    } 
1040
    catch (Exception e) 
1041
    {
1042
      conn.rollback();
1043
      conn.setAutoCommit(true);
1044
      throw e;
1045
    }
1046
    
1047
    //force replicate out the new document to each server in our server list.
1048
    if(serverCode == 1)
1049
    { //start the thread to replicate this new document out to the other servers
1050
      ForceReplicationHandler frh = new ForceReplicationHandler(accnum, action);
1051
    }
1052
      
1053
    return(accnum);
1054
  }
1055

    
1056
  /**
1057
   * Delete an XML file from the database (actually, just make it a revision
1058
   * in the xml_revisions table)
1059
   *
1060
   * @param docid the ID of the document to be deleted from the database
1061
   */
1062
  public static void delete( Connection conn, String accnum,
1063
                                 String user, String[] groups )
1064
                throws Exception 
1065
  {
1066
    // OLD
1067
    //DocumentIdentifier id = new DocumentIdentifier(accnum);
1068
    //String docid = id.getIdentifier();
1069
    //String rev = id.getRev();
1070
    
1071
    // OLD
1072
    // Determine if the docid,rev are OK for DELETE
1073
    //AccessionNumber ac = new AccessionNumber(conn);
1074
    //docid = ac.generate(docid, rev, "DELETE");
1075

    
1076
    // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1077
    AccessionNumber ac = new AccessionNumber(conn, accnum, "DELETE");
1078
    String docid = ac.getDocid();
1079
    String rev = ac.getRev();
1080
    
1081

    
1082
    // check for 'write' permission for 'user' to delete this document
1083
    if ( !hasPermission(conn, user, groups, docid) ) {
1084
      throw new Exception("User " + user + 
1085
              " does not have permission to delete XML Document #" + accnum);
1086
    }
1087

    
1088
    conn.setAutoCommit(false);
1089
    // Copy the record to the xml_revisions table
1090
    DocumentImpl.archiveDocRevision( conn, docid, user );
1091

    
1092
    // Now delete it from the xml_documents table
1093
    
1094
    Statement stmt = conn.createStatement();
1095
    stmt.execute("DELETE FROM xml_index WHERE docid = '" + docid + "'");
1096
    //stmt.execute("DELETE FROM xml_access WHERE docid = '" + docid + "'");
1097
    stmt.execute("DELETE FROM xml_access WHERE accessfileid = '" + docid + "'");
1098
    stmt.execute("DELETE FROM xml_relation WHERE docid = '" + docid + "'");
1099
    stmt.execute("DELETE FROM xml_documents WHERE docid = '" + docid + "'");
1100
    stmt.close();
1101
    conn.commit();
1102
    conn.setAutoCommit(true);
1103
    //IF this is a package document:
1104
    //delete all of the relations that this document created.
1105
    //if the deleted document is a package document its relations should 
1106
    //no longer be active if it has been deleted from the system.
1107
    
1108
  }
1109

    
1110
  /** 
1111
    * Check for "WRITE" permission on @docid for @user and/or @groups 
1112
    * from DB connection 
1113
    */
1114
  private static boolean hasPermission ( Connection conn, String user,
1115
                                  String[] groups, String docid ) 
1116
                  throws SQLException
1117
  {
1118
    // Check for WRITE permission on @docid for @user and/or @groups
1119
    AccessControlList aclobj = new AccessControlList(conn);
1120
    return aclobj.hasPermission("WRITE", user, groups, docid);
1121
  }
1122

    
1123
  /** 
1124
    * Check for "READ" permission base on docid, user and group
1125
    *@docid, the document
1126
    *@user, user name
1127
    *@group, user's group
1128
    * 
1129
    */
1130
  public boolean hasReadPermission ( Connection conn, String user,
1131
                                  String[] groups, String docId ) 
1132
                  throws SQLException
1133
  {
1134
    // Check for READ permission on @docid for @user and/or @groups
1135
    AccessControlList aclObj = new AccessControlList(conn);
1136
    return aclObj.hasPermission("READ", user, groups, docId);
1137
  }  
1138

    
1139
  /**
1140
   * Set up the parser handlers for writing the document to the database
1141
   */
1142
  private static XMLReader initializeParser(Connection conn, String action,
1143
                                   String docid, boolean validate, 
1144
                                   String user, String[] groups, String pub, 
1145
                                   int serverCode, Reader dtd) 
1146
                           throws Exception 
1147
  {
1148
    XMLReader parser = null;
1149
    //
1150
    // Set up the SAX document handlers for parsing
1151
    //
1152
    try {
1153
      ContentHandler chandler = new DBSAXHandler(conn, action, docid,
1154
                                                 user, groups, pub, serverCode);
1155
      EntityResolver eresolver= new DBEntityResolver(conn,
1156
                                                 (DBSAXHandler)chandler, dtd);
1157
      DTDHandler dtdhandler   = new DBDTDHandler(conn);
1158

    
1159
      // Get an instance of the parser
1160
      String parserName = MetaCatUtil.getOption("saxparser");
1161
      parser = XMLReaderFactory.createXMLReader(parserName);
1162

    
1163
      // Turn on validation
1164
      parser.setFeature("http://xml.org/sax/features/validation", validate);
1165
      // Turn off Including all external parameter entities
1166
      // (the external DTD subset also)
1167
      // Doesn't work well, probably the feature name is not correct
1168
      // parser.setFeature(
1169
      //  "http://xml.org/sax/features/external-parameter-entities", false);
1170
      
1171
      // Set Handlers in the parser
1172
      parser.setProperty("http://xml.org/sax/properties/declaration-handler",
1173
                         chandler);
1174
      parser.setProperty("http://xml.org/sax/properties/lexical-handler",
1175
                         chandler);
1176
      parser.setContentHandler((ContentHandler)chandler);
1177
      parser.setEntityResolver((EntityResolver)eresolver);
1178
      parser.setDTDHandler((DTDHandler)dtdhandler);
1179
      parser.setErrorHandler((ErrorHandler)chandler);
1180

    
1181
    } catch (Exception e) {
1182
      throw e;
1183
    }
1184

    
1185
    return parser;
1186
  }
1187

    
1188
  /** Save a document entry in the xml_revisions table */
1189
  private static void archiveDocRevision(Connection conn, String docid,
1190
                                         String user) 
1191
                                         throws SQLException {
1192
    String sysdate = dbAdapter.getDateTimeFunction();
1193
    
1194
    // create a record in xml_revisions table 
1195
    // for that document as selected from xml_documents
1196
    PreparedStatement pstmt = conn.prepareStatement(
1197
      "INSERT INTO xml_revisions " +
1198
        "(docid, rootnodeid, docname, doctype, " +
1199
        "user_owner, user_updated, date_created, date_updated, " +
1200
        "server_location, rev, public_access, catalog_id) " +
1201
      "SELECT ?, rootnodeid, docname, doctype, " + 
1202
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
1203
        "server_location, rev, public_access, catalog_id " +
1204
      "FROM xml_documents " +
1205
      "WHERE docid = ?");
1206
    // Bind the values to the query and execute it
1207
    pstmt.setString(1, docid);
1208
    pstmt.setString(2, user);
1209
    pstmt.setString(3, docid);
1210
    pstmt.execute();
1211
    pstmt.close();
1212

    
1213
  }
1214

    
1215
  /**
1216
   * the main routine used to test the DBWriter utility.
1217
   * <p>
1218
   * Usage: java DocumentImpl <-f filename -a action -d docid>
1219
   *
1220
   * @param filename the filename to be loaded into the database
1221
   * @param action the action to perform (READ, INSERT, UPDATE, DELETE)
1222
   * @param docid the id of the document to process
1223
   */
1224
  static public void main(String[] args) {
1225
     
1226
    try {
1227
      String filename    = null;
1228
      String dtdfilename = null;
1229
      String action      = null;
1230
      String docid       = null;
1231
      boolean showRuntime = false;
1232
      boolean useOldReadAlgorithm = false;
1233

    
1234
      // Parse the command line arguments
1235
      for ( int i=0 ; i < args.length; ++i ) {
1236
        if ( args[i].equals( "-f" ) ) {
1237
          filename =  args[++i];
1238
        } else if ( args[i].equals( "-r" ) ) {
1239
          dtdfilename =  args[++i];
1240
        } else if ( args[i].equals( "-a" ) ) {
1241
          action =  args[++i];
1242
        } else if ( args[i].equals( "-d" ) ) {
1243
          docid =  args[++i];
1244
        } else if ( args[i].equals( "-t" ) ) {
1245
          showRuntime = true;
1246
        } else if ( args[i].equals( "-old" ) ) {
1247
          useOldReadAlgorithm = true;
1248
        } else {
1249
          System.err.println
1250
            ( "   args[" +i+ "] '" +args[i]+ "' ignored." );
1251
        }
1252
      }
1253
      
1254
      // Check if the required arguments are provided
1255
      boolean argsAreValid = false;
1256
      if (action != null) {
1257
        if (action.equals("INSERT")) {
1258
          if (filename != null) {
1259
            argsAreValid = true;
1260
          } 
1261
        } else if (action.equals("UPDATE")) {
1262
          if ((filename != null) && (docid != null)) {
1263
            argsAreValid = true;
1264
          } 
1265
        } else if (action.equals("DELETE")) {
1266
          if (docid != null) {
1267
            argsAreValid = true;
1268
          } 
1269
        } else if (action.equals("READ")) {
1270
          if (docid != null) {
1271
            argsAreValid = true;
1272
          } 
1273
        } 
1274
      } 
1275

    
1276
      // Print usage message if the arguments are not valid
1277
      if (!argsAreValid) {
1278
        System.err.println("Wrong number of arguments!!!");
1279
        System.err.println(
1280
          "USAGE: java DocumentImpl [-t] <-a INSERT> [-d docid] <-f filename> "+
1281
          "[-r dtdfilename]");
1282
        System.err.println(
1283
          "   OR: java DocumentImpl [-t] <-a UPDATE -d docid -f filename> " +
1284
          "[-r dtdfilename]");
1285
        System.err.println(
1286
          "   OR: java DocumentImpl [-t] <-a DELETE -d docid>");
1287
        System.err.println(
1288
          "   OR: java DocumentImpl [-t] [-old] <-a READ -d docid>");
1289
        return;
1290
      }
1291
      
1292
      // Time the request if asked for
1293
      double startTime = System.currentTimeMillis();
1294
      
1295
      // Open a connection to the database
1296
      MetaCatUtil util = new MetaCatUtil();
1297
      Connection dbconn = util.openDBConnection();
1298

    
1299
      double connTime = System.currentTimeMillis();
1300
      // Execute the action requested (READ, INSERT, UPDATE, DELETE)
1301
      if (action.equals("READ")) {
1302
          DocumentImpl xmldoc = new DocumentImpl( dbconn, docid );
1303
          if (useOldReadAlgorithm) {
1304
            System.out.println(xmldoc.readUsingSlowAlgorithm());
1305
          } else {
1306
            xmldoc.toXml(new PrintWriter(System.out));
1307
          }
1308
      } else if (action.equals("DELETE")) {
1309
        DocumentImpl.delete(dbconn, docid, null, null);
1310
        System.out.println("Document deleted: " + docid);
1311
      } else {
1312
        String newdocid = DocumentImpl.write(dbconn, filename, null,
1313
                                             dtdfilename, action, docid,
1314
                                             null, null);
1315
        if ((docid != null) && (!docid.equals(newdocid))) {
1316
          if (action.equals("INSERT")) {
1317
            System.out.println("New document ID generated!!! ");
1318
          } else if (action.equals("UPDATE")) {
1319
            System.out.println("ERROR: Couldn't update document!!! ");
1320
          }
1321
        } else if ((docid == null) && (action.equals("UPDATE"))) {
1322
          System.out.println("ERROR: Couldn't update document!!! ");
1323
        }
1324
        System.out.println("Document processing finished for: " + filename
1325
              + " (" + newdocid + ")");
1326
      }
1327

    
1328
      double stopTime = System.currentTimeMillis();
1329
      double dbOpenTime = (connTime - startTime)/1000;
1330
      double insertTime = (stopTime - connTime)/1000;
1331
      double executionTime = (stopTime - startTime)/1000;
1332
      if (showRuntime) {
1333
        System.out.println("\n\nTotal Execution time was: " + 
1334
                           executionTime + " seconds.");
1335
        System.out.println("Time to open DB connection was: " + dbOpenTime + 
1336
                           " seconds.");
1337
        System.out.println("Time to insert document was: " + insertTime +
1338
                           " seconds.");
1339
      }
1340
      dbconn.close();
1341
    } catch (McdbException me) {
1342
      me.toXml(new PrintWriter(System.err));
1343
    } catch (AccessionNumberException ane) {
1344
      System.out.println(ane.getMessage());
1345
    } catch (Exception e) {
1346
      System.err.println("EXCEPTION HANDLING REQUIRED");
1347
      System.err.println(e.getMessage());
1348
      e.printStackTrace(System.err);
1349
    }
1350
  }
1351
}
(23-23/40)