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