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