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