Project

General

Profile

1 393 jones
/**
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$'
10
 *     '$Date$'
11
 * '$Revision$'
12 669 jones
 *
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 393 jones
 */
27
28
package edu.ucsb.nceas.metacat;
29
30
import java.sql.*;
31 429 jones
import java.io.File;
32
import java.io.FileReader;
33
import java.io.IOException;
34 393 jones
import java.io.PrintWriter;
35 429 jones
import java.io.Reader;
36
import java.io.StringWriter;
37
import java.io.Writer;
38 561 berkley
import java.io.InputStreamReader;
39 393 jones
40 798 jones
import java.text.SimpleDateFormat;
41
42
import java.util.Date;
43 429 jones
import java.util.Iterator;
44 407 jones
import java.util.Stack;
45 429 jones
import java.util.TreeSet;
46 577 berkley
import java.util.Enumeration;
47 407 jones
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 561 berkley
import java.net.URL;
60
61 777 bojilova
import edu.ucsb.nceas.dbadapter.AbstractDatabase;
62 747 bojilova
63 393 jones
/**
64
 * A class that represents an XML document. It can be created with a simple
65 407 jones
 * document identifier from a database connection.  It also will write an
66
 * XML text document to a database connection using SAX.
67 393 jones
 */
68
public class DocumentImpl {
69
70 425 bojilova
  static final int ALL = 1;
71
  static final int WRITE = 2;
72
  static final int READ = 4;
73 777 bojilova
  private static final AbstractDatabase dbAdapter = MetaCatUtil.dbAdapter;
74 425 bojilova
75 393 jones
  private Connection conn = null;
76
  private String docid = null;
77
  private String docname = null;
78
  private String doctype = null;
79 691 bojilova
// DOCTITLE attr cleared from the db
80
//  private String doctitle = null;
81 465 berkley
  private String createdate = null;
82
  private String updatedate = null;
83 393 jones
  private String system_id = null;
84 561 berkley
  private String userowner = null;
85
  private String userupdated = null;
86 575 berkley
  private int rev;
87 561 berkley
  private int serverlocation;
88 697 bojilova
  private String publicaccess;
89 393 jones
  private long rootnodeid;
90
  private ElementNode rootNode = null;
91 429 jones
  private TreeSet nodeRecordList = null;
92 790 bojilova
93
  /**
94 800 jones
   * 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 790 bojilova
   *
99
   * @param conn the database connection from which to read the document
100 800 jones
   * @param docid the identifier of the document to be created
101
   * @param readNodes flag indicating whether the xmlnodes should be read
102 790 bojilova
   */
103 802 bojilova
  public DocumentImpl(Connection conn, String docid, boolean readNodes)
104
         throws McdbException
105 790 bojilova
  {
106 801 jones
    try {
107
      this.conn = conn;
108
      this.docid = docid;
109
110
      // Look up the document information
111
      getDocumentInfo(docid);
112 800 jones
113 801 jones
      if (readNodes) {
114 800 jones
        // 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 801 jones
      }
120 800 jones
121 801 jones
    } catch (McdbException ex) {
122
      throw ex;
123
    } catch (Throwable t) {
124
      throw new McdbException("Error reading document from " +
125
                              "DocumentImpl.DocumentImpl: " + docid);
126 800 jones
    }
127 790 bojilova
  }
128 393 jones
129
  /**
130 396 jones
   * Constructor, creates document from database connection, used
131
   * for reading the document
132 393 jones
   *
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 801 jones
    this(conn, docid, true);
139 393 jones
  }
140
141 396 jones
  /**
142 415 jones
   * 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 396 jones
   *
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 680 bojilova
   * @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 396 jones
   *
164
   */
165
  public DocumentImpl(Connection conn, long rootnodeid, String docname,
166 549 berkley
                      String doctype, String docid, String action, String user,
167 697 bojilova
                      String pub, String catalogid, int serverCode)
168 549 berkley
                      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 697 bojilova
    writeDocumentToDB(action, user, pub, catalogid, serverCode);
176 549 berkley
  }
177
178 798 jones
  /**
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 407 jones
208 798 jones
    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 946 tao
      String sqlDateString = "to_date('" + dateString +
220
                                          "', 'YY-MM-DD HH24:MI:SS')";
221 798 jones
222
      StringBuffer sql = new StringBuffer();
223
      sql.append("insert into xml_documents (docid, docname, doctype, ");
224 946 tao
      sql.append("user_owner, user_updated, server_location, rev,date_created");
225 798 jones
      sql.append(", date_updated, public_access) values ('");
226
      sql.append(docid).append("','");
227
      sql.append(docname).append("','");
228
      sql.append(doctype).append("','");
229
      sql.append(user).append("','");
230
      sql.append(user).append("','");
231
      sql.append(serverCode).append("','");
232
      sql.append(rev).append("',");
233
      sql.append(sqlDateString).append(",");
234
      sql.append(sqlDateString).append(",");
235
      sql.append("'0')");
236
      //System.out.println("sql: " + sql.toString());
237
238
      PreparedStatement pstmt = dbconn.prepareStatement(sql.toString());
239
      pstmt.execute();
240
      pstmt.close();
241
      dbconn.close();
242
    } finally {
243
      util.returnConnection(dbconn);
244
    }
245
  }
246
247 393 jones
  /**
248
   * get the document name
249
   */
250
  public String getDocname() {
251
    return docname;
252
  }
253
254
  /**
255
   * get the document type (which is the PublicID)
256
   */
257
  public String getDoctype() {
258
    return doctype;
259
  }
260
261
  /**
262
   * get the system identifier
263
   */
264
  public String getSystemID() {
265
    return system_id;
266
  }
267
268
  /**
269
   * get the root node identifier
270
   */
271
  public long getRootNodeID() {
272
    return rootnodeid;
273
  }
274 465 berkley
275
  /**
276
   * get the creation date
277
   */
278
  public String getCreateDate() {
279
    return createdate;
280
  }
281
282
  /**
283
   * get the update date
284
   */
285
  public String getUpdateDate() {
286
    return updatedate;
287
  }
288 393 jones
289 396 jones
  /**
290
   * Get the document identifier (docid)
291
   */
292
  public String getDocID() {
293
    return docid;
294
  }
295 465 berkley
296 691 bojilova
// DOCTITLE attr cleared from the db
297
//  /**
298
//   *get the document title
299
//   */
300
//  public String getDocTitle() {
301
//    return doctitle;
302
//  }
303 561 berkley
304
  public String getUserowner() {
305
    return userowner;
306
  }
307
308
  public String getUserupdated() {
309
    return userupdated;
310
  }
311
312
  public int getServerlocation() {
313
    return serverlocation;
314
  }
315
316 697 bojilova
  public String getPublicaccess() {
317 561 berkley
    return publicaccess;
318
  }
319 575 berkley
320
  public int getRev() {
321
    return rev;
322
  }
323 396 jones
324 393 jones
  /**
325 429 jones
   * Print a string representation of the XML document
326 393 jones
   */
327
  public String toString()
328
  {
329 429 jones
    StringWriter docwriter = new StringWriter();
330 800 jones
    try {
331
      this.toXml(docwriter);
332
    } catch (McdbException mcdbe) {
333
      return null;
334
    }
335 429 jones
    String document = docwriter.toString();
336
    return document;
337
  }
338
339
  /**
340
   * Get a text representation of the XML document as a string
341
   * This older algorithm uses a recursive tree of Objects to represent the
342
   * nodes of the tree.  Each object is passed the data for the document
343
   * and searches all of the document data to find its children nodes and
344
   * recursively build.  Thus, because each node reads the whole document,
345
   * this algorithm is extremely slow for larger documents, and the time
346
   * to completion is O(N^N) wrt the number of nodes.  See toXml() for a
347
   * better algorithm.
348
   */
349 800 jones
  public String readUsingSlowAlgorithm() throws McdbException
350 429 jones
  {
351 393 jones
    StringBuffer doc = new StringBuffer();
352
353 800 jones
    // First, check that we have the needed node data, and get it if not
354
    if (nodeRecordList == null) {
355
      nodeRecordList = getNodeRecordList(rootnodeid);
356
    }
357
358 429 jones
    // Create the elements from the downloaded data in the TreeSet
359
    rootNode = new ElementNode(nodeRecordList, rootnodeid);
360
361 393 jones
    // Append the resulting document to the StringBuffer and return it
362
    doc.append("<?xml version=\"1.0\"?>\n");
363
364
    if (docname != null) {
365
      if ((doctype != null) && (system_id != null)) {
366
        doc.append("<!DOCTYPE " + docname + " PUBLIC \"" + doctype +
367
                   "\" \"" + system_id + "\">\n");
368
      } else {
369
        doc.append("<!DOCTYPE " + docname + ">\n");
370
      }
371
    }
372
    doc.append(rootNode.toString());
373
374
    return (doc.toString());
375
  }
376
377
  /**
378 429 jones
   * Print a text representation of the XML document to a Writer
379
   *
380
   * @param pw the Writer to which we print the document
381
   */
382 800 jones
  public void toXml(Writer pw) throws McdbException
383 429 jones
  {
384
    PrintWriter out = null;
385
    if (pw instanceof PrintWriter) {
386
      out = (PrintWriter)pw;
387
    } else {
388
      out = new PrintWriter(pw);
389
    }
390
391
    MetaCatUtil util = new MetaCatUtil();
392
393 800 jones
    // First, check that we have the needed node data, and get it if not
394
    if (nodeRecordList == null) {
395
      nodeRecordList = getNodeRecordList(rootnodeid);
396
    }
397
398 429 jones
    Stack openElements = new Stack();
399
    boolean atRootElement = true;
400
    boolean previousNodeWasElement = false;
401
402
    // Step through all of the node records we were given
403
    Iterator it = nodeRecordList.iterator();
404
    while (it.hasNext()) {
405
      NodeRecord currentNode = (NodeRecord)it.next();
406
      //util.debugMessage("[Got Node ID: " + currentNode.nodeid +
407
                          //" (" + currentNode.parentnodeid +
408
                          //", " + currentNode.nodeindex +
409
                          //", " + currentNode.nodetype +
410
                          //", " + currentNode.nodename +
411
                          //", " + currentNode.nodedata + ")]");
412
      // Print the end tag for the previous node if needed
413
      //
414
      // This is determined by inspecting the parent nodeid for the
415
      // currentNode.  If it is the same as the nodeid of the last element
416
      // that was pushed onto the stack, then we are still in that previous
417
      // parent element, and we do nothing.  However, if it differs, then we
418
      // have returned to a level above the previous parent, so we go into
419
      // a loop and pop off nodes and print out their end tags until we get
420
      // the node on the stack to match the currentNode parentnodeid
421
      //
422
      // So, this of course means that we rely on the list of elements
423
      // having been sorted in a depth first traversal of the nodes, which
424
      // is handled by the NodeComparator class used by the TreeSet
425
      if (!atRootElement) {
426
        NodeRecord currentElement = (NodeRecord)openElements.peek();
427
        if ( currentNode.parentnodeid != currentElement.nodeid ) {
428
          while ( currentNode.parentnodeid != currentElement.nodeid ) {
429
            currentElement = (NodeRecord)openElements.pop();
430
            util.debugMessage("\n POPPED: " + currentElement.nodename);
431 451 bojilova
            if (previousNodeWasElement) {
432
              out.print(">");
433
              previousNodeWasElement = false;
434
            }
435 826 bojilova
            if ( currentElement.nodeprefix != null ) {
436
              out.print("</" + currentElement.nodeprefix + ":" +
437
                        currentElement.nodename + ">" );
438
            } else {
439
              out.print("</" + currentElement.nodename + ">" );
440
            }
441 429 jones
            currentElement = (NodeRecord)openElements.peek();
442
          }
443
        }
444
      }
445
446
      // Handle the DOCUMENT node
447
      if (currentNode.nodetype.equals("DOCUMENT")) {
448
        out.println("<?xml version=\"1.0\"?>");
449
450
        if (docname != null) {
451
          if ((doctype != null) && (system_id != null)) {
452
            out.println("<!DOCTYPE " + docname + " PUBLIC \"" + doctype +
453
                       "\" \"" + system_id + "\">");
454
          } else {
455
            out.println("<!DOCTYPE " + docname + ">");
456
          }
457
        }
458
459
      // Handle the ELEMENT nodes
460
      } else if (currentNode.nodetype.equals("ELEMENT")) {
461
        if (atRootElement) {
462
          atRootElement = false;
463
        } else {
464
          if (previousNodeWasElement) {
465
            out.print(">");
466
          }
467
        }
468
        openElements.push(currentNode);
469
        util.debugMessage("\n PUSHED: " + currentNode.nodename);
470
        previousNodeWasElement = true;
471 826 bojilova
        if ( currentNode.nodeprefix != null ) {
472
          out.print("<" + currentNode.nodeprefix + ":" + currentNode.nodename);
473
        } else {
474
          out.print("<" + currentNode.nodename);
475
        }
476 429 jones
477
      // Handle the ATTRIBUTE nodes
478
      } else if (currentNode.nodetype.equals("ATTRIBUTE")) {
479 826 bojilova
        if ( currentNode.nodeprefix != null ) {
480
          out.print(" " + currentNode.nodeprefix + ":" + currentNode.nodename +
481
                    "=\"" + currentNode.nodedata + "\"");
482
        } else {
483
          out.print(" " + currentNode.nodename + "=\"" +
484
                    currentNode.nodedata + "\"");
485
        }
486 821 bojilova
487
      // Handle the NAMESPACE nodes
488
      } else if (currentNode.nodetype.equals("NAMESPACE")) {
489
        out.print(" xmlns:" + currentNode.nodename + "=\""
490
                 + currentNode.nodedata + "\"");
491
492
      // Handle the TEXT nodes
493 429 jones
      } else if (currentNode.nodetype.equals("TEXT")) {
494
        if (previousNodeWasElement) {
495
          out.print(">");
496
        }
497
        out.print(currentNode.nodedata);
498
        previousNodeWasElement = false;
499
500
      // Handle the COMMENT nodes
501
      } else if (currentNode.nodetype.equals("COMMENT")) {
502
        if (previousNodeWasElement) {
503
          out.print(">");
504
        }
505
        out.print("<!--" + currentNode.nodedata + "-->");
506
        previousNodeWasElement = false;
507
508
      // Handle the PI nodes
509
      } else if (currentNode.nodetype.equals("PI")) {
510
        if (previousNodeWasElement) {
511
          out.print(">");
512
        }
513
        out.print("<?" + currentNode.nodename + " " +
514
                        currentNode.nodedata + "?>");
515
        previousNodeWasElement = false;
516
517
      // Handle any other node type (do nothing)
518
      } else {
519
        // Any other types of nodes are not handled.
520
        // Probably should throw an exception here to indicate this
521
      }
522
      out.flush();
523
    }
524
525
    // Print the final end tag for the root element
526 686 berkley
    while(!openElements.empty())
527
    {
528
      NodeRecord currentElement = (NodeRecord)openElements.pop();
529
      util.debugMessage("\n POPPED: " + currentElement.nodename);
530 826 bojilova
      if ( currentElement.nodeprefix != null ) {
531
        out.print("</" + currentElement.nodeprefix + ":" +
532
                  currentElement.nodename + ">" );
533
      } else {
534
        out.print("</" + currentElement.nodename + ">" );
535
      }
536 686 berkley
    }
537 429 jones
    out.flush();
538
  }
539 622 berkley
540
  private boolean isRevisionOnly(DocumentIdentifier docid) throws Exception
541
  {
542
    //System.out.println("inRevisionOnly");
543
    PreparedStatement pstmt;
544
    String rev = docid.getRev();
545
    String newid = docid.getIdentifier();
546
    pstmt = conn.prepareStatement("select rev from xml_documents " +
547
                                  "where docid like '" + newid + "'");
548
    pstmt.execute();
549
    ResultSet rs = pstmt.getResultSet();
550
    boolean tablehasrows = rs.next();
551
    if(rev.equals("newest") || rev.equals("all"))
552
    {
553
      return false;
554
    }
555
556
    if(tablehasrows)
557
    {
558
      int r = rs.getInt(1);
559 667 berkley
      pstmt.close();
560 622 berkley
      if(new Integer(rev).intValue() == r)
561
      { //the current revision in in xml_documents
562
        //System.out.println("returning false");
563
        return false;
564
      }
565
      else if(new Integer(rev).intValue() < r)
566
      { //the current revision is in xml_revisions.
567
        //System.out.println("returning true");
568
        return true;
569
      }
570
      else if(new Integer(rev).intValue() > r)
571
      { //error, rev cannot be greater than r
572
        throw new Exception("requested revision cannot be greater than " +
573
                            "the latest revision number.");
574
      }
575
    }
576
    throw new Exception("the requested docid '" + docid.toString() +
577
                        "' does not exist");
578
  }
579 429 jones
580 800 jones
  private void getDocumentInfo(String docid) throws McdbException,
581 622 berkley
                                                    AccessionNumberException
582
  {
583
    getDocumentInfo(new DocumentIdentifier(docid));
584
  }
585
586 429 jones
  /**
587 393 jones
   * Look up the document type information from the database
588
   *
589
   * @param docid the id of the document to look up
590
   */
591 622 berkley
  private void getDocumentInfo(DocumentIdentifier docid) throws McdbException
592 393 jones
  {
593
    PreparedStatement pstmt;
594 622 berkley
    String table = "xml_documents";
595
596
    try
597
    {
598
      if(isRevisionOnly(docid))
599
      { //pull the document from xml_revisions instead of from xml_documents;
600
        table = "xml_revisions";
601
      }
602
    }
603
    catch(Exception e)
604
    {
605 675 berkley
      System.out.println("error in DocumentImpl.getDocumentInfo: " +
606
                          e.getMessage());
607 622 berkley
    }
608
609
    //deal with the key words here.
610
611
    if(docid.getRev().equals("all"))
612
    {
613
614
    }
615
616 393 jones
    try {
617 622 berkley
      StringBuffer sql = new StringBuffer();
618 691 bojilova
// DOCTITLE attr cleared from the db
619
//      sql.append("SELECT docname, doctype, rootnodeid, doctitle, ");
620
      sql.append("SELECT docname, doctype, rootnodeid, ");
621 697 bojilova
      sql.append("date_created, date_updated, user_owner, user_updated, ");
622
      sql.append("server_location, public_access, rev");
623
      sql.append(" FROM ").append(table);
624 622 berkley
      sql.append(" WHERE docid LIKE '").append(docid.getIdentifier());
625
      sql.append("' and rev like '").append(docid.getRev()).append("'");
626
      //System.out.println(sql.toString());
627 393 jones
      pstmt =
628 622 berkley
        conn.prepareStatement(sql.toString());
629 393 jones
      // Bind the values to the query
630 622 berkley
      //pstmt.setString(1, docid.getIdentifier());
631
      //pstmt.setString(2, docid.getRev());
632 393 jones
633
      pstmt.execute();
634
      ResultSet rs = pstmt.getResultSet();
635
      boolean tableHasRows = rs.next();
636
      if (tableHasRows) {
637 561 berkley
        this.docname        = rs.getString(1);
638
        this.doctype        = rs.getString(2);
639
        this.rootnodeid     = rs.getLong(3);
640 691 bojilova
// DOCTITLE attr cleared from the db
641
//        this.doctitle       = rs.getString(4);
642 692 bojilova
        this.createdate     = rs.getString(4);
643
        this.updatedate     = rs.getString(5);
644
        this.userowner      = rs.getString(6);
645
        this.userupdated    = rs.getString(7);
646
        this.serverlocation = rs.getInt(8);
647 697 bojilova
        this.publicaccess   = rs.getString(9);
648
        this.rev            = rs.getInt(10);
649 393 jones
      }
650 818 berkley
      pstmt.close();
651 393 jones
      if (this.doctype != null) {
652
        pstmt =
653
          conn.prepareStatement("SELECT system_id " +
654
                                  "FROM xml_catalog " +
655 769 bojilova
                                 "WHERE public_id = ?");
656 393 jones
        // Bind the values to the query
657
        pstmt.setString(1, doctype);
658
659
        pstmt.execute();
660
        rs = pstmt.getResultSet();
661
        tableHasRows = rs.next();
662
        if (tableHasRows) {
663
          this.system_id  = rs.getString(1);
664
        }
665 818 berkley
        pstmt.close();
666 393 jones
      }
667
    } catch (SQLException e) {
668 675 berkley
      System.out.println("error in DocumentImpl.getDocumentInfo: " +
669
                          e.getMessage());
670 622 berkley
      e.printStackTrace(System.out);
671 675 berkley
      throw new McdbException("Error accessing database connection in " +
672
                              "DocumentImpl.getDocumentInfo: ", e);
673 393 jones
    }
674
675
    if (this.docname == null) {
676
      throw new McdbDocNotFoundException("Document not found: " + docid);
677
    }
678
  }
679
680
  /**
681
   * Look up the node data from the database
682
   *
683 396 jones
   * @param rootnodeid the id of the root node of the node tree to look up
684 393 jones
   */
685 396 jones
  private TreeSet getNodeRecordList(long rootnodeid) throws McdbException
686 393 jones
  {
687
    PreparedStatement pstmt;
688
    TreeSet nodeRecordList = new TreeSet(new NodeComparator());
689
    long nodeid = 0;
690
    long parentnodeid = 0;
691
    long nodeindex = 0;
692
    String nodetype = null;
693
    String nodename = null;
694 826 bojilova
    String nodeprefix = null;
695 393 jones
    String nodedata = null;
696 899 berkley
    String quotechar = dbAdapter.getStringDelimiter();
697 393 jones
698
    try {
699
      pstmt =
700
      conn.prepareStatement("SELECT nodeid,parentnodeid,nodeindex, " +
701 899 berkley
           "nodetype,nodename,nodeprefix,nodedata " +
702 396 jones
           "FROM xml_nodes WHERE rootnodeid = ?");
703 393 jones
704
      // Bind the values to the query
705 396 jones
      pstmt.setLong(1, rootnodeid);
706 393 jones
707
      pstmt.execute();
708
      ResultSet rs = pstmt.getResultSet();
709
      boolean tableHasRows = rs.next();
710
      while (tableHasRows) {
711
        nodeid = rs.getLong(1);
712
        parentnodeid = rs.getLong(2);
713
        nodeindex = rs.getLong(3);
714
        nodetype = rs.getString(4);
715
        nodename = rs.getString(5);
716 826 bojilova
        nodeprefix = rs.getString(6);
717
        nodedata = rs.getString(7);
718 899 berkley
        nodedata = MetaCatUtil.normalize(nodedata);
719 393 jones
        // add the data to the node record list hashtable
720 826 bojilova
        NodeRecord currentRecord = new NodeRecord(nodeid,parentnodeid,nodeindex,
721 946 tao
                                      nodetype, nodename, nodeprefix, nodedata);
722 393 jones
        nodeRecordList.add(currentRecord);
723
724
        // Advance to the next node
725
        tableHasRows = rs.next();
726
      }
727
      pstmt.close();
728
729
    } catch (SQLException e) {
730 826 bojilova
      throw new McdbException("Error in DocumentImpl.getNodeRecordList " +
731
                              e.getMessage());
732 393 jones
    }
733
734
    if (nodeRecordList != null) {
735
      return nodeRecordList;
736
    } else {
737
      throw new McdbException("Error getting node data: " + docid);
738
    }
739
  }
740 549 berkley
741 697 bojilova
// NOT USED ANY MORE
742
//  /** creates SQL code and inserts new document into DB connection
743
//   default serverCode of 1*/
744
//  private void writeDocumentToDB(String action, String user)
745
//               throws SQLException, Exception
746
//  {
747
//    writeDocumentToDB(action, user, null, 1);
748
//  }
749 393 jones
750 459 bojilova
 /** creates SQL code and inserts new document into DB connection */
751 680 bojilova
  private void writeDocumentToDB(String action, String user, String pub,
752 697 bojilova
                                 String catalogid, int serverCode)
753 459 bojilova
               throws SQLException, Exception {
754 747 bojilova
755 754 bojilova
    String sysdate = dbAdapter.getDateTimeFunction();
756 747 bojilova
757 459 bojilova
    try {
758
      PreparedStatement pstmt = null;
759
760
      if (action.equals("INSERT")) {
761
        //AccessionNumber ac = new AccessionNumber();
762
        //this.docid = ac.generate(docid, "INSERT");
763
        pstmt = conn.prepareStatement(
764 697 bojilova
                "INSERT INTO xml_documents " +
765
                "(docid, rootnodeid, docname, doctype, " +
766
                "user_owner, user_updated, date_created, date_updated, " +
767
                "public_access, catalog_id, server_location) " +
768 747 bojilova
                "VALUES (?, ?, ?, ?, ?, ?, " + sysdate + ", " + sysdate +
769
                ", ?, ?, ?)");
770 549 berkley
        //note that the server_location is set to 1.
771
        //this means that "localhost" in the xml_replication table must
772
        //always be the first entry!!!!!
773
774 459 bojilova
        // Bind the values to the query
775
        pstmt.setString(1, this.docid);
776
        pstmt.setLong(2, rootnodeid);
777
        pstmt.setString(3, docname);
778
        pstmt.setString(4, doctype);
779
        pstmt.setString(5, user);
780
        pstmt.setString(6, user);
781 680 bojilova
        if ( pub == null ) {
782
          pstmt.setString(7, null);
783 697 bojilova
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
784 680 bojilova
          pstmt.setInt(7, 1);
785 697 bojilova
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
786 680 bojilova
          pstmt.setInt(7, 0);
787
        }
788 697 bojilova
        pstmt.setString(8, catalogid);
789
        pstmt.setInt(9, serverCode);
790 459 bojilova
      } else if (action.equals("UPDATE")) {
791
792
        // Save the old document entry in a backup table
793
        DocumentImpl.archiveDocRevision( conn, docid, user );
794 575 berkley
        DocumentImpl thisdoc = new DocumentImpl(conn, docid);
795
        int thisrev = thisdoc.getRev();
796
        thisrev++;
797 459 bojilova
        // Delete index for the old version of docid
798
        // The new index is inserting on the next calls to DBSAXNode
799
        pstmt = conn.prepareStatement(
800
                "DELETE FROM xml_index WHERE docid='" + this.docid + "'");
801
        pstmt.execute();
802 818 berkley
        pstmt.close();
803 459 bojilova
804
        // Update the new document to reflect the new node tree
805
        pstmt = conn.prepareStatement(
806
            "UPDATE xml_documents " +
807
            "SET rootnodeid = ?, docname = ?, doctype = ?, " +
808 747 bojilova
            "user_updated = ?, date_updated = " + sysdate + ", " +
809 697 bojilova
            "server_location = ?, rev = ?, public_access = ?, catalog_id = ? " +
810 769 bojilova
            "WHERE docid = ?");
811 459 bojilova
        // Bind the values to the query
812
        pstmt.setLong(1, rootnodeid);
813
        pstmt.setString(2, docname);
814
        pstmt.setString(3, doctype);
815
        pstmt.setString(4, user);
816 549 berkley
        pstmt.setInt(5, serverCode);
817 575 berkley
        pstmt.setInt(6, thisrev);
818 680 bojilova
        if ( pub == null ) {
819
          pstmt.setString(7, null);
820 697 bojilova
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
821 680 bojilova
          pstmt .setInt(7, 1);
822 697 bojilova
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
823 680 bojilova
          pstmt.setInt(7, 0);
824
        }
825 697 bojilova
        pstmt.setString(8, catalogid);
826
        pstmt.setString(9, this.docid);
827 575 berkley
828 459 bojilova
      } else {
829
        System.err.println("Action not supported: " + action);
830
      }
831
832
      // Do the insertion
833
      pstmt.execute();
834
      pstmt.close();
835
836
    } catch (SQLException sqle) {
837
      throw sqle;
838
    } catch (Exception e) {
839
      throw e;
840
    }
841
  }
842
843
  /**
844 407 jones
   * Write an XML file to the database, given a filename
845 393 jones
   *
846 408 jones
   * @param conn the JDBC connection to the database
847 407 jones
   * @param filename the filename to be loaded into the database
848 680 bojilova
   * @param pub flag for public "read" access on document
849
   * @param dtdfilename the dtd to be uploaded on server's file system
850 407 jones
   * @param action the action to be performed (INSERT OR UPDATE)
851
   * @param docid the docid to use for the INSERT OR UPDATE
852 680 bojilova
   * @param user the user that owns the document
853 802 bojilova
   * @param groups the groups to which user belongs
854 393 jones
   */
855 598 bojilova
  public static String write(Connection conn,String filename,
856 680 bojilova
                             String pub, String dtdfilename,
857 598 bojilova
                             String action, String docid, String user,
858 802 bojilova
                             String[] groups )
859 457 bojilova
                throws Exception {
860 598 bojilova
861
    Reader dtd = null;
862
    if ( dtdfilename != null ) {
863
      dtd = new FileReader(new File(dtdfilename).toString());
864
    }
865 555 bojilova
    return write ( conn, new FileReader(new File(filename).toString()),
866 802 bojilova
                   pub, dtd, action, docid, user, groups, false);
867 407 jones
  }
868 598 bojilova
869 680 bojilova
  public static String write(Connection conn,Reader xml,String pub,Reader dtd,
870 598 bojilova
                             String action, String docid, String user,
871 802 bojilova
                             String[] groups, boolean validate)
872 549 berkley
                throws Exception {
873 802 bojilova
    return write(conn,xml,pub,dtd,action,docid,user,groups,1,false,validate);
874 598 bojilova
  }
875
876 680 bojilova
  public static String write(Connection conn, Reader xml, String pub,
877 598 bojilova
                             String action, String docid, String user,
878 802 bojilova
                             String[] groups )
879 598 bojilova
                throws Exception {
880 571 berkley
    if(action.equals("UPDATE"))
881
    {//if the document is being updated then use the servercode from the
882
     //originally inserted document.
883
      DocumentImpl doc = new DocumentImpl(conn, docid);
884
      int servercode = doc.getServerlocation();
885 802 bojilova
      return write(conn, xml, pub, action, docid, user, groups, servercode);
886 571 berkley
    }
887
    else
888
    {//if the file is being inserted then the servercode is always 1
889 802 bojilova
      return write(conn, xml, pub, action, docid, user, groups, 1);
890 571 berkley
    }
891 549 berkley
  }
892
893 559 berkley
  public static String write( Connection conn, Reader xml,
894
                              String action, String docid, String user,
895 802 bojilova
                              String[] groups, int serverCode )
896 598 bojilova
                throws Exception
897 559 berkley
  {
898 802 bojilova
    return write(conn,xml,null,action,docid,user,groups,serverCode);
899 559 berkley
  }
900
901 680 bojilova
  public static String write( Connection conn, Reader xml, String pub,
902 577 berkley
                              String action, String docid, String user,
903 802 bojilova
                              String[] groups, int serverCode)
904 598 bojilova
                throws Exception
905 577 berkley
  {
906 802 bojilova
    return write(conn,xml,pub,null,action,docid,user,groups,
907 695 bojilova
                 serverCode,false,false);
908 577 berkley
  }
909
910 680 bojilova
  public static String write( Connection conn, Reader xml, String pub,
911 600 bojilova
                              String action, String docid, String user,
912 802 bojilova
                              String[] groups, int serverCode, boolean override)
913 600 bojilova
                throws Exception
914
  {
915 802 bojilova
    return write(conn,xml,pub,null,action,docid,user,groups,
916 695 bojilova
                 serverCode,override,false);
917 600 bojilova
  }
918
919 407 jones
  /**
920
   * Write an XML file to the database, given a Reader
921
   *
922 408 jones
   * @param conn the JDBC connection to the database
923 407 jones
   * @param xml the xml stream to be loaded into the database
924 680 bojilova
   * @param pub flag for public "read" access on xml document
925
   * @param dtd the dtd to be uploaded on server's file system
926 734 bojilova
   * @param action the action to be performed (INSERT or UPDATE)
927
   * @param accnum the docid + rev# to use on INSERT or UPDATE
928 580 berkley
   * @param user the user that owns the document
929 802 bojilova
   * @param groups the groups to which user belongs
930 580 berkley
   * @param serverCode the serverid from xml_replication on which this document
931
   *        resides.
932
   * @param override flag to stop insert replication checking.
933
   *        if override = true then a document not belonging to the local server
934
   *        will not be checked upon update for a file lock.
935
   *        if override = false then a document not from this server, upon
936
   *        update will be locked and version checked.
937 407 jones
   */
938 559 berkley
939 680 bojilova
  public static String write( Connection conn,Reader xml,String pub,Reader dtd,
940 734 bojilova
                              String action, String accnum, String user,
941 802 bojilova
                              String[] groups, int serverCode, boolean override,
942 695 bojilova
                              boolean validate)
943 598 bojilova
                throws Exception
944 573 berkley
  {
945 779 bojilova
    // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
946
    AccessionNumber ac = new AccessionNumber(conn, accnum, action);
947
    String docid = ac.getDocid();
948
    String rev = ac.getRev();
949
950 590 berkley
    MetaCatUtil.debugMessage("action: " + action + " servercode: " +
951
                             serverCode + " override: " + override);
952 580 berkley
953 577 berkley
    if((serverCode != 1 && action.equals("UPDATE")) && !override)
954 559 berkley
    { //if this document being written is not a resident of this server then
955
      //we need to try to get a lock from it's resident server.  If the
956
      //resident server will not give a lock then we send the user a message
957
      //saying that he/she needs to download a new copy of the file and
958
      //merge the differences manually.
959 567 berkley
      int istreamInt;
960 561 berkley
      char istreamChar;
961 779 bojilova
      DocumentIdentifier id = new DocumentIdentifier(accnum);
962
      String updaterev = id.getRev();
963 561 berkley
      String server = MetacatReplication.getServer(serverCode);
964 734 bojilova
      MetacatReplication.replLog("attempting to lock " + accnum);
965 837 bojilova
      URL u = new URL("https://" + server + "?action=getlock&updaterev=" +
966 779 bojilova
                      updaterev + "&docid=" + docid);
967 574 berkley
      System.out.println("sending message: " + u.toString());
968 569 berkley
      String serverResStr = MetacatReplication.getURLContent(u);
969 946 tao
      String openingtag =serverResStr.substring(0, serverResStr.indexOf(">")+1);
970 571 berkley
971 561 berkley
      if(openingtag.equals("<lockgranted>"))
972
      {//the lock was granted go ahead with the insert
973 571 berkley
        try
974
        {
975 734 bojilova
          MetacatReplication.replLog("lock granted for " + accnum + " from " +
976 584 berkley
                                      server);
977 734 bojilova
          XMLReader parser = initializeParser(conn, action, docid, validate,
978 946 tao
                                            user, groups, pub, serverCode, dtd);
979 571 berkley
          conn.setAutoCommit(false);
980 695 bojilova
          parser.parse(new InputSource(xml));
981 571 berkley
          conn.commit();
982
          conn.setAutoCommit(true);
983
        }
984
        catch (Exception e)
985
        {
986
          conn.rollback();
987
          conn.setAutoCommit(true);
988
          throw e;
989
        }
990
991
        //after inserting the document locally, tell the document's home server
992
        //to come get a copy from here.
993 835 bojilova
        ForceReplicationHandler frh = new ForceReplicationHandler(accnum);
994 590 berkley
995 779 bojilova
        return (accnum);
996 561 berkley
      }
997 734 bojilova
998 561 berkley
      else if(openingtag.equals("<filelocked>"))
999
      {//the file is currently locked by another user
1000
       //notify our user to wait a few minutes, check out a new copy and try
1001
       //again.
1002 584 berkley
        //System.out.println("file locked");
1003 734 bojilova
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1004 584 berkley
                                   server + " reason: file already locked");
1005 571 berkley
        throw new Exception("The file specified is already locked by another " +
1006
                            "user.  Please wait 30 seconds, checkout the " +
1007
                            "newer document, merge your changes and try " +
1008
                            "again.");
1009 561 berkley
      }
1010
      else if(openingtag.equals("<outdatedfile>"))
1011
      {//our file is outdated.  notify our user to check out a new copy of the
1012
       //file and merge his version with the new version.
1013 584 berkley
        //System.out.println("outdated file");
1014 734 bojilova
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1015 584 berkley
                                    server + " reason: local file outdated");
1016 571 berkley
        throw new Exception("The file you are trying to update is an outdated" +
1017
                            " version.  Please checkout the newest document, " +
1018
                            "merge your changes and try again.");
1019 561 berkley
      }
1020 559 berkley
    }
1021 571 berkley
1022 425 bojilova
    if ( action.equals("UPDATE") ) {
1023 441 bojilova
      // check for 'write' permission for 'user' to update this document
1024 628 berkley
1025 802 bojilova
      if ( !hasPermission(conn, user, groups, docid) ) {
1026 441 bojilova
        throw new Exception("User " + user +
1027 734 bojilova
              " does not have permission to update XML Document #" + accnum);
1028 425 bojilova
      }
1029
    }
1030
1031 571 berkley
    try
1032 638 bojilova
    {
1033 734 bojilova
      XMLReader parser = initializeParser(conn, action, docid, validate,
1034 802 bojilova
                                          user, groups, pub, serverCode, dtd);
1035 555 bojilova
      conn.setAutoCommit(false);
1036
      parser.parse(new InputSource(xml));
1037
      conn.commit();
1038
      conn.setAutoCommit(true);
1039 571 berkley
    }
1040
    catch (Exception e)
1041
    {
1042 555 bojilova
      conn.rollback();
1043
      conn.setAutoCommit(true);
1044
      throw e;
1045
    }
1046 577 berkley
1047
    //force replicate out the new document to each server in our server list.
1048
    if(serverCode == 1)
1049 582 berkley
    { //start the thread to replicate this new document out to the other servers
1050 835 bojilova
      ForceReplicationHandler frh = new ForceReplicationHandler(accnum, action);
1051 577 berkley
    }
1052 457 bojilova
1053 779 bojilova
    return(accnum);
1054 393 jones
  }
1055 396 jones
1056 407 jones
  /**
1057
   * Delete an XML file from the database (actually, just make it a revision
1058
   * in the xml_revisions table)
1059
   *
1060
   * @param docid the ID of the document to be deleted from the database
1061
   */
1062 734 bojilova
  public static void delete( Connection conn, String accnum,
1063 802 bojilova
                                 String user, String[] groups )
1064 734 bojilova
                throws Exception
1065
  {
1066 779 bojilova
    // OLD
1067
    //DocumentIdentifier id = new DocumentIdentifier(accnum);
1068
    //String docid = id.getIdentifier();
1069
    //String rev = id.getRev();
1070 628 berkley
1071 779 bojilova
    // OLD
1072 734 bojilova
    // Determine if the docid,rev are OK for DELETE
1073 779 bojilova
    //AccessionNumber ac = new AccessionNumber(conn);
1074
    //docid = ac.generate(docid, rev, "DELETE");
1075 396 jones
1076 779 bojilova
    // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1077
    AccessionNumber ac = new AccessionNumber(conn, accnum, "DELETE");
1078
    String docid = ac.getDocid();
1079
    String rev = ac.getRev();
1080
1081
1082 441 bojilova
    // check for 'write' permission for 'user' to delete this document
1083 802 bojilova
    if ( !hasPermission(conn, user, groups, docid) ) {
1084 441 bojilova
      throw new Exception("User " + user +
1085 734 bojilova
              " does not have permission to delete XML Document #" + accnum);
1086 425 bojilova
    }
1087
1088 407 jones
    conn.setAutoCommit(false);
1089
    // Copy the record to the xml_revisions table
1090 425 bojilova
    DocumentImpl.archiveDocRevision( conn, docid, user );
1091 396 jones
1092 407 jones
    // Now delete it from the xml_documents table
1093 628 berkley
1094 407 jones
    Statement stmt = conn.createStatement();
1095 425 bojilova
    stmt.execute("DELETE FROM xml_index WHERE docid = '" + docid + "'");
1096 688 bojilova
    //stmt.execute("DELETE FROM xml_access WHERE docid = '" + docid + "'");
1097 645 bojilova
    stmt.execute("DELETE FROM xml_access WHERE accessfileid = '" + docid + "'");
1098
    stmt.execute("DELETE FROM xml_relation WHERE docid = '" + docid + "'");
1099 785 bojilova
    stmt.execute("DELETE FROM xml_documents WHERE docid = '" + docid + "'");
1100 407 jones
    stmt.close();
1101
    conn.commit();
1102 457 bojilova
    conn.setAutoCommit(true);
1103 634 berkley
    //IF this is a package document:
1104
    //delete all of the relations that this document created.
1105
    //if the deleted document is a package document its relations should
1106
    //no longer be active if it has been deleted from the system.
1107 645 bojilova
1108 407 jones
  }
1109 638 bojilova
1110 570 bojilova
  /**
1111 802 bojilova
    * Check for "WRITE" permission on @docid for @user and/or @groups
1112 570 bojilova
    * from DB connection
1113
    */
1114 802 bojilova
  private static boolean hasPermission ( Connection conn, String user,
1115
                                  String[] groups, String docid )
1116
                  throws SQLException
1117 570 bojilova
  {
1118 802 bojilova
    // Check for WRITE permission on @docid for @user and/or @groups
1119 570 bojilova
    AccessControlList aclobj = new AccessControlList(conn);
1120 802 bojilova
    return aclobj.hasPermission("WRITE", user, groups, docid);
1121 425 bojilova
  }
1122
1123 946 tao
  /**
1124
    * Check for "READ" permission base on docid, user and group
1125
    *@docid, the document
1126
    *@user, user name
1127
    *@group, user's group
1128
    *
1129
    */
1130
  public boolean hasReadPermission ( Connection conn, String user,
1131
                                  String[] groups, String docId )
1132
                  throws SQLException
1133
  {
1134
    // Check for READ permission on @docid for @user and/or @groups
1135
    AccessControlList aclObj = new AccessControlList(conn);
1136
    return aclObj.hasPermission("READ", user, groups, docId);
1137
  }
1138
1139 396 jones
  /**
1140 407 jones
   * Set up the parser handlers for writing the document to the database
1141
   */
1142 598 bojilova
  private static XMLReader initializeParser(Connection conn, String action,
1143 695 bojilova
                                   String docid, boolean validate,
1144 802 bojilova
                                   String user, String[] groups, String pub,
1145 695 bojilova
                                   int serverCode, Reader dtd)
1146 598 bojilova
                           throws Exception
1147
  {
1148 407 jones
    XMLReader parser = null;
1149
    //
1150
    // Set up the SAX document handlers for parsing
1151
    //
1152
    try {
1153 645 bojilova
      ContentHandler chandler = new DBSAXHandler(conn, action, docid,
1154 802 bojilova
                                                 user, groups, pub, serverCode);
1155 645 bojilova
      EntityResolver eresolver= new DBEntityResolver(conn,
1156
                                                 (DBSAXHandler)chandler, dtd);
1157 598 bojilova
      DTDHandler dtdhandler   = new DBDTDHandler(conn);
1158 407 jones
1159
      // Get an instance of the parser
1160 802 bojilova
      String parserName = MetaCatUtil.getOption("saxparser");
1161 407 jones
      parser = XMLReaderFactory.createXMLReader(parserName);
1162
1163 660 bojilova
      // Turn on validation
1164 695 bojilova
      parser.setFeature("http://xml.org/sax/features/validation", validate);
1165 660 bojilova
      // Turn off Including all external parameter entities
1166
      // (the external DTD subset also)
1167
      // Doesn't work well, probably the feature name is not correct
1168
      // parser.setFeature(
1169
      //  "http://xml.org/sax/features/external-parameter-entities", false);
1170 407 jones
1171
      // Set Handlers in the parser
1172
      parser.setProperty("http://xml.org/sax/properties/declaration-handler",
1173
                         chandler);
1174
      parser.setProperty("http://xml.org/sax/properties/lexical-handler",
1175
                         chandler);
1176
      parser.setContentHandler((ContentHandler)chandler);
1177 598 bojilova
      parser.setEntityResolver((EntityResolver)eresolver);
1178 407 jones
      parser.setDTDHandler((DTDHandler)dtdhandler);
1179
      parser.setErrorHandler((ErrorHandler)chandler);
1180
1181
    } catch (Exception e) {
1182 457 bojilova
      throw e;
1183 407 jones
    }
1184
1185
    return parser;
1186
  }
1187
1188 459 bojilova
  /** Save a document entry in the xml_revisions table */
1189
  private static void archiveDocRevision(Connection conn, String docid,
1190 552 berkley
                                         String user)
1191
                                         throws SQLException {
1192 754 bojilova
    String sysdate = dbAdapter.getDateTimeFunction();
1193 747 bojilova
1194 459 bojilova
    // create a record in xml_revisions table
1195
    // for that document as selected from xml_documents
1196
    PreparedStatement pstmt = conn.prepareStatement(
1197
      "INSERT INTO xml_revisions " +
1198 771 bojilova
        "(docid, rootnodeid, docname, doctype, " +
1199 697 bojilova
        "user_owner, user_updated, date_created, date_updated, " +
1200
        "server_location, rev, public_access, catalog_id) " +
1201 771 bojilova
      "SELECT ?, rootnodeid, docname, doctype, " +
1202 747 bojilova
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
1203
        "server_location, rev, public_access, catalog_id " +
1204 459 bojilova
      "FROM xml_documents " +
1205
      "WHERE docid = ?");
1206
    // Bind the values to the query and execute it
1207
    pstmt.setString(1, docid);
1208
    pstmt.setString(2, user);
1209
    pstmt.setString(3, docid);
1210
    pstmt.execute();
1211
    pstmt.close();
1212
1213
  }
1214
1215 407 jones
  /**
1216
   * the main routine used to test the DBWriter utility.
1217
   * <p>
1218
   * Usage: java DocumentImpl <-f filename -a action -d docid>
1219
   *
1220
   * @param filename the filename to be loaded into the database
1221
   * @param action the action to perform (READ, INSERT, UPDATE, DELETE)
1222
   * @param docid the id of the document to process
1223
   */
1224
  static public void main(String[] args) {
1225
1226
    try {
1227 555 bojilova
      String filename    = null;
1228 598 bojilova
      String dtdfilename = null;
1229 555 bojilova
      String action      = null;
1230
      String docid       = null;
1231 429 jones
      boolean showRuntime = false;
1232
      boolean useOldReadAlgorithm = false;
1233 407 jones
1234 408 jones
      // Parse the command line arguments
1235 407 jones
      for ( int i=0 ; i < args.length; ++i ) {
1236
        if ( args[i].equals( "-f" ) ) {
1237
          filename =  args[++i];
1238 598 bojilova
        } else if ( args[i].equals( "-r" ) ) {
1239
          dtdfilename =  args[++i];
1240 407 jones
        } else if ( args[i].equals( "-a" ) ) {
1241
          action =  args[++i];
1242
        } else if ( args[i].equals( "-d" ) ) {
1243
          docid =  args[++i];
1244 429 jones
        } else if ( args[i].equals( "-t" ) ) {
1245
          showRuntime = true;
1246
        } else if ( args[i].equals( "-old" ) ) {
1247
          useOldReadAlgorithm = true;
1248 407 jones
        } else {
1249
          System.err.println
1250
            ( "   args[" +i+ "] '" +args[i]+ "' ignored." );
1251
        }
1252
      }
1253
1254 408 jones
      // Check if the required arguments are provided
1255 407 jones
      boolean argsAreValid = false;
1256
      if (action != null) {
1257
        if (action.equals("INSERT")) {
1258
          if (filename != null) {
1259
            argsAreValid = true;
1260
          }
1261
        } else if (action.equals("UPDATE")) {
1262
          if ((filename != null) && (docid != null)) {
1263
            argsAreValid = true;
1264
          }
1265
        } else if (action.equals("DELETE")) {
1266
          if (docid != null) {
1267
            argsAreValid = true;
1268
          }
1269
        } else if (action.equals("READ")) {
1270
          if (docid != null) {
1271
            argsAreValid = true;
1272
          }
1273
        }
1274
      }
1275
1276 408 jones
      // Print usage message if the arguments are not valid
1277 407 jones
      if (!argsAreValid) {
1278
        System.err.println("Wrong number of arguments!!!");
1279
        System.err.println(
1280 598 bojilova
          "USAGE: java DocumentImpl [-t] <-a INSERT> [-d docid] <-f filename> "+
1281 680 bojilova
          "[-r dtdfilename]");
1282 407 jones
        System.err.println(
1283 598 bojilova
          "   OR: java DocumentImpl [-t] <-a UPDATE -d docid -f filename> " +
1284 680 bojilova
          "[-r dtdfilename]");
1285 407 jones
        System.err.println(
1286 429 jones
          "   OR: java DocumentImpl [-t] <-a DELETE -d docid>");
1287 407 jones
        System.err.println(
1288 429 jones
          "   OR: java DocumentImpl [-t] [-old] <-a READ -d docid>");
1289 407 jones
        return;
1290
      }
1291 429 jones
1292
      // Time the request if asked for
1293
      double startTime = System.currentTimeMillis();
1294
1295 407 jones
      // Open a connection to the database
1296
      MetaCatUtil util = new MetaCatUtil();
1297
      Connection dbconn = util.openDBConnection();
1298
1299 463 berkley
      double connTime = System.currentTimeMillis();
1300 408 jones
      // Execute the action requested (READ, INSERT, UPDATE, DELETE)
1301 407 jones
      if (action.equals("READ")) {
1302
          DocumentImpl xmldoc = new DocumentImpl( dbconn, docid );
1303 429 jones
          if (useOldReadAlgorithm) {
1304
            System.out.println(xmldoc.readUsingSlowAlgorithm());
1305
          } else {
1306
            xmldoc.toXml(new PrintWriter(System.out));
1307
          }
1308 408 jones
      } else if (action.equals("DELETE")) {
1309 425 bojilova
        DocumentImpl.delete(dbconn, docid, null, null);
1310 408 jones
        System.out.println("Document deleted: " + docid);
1311 407 jones
      } else {
1312 680 bojilova
        String newdocid = DocumentImpl.write(dbconn, filename, null,
1313 598 bojilova
                                             dtdfilename, action, docid,
1314
                                             null, null);
1315 408 jones
        if ((docid != null) && (!docid.equals(newdocid))) {
1316
          if (action.equals("INSERT")) {
1317
            System.out.println("New document ID generated!!! ");
1318
          } else if (action.equals("UPDATE")) {
1319
            System.out.println("ERROR: Couldn't update document!!! ");
1320 407 jones
          }
1321 408 jones
        } else if ((docid == null) && (action.equals("UPDATE"))) {
1322
          System.out.println("ERROR: Couldn't update document!!! ");
1323 407 jones
        }
1324 408 jones
        System.out.println("Document processing finished for: " + filename
1325
              + " (" + newdocid + ")");
1326 407 jones
      }
1327
1328 429 jones
      double stopTime = System.currentTimeMillis();
1329 463 berkley
      double dbOpenTime = (connTime - startTime)/1000;
1330
      double insertTime = (stopTime - connTime)/1000;
1331 429 jones
      double executionTime = (stopTime - startTime)/1000;
1332
      if (showRuntime) {
1333 463 berkley
        System.out.println("\n\nTotal Execution time was: " +
1334
                           executionTime + " seconds.");
1335
        System.out.println("Time to open DB connection was: " + dbOpenTime +
1336
                           " seconds.");
1337
        System.out.println("Time to insert document was: " + insertTime +
1338
                           " seconds.");
1339 429 jones
      }
1340 463 berkley
      dbconn.close();
1341 407 jones
    } catch (McdbException me) {
1342
      me.toXml(new PrintWriter(System.err));
1343
    } catch (AccessionNumberException ane) {
1344
      System.out.println(ane.getMessage());
1345
    } catch (Exception e) {
1346
      System.err.println("EXCEPTION HANDLING REQUIRED");
1347
      System.err.println(e.getMessage());
1348
      e.printStackTrace(System.err);
1349
    }
1350
  }
1351 393 jones
}