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: bojilova $'
10
 *     '$Date: 2001-09-12 14:49:26 -0700 (Wed, 12 Sep 2001) $'
11
 * '$Revision: 826 $'
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 + "', 'YY-MM-DD HH24:MI:SS')";
220
  
221
      StringBuffer sql = new StringBuffer();
222
      sql.append("insert into xml_documents (docid, docname, doctype, ");
223
      sql.append("user_owner, user_updated, server_location, rev, date_created");
224
      sql.append(", date_updated, public_access) values ('");
225
      sql.append(docid).append("','");
226
      sql.append(docname).append("','");
227
      sql.append(doctype).append("','");
228
      sql.append(user).append("','");
229
      sql.append(user).append("','");
230
      sql.append(serverCode).append("','");
231
      sql.append(rev).append("',");
232
      sql.append(sqlDateString).append(",");
233
      sql.append(sqlDateString).append(",");
234
      sql.append("'0')");
235
      //System.out.println("sql: " + sql.toString());
236

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
696
    try {
697
      pstmt =
698
      conn.prepareStatement("SELECT nodeid,parentnodeid,nodeindex, " +
699
           "nodetype,nodename,nodeprefix,"+               
700
           "replace(" +
701
           "replace(" +
702
           "replace(nodedata,'&','&amp;') " +
703
           ",'<','&lt;') " +
704
           ",'>','&gt;') " +
705
           "FROM xml_nodes WHERE rootnodeid = ?");
706

    
707
      // Bind the values to the query
708
      pstmt.setLong(1, rootnodeid);
709

    
710
      pstmt.execute();
711
      ResultSet rs = pstmt.getResultSet();
712
      boolean tableHasRows = rs.next();
713
      while (tableHasRows) {
714
        nodeid = rs.getLong(1);
715
        parentnodeid = rs.getLong(2);
716
        nodeindex = rs.getLong(3);
717
        nodetype = rs.getString(4);
718
        nodename = rs.getString(5);
719
        nodeprefix = rs.getString(6);
720
        nodedata = rs.getString(7);
721

    
722
        // add the data to the node record list hashtable
723
        NodeRecord currentRecord = new NodeRecord(nodeid,parentnodeid,nodeindex,
724
                                       nodetype, nodename, nodeprefix, nodedata);
725
        nodeRecordList.add(currentRecord);
726

    
727
        // Advance to the next node
728
        tableHasRows = rs.next();
729
      } 
730
      pstmt.close();
731

    
732
    } catch (SQLException e) {
733
      throw new McdbException("Error in DocumentImpl.getNodeRecordList " +
734
                              e.getMessage());
735
    }
736

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

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

    
758
    String sysdate = dbAdapter.getDateTimeFunction();
759

    
760
    try {
761
      PreparedStatement pstmt = null;
762

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

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

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

    
831
      } else {
832
        System.err.println("Action not supported: " + action);
833
      }
834

    
835
      // Do the insertion
836
      pstmt.execute();
837
      pstmt.close();
838

    
839
    } catch (SQLException sqle) {
840
      throw sqle;
841
    } catch (Exception e) {
842
      throw e;
843
    }
844
  }
845

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

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

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

    
942
  public static String write( Connection conn,Reader xml,String pub,Reader dtd,
943
                              String action, String accnum, String user,
944
                              String[] groups, int serverCode, boolean override,
945
                              boolean validate)
946
                throws Exception
947
  {
948
//    int rev = 1;
949
//    String docid = null;
950
//    MetaCatUtil util = new MetaCatUtil();
951
//    String sep = util.getOption("accNumSeparator");
952
/*    
953
    if ( accnum != null ) {
954
      // check the correctness of accnum;
955
      // split accnum in docid and rev in order to
956
      // preserve the current implementation of processing and storing,
957
      // but show the whole accnum to the client.
958
      DocumentIdentifier id = new DocumentIdentifier(accnum);
959
      docid = id.getIdentifier();
960
      rev = (new Integer(id.getRev())).intValue();
961
      sep = id.getSeparator();
962
    }
963
*/    
964
    // OLD
965
    // Determine if the docid,rev are OK for INSERT or UPDATE
966
    // Generate new docid on INSERT, if one is not provided.
967
    //AccessionNumber ac = new AccessionNumber(conn);
968
    //docid = ac.generate(docid, java.lang.String.valueOf(rev), action); 
969
    
970
    // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
971
    AccessionNumber ac = new AccessionNumber(conn, accnum, action);
972
    String docid = ac.getDocid();
973
    String rev = ac.getRev();
974
    
975
    MetaCatUtil.debugMessage("action: " + action + " servercode: " + 
976
                             serverCode + " override: " + override);
977
                        
978
    if((serverCode != 1 && action.equals("UPDATE")) && !override)
979
    { //if this document being written is not a resident of this server then
980
      //we need to try to get a lock from it's resident server.  If the
981
      //resident server will not give a lock then we send the user a message
982
      //saying that he/she needs to download a new copy of the file and
983
      //merge the differences manually.
984
      int istreamInt; 
985
      char istreamChar;
986
      DocumentIdentifier id = new DocumentIdentifier(accnum);
987
      String updaterev = id.getRev();
988
      String server = MetacatReplication.getServer(serverCode);
989
      MetacatReplication.replLog("attempting to lock " + accnum);
990
      URL u = new URL("http://" + server + "?action=getlock&updaterev=" + 
991
                      updaterev + "&docid=" + docid);
992
      System.out.println("sending message: " + u.toString());
993
      String serverResStr = MetacatReplication.getURLContent(u);
994
      String openingtag = serverResStr.substring(0, serverResStr.indexOf(">")+1);
995
      
996
      if(openingtag.equals("<lockgranted>"))
997
      {//the lock was granted go ahead with the insert
998
        try 
999
        {
1000
          MetacatReplication.replLog("lock granted for " + accnum + " from " +
1001
                                      server);
1002
          XMLReader parser = initializeParser(conn, action, docid, validate,
1003
                                              user, groups, pub, serverCode, dtd);
1004
          conn.setAutoCommit(false);
1005
          parser.parse(new InputSource(xml)); 
1006
          conn.commit();
1007
          conn.setAutoCommit(true);
1008
        } 
1009
        catch (Exception e) 
1010
        {
1011
          conn.rollback();
1012
          conn.setAutoCommit(true);
1013
          throw e;
1014
        }
1015
                
1016
        //after inserting the document locally, tell the document's home server
1017
        //to come get a copy from here.
1018
        ForceReplicationHandler frh = new ForceReplicationHandler(docid);
1019
        
1020
        // OLD
1021
        //rev++;
1022
        //return (docid + sep + rev);
1023
        return (accnum);
1024
      }
1025

    
1026
      else if(openingtag.equals("<filelocked>"))
1027
      {//the file is currently locked by another user
1028
       //notify our user to wait a few minutes, check out a new copy and try
1029
       //again.
1030
        //System.out.println("file locked");
1031
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1032
                                   server + " reason: file already locked");
1033
        throw new Exception("The file specified is already locked by another " +
1034
                            "user.  Please wait 30 seconds, checkout the " +
1035
                            "newer document, merge your changes and try " +
1036
                            "again.");
1037
      }
1038
      else if(openingtag.equals("<outdatedfile>"))
1039
      {//our file is outdated.  notify our user to check out a new copy of the
1040
       //file and merge his version with the new version.
1041
        //System.out.println("outdated file");
1042
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1043
                                    server + " reason: local file outdated");
1044
        throw new Exception("The file you are trying to update is an outdated" +
1045
                            " version.  Please checkout the newest document, " +
1046
                            "merge your changes and try again.");
1047
      }
1048
    }
1049
    
1050
    if ( action.equals("UPDATE") ) {
1051
      // check for 'write' permission for 'user' to update this document
1052

    
1053
      if ( !hasPermission(conn, user, groups, docid) ) {
1054
        throw new Exception("User " + user + 
1055
              " does not have permission to update XML Document #" + accnum);
1056
      }          
1057
      //rev++;
1058
    }
1059

    
1060
    try 
1061
    { 
1062
      XMLReader parser = initializeParser(conn, action, docid, validate,
1063
                                          user, groups, pub, serverCode, dtd);
1064
      conn.setAutoCommit(false);
1065
      parser.parse(new InputSource(xml));
1066
      conn.commit();
1067
      conn.setAutoCommit(true);
1068
    } 
1069
    catch (Exception e) 
1070
    {
1071
      conn.rollback();
1072
      conn.setAutoCommit(true);
1073
      throw e;
1074
    }
1075
    
1076
    //force replicate out the new document to each server in our server list.
1077
    if(serverCode == 1)
1078
    { //start the thread to replicate this new document out to the other servers
1079
//      ForceReplicationHandler frh = new ForceReplicationHandler(docid, action);
1080
    }
1081
      
1082
    //return (docid + sep + rev);
1083
    return(accnum);
1084
  }
1085

    
1086
  /**
1087
   * Delete an XML file from the database (actually, just make it a revision
1088
   * in the xml_revisions table)
1089
   *
1090
   * @param docid the ID of the document to be deleted from the database
1091
   */
1092
  public static void delete( Connection conn, String accnum,
1093
                                 String user, String[] groups )
1094
                throws Exception 
1095
  {
1096
    // OLD
1097
    //DocumentIdentifier id = new DocumentIdentifier(accnum);
1098
    //String docid = id.getIdentifier();
1099
    //String rev = id.getRev();
1100
    
1101
    // OLD
1102
    // Determine if the docid,rev are OK for DELETE
1103
    //AccessionNumber ac = new AccessionNumber(conn);
1104
    //docid = ac.generate(docid, rev, "DELETE");
1105

    
1106
    // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1107
    AccessionNumber ac = new AccessionNumber(conn, accnum, "DELETE");
1108
    String docid = ac.getDocid();
1109
    String rev = ac.getRev();
1110
    
1111

    
1112
    // check for 'write' permission for 'user' to delete this document
1113
    if ( !hasPermission(conn, user, groups, docid) ) {
1114
      throw new Exception("User " + user + 
1115
              " does not have permission to delete XML Document #" + accnum);
1116
    }
1117

    
1118
    conn.setAutoCommit(false);
1119
    // Copy the record to the xml_revisions table
1120
    DocumentImpl.archiveDocRevision( conn, docid, user );
1121

    
1122
    // Now delete it from the xml_documents table
1123
    
1124
    Statement stmt = conn.createStatement();
1125
    stmt.execute("DELETE FROM xml_index WHERE docid = '" + docid + "'");
1126
    //stmt.execute("DELETE FROM xml_access WHERE docid = '" + docid + "'");
1127
    stmt.execute("DELETE FROM xml_access WHERE accessfileid = '" + docid + "'");
1128
    stmt.execute("DELETE FROM xml_relation WHERE docid = '" + docid + "'");
1129
    stmt.execute("DELETE FROM xml_documents WHERE docid = '" + docid + "'");
1130
    stmt.close();
1131
    conn.commit();
1132
    conn.setAutoCommit(true);
1133
    //IF this is a package document:
1134
    //delete all of the relations that this document created.
1135
    //if the deleted document is a package document its relations should 
1136
    //no longer be active if it has been deleted from the system.
1137
    
1138
  }
1139

    
1140
  /** 
1141
    * Check for "WRITE" permission on @docid for @user and/or @groups 
1142
    * from DB connection 
1143
    */
1144
  private static boolean hasPermission ( Connection conn, String user,
1145
                                  String[] groups, String docid ) 
1146
                  throws SQLException
1147
  {
1148
    // Check for WRITE permission on @docid for @user and/or @groups
1149
    AccessControlList aclobj = new AccessControlList(conn);
1150
    return aclobj.hasPermission("WRITE", user, groups, docid);
1151
  }
1152

    
1153
  /**
1154
   * Set up the parser handlers for writing the document to the database
1155
   */
1156
  private static XMLReader initializeParser(Connection conn, String action,
1157
                                   String docid, boolean validate, 
1158
                                   String user, String[] groups, String pub, 
1159
                                   int serverCode, Reader dtd) 
1160
                           throws Exception 
1161
  {
1162
    XMLReader parser = null;
1163
    //
1164
    // Set up the SAX document handlers for parsing
1165
    //
1166
    try {
1167
      ContentHandler chandler = new DBSAXHandler(conn, action, docid,
1168
                                                 user, groups, pub, serverCode);
1169
      EntityResolver eresolver= new DBEntityResolver(conn,
1170
                                                 (DBSAXHandler)chandler, dtd);
1171
      DTDHandler dtdhandler   = new DBDTDHandler(conn);
1172

    
1173
      // Get an instance of the parser
1174
      String parserName = MetaCatUtil.getOption("saxparser");
1175
      parser = XMLReaderFactory.createXMLReader(parserName);
1176

    
1177
      // Turn on validation
1178
      parser.setFeature("http://xml.org/sax/features/validation", validate);
1179
      // Turn off Including all external parameter entities
1180
      // (the external DTD subset also)
1181
      // Doesn't work well, probably the feature name is not correct
1182
      // parser.setFeature(
1183
      //  "http://xml.org/sax/features/external-parameter-entities", false);
1184
      
1185
      // Set Handlers in the parser
1186
      parser.setProperty("http://xml.org/sax/properties/declaration-handler",
1187
                         chandler);
1188
      parser.setProperty("http://xml.org/sax/properties/lexical-handler",
1189
                         chandler);
1190
      parser.setContentHandler((ContentHandler)chandler);
1191
      parser.setEntityResolver((EntityResolver)eresolver);
1192
      parser.setDTDHandler((DTDHandler)dtdhandler);
1193
      parser.setErrorHandler((ErrorHandler)chandler);
1194

    
1195
    } catch (Exception e) {
1196
      throw e;
1197
    }
1198

    
1199
    return parser;
1200
  }
1201

    
1202
  /** Save a document entry in the xml_revisions table */
1203
  private static void archiveDocRevision(Connection conn, String docid,
1204
                                         String user) 
1205
                                         throws SQLException {
1206
    String sysdate = dbAdapter.getDateTimeFunction();
1207
    
1208
    // create a record in xml_revisions table 
1209
    // for that document as selected from xml_documents
1210
    PreparedStatement pstmt = conn.prepareStatement(
1211
      "INSERT INTO xml_revisions " +
1212
        "(docid, rootnodeid, docname, doctype, " +
1213
        "user_owner, user_updated, date_created, date_updated, " +
1214
        "server_location, rev, public_access, catalog_id) " +
1215
      "SELECT ?, rootnodeid, docname, doctype, " + 
1216
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
1217
        "server_location, rev, public_access, catalog_id " +
1218
      "FROM xml_documents " +
1219
      "WHERE docid = ?");
1220
    // Bind the values to the query and execute it
1221
    pstmt.setString(1, docid);
1222
    pstmt.setString(2, user);
1223
    pstmt.setString(3, docid);
1224
    pstmt.execute();
1225
    pstmt.close();
1226

    
1227
  }
1228

    
1229
  /**
1230
   * the main routine used to test the DBWriter utility.
1231
   * <p>
1232
   * Usage: java DocumentImpl <-f filename -a action -d docid>
1233
   *
1234
   * @param filename the filename to be loaded into the database
1235
   * @param action the action to perform (READ, INSERT, UPDATE, DELETE)
1236
   * @param docid the id of the document to process
1237
   */
1238
  static public void main(String[] args) {
1239
     
1240
    try {
1241
      String filename    = null;
1242
      String dtdfilename = null;
1243
      String action      = null;
1244
      String docid       = null;
1245
      boolean showRuntime = false;
1246
      boolean useOldReadAlgorithm = false;
1247

    
1248
      // Parse the command line arguments
1249
      for ( int i=0 ; i < args.length; ++i ) {
1250
        if ( args[i].equals( "-f" ) ) {
1251
          filename =  args[++i];
1252
        } else if ( args[i].equals( "-r" ) ) {
1253
          dtdfilename =  args[++i];
1254
        } else if ( args[i].equals( "-a" ) ) {
1255
          action =  args[++i];
1256
        } else if ( args[i].equals( "-d" ) ) {
1257
          docid =  args[++i];
1258
        } else if ( args[i].equals( "-t" ) ) {
1259
          showRuntime = true;
1260
        } else if ( args[i].equals( "-old" ) ) {
1261
          useOldReadAlgorithm = true;
1262
        } else {
1263
          System.err.println
1264
            ( "   args[" +i+ "] '" +args[i]+ "' ignored." );
1265
        }
1266
      }
1267
      
1268
      // Check if the required arguments are provided
1269
      boolean argsAreValid = false;
1270
      if (action != null) {
1271
        if (action.equals("INSERT")) {
1272
          if (filename != null) {
1273
            argsAreValid = true;
1274
          } 
1275
        } else if (action.equals("UPDATE")) {
1276
          if ((filename != null) && (docid != null)) {
1277
            argsAreValid = true;
1278
          } 
1279
        } else if (action.equals("DELETE")) {
1280
          if (docid != null) {
1281
            argsAreValid = true;
1282
          } 
1283
        } else if (action.equals("READ")) {
1284
          if (docid != null) {
1285
            argsAreValid = true;
1286
          } 
1287
        } 
1288
      } 
1289

    
1290
      // Print usage message if the arguments are not valid
1291
      if (!argsAreValid) {
1292
        System.err.println("Wrong number of arguments!!!");
1293
        System.err.println(
1294
          "USAGE: java DocumentImpl [-t] <-a INSERT> [-d docid] <-f filename> "+
1295
          "[-r dtdfilename]");
1296
        System.err.println(
1297
          "   OR: java DocumentImpl [-t] <-a UPDATE -d docid -f filename> " +
1298
          "[-r dtdfilename]");
1299
        System.err.println(
1300
          "   OR: java DocumentImpl [-t] <-a DELETE -d docid>");
1301
        System.err.println(
1302
          "   OR: java DocumentImpl [-t] [-old] <-a READ -d docid>");
1303
        return;
1304
      }
1305
      
1306
      // Time the request if asked for
1307
      double startTime = System.currentTimeMillis();
1308
      
1309
      // Open a connection to the database
1310
      MetaCatUtil util = new MetaCatUtil();
1311
      Connection dbconn = util.openDBConnection();
1312

    
1313
      double connTime = System.currentTimeMillis();
1314
      // Execute the action requested (READ, INSERT, UPDATE, DELETE)
1315
      if (action.equals("READ")) {
1316
          DocumentImpl xmldoc = new DocumentImpl( dbconn, docid );
1317
          if (useOldReadAlgorithm) {
1318
            System.out.println(xmldoc.readUsingSlowAlgorithm());
1319
          } else {
1320
            xmldoc.toXml(new PrintWriter(System.out));
1321
          }
1322
      } else if (action.equals("DELETE")) {
1323
        DocumentImpl.delete(dbconn, docid, null, null);
1324
        System.out.println("Document deleted: " + docid);
1325
      } else {
1326
        String newdocid = DocumentImpl.write(dbconn, filename, null,
1327
                                             dtdfilename, action, docid,
1328
                                             null, null);
1329
        if ((docid != null) && (!docid.equals(newdocid))) {
1330
          if (action.equals("INSERT")) {
1331
            System.out.println("New document ID generated!!! ");
1332
          } else if (action.equals("UPDATE")) {
1333
            System.out.println("ERROR: Couldn't update document!!! ");
1334
          }
1335
        } else if ((docid == null) && (action.equals("UPDATE"))) {
1336
          System.out.println("ERROR: Couldn't update document!!! ");
1337
        }
1338
        System.out.println("Document processing finished for: " + filename
1339
              + " (" + newdocid + ")");
1340
      }
1341

    
1342
      double stopTime = System.currentTimeMillis();
1343
      double dbOpenTime = (connTime - startTime)/1000;
1344
      double insertTime = (stopTime - connTime)/1000;
1345
      double executionTime = (stopTime - startTime)/1000;
1346
      if (showRuntime) {
1347
        System.out.println("\n\nTotal Execution time was: " + 
1348
                           executionTime + " seconds.");
1349
        System.out.println("Time to open DB connection was: " + dbOpenTime + 
1350
                           " seconds.");
1351
        System.out.println("Time to insert document was: " + insertTime +
1352
                           " seconds.");
1353
      }
1354
      dbconn.close();
1355
    } catch (McdbException me) {
1356
      me.toXml(new PrintWriter(System.err));
1357
    } catch (AccessionNumberException ane) {
1358
      System.out.println(ane.getMessage());
1359
    } catch (Exception e) {
1360
      System.err.println("EXCEPTION HANDLING REQUIRED");
1361
      System.err.println(e.getMessage());
1362
      e.printStackTrace(System.err);
1363
    }
1364
  }
1365
}
(23-23/40)