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
      // Print the end tag for the previous node if needed
412
      //
413
      // This is determined by inspecting the parent nodeid for the
414
      // currentNode.  If it is the same as the nodeid of the last element
415
      // that was pushed onto the stack, then we are still in that previous
416
      // parent element, and we do nothing.  However, if it differs, then we
417
      // have returned to a level above the previous parent, so we go into
418
      // a loop and pop off nodes and print out their end tags until we get
419
      // the node on the stack to match the currentNode parentnodeid
420
      //
421
      // So, this of course means that we rely on the list of elements
422
      // having been sorted in a depth first traversal of the nodes, which
423
      // is handled by the NodeComparator class used by the TreeSet
424
      if (!atRootElement) {
425
        NodeRecord currentElement = (NodeRecord)openElements.peek();
426
        if ( currentNode.parentnodeid != currentElement.nodeid ) {
427
          while ( currentNode.parentnodeid != currentElement.nodeid ) {
428
            currentElement = (NodeRecord)openElements.pop();
429
            util.debugMessage("\n POPPED: " + currentElement.nodename);
430 451 bojilova
            if (previousNodeWasElement) {
431
              out.print(">");
432
              previousNodeWasElement = false;
433
            }
434 826 bojilova
            if ( currentElement.nodeprefix != null ) {
435
              out.print("</" + currentElement.nodeprefix + ":" +
436
                        currentElement.nodename + ">" );
437
            } else {
438
              out.print("</" + currentElement.nodename + ">" );
439
            }
440 429 jones
            currentElement = (NodeRecord)openElements.peek();
441
          }
442
        }
443
      }
444
445
      // Handle the DOCUMENT node
446
      if (currentNode.nodetype.equals("DOCUMENT")) {
447
        out.println("<?xml version=\"1.0\"?>");
448
449
        if (docname != null) {
450
          if ((doctype != null) && (system_id != null)) {
451
            out.println("<!DOCTYPE " + docname + " PUBLIC \"" + doctype +
452
                       "\" \"" + system_id + "\">");
453
          } else {
454
            out.println("<!DOCTYPE " + docname + ">");
455
          }
456
        }
457
458
      // Handle the ELEMENT nodes
459
      } else if (currentNode.nodetype.equals("ELEMENT")) {
460
        if (atRootElement) {
461
          atRootElement = false;
462
        } else {
463
          if (previousNodeWasElement) {
464
            out.print(">");
465
          }
466
        }
467
        openElements.push(currentNode);
468
        util.debugMessage("\n PUSHED: " + currentNode.nodename);
469
        previousNodeWasElement = true;
470 826 bojilova
        if ( currentNode.nodeprefix != null ) {
471
          out.print("<" + currentNode.nodeprefix + ":" + currentNode.nodename);
472
        } else {
473
          out.print("<" + currentNode.nodename);
474
        }
475 429 jones
476
      // Handle the ATTRIBUTE nodes
477
      } else if (currentNode.nodetype.equals("ATTRIBUTE")) {
478 826 bojilova
        if ( currentNode.nodeprefix != null ) {
479
          out.print(" " + currentNode.nodeprefix + ":" + currentNode.nodename +
480
                    "=\"" + currentNode.nodedata + "\"");
481
        } else {
482
          out.print(" " + currentNode.nodename + "=\"" +
483
                    currentNode.nodedata + "\"");
484
        }
485 821 bojilova
486
      // Handle the NAMESPACE nodes
487
      } else if (currentNode.nodetype.equals("NAMESPACE")) {
488
        out.print(" xmlns:" + currentNode.nodename + "=\""
489
                 + currentNode.nodedata + "\"");
490
491
      // Handle the TEXT nodes
492 429 jones
      } else if (currentNode.nodetype.equals("TEXT")) {
493
        if (previousNodeWasElement) {
494
          out.print(">");
495
        }
496
        out.print(currentNode.nodedata);
497
        previousNodeWasElement = false;
498
499
      // Handle the COMMENT nodes
500
      } else if (currentNode.nodetype.equals("COMMENT")) {
501
        if (previousNodeWasElement) {
502
          out.print(">");
503
        }
504
        out.print("<!--" + currentNode.nodedata + "-->");
505
        previousNodeWasElement = false;
506
507
      // Handle the PI nodes
508
      } else if (currentNode.nodetype.equals("PI")) {
509
        if (previousNodeWasElement) {
510
          out.print(">");
511
        }
512
        out.print("<?" + currentNode.nodename + " " +
513
                        currentNode.nodedata + "?>");
514
        previousNodeWasElement = false;
515
516
      // Handle any other node type (do nothing)
517
      } else {
518
        // Any other types of nodes are not handled.
519
        // Probably should throw an exception here to indicate this
520
      }
521
      out.flush();
522
    }
523
524
    // Print the final end tag for the root element
525 686 berkley
    while(!openElements.empty())
526
    {
527
      NodeRecord currentElement = (NodeRecord)openElements.pop();
528
      util.debugMessage("\n POPPED: " + currentElement.nodename);
529 826 bojilova
      if ( currentElement.nodeprefix != null ) {
530
        out.print("</" + currentElement.nodeprefix + ":" +
531
                  currentElement.nodename + ">" );
532
      } else {
533
        out.print("</" + currentElement.nodename + ">" );
534
      }
535 686 berkley
    }
536 429 jones
    out.flush();
537
  }
538 622 berkley
539
  private boolean isRevisionOnly(DocumentIdentifier docid) throws Exception
540
  {
541
    //System.out.println("inRevisionOnly");
542
    PreparedStatement pstmt;
543
    String rev = docid.getRev();
544
    String newid = docid.getIdentifier();
545
    pstmt = conn.prepareStatement("select rev from xml_documents " +
546
                                  "where docid like '" + newid + "'");
547
    pstmt.execute();
548
    ResultSet rs = pstmt.getResultSet();
549
    boolean tablehasrows = rs.next();
550
    if(rev.equals("newest") || rev.equals("all"))
551
    {
552
      return false;
553
    }
554
555
    if(tablehasrows)
556
    {
557
      int r = rs.getInt(1);
558 667 berkley
      pstmt.close();
559 622 berkley
      if(new Integer(rev).intValue() == r)
560
      { //the current revision in in xml_documents
561
        //System.out.println("returning false");
562
        return false;
563
      }
564
      else if(new Integer(rev).intValue() < r)
565
      { //the current revision is in xml_revisions.
566
        //System.out.println("returning true");
567
        return true;
568
      }
569
      else if(new Integer(rev).intValue() > r)
570
      { //error, rev cannot be greater than r
571
        throw new Exception("requested revision cannot be greater than " +
572
                            "the latest revision number.");
573
      }
574
    }
575
    throw new Exception("the requested docid '" + docid.toString() +
576
                        "' does not exist");
577
  }
578 429 jones
579 800 jones
  private void getDocumentInfo(String docid) throws McdbException,
580 622 berkley
                                                    AccessionNumberException
581
  {
582
    getDocumentInfo(new DocumentIdentifier(docid));
583
  }
584
585 429 jones
  /**
586 393 jones
   * Look up the document type information from the database
587
   *
588
   * @param docid the id of the document to look up
589
   */
590 622 berkley
  private void getDocumentInfo(DocumentIdentifier docid) throws McdbException
591 393 jones
  {
592
    PreparedStatement pstmt;
593 622 berkley
    String table = "xml_documents";
594
595
    try
596
    {
597
      if(isRevisionOnly(docid))
598
      { //pull the document from xml_revisions instead of from xml_documents;
599
        table = "xml_revisions";
600
      }
601
    }
602
    catch(Exception e)
603
    {
604 675 berkley
      System.out.println("error in DocumentImpl.getDocumentInfo: " +
605
                          e.getMessage());
606 622 berkley
    }
607
608
    //deal with the key words here.
609
610
    if(docid.getRev().equals("all"))
611
    {
612
613
    }
614
615 393 jones
    try {
616 622 berkley
      StringBuffer sql = new StringBuffer();
617 691 bojilova
// DOCTITLE attr cleared from the db
618
//      sql.append("SELECT docname, doctype, rootnodeid, doctitle, ");
619
      sql.append("SELECT docname, doctype, rootnodeid, ");
620 697 bojilova
      sql.append("date_created, date_updated, user_owner, user_updated, ");
621
      sql.append("server_location, public_access, rev");
622
      sql.append(" FROM ").append(table);
623 622 berkley
      sql.append(" WHERE docid LIKE '").append(docid.getIdentifier());
624
      sql.append("' and rev like '").append(docid.getRev()).append("'");
625
      //System.out.println(sql.toString());
626 393 jones
      pstmt =
627 622 berkley
        conn.prepareStatement(sql.toString());
628 393 jones
      // Bind the values to the query
629 622 berkley
      //pstmt.setString(1, docid.getIdentifier());
630
      //pstmt.setString(2, docid.getRev());
631 393 jones
632
      pstmt.execute();
633
      ResultSet rs = pstmt.getResultSet();
634
      boolean tableHasRows = rs.next();
635
      if (tableHasRows) {
636 561 berkley
        this.docname        = rs.getString(1);
637
        this.doctype        = rs.getString(2);
638
        this.rootnodeid     = rs.getLong(3);
639 691 bojilova
// DOCTITLE attr cleared from the db
640
//        this.doctitle       = rs.getString(4);
641 692 bojilova
        this.createdate     = rs.getString(4);
642
        this.updatedate     = rs.getString(5);
643
        this.userowner      = rs.getString(6);
644
        this.userupdated    = rs.getString(7);
645
        this.serverlocation = rs.getInt(8);
646 697 bojilova
        this.publicaccess   = rs.getString(9);
647
        this.rev            = rs.getInt(10);
648 393 jones
      }
649 818 berkley
      pstmt.close();
650 393 jones
      if (this.doctype != null) {
651
        pstmt =
652
          conn.prepareStatement("SELECT system_id " +
653
                                  "FROM xml_catalog " +
654 769 bojilova
                                 "WHERE public_id = ?");
655 393 jones
        // Bind the values to the query
656
        pstmt.setString(1, doctype);
657
658
        pstmt.execute();
659
        rs = pstmt.getResultSet();
660
        tableHasRows = rs.next();
661
        if (tableHasRows) {
662
          this.system_id  = rs.getString(1);
663
        }
664 818 berkley
        pstmt.close();
665 393 jones
      }
666
    } catch (SQLException e) {
667 675 berkley
      System.out.println("error in DocumentImpl.getDocumentInfo: " +
668
                          e.getMessage());
669 622 berkley
      e.printStackTrace(System.out);
670 675 berkley
      throw new McdbException("Error accessing database connection in " +
671
                              "DocumentImpl.getDocumentInfo: ", e);
672 393 jones
    }
673
674
    if (this.docname == null) {
675
      throw new McdbDocNotFoundException("Document not found: " + docid);
676
    }
677
  }
678
679
  /**
680
   * Look up the node data from the database
681
   *
682 396 jones
   * @param rootnodeid the id of the root node of the node tree to look up
683 393 jones
   */
684 396 jones
  private TreeSet getNodeRecordList(long rootnodeid) throws McdbException
685 393 jones
  {
686
    PreparedStatement pstmt;
687
    TreeSet nodeRecordList = new TreeSet(new NodeComparator());
688
    long nodeid = 0;
689
    long parentnodeid = 0;
690
    long nodeindex = 0;
691
    String nodetype = null;
692
    String nodename = null;
693 826 bojilova
    String nodeprefix = null;
694 393 jones
    String nodedata = null;
695
696
    try {
697
      pstmt =
698
      conn.prepareStatement("SELECT nodeid,parentnodeid,nodeindex, " +
699 826 bojilova
           "nodetype,nodename,nodeprefix,"+
700 393 jones
           "replace(" +
701
           "replace(" +
702
           "replace(nodedata,'&','&amp;') " +
703
           ",'<','&lt;') " +
704
           ",'>','&gt;') " +
705 396 jones
           "FROM xml_nodes WHERE rootnodeid = ?");
706 393 jones
707
      // Bind the values to the query
708 396 jones
      pstmt.setLong(1, rootnodeid);
709 393 jones
710
      pstmt.execute();
711
      ResultSet rs = pstmt.getResultSet();
712
      boolean tableHasRows = rs.next();
713
      while (tableHasRows) {
714
        nodeid = rs.getLong(1);
715
        parentnodeid = rs.getLong(2);
716
        nodeindex = rs.getLong(3);
717
        nodetype = rs.getString(4);
718
        nodename = rs.getString(5);
719 826 bojilova
        nodeprefix = rs.getString(6);
720
        nodedata = rs.getString(7);
721 393 jones
722
        // add the data to the node record list hashtable
723 826 bojilova
        NodeRecord currentRecord = new NodeRecord(nodeid,parentnodeid,nodeindex,
724
                                       nodetype, nodename, nodeprefix, nodedata);
725 393 jones
        nodeRecordList.add(currentRecord);
726
727
        // Advance to the next node
728
        tableHasRows = rs.next();
729
      }
730
      pstmt.close();
731
732
    } catch (SQLException e) {
733 826 bojilova
      throw new McdbException("Error in DocumentImpl.getNodeRecordList " +
734
                              e.getMessage());
735 393 jones
    }
736
737
    if (nodeRecordList != null) {
738
      return nodeRecordList;
739
    } else {
740
      throw new McdbException("Error getting node data: " + docid);
741
    }
742
  }
743 549 berkley
744 697 bojilova
// NOT USED ANY MORE
745
//  /** creates SQL code and inserts new document into DB connection
746
//   default serverCode of 1*/
747
//  private void writeDocumentToDB(String action, String user)
748
//               throws SQLException, Exception
749
//  {
750
//    writeDocumentToDB(action, user, null, 1);
751
//  }
752 393 jones
753 459 bojilova
 /** creates SQL code and inserts new document into DB connection */
754 680 bojilova
  private void writeDocumentToDB(String action, String user, String pub,
755 697 bojilova
                                 String catalogid, int serverCode)
756 459 bojilova
               throws SQLException, Exception {
757 747 bojilova
758 754 bojilova
    String sysdate = dbAdapter.getDateTimeFunction();
759 747 bojilova
760 459 bojilova
    try {
761
      PreparedStatement pstmt = null;
762
763
      if (action.equals("INSERT")) {
764
        //AccessionNumber ac = new AccessionNumber();
765
        //this.docid = ac.generate(docid, "INSERT");
766
        pstmt = conn.prepareStatement(
767 697 bojilova
                "INSERT INTO xml_documents " +
768
                "(docid, rootnodeid, docname, doctype, " +
769
                "user_owner, user_updated, date_created, date_updated, " +
770
                "public_access, catalog_id, server_location) " +
771 747 bojilova
                "VALUES (?, ?, ?, ?, ?, ?, " + sysdate + ", " + sysdate +
772
                ", ?, ?, ?)");
773 549 berkley
        //note that the server_location is set to 1.
774
        //this means that "localhost" in the xml_replication table must
775
        //always be the first entry!!!!!
776
777 459 bojilova
        // Bind the values to the query
778
        pstmt.setString(1, this.docid);
779
        pstmt.setLong(2, rootnodeid);
780
        pstmt.setString(3, docname);
781
        pstmt.setString(4, doctype);
782
        pstmt.setString(5, user);
783
        pstmt.setString(6, user);
784 680 bojilova
        if ( pub == null ) {
785
          pstmt.setString(7, null);
786 697 bojilova
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
787 680 bojilova
          pstmt.setInt(7, 1);
788 697 bojilova
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
789 680 bojilova
          pstmt.setInt(7, 0);
790
        }
791 697 bojilova
        pstmt.setString(8, catalogid);
792
        pstmt.setInt(9, serverCode);
793 459 bojilova
      } else if (action.equals("UPDATE")) {
794
795
        // Save the old document entry in a backup table
796
        DocumentImpl.archiveDocRevision( conn, docid, user );
797 575 berkley
        DocumentImpl thisdoc = new DocumentImpl(conn, docid);
798
        int thisrev = thisdoc.getRev();
799
        thisrev++;
800 459 bojilova
        // Delete index for the old version of docid
801
        // The new index is inserting on the next calls to DBSAXNode
802
        pstmt = conn.prepareStatement(
803
                "DELETE FROM xml_index WHERE docid='" + this.docid + "'");
804
        pstmt.execute();
805 818 berkley
        pstmt.close();
806 459 bojilova
807
        // Update the new document to reflect the new node tree
808
        pstmt = conn.prepareStatement(
809
            "UPDATE xml_documents " +
810
            "SET rootnodeid = ?, docname = ?, doctype = ?, " +
811 747 bojilova
            "user_updated = ?, date_updated = " + sysdate + ", " +
812 697 bojilova
            "server_location = ?, rev = ?, public_access = ?, catalog_id = ? " +
813 769 bojilova
            "WHERE docid = ?");
814 459 bojilova
        // Bind the values to the query
815
        pstmt.setLong(1, rootnodeid);
816
        pstmt.setString(2, docname);
817
        pstmt.setString(3, doctype);
818
        pstmt.setString(4, user);
819 549 berkley
        pstmt.setInt(5, serverCode);
820 575 berkley
        pstmt.setInt(6, thisrev);
821 680 bojilova
        if ( pub == null ) {
822
          pstmt.setString(7, null);
823 697 bojilova
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
824 680 bojilova
          pstmt .setInt(7, 1);
825 697 bojilova
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
826 680 bojilova
          pstmt.setInt(7, 0);
827
        }
828 697 bojilova
        pstmt.setString(8, catalogid);
829
        pstmt.setString(9, this.docid);
830 575 berkley
831 459 bojilova
      } else {
832
        System.err.println("Action not supported: " + action);
833
      }
834
835
      // Do the insertion
836
      pstmt.execute();
837
      pstmt.close();
838
839
    } catch (SQLException sqle) {
840
      throw sqle;
841
    } catch (Exception e) {
842
      throw e;
843
    }
844
  }
845
846
  /**
847 407 jones
   * Write an XML file to the database, given a filename
848 393 jones
   *
849 408 jones
   * @param conn the JDBC connection to the database
850 407 jones
   * @param filename the filename to be loaded into the database
851 680 bojilova
   * @param pub flag for public "read" access on document
852
   * @param dtdfilename the dtd to be uploaded on server's file system
853 407 jones
   * @param action the action to be performed (INSERT OR UPDATE)
854
   * @param docid the docid to use for the INSERT OR UPDATE
855 680 bojilova
   * @param user the user that owns the document
856 802 bojilova
   * @param groups the groups to which user belongs
857 393 jones
   */
858 598 bojilova
  public static String write(Connection conn,String filename,
859 680 bojilova
                             String pub, String dtdfilename,
860 598 bojilova
                             String action, String docid, String user,
861 802 bojilova
                             String[] groups )
862 457 bojilova
                throws Exception {
863 598 bojilova
864
    Reader dtd = null;
865
    if ( dtdfilename != null ) {
866
      dtd = new FileReader(new File(dtdfilename).toString());
867
    }
868 555 bojilova
    return write ( conn, new FileReader(new File(filename).toString()),
869 802 bojilova
                   pub, dtd, action, docid, user, groups, false);
870 407 jones
  }
871 598 bojilova
872 680 bojilova
  public static String write(Connection conn,Reader xml,String pub,Reader dtd,
873 598 bojilova
                             String action, String docid, String user,
874 802 bojilova
                             String[] groups, boolean validate)
875 549 berkley
                throws Exception {
876 802 bojilova
    return write(conn,xml,pub,dtd,action,docid,user,groups,1,false,validate);
877 598 bojilova
  }
878
879 680 bojilova
  public static String write(Connection conn, Reader xml, String pub,
880 598 bojilova
                             String action, String docid, String user,
881 802 bojilova
                             String[] groups )
882 598 bojilova
                throws Exception {
883 571 berkley
    if(action.equals("UPDATE"))
884
    {//if the document is being updated then use the servercode from the
885
     //originally inserted document.
886
      DocumentImpl doc = new DocumentImpl(conn, docid);
887
      int servercode = doc.getServerlocation();
888 802 bojilova
      return write(conn, xml, pub, action, docid, user, groups, servercode);
889 571 berkley
    }
890
    else
891
    {//if the file is being inserted then the servercode is always 1
892 802 bojilova
      return write(conn, xml, pub, action, docid, user, groups, 1);
893 571 berkley
    }
894 549 berkley
  }
895
896 559 berkley
  public static String write( Connection conn, Reader xml,
897
                              String action, String docid, String user,
898 802 bojilova
                              String[] groups, int serverCode )
899 598 bojilova
                throws Exception
900 559 berkley
  {
901 802 bojilova
    return write(conn,xml,null,action,docid,user,groups,serverCode);
902 559 berkley
  }
903
904 680 bojilova
  public static String write( Connection conn, Reader xml, String pub,
905 577 berkley
                              String action, String docid, String user,
906 802 bojilova
                              String[] groups, int serverCode)
907 598 bojilova
                throws Exception
908 577 berkley
  {
909 802 bojilova
    return write(conn,xml,pub,null,action,docid,user,groups,
910 695 bojilova
                 serverCode,false,false);
911 577 berkley
  }
912
913 680 bojilova
  public static String write( Connection conn, Reader xml, String pub,
914 600 bojilova
                              String action, String docid, String user,
915 802 bojilova
                              String[] groups, int serverCode, boolean override)
916 600 bojilova
                throws Exception
917
  {
918 802 bojilova
    return write(conn,xml,pub,null,action,docid,user,groups,
919 695 bojilova
                 serverCode,override,false);
920 600 bojilova
  }
921
922 407 jones
  /**
923
   * Write an XML file to the database, given a Reader
924
   *
925 408 jones
   * @param conn the JDBC connection to the database
926 407 jones
   * @param xml the xml stream to be loaded into the database
927 680 bojilova
   * @param pub flag for public "read" access on xml document
928
   * @param dtd the dtd to be uploaded on server's file system
929 734 bojilova
   * @param action the action to be performed (INSERT or UPDATE)
930
   * @param accnum the docid + rev# to use on INSERT or UPDATE
931 580 berkley
   * @param user the user that owns the document
932 802 bojilova
   * @param groups the groups to which user belongs
933 580 berkley
   * @param serverCode the serverid from xml_replication on which this document
934
   *        resides.
935
   * @param override flag to stop insert replication checking.
936
   *        if override = true then a document not belonging to the local server
937
   *        will not be checked upon update for a file lock.
938
   *        if override = false then a document not from this server, upon
939
   *        update will be locked and version checked.
940 407 jones
   */
941 559 berkley
942 680 bojilova
  public static String write( Connection conn,Reader xml,String pub,Reader dtd,
943 734 bojilova
                              String action, String accnum, String user,
944 802 bojilova
                              String[] groups, int serverCode, boolean override,
945 695 bojilova
                              boolean validate)
946 598 bojilova
                throws Exception
947 573 berkley
  {
948 779 bojilova
    // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
949
    AccessionNumber ac = new AccessionNumber(conn, accnum, action);
950
    String docid = ac.getDocid();
951
    String rev = ac.getRev();
952
953 590 berkley
    MetaCatUtil.debugMessage("action: " + action + " servercode: " +
954
                             serverCode + " override: " + override);
955 580 berkley
956 577 berkley
    if((serverCode != 1 && action.equals("UPDATE")) && !override)
957 559 berkley
    { //if this document being written is not a resident of this server then
958
      //we need to try to get a lock from it's resident server.  If the
959
      //resident server will not give a lock then we send the user a message
960
      //saying that he/she needs to download a new copy of the file and
961
      //merge the differences manually.
962 567 berkley
      int istreamInt;
963 561 berkley
      char istreamChar;
964 779 bojilova
      DocumentIdentifier id = new DocumentIdentifier(accnum);
965
      String updaterev = id.getRev();
966 561 berkley
      String server = MetacatReplication.getServer(serverCode);
967 734 bojilova
      MetacatReplication.replLog("attempting to lock " + accnum);
968 837 bojilova
      URL u = new URL("https://" + server + "?action=getlock&updaterev=" +
969 779 bojilova
                      updaterev + "&docid=" + docid);
970 574 berkley
      System.out.println("sending message: " + u.toString());
971 569 berkley
      String serverResStr = MetacatReplication.getURLContent(u);
972 567 berkley
      String openingtag = serverResStr.substring(0, serverResStr.indexOf(">")+1);
973 571 berkley
974 561 berkley
      if(openingtag.equals("<lockgranted>"))
975
      {//the lock was granted go ahead with the insert
976 571 berkley
        try
977
        {
978 734 bojilova
          MetacatReplication.replLog("lock granted for " + accnum + " from " +
979 584 berkley
                                      server);
980 734 bojilova
          XMLReader parser = initializeParser(conn, action, docid, validate,
981 802 bojilova
                                              user, groups, pub, serverCode, dtd);
982 571 berkley
          conn.setAutoCommit(false);
983 695 bojilova
          parser.parse(new InputSource(xml));
984 571 berkley
          conn.commit();
985
          conn.setAutoCommit(true);
986
        }
987
        catch (Exception e)
988
        {
989
          conn.rollback();
990
          conn.setAutoCommit(true);
991
          throw e;
992
        }
993
994
        //after inserting the document locally, tell the document's home server
995
        //to come get a copy from here.
996 835 bojilova
        ForceReplicationHandler frh = new ForceReplicationHandler(accnum);
997 590 berkley
998 779 bojilova
        return (accnum);
999 561 berkley
      }
1000 734 bojilova
1001 561 berkley
      else if(openingtag.equals("<filelocked>"))
1002
      {//the file is currently locked by another user
1003
       //notify our user to wait a few minutes, check out a new copy and try
1004
       //again.
1005 584 berkley
        //System.out.println("file locked");
1006 734 bojilova
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1007 584 berkley
                                   server + " reason: file already locked");
1008 571 berkley
        throw new Exception("The file specified is already locked by another " +
1009
                            "user.  Please wait 30 seconds, checkout the " +
1010
                            "newer document, merge your changes and try " +
1011
                            "again.");
1012 561 berkley
      }
1013
      else if(openingtag.equals("<outdatedfile>"))
1014
      {//our file is outdated.  notify our user to check out a new copy of the
1015
       //file and merge his version with the new version.
1016 584 berkley
        //System.out.println("outdated file");
1017 734 bojilova
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1018 584 berkley
                                    server + " reason: local file outdated");
1019 571 berkley
        throw new Exception("The file you are trying to update is an outdated" +
1020
                            " version.  Please checkout the newest document, " +
1021
                            "merge your changes and try again.");
1022 561 berkley
      }
1023 559 berkley
    }
1024 571 berkley
1025 425 bojilova
    if ( action.equals("UPDATE") ) {
1026 441 bojilova
      // check for 'write' permission for 'user' to update this document
1027 628 berkley
1028 802 bojilova
      if ( !hasPermission(conn, user, groups, docid) ) {
1029 441 bojilova
        throw new Exception("User " + user +
1030 734 bojilova
              " does not have permission to update XML Document #" + accnum);
1031 425 bojilova
      }
1032
    }
1033
1034 571 berkley
    try
1035 638 bojilova
    {
1036 734 bojilova
      XMLReader parser = initializeParser(conn, action, docid, validate,
1037 802 bojilova
                                          user, groups, pub, serverCode, dtd);
1038 555 bojilova
      conn.setAutoCommit(false);
1039
      parser.parse(new InputSource(xml));
1040
      conn.commit();
1041
      conn.setAutoCommit(true);
1042 571 berkley
    }
1043
    catch (Exception e)
1044
    {
1045 555 bojilova
      conn.rollback();
1046
      conn.setAutoCommit(true);
1047
      throw e;
1048
    }
1049 577 berkley
1050
    //force replicate out the new document to each server in our server list.
1051
    if(serverCode == 1)
1052 582 berkley
    { //start the thread to replicate this new document out to the other servers
1053 835 bojilova
      ForceReplicationHandler frh = new ForceReplicationHandler(accnum, action);
1054 577 berkley
    }
1055 457 bojilova
1056 779 bojilova
    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
}