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-03-05 13:11:15 -0800 (Tue, 05 Mar 2002) $'
11
 * '$Revision: 958 $'
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 updatedVersion=null;
78
  private String docname = null;
79
  private String doctype = null;
80
// DOCTITLE attr cleared from the db
81
//  private String doctitle = null;
82
  private String createdate = null;
83
  private String updatedate = null;
84
  private String system_id = null;
85
  private String userowner = null;
86
  private String userupdated = null;
87
  private int rev;
88
  private int serverlocation;
89
  private String publicaccess; 
90
  private long rootnodeid;
91
  private ElementNode rootNode = null;
92
  private TreeSet nodeRecordList = null;
93
  
94
  /**
95
   * Constructor used to create a document and read the document information
96
   * from the database.  If readNodes is false, then the node data is not 
97
   * read at this time, but is deferred until it is needed (such as when a 
98
   * call to toXml() is made).  
99
   *
100
   * @param conn the database connection from which to read the document
101
   * @param docid the identifier of the document to be created
102
   * @param readNodes flag indicating whether the xmlnodes should be read
103
   */
104
  public DocumentImpl(Connection conn, String docid, boolean readNodes) 
105
         throws McdbException 
106
  {
107
    try {
108
      this.conn = conn;
109
      this.docid = docid;
110
      
111
      // Look up the document information
112
      getDocumentInfo(docid);
113

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

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

    
142
  /** 
143
   * Construct a new document instance, writing the contents to the database.
144
   * This method is called from DBSAXHandler because we need to know the
145
   * root element name for documents without a DOCTYPE before creating it.
146
   *
147
   * @param conn the JDBC Connection to which all information is written
148
   * @param rootnodeid - sequence id of the root node in the document
149
   * @param docname - the name of DTD, i.e. the name immediately following 
150
   *        the DOCTYPE keyword ( should be the root element name ) or
151
   *        the root element name if no DOCTYPE declaration provided
152
   *        (Oracle's and IBM parsers are not aware if it is not the 
153
   *        root element name)
154
   * @param doctype - Public ID of the DTD, i.e. the name immediately 
155
   *                  following the PUBLIC keyword in DOCTYPE declaration or
156
   *                  the docname if no Public ID provided or
157
   *                  null if no DOCTYPE declaration provided
158
   * @param docid the docid to use for the INSERT OR UPDATE
159
   * @param action the action to be performed (INSERT OR UPDATE)
160
   * @param user the user that owns the document
161
   * @param pub flag for public "read" access on document
162
   * @param serverCode the serverid from xml_replication on which this document
163
   *        resides.
164
   *
165
   */
166
  public DocumentImpl(Connection conn, long rootnodeid, String docname, 
167
                      String doctype, String docid, String action, String user,
168
                      String pub, String catalogid, int serverCode)
169
                      throws SQLException, Exception
170
  {
171
    this.conn = conn;
172
    this.rootnodeid = rootnodeid;
173
    this.docname = docname;
174
    this.doctype = doctype;
175
    this.docid = docid;
176
    writeDocumentToDB(action, user, pub, catalogid, serverCode);
177
  }
178
  
179
  /** 
180
   * Construct a new document instance, writing the contents to the database.
181
   * This method is called from DBSAXHandler because we need to know the
182
   * root element name for documents without a DOCTYPE before creating it.
183
   *
184
   * In this constructor, the docid is without rev. There is a string rev to 
185
   * specify the revision user want to upadate. The revion is only need to be
186
   * greater than current one. It is not need to be sequent number just after
187
   * current one. So it is only used in update action
188
   * @param conn the JDBC Connection to which all information is written
189
   * @param rootnodeid - sequence id of the root node in the document
190
   * @param docname - the name of DTD, i.e. the name immediately following 
191
   *        the DOCTYPE keyword ( should be the root element name ) or
192
   *        the root element name if no DOCTYPE declaration provided
193
   *        (Oracle's and IBM parsers are not aware if it is not the 
194
   *        root element name)
195
   * @param doctype - Public ID of the DTD, i.e. the name immediately 
196
   *                  following the PUBLIC keyword in DOCTYPE declaration or
197
   *                  the docname if no Public ID provided or
198
   *                  null if no DOCTYPE declaration provided
199
   * @param docid the docid to use for the UPDATE, no version number
200
   * @param version, need to be update
201
   * @param action the action to be performed (INSERT OR UPDATE)
202
   * @param user the user that owns the document
203
   * @param pub flag for public "read" access on document
204
   * @param serverCode the serverid from xml_replication on which this document
205
   *        resides.
206
   *
207
   */
208
  public DocumentImpl(Connection conn, long rootNodeId, String docName, 
209
                      String docType, String docId, String newRevision, 
210
                      String action, String user,
211
                      String pub, String catalogId, int serverCode)
212
                      throws SQLException, Exception
213
  {
214
    this.conn = conn;
215
    this.rootnodeid = rootNodeId;
216
    this.docname = docName;
217
    this.doctype = docType;
218
    this.docid = docId;
219
    this.updatedVersion = newRevision;
220
    writeDocumentToDB(action, user, pub, catalogId, serverCode);
221
  }
222
  
223
  /**
224
   * Register a document that resides on the filesystem with the database.
225
   * (ie, just an entry in xml_documents, nothing in xml_nodes).
226
   * Creates a reference to a filesystem document (used for non-xml data files).
227
   *
228
   * @param conn the JDBC Connection to which all information is written
229
   * @param docname - the name of DTD, i.e. the name immediately following 
230
   *        the DOCTYPE keyword ( should be the root element name ) or
231
   *        the root element name if no DOCTYPE declaration provided
232
   *        (Oracle's and IBM parsers are not aware if it is not the 
233
   *        root element name)
234
   * @param doctype - Public ID of the DTD, i.e. the name immediately 
235
   *                  following the PUBLIC keyword in DOCTYPE declaration or
236
   *                  the docname if no Public ID provided or
237
   *                  null if no DOCTYPE declaration provided
238
   * @param accnum the accession number to use for the INSERT OR UPDATE, which 
239
   *               includes a revision number for this revision of the document 
240
   *               (e.g., knb.1.1)
241
   * @param user the user that owns the document
242
   * @param serverCode the serverid from xml_replication on which this document
243
   *        resides.
244
   */
245
  public static void registerDocument(
246
                     String docname, String doctype, String accnum, 
247
                     String user, int serverCode)
248
                     throws SQLException, AccessionNumberException, Exception
249
  {
250
    Connection dbconn = null;
251
    MetaCatUtil util = new MetaCatUtil();
252

    
253
    try {
254
      dbconn = util.openDBConnection();
255

    
256
      AccessionNumber ac = new AccessionNumber(dbconn, accnum, "insert");
257
      String docid = ac.getDocid();
258
      String rev = ac.getRev();
259
  
260
      SimpleDateFormat formatter = new SimpleDateFormat ("yy-MM-dd HH:mm:ss");
261
      Date localtime = new Date();
262
      String dateString = formatter.format(localtime);
263
  
264
      String sqlDateString = "to_date('" + dateString + 
265
                                          "', 'YY-MM-DD HH24:MI:SS')";
266
  
267
      StringBuffer sql = new StringBuffer();
268
      sql.append("insert into xml_documents (docid, docname, doctype, ");
269
      sql.append("user_owner, user_updated, server_location, rev,date_created");
270
      sql.append(", date_updated, public_access) values ('");
271
      sql.append(docid).append("','");
272
      sql.append(docname).append("','");
273
      sql.append(doctype).append("','");
274
      sql.append(user).append("','");
275
      sql.append(user).append("','");
276
      sql.append(serverCode).append("','");
277
      sql.append(rev).append("',");
278
      sql.append(sqlDateString).append(",");
279
      sql.append(sqlDateString).append(",");
280
      sql.append("'0')");
281
      //System.out.println("sql: " + sql.toString());
282

    
283
      PreparedStatement pstmt = dbconn.prepareStatement(sql.toString());
284
      pstmt.execute();
285
      pstmt.close();
286
      dbconn.close();
287
    } finally {
288
      util.returnConnection(dbconn);
289
    }    
290
  }
291

    
292
  /**
293
   * get the document name
294
   */
295
  public String getDocname() {
296
    return docname;
297
  }
298

    
299
  /**
300
   * get the document type (which is the PublicID)
301
   */
302
  public String getDoctype() {
303
    return doctype;
304
  }
305

    
306
  /**
307
   * get the system identifier
308
   */
309
  public String getSystemID() {
310
    return system_id;
311
  }
312

    
313
  /**
314
   * get the root node identifier
315
   */
316
  public long getRootNodeID() {
317
    return rootnodeid;
318
  }
319
  
320
  /**
321
   * get the creation date
322
   */
323
  public String getCreateDate() {
324
    return createdate;
325
  }
326
  
327
  /**
328
   * get the update date
329
   */
330
  public String getUpdateDate() {
331
    return updatedate;
332
  }
333

    
334
  /** 
335
   * Get the document identifier (docid)
336
   */
337
  public String getDocID() {
338
    return docid;
339
  }
340
  
341
// DOCTITLE attr cleared from the db
342
//  /**
343
//   *get the document title
344
//   */
345
//  public String getDocTitle() {
346
//    return doctitle;
347
//  }
348
  
349
  public String getUserowner() {
350
    return userowner;
351
  }
352
  
353
  public String getUserupdated() {
354
    return userupdated;
355
  }
356
  
357
  public int getServerlocation() {
358
    return serverlocation;
359
  }
360
  
361
  public String getPublicaccess() {
362
    return publicaccess;
363
  }
364
  
365
  public int getRev() {
366
    return rev;
367
  }
368
  
369
   /**
370
   * Print a string representation of the XML document
371
   */
372
  public String toString()
373
  {
374
    StringWriter docwriter = new StringWriter();
375
    try {
376
      this.toXml(docwriter);
377
    } catch (McdbException mcdbe) {
378
      return null;
379
    }
380
    String document = docwriter.toString();
381
    return document;
382
  }
383

    
384
  /**
385
   * Get a text representation of the XML document as a string
386
   * This older algorithm uses a recursive tree of Objects to represent the
387
   * nodes of the tree.  Each object is passed the data for the document 
388
   * and searches all of the document data to find its children nodes and
389
   * recursively build.  Thus, because each node reads the whole document,
390
   * this algorithm is extremely slow for larger documents, and the time
391
   * to completion is O(N^N) wrt the number of nodes.  See toXml() for a
392
   * better algorithm.
393
   */
394
  public String readUsingSlowAlgorithm() throws McdbException
395
  {
396
    StringBuffer doc = new StringBuffer();
397

    
398
    // First, check that we have the needed node data, and get it if not
399
    if (nodeRecordList == null) {
400
      nodeRecordList = getNodeRecordList(rootnodeid);
401
    }
402

    
403
    // Create the elements from the downloaded data in the TreeSet
404
    rootNode = new ElementNode(nodeRecordList, rootnodeid);
405

    
406
    // Append the resulting document to the StringBuffer and return it
407
    doc.append("<?xml version=\"1.0\"?>\n");
408
      
409
    if (docname != null) {
410
      if ((doctype != null) && (system_id != null)) {
411
        doc.append("<!DOCTYPE " + docname + " PUBLIC \"" + doctype + 
412
                   "\" \"" + system_id + "\">\n");
413
      } else {
414
        doc.append("<!DOCTYPE " + docname + ">\n");
415
      }
416
    }
417
    doc.append(rootNode.toString());
418
  
419
    return (doc.toString());
420
  }
421

    
422
  /**
423
   * Print a text representation of the XML document to a Writer
424
   *
425
   * @param pw the Writer to which we print the document
426
   */
427
  public void toXml(Writer pw) throws McdbException
428
  {
429
    PrintWriter out = null;
430
    if (pw instanceof PrintWriter) {
431
      out = (PrintWriter)pw;
432
    } else {
433
      out = new PrintWriter(pw);
434
    }
435

    
436
    MetaCatUtil util = new MetaCatUtil();
437
    
438
    // First, check that we have the needed node data, and get it if not
439
    if (nodeRecordList == null) {
440
      nodeRecordList = getNodeRecordList(rootnodeid);
441
    }
442

    
443
    Stack openElements = new Stack();
444
    boolean atRootElement = true;
445
    boolean previousNodeWasElement = false;
446

    
447
    // Step through all of the node records we were given
448
    Iterator it = nodeRecordList.iterator();
449
    while (it.hasNext()) {
450
      NodeRecord currentNode = (NodeRecord)it.next();
451
      //util.debugMessage("[Got Node ID: " + currentNode.nodeid +
452
                          //" (" + currentNode.parentnodeid +
453
                          //", " + currentNode.nodeindex + 
454
                          //", " + currentNode.nodetype + 
455
                          //", " + currentNode.nodename + 
456
                          //", " + currentNode.nodedata + ")]");
457
      // Print the end tag for the previous node if needed
458
      //
459
      // This is determined by inspecting the parent nodeid for the
460
      // currentNode.  If it is the same as the nodeid of the last element
461
      // that was pushed onto the stack, then we are still in that previous
462
      // parent element, and we do nothing.  However, if it differs, then we
463
      // have returned to a level above the previous parent, so we go into
464
      // a loop and pop off nodes and print out their end tags until we get
465
      // the node on the stack to match the currentNode parentnodeid
466
      //
467
      // So, this of course means that we rely on the list of elements
468
      // having been sorted in a depth first traversal of the nodes, which
469
      // is handled by the NodeComparator class used by the TreeSet
470
      if (!atRootElement) {
471
        NodeRecord currentElement = (NodeRecord)openElements.peek();
472
        if ( currentNode.parentnodeid != currentElement.nodeid ) {
473
          while ( currentNode.parentnodeid != currentElement.nodeid ) {
474
            currentElement = (NodeRecord)openElements.pop();
475
            util.debugMessage("\n POPPED: " + currentElement.nodename);
476
            if (previousNodeWasElement) {
477
              out.print(">");
478
              previousNodeWasElement = false;
479
            }  
480
            if ( currentElement.nodeprefix != null ) {
481
              out.print("</" + currentElement.nodeprefix + ":" + 
482
                        currentElement.nodename + ">" );
483
            } else {
484
              out.print("</" + currentElement.nodename + ">" );
485
            }
486
            currentElement = (NodeRecord)openElements.peek();
487
          }
488
        }
489
      }
490

    
491
      // Handle the DOCUMENT node
492
      if (currentNode.nodetype.equals("DOCUMENT")) {
493
        out.println("<?xml version=\"1.0\"?>");
494
      
495
        if (docname != null) {
496
          if ((doctype != null) && (system_id != null)) {
497
            out.println("<!DOCTYPE " + docname + " PUBLIC \"" + doctype + 
498
                       "\" \"" + system_id + "\">");
499
          } else {
500
            out.println("<!DOCTYPE " + docname + ">");
501
          }
502
        }
503

    
504
      // Handle the ELEMENT nodes
505
      } else if (currentNode.nodetype.equals("ELEMENT")) {
506
        if (atRootElement) {
507
          atRootElement = false;
508
        } else {
509
          if (previousNodeWasElement) {
510
            out.print(">");
511
          }
512
        }
513
        openElements.push(currentNode);
514
        util.debugMessage("\n PUSHED: " + currentNode.nodename);
515
        previousNodeWasElement = true;
516
        if ( currentNode.nodeprefix != null ) {
517
          out.print("<" + currentNode.nodeprefix + ":" + currentNode.nodename);
518
        } else {
519
          out.print("<" + currentNode.nodename);
520
        }
521

    
522
      // Handle the ATTRIBUTE nodes
523
      } else if (currentNode.nodetype.equals("ATTRIBUTE")) {
524
        if ( currentNode.nodeprefix != null ) {
525
          out.print(" " + currentNode.nodeprefix + ":" + currentNode.nodename +
526
                    "=\"" + currentNode.nodedata + "\"");
527
        } else {
528
          out.print(" " + currentNode.nodename + "=\"" +
529
                    currentNode.nodedata + "\"");
530
        }
531

    
532
      // Handle the NAMESPACE nodes
533
      } else if (currentNode.nodetype.equals("NAMESPACE")) {
534
        out.print(" xmlns:" + currentNode.nodename + "=\""
535
                 + currentNode.nodedata + "\"");
536

    
537
      // Handle the TEXT nodes
538
      } else if (currentNode.nodetype.equals("TEXT")) {
539
        if (previousNodeWasElement) {
540
          out.print(">");
541
        }
542
        out.print(currentNode.nodedata);
543
        previousNodeWasElement = false;
544

    
545
      // Handle the COMMENT nodes
546
      } else if (currentNode.nodetype.equals("COMMENT")) {
547
        if (previousNodeWasElement) {
548
          out.print(">");
549
        }
550
        out.print("<!--" + currentNode.nodedata + "-->");
551
        previousNodeWasElement = false;
552

    
553
      // Handle the PI nodes
554
      } else if (currentNode.nodetype.equals("PI")) {
555
        if (previousNodeWasElement) {
556
          out.print(">");
557
        }
558
        out.print("<?" + currentNode.nodename + " " +
559
                        currentNode.nodedata + "?>");
560
        previousNodeWasElement = false;
561

    
562
      // Handle any other node type (do nothing)
563
      } else {
564
        // Any other types of nodes are not handled.
565
        // Probably should throw an exception here to indicate this
566
      }
567
      out.flush();
568
    }
569

    
570
    // Print the final end tag for the root element
571
    while(!openElements.empty())
572
    {
573
      NodeRecord currentElement = (NodeRecord)openElements.pop();
574
      util.debugMessage("\n POPPED: " + currentElement.nodename);
575
      if ( currentElement.nodeprefix != null ) {
576
        out.print("</" + currentElement.nodeprefix + ":" + 
577
                  currentElement.nodename + ">" );
578
      } else {
579
        out.print("</" + currentElement.nodename + ">" );
580
      }
581
    }
582
    out.flush();
583
  }
584
  
585
  private boolean isRevisionOnly(DocumentIdentifier docid) throws Exception
586
  {
587
    //System.out.println("inRevisionOnly");
588
    PreparedStatement pstmt;
589
    String rev = docid.getRev();
590
    String newid = docid.getIdentifier();
591
    pstmt = conn.prepareStatement("select rev from xml_documents " +
592
                                  "where docid like '" + newid + "'");
593
    pstmt.execute();
594
    ResultSet rs = pstmt.getResultSet();
595
    boolean tablehasrows = rs.next();
596
    if(rev.equals("newest") || rev.equals("all"))
597
    {
598
      return false;
599
    }
600
    
601
    if(tablehasrows)
602
    {
603
      int r = rs.getInt(1);
604
      pstmt.close();
605
      if(new Integer(rev).intValue() == r)
606
      { //the current revision in in xml_documents
607
        //System.out.println("returning false");
608
        return false;
609
      }
610
      else if(new Integer(rev).intValue() < r)
611
      { //the current revision is in xml_revisions.
612
        //System.out.println("returning true");
613
        return true;
614
      }
615
      else if(new Integer(rev).intValue() > r)
616
      { //error, rev cannot be greater than r
617
        throw new Exception("requested revision cannot be greater than " +
618
                            "the latest revision number.");
619
      }
620
    }
621
    throw new Exception("the requested docid '" + docid.toString() + 
622
                        "' does not exist");
623
  }
624

    
625
  private void getDocumentInfo(String docid) throws McdbException, 
626
                                                    AccessionNumberException
627
  {
628
    getDocumentInfo(new DocumentIdentifier(docid));
629
  }
630
  
631
  /**
632
   * Look up the document type information from the database
633
   *
634
   * @param docid the id of the document to look up
635
   */
636
  private void getDocumentInfo(DocumentIdentifier docid) throws McdbException 
637
  {
638
    PreparedStatement pstmt;
639
    String table = "xml_documents";
640
    
641
    try
642
    {
643
      if(isRevisionOnly(docid))
644
      { //pull the document from xml_revisions instead of from xml_documents;
645
        table = "xml_revisions";
646
      }
647
    }
648
    catch(Exception e)
649
    {
650
      System.out.println("error in DocumentImpl.getDocumentInfo: " + 
651
                          e.getMessage());
652
    }
653
    
654
    //deal with the key words here.
655
    
656
    if(docid.getRev().equals("all"))
657
    {
658
      
659
    }
660
    
661
    try {
662
      StringBuffer sql = new StringBuffer();
663
// DOCTITLE attr cleared from the db
664
//      sql.append("SELECT docname, doctype, rootnodeid, doctitle, ");
665
      sql.append("SELECT docname, doctype, rootnodeid, ");
666
      sql.append("date_created, date_updated, user_owner, user_updated, ");
667
      sql.append("server_location, public_access, rev");
668
      sql.append(" FROM ").append(table);
669
      sql.append(" WHERE docid LIKE '").append(docid.getIdentifier());
670
      sql.append("' and rev like '").append(docid.getRev()).append("'");
671
      //System.out.println(sql.toString());
672
      pstmt =
673
        conn.prepareStatement(sql.toString());
674
      // Bind the values to the query
675
      //pstmt.setString(1, docid.getIdentifier());
676
      //pstmt.setString(2, docid.getRev());
677

    
678
      pstmt.execute();
679
      ResultSet rs = pstmt.getResultSet();
680
      boolean tableHasRows = rs.next();
681
      if (tableHasRows) {
682
        this.docname        = rs.getString(1);
683
        this.doctype        = rs.getString(2);
684
        this.rootnodeid     = rs.getLong(3);
685
// DOCTITLE attr cleared from the db
686
//        this.doctitle       = rs.getString(4);
687
        this.createdate     = rs.getString(4);
688
        this.updatedate     = rs.getString(5);
689
        this.userowner      = rs.getString(6);
690
        this.userupdated    = rs.getString(7);
691
        this.serverlocation = rs.getInt(8);
692
        this.publicaccess   = rs.getString(9);
693
        this.rev            = rs.getInt(10);
694
      } 
695
      pstmt.close();
696
      if (this.doctype != null) {
697
        pstmt =
698
          conn.prepareStatement("SELECT system_id " +
699
                                  "FROM xml_catalog " +
700
                                 "WHERE public_id = ?");
701
        // Bind the values to the query
702
        pstmt.setString(1, doctype);
703
  
704
        pstmt.execute();
705
        rs = pstmt.getResultSet();
706
        tableHasRows = rs.next();
707
        if (tableHasRows) {
708
          this.system_id  = rs.getString(1);
709
        } 
710
        pstmt.close();
711
      }
712
    } catch (SQLException e) {
713
      System.out.println("error in DocumentImpl.getDocumentInfo: " + 
714
                          e.getMessage());
715
      e.printStackTrace(System.out);
716
      throw new McdbException("Error accessing database connection in " +
717
                              "DocumentImpl.getDocumentInfo: ", e);
718
    }
719

    
720
    if (this.docname == null) {
721
      throw new McdbDocNotFoundException("Document not found: " + docid);
722
    }
723
  }
724

    
725
  /**
726
   * Look up the node data from the database
727
   *
728
   * @param rootnodeid the id of the root node of the node tree to look up
729
   */
730
  private TreeSet getNodeRecordList(long rootnodeid) throws McdbException 
731
  {
732
    PreparedStatement pstmt;
733
    TreeSet nodeRecordList = new TreeSet(new NodeComparator());
734
    long nodeid = 0;
735
    long parentnodeid = 0;
736
    long nodeindex = 0;
737
    String nodetype = null;
738
    String nodename = null;
739
    String nodeprefix = null;
740
    String nodedata = null;
741
    String quotechar = dbAdapter.getStringDelimiter();
742

    
743
    try {
744
      pstmt =
745
      conn.prepareStatement("SELECT nodeid,parentnodeid,nodeindex, " +
746
           "nodetype,nodename,nodeprefix,nodedata " +               
747
           "FROM xml_nodes WHERE rootnodeid = ?");
748

    
749
      // Bind the values to the query
750
      pstmt.setLong(1, rootnodeid);
751

    
752
      pstmt.execute();
753
      ResultSet rs = pstmt.getResultSet();
754
      boolean tableHasRows = rs.next();
755
      while (tableHasRows) {
756
        nodeid = rs.getLong(1);
757
        parentnodeid = rs.getLong(2);
758
        nodeindex = rs.getLong(3);
759
        nodetype = rs.getString(4);
760
        nodename = rs.getString(5);
761
        nodeprefix = rs.getString(6);
762
        nodedata = rs.getString(7);
763
        nodedata = MetaCatUtil.normalize(nodedata);
764
        // add the data to the node record list hashtable
765
        NodeRecord currentRecord = new NodeRecord(nodeid,parentnodeid,nodeindex,
766
                                      nodetype, nodename, nodeprefix, nodedata);
767
        nodeRecordList.add(currentRecord);
768

    
769
        // Advance to the next node
770
        tableHasRows = rs.next();
771
      } 
772
      pstmt.close();
773

    
774
    } catch (SQLException e) {
775
      throw new McdbException("Error in DocumentImpl.getNodeRecordList " +
776
                              e.getMessage());
777
    }
778

    
779
    if (nodeRecordList != null) {
780
      return nodeRecordList;
781
    } else {
782
      throw new McdbException("Error getting node data: " + docid);
783
    }
784
  }
785
  
786
// NOT USED ANY MORE
787
//  /** creates SQL code and inserts new document into DB connection 
788
//   default serverCode of 1*/
789
//  private void writeDocumentToDB(String action, String user)
790
//               throws SQLException, Exception
791
//  {
792
//    writeDocumentToDB(action, user, null, 1);
793
//  }
794

    
795
 /** creates SQL code and inserts new document into DB connection */
796
  private void writeDocumentToDB(String action, String user, String pub, 
797
                                 String catalogid, int serverCode) 
798
               throws SQLException, Exception {
799
    String sysdate = dbAdapter.getDateTimeFunction();
800

    
801
    try {
802
      PreparedStatement pstmt = null;
803

    
804
      if (action.equals("INSERT")) {
805
        //AccessionNumber ac = new AccessionNumber();
806
        //this.docid = ac.generate(docid, "INSERT");
807
        pstmt = conn.prepareStatement(
808
                "INSERT INTO xml_documents " +
809
                "(docid, rootnodeid, docname, doctype, " + 
810
                "user_owner, user_updated, date_created, date_updated, " + 
811
                "public_access, catalog_id, server_location) " +
812
                "VALUES (?, ?, ?, ?, ?, ?, " + sysdate + ", " + sysdate + 
813
                ", ?, ?, ?)");
814
        //note that the server_location is set to 1. 
815
        //this means that "localhost" in the xml_replication table must
816
        //always be the first entry!!!!!
817
        
818
        // Bind the values to the query
819
        pstmt.setString(1, this.docid);
820
        pstmt.setLong(2, rootnodeid);
821
        pstmt.setString(3, docname);
822
        pstmt.setString(4, doctype);
823
        pstmt.setString(5, user);
824
        pstmt.setString(6, user);
825
        if ( pub == null ) {
826
          pstmt.setString(7, null);
827
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
828
          pstmt.setInt(7, 1);
829
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
830
          pstmt.setInt(7, 0);
831
        }
832
        pstmt.setString(8, catalogid);
833
        pstmt.setInt(9, serverCode);
834
      } else if (action.equals("UPDATE")) {
835

    
836
        // Save the old document entry in a backup table
837
        DocumentImpl.archiveDocRevision( conn, docid, user );
838
        DocumentImpl thisdoc = new DocumentImpl(conn, docid);
839
        int thisrev = thisdoc.getRev();
840
        
841
        //if the updated vesion is not greater than current one,
842
        //throw it into a exception
843
        if (Integer.parseInt(updatedVersion)<=thisrev)
844
        {
845
          throw new Exception("Next revision number couldn't be less"
846
                               +" than or equal "+ thisrev);
847
        }
848
        else
849
        {
850
          //set the user specified revision 
851
          thisrev=Integer.parseInt(updatedVersion);
852
        }
853
        
854
        // Delete index for the old version of docid
855
        // The new index is inserting on the next calls to DBSAXNode
856
        pstmt = conn.prepareStatement(
857
                "DELETE FROM xml_index WHERE docid='" + this.docid + "'");
858
        pstmt.execute();
859
        pstmt.close();
860

    
861
        // Update the new document to reflect the new node tree
862
        pstmt = conn.prepareStatement(
863
            "UPDATE xml_documents " +
864
            "SET rootnodeid = ?, docname = ?, doctype = ?, " +
865
            "user_updated = ?, date_updated = " + sysdate + ", " +
866
            "server_location = ?, rev = ?, public_access = ?, catalog_id = ? " +
867
            "WHERE docid = ?");
868
        // Bind the values to the query
869
        pstmt.setLong(1, rootnodeid);
870
        pstmt.setString(2, docname);
871
        pstmt.setString(3, doctype);
872
        pstmt.setString(4, user);
873
        pstmt.setInt(5, serverCode);
874
        pstmt.setInt(6, thisrev);
875
        if ( pub == null ) {
876
          pstmt.setString(7, null);
877
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
878
          pstmt .setInt(7, 1);
879
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
880
          pstmt.setInt(7, 0);
881
        }
882
        pstmt.setString(8, catalogid);
883
        pstmt.setString(9, this.docid);
884

    
885
      } else {
886
        System.err.println("Action not supported: " + action);
887
      }
888

    
889
      // Do the insertion
890
      pstmt.execute();
891
      pstmt.close();
892

    
893
    } catch (SQLException sqle) {
894
      throw sqle;
895
    } catch (Exception e) {
896
      throw e;
897
    }
898
  }
899

    
900
  /**
901
   * Write an XML file to the database, given a filename
902
   *
903
   * @param conn the JDBC connection to the database
904
   * @param filename the filename to be loaded into the database
905
   * @param pub flag for public "read" access on document
906
   * @param dtdfilename the dtd to be uploaded on server's file system
907
   * @param action the action to be performed (INSERT OR UPDATE)
908
   * @param docid the docid to use for the INSERT OR UPDATE
909
   * @param user the user that owns the document
910
   * @param groups the groups to which user belongs
911
   */
912
  public static String write(Connection conn,String filename,
913
                             String pub, String dtdfilename,
914
                             String action, String docid, String user,
915
                             String[] groups )
916
                throws Exception {
917
                  
918
    Reader dtd = null;
919
    if ( dtdfilename != null ) {
920
      dtd = new FileReader(new File(dtdfilename).toString());
921
    }
922
    return write ( conn, new FileReader(new File(filename).toString()),
923
                   pub, dtd, action, docid, user, groups, false);
924
  }
925

    
926
  public static String write(Connection conn,Reader xml,String pub,Reader dtd,
927
                             String action, String docid, String user,
928
                             String[] groups, boolean validate)
929
                throws Exception {
930
    return write(conn,xml,pub,dtd,action,docid,user,groups,1,false,validate);
931
  }
932

    
933
  public static String write(Connection conn, Reader xml, String pub,
934
                             String action, String docid, String user,
935
                             String[] groups )
936
                throws Exception {
937
    if(action.equals("UPDATE"))
938
    {//if the document is being updated then use the servercode from the 
939
     //originally inserted document.
940
      DocumentImpl doc = new DocumentImpl(conn, docid);
941
      int servercode = doc.getServerlocation();
942
      return write(conn, xml, pub, action, docid, user, groups, servercode);
943
    }
944
    else
945
    {//if the file is being inserted then the servercode is always 1
946
      return write(conn, xml, pub, action, docid, user, groups, 1);
947
    }
948
  }
949
  
950
  public static String write( Connection conn, Reader xml,
951
                              String action, String docid, String user,
952
                              String[] groups, int serverCode )
953
                throws Exception
954
  {
955
    return write(conn,xml,null,action,docid,user,groups,serverCode);
956
  }
957
  
958
  public static String write( Connection conn, Reader xml, String pub,
959
                              String action, String docid, String user,
960
                              String[] groups, int serverCode) 
961
                throws Exception
962
  {
963
    return write(conn,xml,pub,null,action,docid,user,groups,
964
                 serverCode,false,false);
965
  }
966
  
967
  public static String write( Connection conn, Reader xml, String pub,
968
                              String action, String docid, String user,
969
                              String[] groups, int serverCode, boolean override)
970
                throws Exception
971
  {
972
    return write(conn,xml,pub,null,action,docid,user,groups,
973
                 serverCode,override,false);
974
  }
975
  
976
  /**
977
   * Write an XML file to the database, given a Reader
978
   *
979
   * @param conn the JDBC connection to the database
980
   * @param xml the xml stream to be loaded into the database
981
   * @param pub flag for public "read" access on xml document
982
   * @param dtd the dtd to be uploaded on server's file system
983
   * @param action the action to be performed (INSERT or UPDATE)
984
   * @param accnum the docid + rev# to use on INSERT or UPDATE
985
   * @param user the user that owns the document
986
   * @param groups the groups to which user belongs
987
   * @param serverCode the serverid from xml_replication on which this document
988
   *        resides.
989
   * @param override flag to stop insert replication checking.
990
   *        if override = true then a document not belonging to the local server
991
   *        will not be checked upon update for a file lock.
992
   *        if override = false then a document not from this server, upon 
993
   *        update will be locked and version checked.
994
   */
995

    
996
  public static String write( Connection conn,Reader xml,String pub,Reader dtd,
997
                              String action, String accnum, String user,
998
                              String[] groups, int serverCode, boolean override,
999
                              boolean validate)
1000
                throws Exception
1001
  {
1002
    // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1003
    AccessionNumber ac = new AccessionNumber(conn, accnum, action);
1004
    String docid = ac.getDocid();
1005
    String rev = ac.getRev();
1006
    MetaCatUtil.debugMessage("action: " + action + " servercode: " + 
1007
                             serverCode + " override: " + override);
1008
                        
1009
    if((serverCode != 1 && action.equals("UPDATE")) && !override)
1010
    { //if this document being written is not a resident of this server then
1011
      //we need to try to get a lock from it's resident server.  If the
1012
      //resident server will not give a lock then we send the user a message
1013
      //saying that he/she needs to download a new copy of the file and
1014
      //merge the differences manually.
1015
      int istreamInt; 
1016
      char istreamChar;
1017
      DocumentIdentifier id = new DocumentIdentifier(accnum);
1018
      String updaterev = id.getRev();
1019
      String server = MetacatReplication.getServer(serverCode);
1020
      MetacatReplication.replLog("attempting to lock " + accnum);
1021
      URL u = new URL("https://" + server + "?action=getlock&updaterev=" + 
1022
                      updaterev + "&docid=" + docid);
1023
      System.out.println("sending message: " + u.toString());
1024
      String serverResStr = MetacatReplication.getURLContent(u);
1025
      String openingtag =serverResStr.substring(0, serverResStr.indexOf(">")+1);
1026
      
1027
      if(openingtag.equals("<lockgranted>"))
1028
      {//the lock was granted go ahead with the insert
1029
        try 
1030
        {
1031
          MetacatReplication.replLog("lock granted for " + accnum + " from " +
1032
                                      server);
1033
          XMLReader parser = initializeParser(conn, action, docid, updaterev,
1034
                                  validate, 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
        //after inserting the document locally, tell the document's home server
1048
        //to come get a copy from here.
1049
        ForceReplicationHandler frh = new ForceReplicationHandler(accnum);
1050
        
1051
        return (accnum);
1052
      }
1053

    
1054
      else if(openingtag.equals("<filelocked>"))
1055
      {//the file is currently locked by another user
1056
       //notify our user to wait a few minutes, check out a new copy and try
1057
       //again.
1058
        //System.out.println("file locked");
1059
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1060
                                   server + " reason: file already locked");
1061
        throw new Exception("The file specified is already locked by another " +
1062
                            "user.  Please wait 30 seconds, checkout the " +
1063
                            "newer document, merge your changes and try " +
1064
                            "again.");
1065
      }
1066
      else if(openingtag.equals("<outdatedfile>"))
1067
      {//our file is outdated.  notify our user to check out a new copy of the
1068
       //file and merge his version with the new version.
1069
        //System.out.println("outdated file");
1070
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1071
                                    server + " reason: local file outdated");
1072
        throw new Exception("The file you are trying to update is an outdated" +
1073
                            " version.  Please checkout the newest document, " +
1074
                            "merge your changes and try again.");
1075
      }
1076
    }
1077
    
1078
    if ( action.equals("UPDATE") ) {
1079
      // check for 'write' permission for 'user' to update this document
1080

    
1081
      if ( !hasPermission(conn, user, groups, docid) ) {
1082
        throw new Exception("User " + user + 
1083
              " does not have permission to update XML Document #" + accnum);
1084
      }          
1085
    }
1086

    
1087
    try 
1088
    { 
1089
      
1090
      XMLReader parser = initializeParser(conn, action, docid, rev, validate,
1091
                                          user, groups, pub, serverCode, dtd);
1092
      conn.setAutoCommit(false);
1093
      parser.parse(new InputSource(xml));
1094
      conn.commit();
1095
      conn.setAutoCommit(true);
1096
    } 
1097
    catch (Exception e) 
1098
    {
1099
      conn.rollback();
1100
      conn.setAutoCommit(true);
1101
      throw e;
1102
    }
1103
    
1104
    //force replicate out the new document to each server in our server list.
1105
    if(serverCode == 1)
1106
    { //start the thread to replicate this new document out to the other servers
1107
      ForceReplicationHandler frh = new ForceReplicationHandler(accnum, action);
1108
      
1109
    }
1110
      
1111
    return(accnum);
1112
  }
1113

    
1114
  /**
1115
   * Delete an XML file from the database (actually, just make it a revision
1116
   * in the xml_revisions table)
1117
   *
1118
   * @param docid the ID of the document to be deleted from the database
1119
   */
1120
  public static void delete( Connection conn, String accnum,
1121
                                 String user, String[] groups )
1122
                throws Exception 
1123
  {
1124
    // OLD
1125
    //DocumentIdentifier id = new DocumentIdentifier(accnum);
1126
    //String docid = id.getIdentifier();
1127
    //String rev = id.getRev();
1128
    
1129
    // OLD
1130
    // Determine if the docid,rev are OK for DELETE
1131
    //AccessionNumber ac = new AccessionNumber(conn);
1132
    //docid = ac.generate(docid, rev, "DELETE");
1133

    
1134
    // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1135
    AccessionNumber ac = new AccessionNumber(conn, accnum, "DELETE");
1136
    String docid = ac.getDocid();
1137
    String rev = ac.getRev();
1138
    
1139

    
1140
    // check for 'write' permission for 'user' to delete this document
1141
    if ( !hasPermission(conn, user, groups, docid) ) {
1142
      throw new Exception("User " + user + 
1143
              " does not have permission to delete XML Document #" + accnum);
1144
    }
1145

    
1146
    conn.setAutoCommit(false);
1147
    // Copy the record to the xml_revisions table
1148
    DocumentImpl.archiveDocRevision( conn, docid, user );
1149

    
1150
    // Now delete it from the xml_documents table
1151
    
1152
    Statement stmt = conn.createStatement();
1153
    stmt.execute("DELETE FROM xml_index WHERE docid = '" + docid + "'");
1154
    //stmt.execute("DELETE FROM xml_access WHERE docid = '" + docid + "'");
1155
    stmt.execute("DELETE FROM xml_access WHERE accessfileid = '" + docid + "'");
1156
    stmt.execute("DELETE FROM xml_relation WHERE docid = '" + docid + "'");
1157
    stmt.execute("DELETE FROM xml_documents WHERE docid = '" + docid + "'");
1158
    stmt.close();
1159
    conn.commit();
1160
    conn.setAutoCommit(true);
1161
    //IF this is a package document:
1162
    //delete all of the relations that this document created.
1163
    //if the deleted document is a package document its relations should 
1164
    //no longer be active if it has been deleted from the system.
1165
    
1166
  }
1167

    
1168
  /** 
1169
    * Check for "WRITE" permission on @docid for @user and/or @groups 
1170
    * from DB connection 
1171
    */
1172
  private static boolean hasPermission ( Connection conn, String user,
1173
                                  String[] groups, String docid ) 
1174
                  throws SQLException, Exception
1175
  {
1176
    // Check for WRITE permission on @docid for @user and/or @groups
1177
    AccessControlList aclobj = new AccessControlList(conn);
1178
    return aclobj.hasPermission("WRITE", user, groups, docid);
1179
  }
1180

    
1181
  /** 
1182
    * Check for "READ" permission base on docid, user and group
1183
    *@docid, the document
1184
    *@user, user name
1185
    *@group, user's group
1186
    * 
1187
    */
1188
  public boolean hasReadPermission ( Connection conn, String user,
1189
                                  String[] groups, String docId ) 
1190
                  throws SQLException, Exception
1191
  {
1192
    // Check for READ permission on @docid for @user and/or @groups
1193
    AccessControlList aclObj = new AccessControlList(conn);
1194
    return aclObj.hasPermission("READ", user, groups, docId);
1195
  }  
1196

    
1197
  /**
1198
   * Set up the parser handlers for writing the document to the database
1199
   */
1200
  private static XMLReader initializeParser(Connection conn, String action,
1201
                               String docid, String rev, boolean validate, 
1202
                                   String user, String[] groups, String pub, 
1203
                                   int serverCode, Reader dtd) 
1204
                           throws Exception 
1205
  {
1206
    XMLReader parser = null;
1207
    //
1208
    // Set up the SAX document handlers for parsing
1209
    //
1210
    try {
1211
      //create a DBSAXHandler object which has the revision specification
1212
      ContentHandler chandler = new DBSAXHandler(conn, action, docid, rev,
1213
                                                 user, groups, pub, serverCode);
1214
      EntityResolver eresolver= new DBEntityResolver(conn,
1215
                                                 (DBSAXHandler)chandler, dtd);
1216
      DTDHandler dtdhandler   = new DBDTDHandler(conn);
1217

    
1218
      // Get an instance of the parser
1219
      String parserName = MetaCatUtil.getOption("saxparser");
1220
      parser = XMLReaderFactory.createXMLReader(parserName);
1221

    
1222
      // Turn on validation
1223
      parser.setFeature("http://xml.org/sax/features/validation", validate);
1224
      // Turn off Including all external parameter entities
1225
      // (the external DTD subset also)
1226
      // Doesn't work well, probably the feature name is not correct
1227
      // parser.setFeature(
1228
      //  "http://xml.org/sax/features/external-parameter-entities", false);
1229
      
1230
      // Set Handlers in the parser
1231
      parser.setProperty("http://xml.org/sax/properties/declaration-handler",
1232
                         chandler);
1233
      parser.setProperty("http://xml.org/sax/properties/lexical-handler",
1234
                         chandler);
1235
      parser.setContentHandler((ContentHandler)chandler);
1236
      parser.setEntityResolver((EntityResolver)eresolver);
1237
      parser.setDTDHandler((DTDHandler)dtdhandler);
1238
      parser.setErrorHandler((ErrorHandler)chandler);
1239

    
1240
    } catch (Exception e) {
1241
      throw e;
1242
    }
1243

    
1244
    return parser;
1245
  }
1246

    
1247
  /** Save a document entry in the xml_revisions table */
1248
  private static void archiveDocRevision(Connection conn, String docid,
1249
                                         String user) 
1250
                                         throws SQLException {
1251
    String sysdate = dbAdapter.getDateTimeFunction();
1252
    // create a record in xml_revisions table 
1253
    // for that document as selected from xml_documents
1254
    PreparedStatement pstmt = conn.prepareStatement(
1255
      "INSERT INTO xml_revisions " +
1256
        "(docid, rootnodeid, docname, doctype, " +
1257
        "user_owner, user_updated, date_created, date_updated, " +
1258
        "server_location, rev, public_access, catalog_id) " +
1259
      "SELECT ?, rootnodeid, docname, doctype, " + 
1260
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
1261
        "server_location, rev, public_access, catalog_id " +
1262
      "FROM xml_documents " +
1263
      "WHERE docid = ?");
1264
    // Bind the values to the query and execute it
1265
    pstmt.setString(1, docid);
1266
    pstmt.setString(2, user);
1267
    pstmt.setString(3, docid);
1268
    pstmt.execute();
1269
    pstmt.close();
1270

    
1271
  }
1272

    
1273
  /**
1274
   * the main routine used to test the DBWriter utility.
1275
   * <p>
1276
   * Usage: java DocumentImpl <-f filename -a action -d docid>
1277
   *
1278
   * @param filename the filename to be loaded into the database
1279
   * @param action the action to perform (READ, INSERT, UPDATE, DELETE)
1280
   * @param docid the id of the document to process
1281
   */
1282
  static public void main(String[] args) {
1283
     
1284
    try {
1285
      String filename    = null;
1286
      String dtdfilename = null;
1287
      String action      = null;
1288
      String docid       = null;
1289
      boolean showRuntime = false;
1290
      boolean useOldReadAlgorithm = false;
1291

    
1292
      // Parse the command line arguments
1293
      for ( int i=0 ; i < args.length; ++i ) {
1294
        if ( args[i].equals( "-f" ) ) {
1295
          filename =  args[++i];
1296
        } else if ( args[i].equals( "-r" ) ) {
1297
          dtdfilename =  args[++i];
1298
        } else if ( args[i].equals( "-a" ) ) {
1299
          action =  args[++i];
1300
        } else if ( args[i].equals( "-d" ) ) {
1301
          docid =  args[++i];
1302
        } else if ( args[i].equals( "-t" ) ) {
1303
          showRuntime = true;
1304
        } else if ( args[i].equals( "-old" ) ) {
1305
          useOldReadAlgorithm = true;
1306
        } else {
1307
          System.err.println
1308
            ( "   args[" +i+ "] '" +args[i]+ "' ignored." );
1309
        }
1310
      }
1311
      
1312
      // Check if the required arguments are provided
1313
      boolean argsAreValid = false;
1314
      if (action != null) {
1315
        if (action.equals("INSERT")) {
1316
          if (filename != null) {
1317
            argsAreValid = true;
1318
          } 
1319
        } else if (action.equals("UPDATE")) {
1320
          if ((filename != null) && (docid != null)) {
1321
            argsAreValid = true;
1322
          } 
1323
        } else if (action.equals("DELETE")) {
1324
          if (docid != null) {
1325
            argsAreValid = true;
1326
          } 
1327
        } else if (action.equals("READ")) {
1328
          if (docid != null) {
1329
            argsAreValid = true;
1330
          } 
1331
        } 
1332
      } 
1333

    
1334
      // Print usage message if the arguments are not valid
1335
      if (!argsAreValid) {
1336
        System.err.println("Wrong number of arguments!!!");
1337
        System.err.println(
1338
          "USAGE: java DocumentImpl [-t] <-a INSERT> [-d docid] <-f filename> "+
1339
          "[-r dtdfilename]");
1340
        System.err.println(
1341
          "   OR: java DocumentImpl [-t] <-a UPDATE -d docid -f filename> " +
1342
          "[-r dtdfilename]");
1343
        System.err.println(
1344
          "   OR: java DocumentImpl [-t] <-a DELETE -d docid>");
1345
        System.err.println(
1346
          "   OR: java DocumentImpl [-t] [-old] <-a READ -d docid>");
1347
        return;
1348
      }
1349
      
1350
      // Time the request if asked for
1351
      double startTime = System.currentTimeMillis();
1352
      
1353
      // Open a connection to the database
1354
      MetaCatUtil util = new MetaCatUtil();
1355
      Connection dbconn = util.openDBConnection();
1356

    
1357
      double connTime = System.currentTimeMillis();
1358
      // Execute the action requested (READ, INSERT, UPDATE, DELETE)
1359
      if (action.equals("READ")) {
1360
          DocumentImpl xmldoc = new DocumentImpl( dbconn, docid );
1361
          if (useOldReadAlgorithm) {
1362
            System.out.println(xmldoc.readUsingSlowAlgorithm());
1363
          } else {
1364
            xmldoc.toXml(new PrintWriter(System.out));
1365
          }
1366
      } else if (action.equals("DELETE")) {
1367
        DocumentImpl.delete(dbconn, docid, null, null);
1368
        System.out.println("Document deleted: " + docid);
1369
      } else {
1370
        String newdocid = DocumentImpl.write(dbconn, filename, null,
1371
                                             dtdfilename, action, docid,
1372
                                             null, null);
1373
        if ((docid != null) && (!docid.equals(newdocid))) {
1374
          if (action.equals("INSERT")) {
1375
            System.out.println("New document ID generated!!! ");
1376
          } else if (action.equals("UPDATE")) {
1377
            System.out.println("ERROR: Couldn't update document!!! ");
1378
          }
1379
        } else if ((docid == null) && (action.equals("UPDATE"))) {
1380
          System.out.println("ERROR: Couldn't update document!!! ");
1381
        }
1382
        System.out.println("Document processing finished for: " + filename
1383
              + " (" + newdocid + ")");
1384
      }
1385

    
1386
      double stopTime = System.currentTimeMillis();
1387
      double dbOpenTime = (connTime - startTime)/1000;
1388
      double insertTime = (stopTime - connTime)/1000;
1389
      double executionTime = (stopTime - startTime)/1000;
1390
      if (showRuntime) {
1391
        System.out.println("\n\nTotal Execution time was: " + 
1392
                           executionTime + " seconds.");
1393
        System.out.println("Time to open DB connection was: " + dbOpenTime + 
1394
                           " seconds.");
1395
        System.out.println("Time to insert document was: " + insertTime +
1396
                           " seconds.");
1397
      }
1398
      dbconn.close();
1399
    } catch (McdbException me) {
1400
      me.toXml(new PrintWriter(System.err));
1401
    } catch (AccessionNumberException ane) {
1402
      System.out.println(ane.getMessage());
1403
    } catch (Exception e) {
1404
      System.err.println("EXCEPTION HANDLING REQUIRED");
1405
      System.err.println(e.getMessage());
1406
      e.printStackTrace(System.err);
1407
    }
1408
  }
1409
}
(23-23/40)