Project

General

Profile

1
/**
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: tao $'
10
 *     '$Date: 2002-06-13 11:54:51 -0700 (Thu, 13 Jun 2002) $'
11
 * '$Revision: 1217 $'
12
 *
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
 */
27

    
28
package edu.ucsb.nceas.metacat;
29

    
30
import java.sql.*;
31
import java.io.File;
32
import java.io.FileReader;
33
import java.io.IOException;
34
import java.io.PrintWriter;
35
import java.io.Reader;
36
import java.io.StringWriter;
37
import java.io.Writer;
38
import java.io.InputStreamReader;
39
import java.io.*;
40
import java.text.SimpleDateFormat;
41

    
42
import java.util.Date;
43
import java.util.Iterator;
44
import java.util.Stack;
45
import java.util.TreeSet;
46
import java.util.Enumeration;
47

    
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
import java.net.URL;
60

    
61
import edu.ucsb.nceas.dbadapter.AbstractDatabase;
62

    
63
/**
64
 * A class that represents an XML document. It can be created with a simple
65
 * document identifier from a database connection.  It also will write an
66
 * XML text document to a database connection using SAX.
67
 */
68
public class DocumentImpl {
69

    
70
  static final int ALL = 1;
71
  static final int WRITE = 2;
72
  static final int READ = 4;
73
  private static final AbstractDatabase dbAdapter = MetaCatUtil.dbAdapter;
74

    
75
  private DBConnection connection = null;
76
  private String docid = null;
77
  private String updatedVersion=null;
78
  private String docname = null;
79
  private String doctype = null;
80
// DOCTITLE attr cleared from the db
81
//  private String doctitle = null;
82
  private String createdate = null;
83
  private String updatedate = null;
84
  private String system_id = null;
85
  private String userowner = null;
86
  private String userupdated = null;
87
  private int rev;
88
  private int serverlocation;
89
  private String docHomeServer;
90
  private String publicaccess; 
91
  private long rootnodeid;
92
  private ElementNode rootNode = null;
93
  private TreeSet nodeRecordList = null;
94
  
95
  /**
96
   * Constructor used to create a document and read the document information
97
   * from the database.  If readNodes is false, then the node data is not 
98
   * read at this time, but is deferred until it is needed (such as when a 
99
   * call to toXml() is made).  
100
   *
101
   * @param conn the database connection from which to read the document
102
   * @param docid the identifier of the document to be created
103
   * @param readNodes flag indicating whether the xmlnodes should be read
104
   */
105
  public DocumentImpl(String docid, boolean readNodes) 
106
         throws McdbException 
107
  {
108
    try {
109
      //this.conn = conn;
110
      this.docid = docid;
111
      
112
      // Look up the document information
113
      getDocumentInfo(docid);
114
      
115
      if (readNodes) {
116
        // Download all of the document nodes using a single SQL query
117
        // The sort order of the records is determined by the NodeComparator
118
        // class, and needs to represent a depth-first traversal for the
119
        // toXml() method to work properly
120
        nodeRecordList = getNodeRecordList(rootnodeid);
121
        
122
      }
123
    
124
    } catch (McdbException ex) {
125
      throw ex;
126
    } catch (Throwable t) {
127
      throw new McdbException("Error reading document from " +
128
                              "DocumentImpl.DocumentImpl: " + docid);
129
    }
130
  }
131

    
132
  /**
133
   * Constructor, creates document from database connection, used 
134
   * for reading the document
135
   *
136
   * @param conn the database connection from which to read the document
137
   * @param docid the identifier of the document to be created
138
   */
139
  public DocumentImpl(String docid) throws McdbException 
140
  {
141
    this(docid, true);
142
  }
143

    
144
  /** 
145
   * Construct a new document instance, writing the contents to the database.
146
   * This method is called from DBSAXHandler because we need to know the
147
   * root element name for documents without a DOCTYPE before creating it.
148
   *
149
   * @param conn the JDBC Connection to which all information is written
150
   * @param rootnodeid - sequence id of the root node in the document
151
   * @param docname - the name of DTD, i.e. the name immediately following 
152
   *        the DOCTYPE keyword ( should be the root element name ) or
153
   *        the root element name if no DOCTYPE declaration provided
154
   *        (Oracle's and IBM parsers are not aware if it is not the 
155
   *        root element name)
156
   * @param doctype - Public ID of the DTD, i.e. the name immediately 
157
   *                  following the PUBLIC keyword in DOCTYPE declaration or
158
   *                  the docname if no Public ID provided or
159
   *                  null if no DOCTYPE declaration provided
160
   * @param docid the docid to use for the INSERT OR UPDATE
161
   * @param action the action to be performed (INSERT OR UPDATE)
162
   * @param user the user that owns the document
163
   * @param pub flag for public "read" access on document
164
   * @param serverCode the serverid from xml_replication on which this document
165
   *        resides.
166
   *
167
   */
168
  /*public DocumentImpl(Connection conn, long rootnodeid, String docname, 
169
                      String doctype, String docid, String action, String user,
170
                      String pub, String catalogid, int serverCode)
171
                      throws SQLException, Exception
172
  {
173
    this.conn = conn;
174
    this.rootnodeid = rootnodeid;
175
    this.docname = docname;
176
    this.doctype = doctype;
177
    this.docid = docid;
178
    writeDocumentToDB(action, user, pub, catalogid, serverCode);
179
  }*/
180
  
181
  /** 
182
   * Construct a new document instance, writing the contents to the database.
183
   * This method is called from DBSAXHandler because we need to know the
184
   * root element name for documents without a DOCTYPE before creating it.
185
   *
186
   * In this constructor, the docid is without rev. There is a string rev to 
187
   * specify the revision user want to upadate. The revion is only need to be
188
   * greater than current one. It is not need to be sequent number just after
189
   * current one. So it is only used in update action
190
   * @param conn the JDBC Connection to which all information is written
191
   * @param rootnodeid - sequence id of the root node in the document
192
   * @param docname - the name of DTD, i.e. the name immediately following 
193
   *        the DOCTYPE keyword ( should be the root element name ) or
194
   *        the root element name if no DOCTYPE declaration provided
195
   *        (Oracle's and IBM parsers are not aware if it is not the 
196
   *        root element name)
197
   * @param doctype - Public ID of the DTD, i.e. the name immediately 
198
   *                  following the PUBLIC keyword in DOCTYPE declaration or
199
   *                  the docname if no Public ID provided or
200
   *                  null if no DOCTYPE declaration provided
201
   * @param docid the docid to use for the UPDATE, no version number
202
   * @param version, need to be update
203
   * @param action the action to be performed (INSERT OR UPDATE)
204
   * @param user the user that owns the document
205
   * @param pub flag for public "read" access on document
206
   * @param serverCode the serverid from xml_replication on which this document
207
   *        resides.
208
   *
209
   */
210
  public DocumentImpl(DBConnection conn, long rootNodeId, String docName, 
211
                      String docType, String docId, String newRevision, 
212
                      String action, String user,
213
                      String pub, String catalogId, int serverCode)
214
                      throws SQLException, Exception
215
  {
216
    this.connection = conn;
217
    this.rootnodeid = rootNodeId;
218
    this.docname = docName;
219
    this.doctype = docType;
220
    this.docid = docId;
221
    this.updatedVersion = newRevision;
222
    writeDocumentToDB(action, user, pub, catalogId, serverCode);
223
  }
224
  
225
  /**
226
   * This method will be call in handleUploadRequest in MetacatServlet class
227
   */
228
  public static void registerDocument(
229
                     String docname, String doctype, String accnum, String user)
230
                     throws SQLException, AccessionNumberException, Exception
231
  {
232
    
233
    try
234
    {
235
       // get server location for this doc
236
      int serverLocation=getServerLocationNumber(accnum);
237
      registerDocument(docname, doctype,accnum, user, serverLocation);
238
    }
239
    catch (Exception e)
240
    {
241
      throw e;
242
    }
243
   
244
    
245
  }
246
  /**
247
   * Register a document that resides on the filesystem with the database.
248
   * (ie, just an entry in xml_documents, nothing in xml_nodes).
249
   * Creates a reference to a filesystem document (used for non-xml data files).
250
   * This class only be called in MetaCatServerlet.
251
   * @param conn the JDBC Connection to which all information is written
252
   * @param docname - the name of DTD, i.e. the name immediately following 
253
   *        the DOCTYPE keyword ( should be the root element name ) or
254
   *        the root element name if no DOCTYPE declaration provided
255
   *        (Oracle's and IBM parsers are not aware if it is not the 
256
   *        root element name)
257
   * @param doctype - Public ID of the DTD, i.e. the name immediately 
258
   *                  following the PUBLIC keyword in DOCTYPE declaration or
259
   *                  the docname if no Public ID provided or
260
   *                  null if no DOCTYPE declaration provided
261
   * @param accnum the accession number to use for the INSERT OR UPDATE, which 
262
   *               includes a revision number for this revision of the document 
263
   *               (e.g., knb.1.1)
264
   * @param user the user that owns the document
265
   * @param serverCode the serverid from xml_replication on which this document
266
   *        resides.
267
   */
268
  public static void registerDocument(
269
                     String docname, String doctype, String accnum, 
270
                     String user, int serverCode)
271
                     throws SQLException, AccessionNumberException, Exception
272
  {
273
    DBConnection dbconn = null;
274
    int serialNumber = -1;
275
    PreparedStatement pstmt = null;
276
    //MetaCatUtil util = new MetaCatUtil();
277
    AccessionNumber ac;
278
    try {
279
      //dbconn = util.openDBConnection();
280
      //check out DBConnection
281
      dbconn=DBConnectionPool.
282
                    getDBConnection("DocumentImpl.registerDocument");
283
      serialNumber=dbconn.getCheckOutSerialNumber();
284
      String docIdWithoutRev=MetaCatUtil.getDocIdFromString(accnum);
285
      int userSpecifyRev=MetaCatUtil.getVersionFromString(accnum);
286
      int revInDataBase=getLatestRevisionNumber(docIdWithoutRev);
287
      //revIndataBase=-1, there is no record in xml_documents table
288
      //the data file is a new one, inert it into table
289
      //user specified rev should be great than 0
290
      if (revInDataBase==-1 && userSpecifyRev>0 )
291
      {
292
        ac = new AccessionNumber(accnum, "insert");
293
      }
294
      //rev is greater the last revsion number and revInDataBase isn't -1
295
      // it is a updated data file
296
      else if (userSpecifyRev>revInDataBase && revInDataBase>0)
297
      {
298
        
299
        //archive the old entry 
300
        archiveDocRevision(docIdWithoutRev, user);
301
        //delete the old entry in xml_documents
302
        deleteXMLDocuments(docIdWithoutRev);
303
        ac = new AccessionNumber(accnum, "update");
304
      }
305
      //other situation
306
      else
307
      {
308
        
309
        throw new Exception("Revision number couldn't be "
310
                    +userSpecifyRev);
311
      }
312
      String docid = ac.getDocid();
313
      String rev = ac.getRev();
314
      SimpleDateFormat formatter = new SimpleDateFormat ("yy-MM-dd HH:mm:ss");
315
      Date localtime = new Date();
316
      String dateString = formatter.format(localtime);
317
  
318
      String sqlDateString = "to_date('" + dateString + 
319
                                          "', 'YY-MM-DD HH24:MI:SS')";
320
  
321
      StringBuffer sql = new StringBuffer();
322
      sql.append("insert into xml_documents (docid, docname, doctype, ");
323
      sql.append("user_owner, user_updated, server_location, rev,date_created");
324
      sql.append(", date_updated, public_access) values ('");
325
      sql.append(docid).append("','");
326
      sql.append(docname).append("','");
327
      sql.append(doctype).append("','");
328
      sql.append(user).append("','");
329
      sql.append(user).append("','");
330
      sql.append(serverCode).append("','");
331
      sql.append(rev).append("',");
332
      sql.append(sqlDateString).append(",");
333
      sql.append(sqlDateString).append(",");
334
      sql.append("'0')");
335
      pstmt = dbconn.prepareStatement(sql.toString());
336
      pstmt.execute();
337
      pstmt.close();
338
      //dbconn.close();
339
    } 
340
    finally 
341
    {
342
      try
343
      {
344
        pstmt.close();
345
      }
346
      finally
347
      {
348
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
349
      }
350
    }    
351
  }
352
  
353
    /**
354
   * Register a document that resides on the filesystem with the database.
355
   * (ie, just an entry in xml_documents, nothing in xml_nodes).
356
   * Creates a reference to a filesystem document (used for non-xml data files)
357
   * This method will be called for register data file in xml_documents in 
358
   * Replication.
359
   * This method is revised from registerDocument.
360
   *
361
   * @param conn the JDBC Connection to which all information is written
362
   * @param docname - the name of DTD, i.e. the name immediately following 
363
   *        the DOCTYPE keyword ( should be the root element name ) or
364
   *        the root element name if no DOCTYPE declaration provided
365
   *        (Oracle's and IBM parsers are not aware if it is not the 
366
   *        root element name)
367
   * @param doctype - Public ID of the DTD, i.e. the name immediately 
368
   *                  following the PUBLIC keyword in DOCTYPE declaration or
369
   *                  the docname if no Public ID provided or
370
   *                  null if no DOCTYPE declaration provided
371
   * @param accnum the accession number to use for the INSERT OR UPDATE, which 
372
   *               includes a revision number for this revision of the document 
373
   *               (e.g., knb.1.1)
374
   * @param user the user that owns the document
375
   * @param serverCode the serverid from xml_replication on which this document
376
   *        resides.
377
   */
378
  public static void registerDocumentInReplication(
379
                     String docname, String doctype, String accnum, 
380
                     String user, int serverCode)
381
                     throws SQLException, AccessionNumberException, Exception
382
  {
383
    DBConnection dbconn = null;
384
    int serialNumber = -1;
385
    //MetaCatUtil util = new MetaCatUtil();
386
    AccessionNumber ac;
387
    PreparedStatement pstmt = null;
388
    try {
389
      //dbconn = util.openDBConnection();
390
       dbconn=DBConnectionPool.
391
                  getDBConnection("DocumentImpl.registerDocumentInReplication");
392
      serialNumber=dbconn.getCheckOutSerialNumber();
393
      String docIdWithoutRev=MetaCatUtil.getDocIdFromString(accnum);
394
      int userSpecifyRev=MetaCatUtil.getVersionFromString(accnum);
395
      int revInDataBase=getLatestRevisionNumber(docIdWithoutRev);
396
      //revIndataBase=-1, there is no record in xml_documents table
397
      //the data file is a new one, inert it into table
398
      //user specified rev should be great than 0
399
      if (revInDataBase==-1 && userSpecifyRev>0 )
400
      {
401
       
402
        ac = new AccessionNumber(accnum, "insert");
403
      }
404
      //rev is greater the last revsion number and revInDataBase isn't -1
405
      // it is a updated data file
406
      else if (userSpecifyRev>revInDataBase && revInDataBase>0)
407
      {
408
        
409
        //archive the old entry 
410
        archiveDocRevision(docIdWithoutRev, user);
411
        //delete the old entry in xml_documents
412
        deleteXMLDocuments(docIdWithoutRev);
413
        ac = new AccessionNumber(accnum, "update");
414
      }
415
      //other situation
416
      else
417
      {
418
        
419
        throw new Exception("Revision number couldn't be "
420
                    +userSpecifyRev);
421
      }
422
      String docid = ac.getDocid();
423
      String rev = ac.getRev();
424
      SimpleDateFormat formatter = new SimpleDateFormat ("yy-MM-dd HH:mm:ss");
425
      Date localtime = new Date();
426
      String dateString = formatter.format(localtime);
427
  
428
      String sqlDateString = "to_date('" + dateString + 
429
                                          "', 'YY-MM-DD HH24:MI:SS')";
430
  
431
      StringBuffer sql = new StringBuffer();
432
      sql.append("insert into xml_documents (docid, docname, doctype, ");
433
      sql.append("user_owner, user_updated, server_location, rev,date_created");
434
      sql.append(", date_updated, public_access) values ('");
435
      sql.append(docid).append("','");
436
      sql.append(docname).append("','");
437
      sql.append(doctype).append("','");
438
      sql.append(user).append("','");
439
      sql.append(user).append("','");
440
      sql.append(serverCode).append("','");
441
      sql.append(rev).append("',");
442
      sql.append(sqlDateString).append(",");
443
      sql.append(sqlDateString).append(",");
444
      sql.append("'0')");
445
      pstmt = dbconn.prepareStatement(sql.toString());
446
      pstmt.execute();
447
      pstmt.close();
448
      //dbconn.close();
449
    } 
450
    finally 
451
    {
452
      pstmt.close();
453
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
454
    }    
455
  }
456
  
457
 /**
458
   * This method will register a data file entry in xml_documents and save a
459
   * data file input Stream into file system.. It is only used in force 
460
   * replication
461
   *
462
   * @param  input, the input stream which contain the file content.
463
   * @param  , the input stream which contain the file content
464
   * @param docname - the name of DTD, for data file, it is a docid number.
465
   * @param doctype - "BIN" for data file
466
   * @param accnum the accession number to use for the INSERT OR UPDATE, which 
467
   *               includes a revision number for this revision of the document 
468
   *               (e.g., knb.1.1)
469
   * @param user the user that owns the document
470
   * @param serverCode the serverid from xml_replication on which this document
471
   *        resides.
472
   */
473
 public static void writeDataFile(InputStream input, String filePath, 
474
                                  String docname, String doctype, String accnum, 
475
                                  String user, String docHomeServer)
476
                     throws SQLException, AccessionNumberException, Exception
477
 {
478
   int serverCode=-2;
479
    if (filePath==null||filePath.equals(""))
480
    {
481
      throw new 
482
            Exception("Please specify the directory where file will be store");
483
    }
484
    if (accnum==null||accnum.equals(""))
485
    {
486
      throw new Exception("Please specify the stored file name");
487
    }
488
    
489
    //get server code for the home server
490
    serverCode=getServerCode(docHomeServer);
491
    //if the server is not in the xml replication table, insert it.
492
    if (serverCode==-1)
493
    {
494
      insertServerIntoReplicationTable(docHomeServer);
495
      //get server code again
496
      serverCode=getServerCode(docHomeServer);
497
    }
498
    
499
    //make sure user have file lock grant(local metacat means have it too)
500
    //if (getDataFileLockGrant(accnum))
501
    //{
502
      //register data file into xml_documents table
503
      registerDocumentInReplication(docname, doctype, accnum, user, serverCode);
504
      //write inputstream into file system.
505
      File dataDirectory = new File(filePath);
506
      File newFile = new File(dataDirectory, accnum); 
507
       
508
      // create a buffered byte output stream
509
      // that uses a default-sized output buffer
510
      FileOutputStream fos = new FileOutputStream(newFile);
511
      BufferedOutputStream outPut = new BufferedOutputStream(fos);
512

    
513
      BufferedInputStream bis = null;
514
      bis = new BufferedInputStream(input);
515
      byte[] buf = new byte[4 * 1024]; // 4K buffer
516
      int b = bis.read(buf);
517
       
518
      while (b != -1) 
519
      {
520
        outPut.write(buf, 0, b);
521
        b = bis.read(buf);
522
      }
523
      bis.close();
524
	    outPut.close();
525
	    fos.close();
526
    
527
    //}//if
528
 }
529
  
530

    
531
  
532
  public static boolean getDataFileLockGrant(String accnum) 
533
                                                  throws Exception
534
  { 
535
    
536
    try
537
    {
538
      
539
      int serverLocation=getServerLocationNumber(accnum);
540
    
541
      return getDataFileLockGrant(accnum,serverLocation);
542
    }
543
    catch (Exception e)
544
    {
545
     
546
      throw e;
547
    }
548
  }
549
    
550
  /**
551
   * The method will check if metacat can get data file lock grant
552
   * If server code is 1, it get.
553
   * If server code is not 1 but call replication getlock successfully,
554
   * it get
555
   * else, it didn't get
556
   * @param accnum, the ID of the document 
557
   * @param action, the action to the document
558
   * @param serverCode, the server location code
559
   */
560
  public static boolean getDataFileLockGrant(String accnum, int serverCode)
561
                                          throws Exception 
562
  {
563
    boolean flag=true;
564
    //MetaCatUtil util = new MetaCatUtil();
565
    String docid = MetaCatUtil.getDocIdFromString(accnum);
566
    int rev = MetaCatUtil.getVersionFromString(accnum);
567
    
568
    if (serverCode == 1)
569
    {
570
      flag=true;
571
      return flag;
572
    }
573
    
574
    //if((serverCode != 1 && action.equals("UPDATE")) )
575
    if (serverCode != 1)
576
    { //if this document being written is not a resident of this server then
577
      //we need to try to get a lock from it's resident server.  If the
578
      //resident server will not give a lock then we send the user a message
579
      //saying that he/she needs to download a new copy of the file and
580
      //merge the differences manually.
581
      
582
      String server = MetacatReplication.getServer(serverCode);
583
      MetacatReplication.replLog("attempting to lock " + accnum);
584
      URL u = new URL("https://" + server + "?server=" +
585
        MetaCatUtil.getLocalReplicationServerName()+"&action=getlock&updaterev=" 
586
           +rev + "&docid=" + docid);
587
      //System.out.println("sending message: " + u.toString());
588
      String serverResStr = MetacatReplication.getURLContent(u);
589
      String openingtag =serverResStr.substring(0, serverResStr.indexOf(">")+1);
590
      if(openingtag.equals("<lockgranted>"))
591
      {
592
        //the lock was granted go ahead with the insert
593
        //System.out.println("In lockgranted");
594
        MetacatReplication.replLog("lock granted for " + accnum + " from " +
595
                                      server);
596
        flag=true;  
597
        return flag;
598
      }//if
599

    
600
      else if(openingtag.equals("<filelocked>"))
601
      {//the file is currently locked by another user
602
       //notify our user to wait a few minutes, check out a new copy and try
603
       //again.
604
        //System.out.println("file locked");
605
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
606
                                   server + " reason: file already locked");
607
        throw new Exception("The file specified is already locked by another " +
608
                            "user.  Please wait 30 seconds, checkout the " +
609
                            "newer document, merge your changes and try " +
610
                            "again.");
611
      }
612
      else if(openingtag.equals("<outdatedfile>"))
613
      {//our file is outdated.  notify our user to check out a new copy of the
614
       //file and merge his version with the new version.
615
        //System.out.println("outdated file");
616
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
617
                                    server + " reason: local file outdated");
618
        throw new Exception("The file you are trying to update is an outdated" +
619
                            " version.  Please checkout the newest document, " +
620
                            "merge your changes and try again.");
621
      }//else if
622
    }//if
623
    
624
   return flag;
625
   
626
  }//getDataFileLockGrant
627
  
628
  /**
629
   * get the document name
630
   */
631
  public String getDocname() {
632
    return docname;
633
  }
634

    
635
  /**
636
   * get the document type (which is the PublicID)
637
   */
638
  public String getDoctype() {
639
    return doctype;
640
  }
641

    
642
  /**
643
   * get the system identifier
644
   */
645
  public String getSystemID() {
646
    return system_id;
647
  }
648

    
649
  /**
650
   * get the root node identifier
651
   */
652
  public long getRootNodeID() {
653
    return rootnodeid;
654
  }
655
  
656
  /**
657
   * get the creation date
658
   */
659
  public String getCreateDate() {
660
    return createdate;
661
  }
662
  
663
  /**
664
   * get the update date
665
   */
666
  public String getUpdateDate() {
667
    return updatedate;
668
  }
669

    
670
  /** 
671
   * Get the document identifier (docid)
672
   */
673
  public String getDocID() {
674
    return docid;
675
  }
676
  
677
// DOCTITLE attr cleared from the db
678
//  /**
679
//   *get the document title
680
//   */
681
//  public String getDocTitle() {
682
//    return doctitle;
683
//  }
684
  
685
  public String getUserowner() {
686
    return userowner;
687
  }
688
  
689
  public String getUserupdated() {
690
    return userupdated;
691
  }
692
  
693
  public int getServerlocation() {
694
    return serverlocation;
695
  }
696
  
697
  public String getDocHomeServer() {
698
    return docHomeServer;
699
  }
700
  
701
 
702
 
703
  public String getPublicaccess() {
704
    return publicaccess;
705
  }
706
  
707
  public int getRev() {
708
    return rev;
709
  }
710
  
711
   /**
712
   * Print a string representation of the XML document
713
   */
714
  public String toString()
715
  {
716
    StringWriter docwriter = new StringWriter();
717
    try {
718
      this.toXml(docwriter);
719
    } catch (McdbException mcdbe) {
720
      return null;
721
    }
722
    String document = docwriter.toString();
723
    return document;
724
  }
725

    
726
  /**
727
   * Get a text representation of the XML document as a string
728
   * This older algorithm uses a recursive tree of Objects to represent the
729
   * nodes of the tree.  Each object is passed the data for the document 
730
   * and searches all of the document data to find its children nodes and
731
   * recursively build.  Thus, because each node reads the whole document,
732
   * this algorithm is extremely slow for larger documents, and the time
733
   * to completion is O(N^N) wrt the number of nodes.  See toXml() for a
734
   * better algorithm.
735
   */
736
  public String readUsingSlowAlgorithm() throws McdbException
737
  {
738
    StringBuffer doc = new StringBuffer();
739

    
740
    // First, check that we have the needed node data, and get it if not
741
    if (nodeRecordList == null) {
742
      nodeRecordList = getNodeRecordList(rootnodeid);
743
    }
744

    
745
    // Create the elements from the downloaded data in the TreeSet
746
    rootNode = new ElementNode(nodeRecordList, rootnodeid);
747

    
748
    // Append the resulting document to the StringBuffer and return it
749
    doc.append("<?xml version=\"1.0\"?>\n");
750
      
751
    if (docname != null) {
752
      if ((doctype != null) && (system_id != null)) {
753
        doc.append("<!DOCTYPE " + docname + " PUBLIC \"" + doctype + 
754
                   "\" \"" + system_id + "\">\n");
755
      } else {
756
        doc.append("<!DOCTYPE " + docname + ">\n");
757
      }
758
    }
759
    doc.append(rootNode.toString());
760
  
761
    return (doc.toString());
762
  }
763

    
764
  /**
765
   * Print a text representation of the XML document to a Writer
766
   *
767
   * @param pw the Writer to which we print the document
768
   */
769
  public void toXml(Writer pw) throws McdbException
770
  {
771
    PrintWriter out = null;
772
    if (pw instanceof PrintWriter) {
773
      out = (PrintWriter)pw;
774
    } else {
775
      out = new PrintWriter(pw);
776
    }
777

    
778
    MetaCatUtil util = new MetaCatUtil();
779
    
780
    // First, check that we have the needed node data, and get it if not
781
    if (nodeRecordList == null) {
782
      nodeRecordList = getNodeRecordList(rootnodeid);
783
    }
784

    
785
    Stack openElements = new Stack();
786
    boolean atRootElement = true;
787
    boolean previousNodeWasElement = false;
788

    
789
    // Step through all of the node records we were given
790
    Iterator it = nodeRecordList.iterator();
791
    while (it.hasNext()) {
792
      NodeRecord currentNode = (NodeRecord)it.next();
793
      //util.debugMessage("[Got Node ID: " + currentNode.nodeid +
794
                          //" (" + currentNode.parentnodeid +
795
                          //", " + currentNode.nodeindex + 
796
                          //", " + currentNode.nodetype + 
797
                          //", " + currentNode.nodename + 
798
                          //", " + currentNode.nodedata + ")]");
799
      // Print the end tag for the previous node if needed
800
      //
801
      // This is determined by inspecting the parent nodeid for the
802
      // currentNode.  If it is the same as the nodeid of the last element
803
      // that was pushed onto the stack, then we are still in that previous
804
      // parent element, and we do nothing.  However, if it differs, then we
805
      // have returned to a level above the previous parent, so we go into
806
      // a loop and pop off nodes and print out their end tags until we get
807
      // the node on the stack to match the currentNode parentnodeid
808
      //
809
      // So, this of course means that we rely on the list of elements
810
      // having been sorted in a depth first traversal of the nodes, which
811
      // is handled by the NodeComparator class used by the TreeSet
812
      if (!atRootElement) {
813
        NodeRecord currentElement = (NodeRecord)openElements.peek();
814
        if ( currentNode.parentnodeid != currentElement.nodeid ) {
815
          while ( currentNode.parentnodeid != currentElement.nodeid ) {
816
            currentElement = (NodeRecord)openElements.pop();
817
            util.debugMessage("\n POPPED: " + currentElement.nodename);
818
            if (previousNodeWasElement) {
819
              out.print(">");
820
              previousNodeWasElement = false;
821
            }  
822
            if ( currentElement.nodeprefix != null ) {
823
              out.print("</" + currentElement.nodeprefix + ":" + 
824
                        currentElement.nodename + ">" );
825
            } else {
826
              out.print("</" + currentElement.nodename + ">" );
827
            }
828
            currentElement = (NodeRecord)openElements.peek();
829
          }
830
        }
831
      }
832

    
833
      // Handle the DOCUMENT node
834
      if (currentNode.nodetype.equals("DOCUMENT")) {
835
        out.println("<?xml version=\"1.0\"?>");
836
      
837
        if (docname != null) {
838
          if ((doctype != null) && (system_id != null)) {
839
            out.println("<!DOCTYPE " + docname + " PUBLIC \"" + doctype + 
840
                       "\" \"" + system_id + "\">");
841
          } else {
842
            out.println("<!DOCTYPE " + docname + ">");
843
          }
844
        }
845

    
846
      // Handle the ELEMENT nodes
847
      } else if (currentNode.nodetype.equals("ELEMENT")) {
848
        if (atRootElement) {
849
          atRootElement = false;
850
        } else {
851
          if (previousNodeWasElement) {
852
            out.print(">");
853
          }
854
        }
855
        openElements.push(currentNode);
856
        util.debugMessage("\n PUSHED: " + currentNode.nodename);
857
        previousNodeWasElement = true;
858
        if ( currentNode.nodeprefix != null ) {
859
          out.print("<" + currentNode.nodeprefix + ":" + currentNode.nodename);
860
        } else {
861
          out.print("<" + currentNode.nodename);
862
        }
863

    
864
      // Handle the ATTRIBUTE nodes
865
      } else if (currentNode.nodetype.equals("ATTRIBUTE")) {
866
        if ( currentNode.nodeprefix != null ) {
867
          out.print(" " + currentNode.nodeprefix + ":" + currentNode.nodename +
868
                    "=\"" + currentNode.nodedata + "\"");
869
        } else {
870
          out.print(" " + currentNode.nodename + "=\"" +
871
                    currentNode.nodedata + "\"");
872
        }
873

    
874
      // Handle the NAMESPACE nodes
875
      } else if (currentNode.nodetype.equals("NAMESPACE")) {
876
        out.print(" xmlns:" + currentNode.nodename + "=\""
877
                 + currentNode.nodedata + "\"");
878

    
879
      // Handle the TEXT nodes
880
      } else if (currentNode.nodetype.equals("TEXT")) {
881
        if (previousNodeWasElement) {
882
          out.print(">");
883
        }
884
        out.print(currentNode.nodedata);
885
        previousNodeWasElement = false;
886

    
887
      // Handle the COMMENT nodes
888
      } else if (currentNode.nodetype.equals("COMMENT")) {
889
        if (previousNodeWasElement) {
890
          out.print(">");
891
        }
892
        out.print("<!--" + currentNode.nodedata + "-->");
893
        previousNodeWasElement = false;
894

    
895
      // Handle the PI nodes
896
      } else if (currentNode.nodetype.equals("PI")) {
897
        if (previousNodeWasElement) {
898
          out.print(">");
899
        }
900
        out.print("<?" + currentNode.nodename + " " +
901
                        currentNode.nodedata + "?>");
902
        previousNodeWasElement = false;
903

    
904
      // Handle any other node type (do nothing)
905
      } else {
906
        // Any other types of nodes are not handled.
907
        // Probably should throw an exception here to indicate this
908
      }
909
      out.flush();
910
    }
911

    
912
    // Print the final end tag for the root element
913
    while(!openElements.empty())
914
    {
915
      NodeRecord currentElement = (NodeRecord)openElements.pop();
916
      util.debugMessage("\n POPPED: " + currentElement.nodename);
917
      if ( currentElement.nodeprefix != null ) {
918
        out.print("</" + currentElement.nodeprefix + ":" + 
919
                  currentElement.nodename + ">" );
920
      } else {
921
        out.print("</" + currentElement.nodename + ">" );
922
      }
923
    }
924
    out.flush();
925
  }
926
  
927
  private boolean isRevisionOnly(DocumentIdentifier docid) throws Exception
928
  {
929
    //System.out.println("inRevisionOnly");
930
    DBConnection dbconn = null;
931
    int serialNumber = -1;
932
    PreparedStatement pstmt =null;
933
    String rev = docid.getRev();
934
    String newid = docid.getIdentifier();
935
    try
936
    {
937
      dbconn=DBConnectionPool.
938
                    getDBConnection("DocumentImpl.isRevisionOnly");
939
      serialNumber=dbconn.getCheckOutSerialNumber();
940
      pstmt = dbconn.prepareStatement("select rev from xml_documents " +
941
                                  "where docid like '" + newid + "'");
942
      pstmt.execute();
943
      ResultSet rs = pstmt.getResultSet();
944
      boolean tablehasrows = rs.next();
945
      if(rev.equals("newest") || rev.equals("all"))
946
      {
947
        return false;
948
      }
949
    
950
      if(tablehasrows)
951
      {
952
        int r = rs.getInt(1);
953
        pstmt.close();
954
        if(new Integer(rev).intValue() == r)
955
        { //the current revision in in xml_documents
956
          //System.out.println("returning false");
957
          return false;
958
        }
959
        else if(new Integer(rev).intValue() < r)
960
        { //the current revision is in xml_revisions.
961
          //System.out.println("returning true");
962
          return true;
963
        }
964
        else if(new Integer(rev).intValue() > r)
965
        { //error, rev cannot be greater than r
966
          throw new Exception("requested revision cannot be greater than " +
967
                            "the latest revision number.");
968
        }
969
      }
970
      throw new Exception("the requested docid '" + docid.toString() + 
971
                        "' does not exist");
972
    }//try
973
    finally
974
    {
975
      pstmt.close();
976
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
977
    }//finally
978
  }
979

    
980
  private void getDocumentInfo(String docid) throws McdbException, 
981
                                                    AccessionNumberException
982
  {
983
    getDocumentInfo(new DocumentIdentifier(docid));
984
  }
985
  
986
  /**
987
   * Look up the document type information from the database
988
   *
989
   * @param docid the id of the document to look up
990
   */
991
  private void getDocumentInfo(DocumentIdentifier docid) throws McdbException 
992
  {
993
    DBConnection dbconn = null;
994
    int serialNumber = -1;
995
    PreparedStatement pstmt = null;
996
    String table = "xml_documents";
997
        
998
    try
999
    {
1000
      if(isRevisionOnly(docid))
1001
      { //pull the document from xml_revisions instead of from xml_documents;
1002
        table = "xml_revisions";
1003
      }
1004
    }
1005
    catch(Exception e)
1006
    {
1007
      System.out.println("error in DocumentImpl.getDocumentInfo: " + 
1008
                          e.getMessage());
1009
    }
1010
    
1011
    //deal with the key words here.
1012
    
1013
    if(docid.getRev().equals("all"))
1014
    {
1015
      
1016
    }
1017
    
1018
    try 
1019
    {
1020
      dbconn=DBConnectionPool.getDBConnection("DocumentImpl.getDocumentInfo");
1021
      serialNumber=dbconn.getCheckOutSerialNumber();
1022
      StringBuffer sql = new StringBuffer();
1023
// DOCTITLE attr cleared from the db
1024
//      sql.append("SELECT docname, doctype, rootnodeid, doctitle, ");
1025
      sql.append("SELECT docname, doctype, rootnodeid, ");
1026
      sql.append("date_created, date_updated, user_owner, user_updated, ");
1027
      sql.append("server_location, public_access, rev");
1028
      sql.append(" FROM ").append(table);
1029
      sql.append(" WHERE docid LIKE '").append(docid.getIdentifier());
1030
      sql.append("' and rev like '").append(docid.getRev()).append("'");
1031
      //System.out.println(sql.toString());
1032
      pstmt =
1033
        dbconn.prepareStatement(sql.toString());
1034
      // Bind the values to the query
1035
      //pstmt.setString(1, docid.getIdentifier());
1036
      //pstmt.setString(2, docid.getRev());
1037

    
1038
      pstmt.execute();
1039
      ResultSet rs = pstmt.getResultSet();
1040
      boolean tableHasRows = rs.next();
1041
      if (tableHasRows) {
1042
        this.docname        = rs.getString(1);
1043
        this.doctype        = rs.getString(2);
1044
        this.rootnodeid     = rs.getLong(3);
1045
// DOCTITLE attr cleared from the db
1046
//        this.doctitle       = rs.getString(4);
1047
        this.createdate     = rs.getString(4);
1048
        this.updatedate     = rs.getString(5);
1049
        this.userowner      = rs.getString(6);
1050
        this.userupdated    = rs.getString(7);
1051
        this.serverlocation = rs.getInt(8);
1052
        this.publicaccess   = rs.getString(9);
1053
        this.rev            = rs.getInt(10);
1054
      } 
1055
      pstmt.close();
1056
      
1057
      //get doc  home server name
1058
      
1059
      pstmt = dbconn.prepareStatement("select server " +
1060
                        "from xml_replication where serverid = ?");
1061
      //because connection use twise here, so we need to increase one
1062
      dbconn.increaseUsageCount(1);
1063
      pstmt.setInt(1, serverlocation);
1064
      pstmt.execute();
1065
      rs = pstmt.getResultSet();
1066
      tableHasRows = rs.next();
1067
      if (tableHasRows)
1068
      {
1069
        
1070
          String server = rs.getString(1);
1071
          //get homeserver name
1072
          if(!server.equals("localhost"))
1073
          {
1074
            this.docHomeServer=server;
1075
          }
1076
          else
1077
          {
1078
            this.docHomeServer=MetaCatUtil.getLocalReplicationServerName();
1079
          }
1080
          MetaCatUtil.debugMessage("server: "+docHomeServer, 50);
1081
        
1082
      }
1083
      pstmt.close();
1084
      if (this.doctype != null) {
1085
        pstmt =
1086
          dbconn.prepareStatement("SELECT system_id " +
1087
                                  "FROM xml_catalog " +
1088
                                 "WHERE public_id = ?");
1089
        //should increase usage count again
1090
        dbconn.increaseUsageCount(1);
1091
        // Bind the values to the query
1092
        pstmt.setString(1, doctype);
1093
  
1094
        pstmt.execute();
1095
        rs = pstmt.getResultSet();
1096
        tableHasRows = rs.next();
1097
        if (tableHasRows) {
1098
          this.system_id  = rs.getString(1);
1099
        } 
1100
        pstmt.close();
1101
      }
1102
    } catch (SQLException e) {
1103
      System.out.println("error in DocumentImpl.getDocumentInfo: " + 
1104
                          e.getMessage());
1105
      e.printStackTrace(System.out);
1106
      throw new McdbException("Error accessing database connection in " +
1107
                              "DocumentImpl.getDocumentInfo: ", e);
1108
    }
1109
    finally
1110
    {
1111
      try
1112
      {
1113
        pstmt.close();
1114
      }
1115
      catch (SQLException ee)
1116
      {
1117
        MetaCatUtil.debugMessage("error in DocumentImple.getDocumentInfo: "
1118
                                    +ee.getMessage(), 30);
1119
      }//catch
1120
      finally
1121
      {
1122
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1123
      }
1124
    }
1125

    
1126
    if (this.docname == null) {
1127
      throw new McdbDocNotFoundException("Document not found: " + docid);
1128
    }
1129
  }
1130

    
1131
  /**
1132
   * Look up the node data from the database
1133
   *
1134
   * @param rootnodeid the id of the root node of the node tree to look up
1135
   */
1136
  private TreeSet getNodeRecordList(long rootnodeid) throws McdbException
1137
  {
1138
    PreparedStatement pstmt = null;
1139
    DBConnection dbconn = null;
1140
    int serialNumber = -1;
1141
    TreeSet nodeRecordList = new TreeSet(new NodeComparator());
1142
    long nodeid = 0;
1143
    long parentnodeid = 0;
1144
    long nodeindex = 0;
1145
    String nodetype = null;
1146
    String nodename = null;
1147
    String nodeprefix = null;
1148
    String nodedata = null;
1149
    String quotechar = dbAdapter.getStringDelimiter();
1150

    
1151
    try {
1152
      dbconn=DBConnectionPool.
1153
                    getDBConnection("DocumentImpl.getNodeRecordList");
1154
      serialNumber=dbconn.getCheckOutSerialNumber();
1155
      pstmt =
1156
      dbconn.prepareStatement("SELECT nodeid,parentnodeid,nodeindex, " +
1157
           "nodetype,nodename,nodeprefix,nodedata " +               
1158
           "FROM xml_nodes WHERE rootnodeid = ?");
1159

    
1160
      // Bind the values to the query
1161
      pstmt.setLong(1, rootnodeid);
1162

    
1163
      pstmt.execute();
1164
      ResultSet rs = pstmt.getResultSet();
1165
      boolean tableHasRows = rs.next();
1166
      while (tableHasRows) {
1167
        nodeid = rs.getLong(1);
1168
        parentnodeid = rs.getLong(2);
1169
        nodeindex = rs.getLong(3);
1170
        nodetype = rs.getString(4);
1171
        nodename = rs.getString(5);
1172
        nodeprefix = rs.getString(6);
1173
        nodedata = rs.getString(7);
1174
        nodedata = MetaCatUtil.normalize(nodedata);
1175
        // add the data to the node record list hashtable
1176
        NodeRecord currentRecord = new NodeRecord(nodeid,parentnodeid,nodeindex,
1177
                                      nodetype, nodename, nodeprefix, nodedata);
1178
        nodeRecordList.add(currentRecord);
1179

    
1180
        // Advance to the next node
1181
        tableHasRows = rs.next();
1182
      } 
1183
      pstmt.close();
1184

    
1185
    } catch (SQLException e) {
1186
      throw new McdbException("Error in DocumentImpl.getNodeRecordList " +
1187
                              e.getMessage());
1188
    }
1189
    finally
1190
    {
1191
      try
1192
      {
1193
        pstmt.close();
1194
      }
1195
      catch (SQLException ee)
1196
      {
1197
        MetaCatUtil.debugMessage("error in DocumentImpl.getNodeRecordList: "
1198
                                    +ee.getMessage(), 30);
1199
      }
1200
      finally
1201
      {
1202
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1203
      }
1204
    }
1205
      
1206

    
1207
    if (nodeRecordList != null) {
1208
      return nodeRecordList;
1209
    } else {
1210
      throw new McdbException("Error getting node data: " + docid);
1211
    }
1212
  }
1213
  
1214
// NOT USED ANY MORE
1215
//  /** creates SQL code and inserts new document into DB connection 
1216
//   default serverCode of 1*/
1217
//  private void writeDocumentToDB(String action, String user)
1218
//               throws SQLException, Exception
1219
//  {
1220
//    writeDocumentToDB(action, user, null, 1);
1221
//  }
1222

    
1223
 /** creates SQL code and inserts new document into DB connection */
1224
  private void writeDocumentToDB(String action, String user, String pub, 
1225
                                 String catalogid, int serverCode) 
1226
               throws SQLException, Exception {
1227
    String sysdate = dbAdapter.getDateTimeFunction();
1228

    
1229
    try {
1230
      PreparedStatement pstmt = null;
1231

    
1232
      if (action.equals("INSERT")) {
1233
        //AccessionNumber ac = new AccessionNumber();
1234
        //this.docid = ac.generate(docid, "INSERT");
1235
        
1236
        pstmt = connection.prepareStatement(
1237
                "INSERT INTO xml_documents " +
1238
                "(docid, rootnodeid, docname, doctype, " + 
1239
                "user_owner, user_updated, date_created, date_updated, " + 
1240
                "public_access, catalog_id, server_location, rev) " +
1241
                "VALUES (?, ?, ?, ?, ?, ?, " + sysdate + ", " + sysdate + 
1242
                ", ?, ?, ?, ?)");
1243
        // Increase dbconnection usage count
1244
        connection.increaseUsageCount(1);
1245
        
1246
        //note that the server_location is set to 1. 
1247
        //this means that "localhost" in the xml_replication table must
1248
        //always be the first entry!!!!!
1249
        
1250
        // Bind the values to the query
1251
        pstmt.setString(1, this.docid);
1252
        pstmt.setLong(2, rootnodeid);
1253
        pstmt.setString(3, docname);
1254
        pstmt.setString(4, doctype);
1255
        pstmt.setString(5, user);
1256
        pstmt.setString(6, user);
1257
        //public access is usefulless, so set it to null
1258
        pstmt.setString(7, null);
1259
        /*if ( pub == null ) {
1260
          pstmt.setString(7, null);
1261
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
1262
          pstmt.setInt(7, 1);
1263
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
1264
          pstmt.setInt(7, 0);
1265
        }*/
1266
        pstmt.setString(8, catalogid);
1267
        pstmt.setInt(9, serverCode);
1268
        pstmt.setInt(10, Integer.parseInt(updatedVersion)); 
1269
      } else if (action.equals("UPDATE")) {
1270

    
1271
        // Save the old document publicaccessentry in a backup table
1272
        DocumentImpl.archiveDocRevision(connection, docid, user );
1273
        DocumentImpl thisdoc = new DocumentImpl(docid);
1274
        int thisrev = thisdoc.getRev();
1275
        
1276
        //if the updated vesion is not greater than current one,
1277
        //throw it into a exception
1278
        if (Integer.parseInt(updatedVersion)<=thisrev)
1279
        {
1280
          throw new Exception("Next revision number couldn't be less"
1281
                               +" than or equal "+ thisrev);
1282
        }
1283
        else
1284
        {
1285
          //set the user specified revision 
1286
          thisrev=Integer.parseInt(updatedVersion);
1287
        }
1288
        
1289
        // Delete index for the old version of docid
1290
        // The new index is inserting on the next calls to DBSAXNode
1291
        pstmt = connection.prepareStatement(
1292
                "DELETE FROM xml_index WHERE docid='" + this.docid + "'");
1293
        // Increase dbconnection usage count
1294
        connection.increaseUsageCount(1);
1295
        
1296
        pstmt.execute();
1297
        pstmt.close();
1298

    
1299
        // Update the new document to reflect the new node tree
1300
        pstmt = connection.prepareStatement(
1301
            "UPDATE xml_documents " +
1302
            "SET rootnodeid = ?, docname = ?, doctype = ?, " +
1303
            "user_updated = ?, date_updated = " + sysdate + ", " +
1304
            "server_location = ?, rev = ?, public_access = ?, catalog_id = ? " +
1305
            "WHERE docid = ?");
1306
        // Increase dbconnection usage count
1307
        connection.increaseUsageCount(1);
1308
        // Bind the values to the query
1309
        pstmt.setLong(1, rootnodeid);
1310
        pstmt.setString(2, docname);
1311
        pstmt.setString(3, doctype);
1312
        pstmt.setString(4, user);
1313
        pstmt.setInt(5, serverCode);
1314
        pstmt.setInt(6, thisrev);
1315
        pstmt.setString(7, null);
1316
        /*if ( pub == null ) {
1317
          pstmt.setString(7, null);
1318
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
1319
          pstmt .setInt(7, 1);
1320
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
1321
          pstmt.setInt(7, 0);
1322
        }*/
1323
        pstmt.setString(8, catalogid);
1324
        pstmt.setString(9, this.docid);
1325

    
1326
      } else {
1327
        System.err.println("Action not supported: " + action);
1328
      }
1329

    
1330
      // Do the insertion
1331
      pstmt.execute();
1332
      
1333
      pstmt.close();
1334

    
1335
    } catch (SQLException sqle) {
1336
      throw sqle;
1337
    } catch (Exception e) {
1338
      throw e;
1339
    }
1340
  }
1341

    
1342
  /**
1343
   * Write an XML file to the database, given a filename
1344
   *
1345
   * @param conn the JDBC connection to the database
1346
   * @param filename the filename to be loaded into the database
1347
   * @param pub flag for public "read" access on document
1348
   * @param dtdfilename the dtd to be uploaded on server's file system
1349
   * @param action the action to be performed (INSERT OR UPDATE)
1350
   * @param docid the docid to use for the INSERT OR UPDATE
1351
   * @param user the user that owns the document
1352
   * @param groups the groups to which user belongs
1353
   */
1354
  public static String write(DBConnection conn,String filename,
1355
                             String pub, String dtdfilename,
1356
                             String action, String docid, String user,
1357
                             String[] groups )
1358
                throws Exception {
1359
                  
1360
    Reader dtd = null;
1361
    if ( dtdfilename != null ) {
1362
      dtd = new FileReader(new File(dtdfilename).toString());
1363
    }
1364
    return write ( conn, new FileReader(new File(filename).toString()),
1365
                   pub, dtd, action, docid, user, groups, false);
1366
  }
1367

    
1368
  public static String write(DBConnection conn,Reader xml,String pub,Reader dtd,
1369
                             String action, String docid, String user,
1370
                             String[] groups, boolean validate)
1371
                throws Exception {
1372
    //this method will be called in handleUpdateOrInsert method 
1373
    //in MetacatServlet class
1374
    // get server location for this doc
1375
    int serverLocation=getServerLocationNumber(docid);
1376
    //System.out.println("server location: "+serverLocation);
1377
    return write(conn,xml,pub,dtd,action,docid,user,groups,serverLocation,false,
1378
                 validate);
1379
  }
1380

    
1381
  public static String write(DBConnection conn, Reader xml, String pub,
1382
                             String action, String docid, String user,
1383
                             String[] groups )
1384
                throws Exception {
1385
    if(action.equals("UPDATE"))
1386
    {//if the document is being updated then use the servercode from the 
1387
     //originally inserted document.
1388
      DocumentImpl doc = new DocumentImpl(docid);
1389
      int servercode = doc.getServerlocation();
1390
      return write(conn, xml, pub, action, docid, user, groups, servercode);
1391
    }
1392
    else
1393
    {//if the file is being inserted then the servercode is always 1
1394
      return write(conn, xml, pub, action, docid, user, groups, 1);
1395
    }
1396
  }
1397
  
1398
  public static String write(DBConnection conn, Reader xml,
1399
                              String action, String docid, String user,
1400
                              String[] groups, int serverCode )
1401
                throws Exception
1402
  {
1403
    return write(conn,xml,null,action,docid,user,groups,serverCode);
1404
  }
1405
  
1406
  public static String write(DBConnection conn, Reader xml, String pub,
1407
                              String action, String docid, String user,
1408
                              String[] groups, int serverCode) 
1409
                throws Exception
1410
  {
1411
    return write(conn,xml,pub,null,action,docid,user,groups,
1412
                 serverCode,false,false);
1413
  }
1414
  
1415
  public static String write(DBConnection conn, Reader xml, String pub,
1416
                              String action, String docid, String user,
1417
                              String[] groups, int serverCode, boolean override)
1418
                throws Exception
1419
  {
1420
    return write(conn,xml,pub,null,action,docid,user,groups,
1421
                 serverCode,override,false);
1422
  }
1423
  
1424
  /**
1425
   * Write an XML file to the database, given a Reader
1426
   *
1427
   * @param conn the JDBC connection to the database
1428
   * @param xml the xml stream to be loaded into the database
1429
   * @param pub flag for public "read" access on xml document
1430
   * @param dtd the dtd to be uploaded on server's file system
1431
   * @param action the action to be performed (INSERT or UPDATE)
1432
   * @param accnum the docid + rev# to use on INSERT or UPDATE
1433
   * @param user the user that owns the document
1434
   * @param groups the groups to which user belongs
1435
   * @param serverCode the serverid from xml_replication on which this document
1436
   *        resides.
1437
   * @param override flag to stop insert replication checking.
1438
   *        if override = true then a document not belonging to the local server
1439
   *        will not be checked upon update for a file lock.
1440
   *        if override = false then a document not from this server, upon 
1441
   *        update will be locked and version checked.
1442
   */
1443

    
1444
  public static String write(DBConnection conn, Reader xml,String pub,
1445
                         Reader dtd, String action, String accnum, String user,
1446
                         String[] groups, int serverCode, boolean override,
1447
                         boolean validate)
1448
                throws Exception
1449
  {
1450
    // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1451
    //MetaCatUtil util = new MetaCatUtil();
1452
    MetaCatUtil.debugMessage("conn usage count before writting: "
1453
                                      +conn.getUsageCount(), 50);
1454
    AccessionNumber ac = new AccessionNumber(accnum, action);
1455
    String docid = ac.getDocid();
1456
    String rev = ac.getRev();
1457
    MetaCatUtil.debugMessage("action: " + action + " servercode: " + 
1458
                             serverCode + " override: " + override, 10);
1459
                        
1460
    if((serverCode != 1 && action.equals("UPDATE")) && !override)
1461
    { //if this document being written is not a resident of this server then
1462
      //we need to try to get a lock from it's resident server.  If the
1463
      //resident server will not give a lock then we send the user a message
1464
      //saying that he/she needs to download a new copy of the file and
1465
      //merge the differences manually.
1466
      int istreamInt; 
1467
      char istreamChar;
1468
     
1469
      // check for 'write' permission for 'user' to update this document
1470
      if ( !hasPermission(user, groups, docid) ) {
1471
        throw new Exception("User " + user + 
1472
              " does not have permission to update XML Document #" + accnum);
1473
      }        
1474
  
1475
      DocumentIdentifier id = new DocumentIdentifier(accnum);
1476
      String updaterev = id.getRev();
1477
      String server = MetacatReplication.getServer(serverCode);
1478
      MetacatReplication.replLog("attempting to lock " + accnum);
1479
      URL u = new URL("https://" + server + "?server="+
1480
        MetaCatUtil.getLocalReplicationServerName()+"&action=getlock&updaterev=" 
1481
           +updaterev + "&docid=" + docid);
1482
      //System.out.println("sending message: " + u.toString());
1483
      String serverResStr = MetacatReplication.getURLContent(u);
1484
      String openingtag =serverResStr.substring(0, serverResStr.indexOf(">")+1);
1485
      if(openingtag.equals("<lockgranted>"))
1486
      {//the lock was granted go ahead with the insert
1487
        try 
1488
        {
1489
          //System.out.println("In lockgranted");
1490
          MetacatReplication.replLog("lock granted for " + accnum + " from " +
1491
                                      server);
1492
          XMLReader parser = initializeParser(conn, action, docid, updaterev,
1493
                                  validate, user, groups, pub, serverCode, dtd);
1494
          conn.setAutoCommit(false);
1495
          parser.parse(new InputSource(xml)); 
1496
          conn.commit();
1497
          conn.setAutoCommit(true);
1498
        } 
1499
        catch (Exception e) 
1500
        {
1501
          conn.rollback();
1502
          conn.setAutoCommit(true);
1503
          throw e;
1504
        }
1505
                
1506
        
1507
        
1508
        //If Metacat is super hub, tell all servers in its server list to get 
1509
        //the new document, ture mean it is xml document
1510
        if ((MetaCatUtil.getOption("hub")).equals("super"))
1511
        {
1512
          ForceReplicationHandler frh = new ForceReplicationHandler(accnum, 
1513
                true, ReplicationHandler.buildServerList());
1514
        }
1515
        else
1516
        {
1517
          //after inserting the document locally, tell the document's homeserver
1518
          //to come get a copy from here.
1519
         
1520
          ForceReplicationHandler frh = new ForceReplicationHandler(accnum, 
1521
                true, ReplicationHandler.getHomeServer(docid));
1522
        }
1523
        return (accnum);
1524
      }
1525

    
1526
      else if(openingtag.equals("<filelocked>"))
1527
      {//the file is currently locked by another user
1528
       //notify our user to wait a few minutes, check out a new copy and try
1529
       //again.
1530
        //System.out.println("file locked");
1531
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1532
                                   server + " reason: file already locked");
1533
        throw new Exception("The file specified is already locked by another " +
1534
                            "user.  Please wait 30 seconds, checkout the " +
1535
                            "newer document, merge your changes and try " +
1536
                            "again.");
1537
      }
1538
      else if(openingtag.equals("<outdatedfile>"))
1539
      {//our file is outdated.  notify our user to check out a new copy of the
1540
       //file and merge his version with the new version.
1541
        //System.out.println("outdated file");
1542
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1543
                                    server + " reason: local file outdated");
1544
        throw new Exception("The file you are trying to update is an outdated" +
1545
                            " version.  Please checkout the newest document, " +
1546
                            "merge your changes and try again.");
1547
      }
1548
    }
1549
    
1550
    if ( action.equals("UPDATE") ) {
1551
      // check for 'write' permission for 'user' to update this document
1552

    
1553
      if ( !hasPermission(user, groups, docid) ) {
1554
        throw new Exception("User " + user + 
1555
              " does not have permission to update XML Document #" + accnum);
1556
      }          
1557
    }
1558

    
1559
    try 
1560
    { 
1561
      
1562
      XMLReader parser = initializeParser(conn, action, docid, rev, validate,
1563
                                          user, groups, pub, serverCode, dtd);
1564
   
1565
      conn.setAutoCommit(false);
1566
      parser.parse(new InputSource(xml));
1567
      conn.commit();
1568
      conn.setAutoCommit(true);
1569
    } 
1570
    catch (Exception e) 
1571
    {
1572
      conn.rollback();
1573
      conn.setAutoCommit(true);
1574
      throw e;
1575
    }
1576
    
1577
    //force replicate out the new document to each server in our server list.
1578
    if(serverCode == 1)
1579
    { 
1580
      
1581
      //start the thread to replicate this new document out to the other servers
1582
      //true mean it is xml document
1583
      ForceReplicationHandler frh = new ForceReplicationHandler
1584
                (accnum, action, true,ReplicationHandler.buildServerList());
1585
      
1586
    }
1587
    MetaCatUtil.debugMessage("Conn Usage count after writting: "
1588
                                                      +conn.getUsageCount(),50); 
1589
    return(accnum);
1590
  }
1591

    
1592
  /**
1593
   * Write an XML file to the database during replication
1594
   *
1595
   * @param conn the JDBC connection to the database
1596
   * @param xml the xml stream to be loaded into the database
1597
   * @param pub flag for public "read" access on xml document
1598
   * @param dtd the dtd to be uploaded on server's file system
1599
   * @param action the action to be performed (INSERT or UPDATE)
1600
   * @param accnum the docid + rev# to use on INSERT or UPDATE
1601
   * @param user the user that owns the document
1602
   * @param groups the groups to which user belongs
1603
   * @param homeServer the name of server which the document origanlly create
1604
   * @param validate, if the xml document is valid or not
1605
   */
1606

    
1607
  public static String writeReplication(DBConnection conn, Reader xml, 
1608
            String pub, Reader dtd, String action, String accnum, String user,
1609
            String[] groups,String homeServer, boolean validate)
1610
                throws Exception
1611
  {
1612
   
1613
    String docid=MetaCatUtil.getDocIdFromString(accnum);
1614
    String rev=(new Integer(MetaCatUtil.getVersionFromString(accnum))).
1615
                                                                    toString();
1616
    
1617
    //check if xml_documents table has the document or not
1618
    //if not, set action to insert
1619
    if (getLatestRevisionNumber(docid)==-1)
1620
    {
1621
      action="INSERT";
1622
    }
1623
    
1624
    int serverCode=-2;
1625
    //get server code for the home server
1626
    serverCode=getServerCode(homeServer);
1627
    //if the server is not in the xml replication table, insert it.
1628
    if (serverCode==-1)
1629
    {
1630
      insertServerIntoReplicationTable(homeServer);
1631
      //get server code again
1632
      serverCode=getServerCode(homeServer);
1633
    }
1634
      
1635
    MetaCatUtil.debugMessage("action: " + action + " servercode: " + 
1636
                             serverCode, 10);
1637
                        
1638
  
1639

    
1640
    try 
1641
    { 
1642
      
1643
      XMLReader parser = initializeParser(conn, action, docid, rev, validate,
1644
                                          user, groups, pub, serverCode, dtd);
1645
      conn.setAutoCommit(false);
1646
      parser.parse(new InputSource(xml));
1647
      conn.commit();
1648
      conn.setAutoCommit(true);
1649
    } 
1650
    catch (Exception e) 
1651
    {
1652
      conn.rollback();
1653
      conn.setAutoCommit(true);
1654
      throw e;
1655
    }
1656

    
1657
    return(accnum);
1658
  }
1659

    
1660
  
1661
  /**
1662
   * Delete an XML file from the database (actually, just make it a revision
1663
   * in the xml_revisions table)
1664
   *
1665
   * @param docid the ID of the document to be deleted from the database
1666
   */
1667
  public static void delete(String accnum,
1668
                                 String user, String[] groups )
1669
                throws Exception 
1670
  {
1671
    // OLD
1672
    //DocumentIdentifier id = new DocumentIdentifier(accnum);
1673
    //String docid = id.getIdentifier();
1674
    //String rev = id.getRev();
1675
    
1676
    // OLD
1677
    // Determine if the docid,rev are OK for DELETE
1678
    //AccessionNumber ac = new AccessionNumber(conn);
1679
    //docid = ac.generate(docid, rev, "DELETE");
1680
    DBConnection conn = null;
1681
    int serialNumber = -1;
1682
    PreparedStatement pstmt =null;
1683
    try
1684
    {
1685
      //check out DBConnection
1686
      conn=DBConnectionPool.
1687
                    getDBConnection("DocumentImpl.delete");
1688
      serialNumber=conn.getCheckOutSerialNumber();
1689

    
1690
      // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1691
      AccessionNumber ac = new AccessionNumber(accnum, "DELETE");
1692
      String docid = ac.getDocid();
1693
      String rev = ac.getRev();
1694
    
1695

    
1696
    // check for 'write' permission for 'user' to delete this document
1697
      if ( !hasPermission(user, groups, docid) ) {
1698
        throw new Exception("User " + user + 
1699
              " does not have permission to delete XML Document #" + accnum);
1700
      }
1701

    
1702
      conn.setAutoCommit(false);
1703
      // Copy the record to the xml_revisions table
1704
      DocumentImpl.archiveDocRevision(conn, docid, user );
1705

    
1706
      // Now delete it from the xml_index table
1707
      pstmt = conn.prepareStatement("DELETE FROM xml_index WHERE docid = ?");
1708
      pstmt.setString(1,docid);
1709
      pstmt.execute();
1710
      pstmt.close();
1711
      conn.increaseUsageCount(1);
1712
      
1713
      //stmt.execute("DELETE FROM xml_access WHERE docid = '" + docid + "'");
1714
      // Now delete it from xml_access table
1715
      pstmt = conn.
1716
              prepareStatement("DELETE FROM xml_access WHERE accessfileid = ?");
1717
      pstmt.setString(1, docid);
1718
      pstmt.execute();
1719
      pstmt.close();
1720
      conn.increaseUsageCount(1);
1721
      
1722
      // Delete it from relation table
1723
      pstmt = conn.
1724
               prepareStatement("DELETE FROM xml_relation WHERE docid = ?");
1725
      //increase usage count
1726
      conn.increaseUsageCount(1);
1727
      pstmt.setString(1, docid);
1728
      pstmt.execute();
1729
      pstmt.close();
1730
      
1731
      // Delete it from xml_doucments table
1732
      pstmt =conn.prepareStatement("DELETE FROM xml_documents WHERE docid = ?");
1733
      pstmt.setString(1, docid);
1734
      pstmt.execute();
1735
      pstmt.close();
1736
      //Usaga count increase 1
1737
      conn.increaseUsageCount(1);
1738
      
1739
      conn.commit();
1740
      conn.setAutoCommit(true);
1741
    }//try
1742
    finally
1743
    {
1744
      
1745
      try
1746
      {
1747
        // close preparedStatement
1748
        pstmt.close();
1749
      }//try
1750
      finally
1751
      {
1752
        //check in DBonnection
1753
        DBConnectionPool.returnDBConnection(conn, serialNumber);
1754
      }//finally
1755
    }//finally
1756
    //IF this is a package document:
1757
    //delete all of the relations that this document created.
1758
    //if the deleted document is a package document its relations should 
1759
    //no longer be active if it has been deleted from the system.
1760
    
1761
  }
1762

    
1763
  /** 
1764
    * Check for "WRITE" permission on @docid for @user and/or @groups 
1765
    * from DB connection 
1766
    */
1767
  private static boolean hasPermission (String user,
1768
                                  String[] groups, String docid ) 
1769
                  throws SQLException, Exception
1770
  {
1771
    // Check for WRITE permission on @docid for @user and/or @groups
1772
    //AccessControlList aclobj = new AccessControlList(dbconn);
1773
    return AccessControlList.hasPermission("WRITE", user, groups, docid);
1774
    //return aclobj.hasPermission("WRITE", user, groups, docid);
1775
  }
1776

    
1777
  /** 
1778
    * Check for "READ" permission base on docid, user and group
1779
    *@docid, the document
1780
    *@user, user name
1781
    *@group, user's group
1782
    * 
1783
    */
1784
  public static boolean hasReadPermission (String user,
1785
                                  String[] groups, String docId ) 
1786
                  throws SQLException, Exception
1787
  {
1788
    // Check for READ permission on @docid for @user and/or @groups
1789
    //AccessControlList aclObj = new AccessControlList(conn);
1790
    //return aclObj.hasPermission("READ", user, groups, docId);
1791
    return AccessControlList.hasPermission("READ", user, groups, docId);
1792
  }  
1793

    
1794
  /**
1795
   * Set up the parser handlers for writing the document to the database
1796
   */
1797
  private static XMLReader initializeParser(DBConnection dbconn, String action,
1798
                               String docid, String rev, boolean validate, 
1799
                                   String user, String[] groups, String pub, 
1800
                                   int serverCode, Reader dtd) 
1801
                           throws Exception 
1802
  {
1803
    XMLReader parser = null;
1804
    //DBConnection conn = null;
1805
    //int serialNumber = -1;
1806
    //
1807
    // Set up the SAX document handlers for parsing
1808
    //
1809
    try {
1810
       //check out DBConnection
1811
      /*conn=DBConnectionPool.
1812
                    getDBConnection("DocumentImpl.initializeParse");
1813
      serialNumber=conn.getCheckOutSerialNumber();*/
1814
      
1815
      //create a DBSAXHandler object which has the revision specification
1816
      ContentHandler chandler = new DBSAXHandler(dbconn, action, 
1817
                                    docid, rev, user, groups, pub, serverCode);
1818
      EntityResolver eresolver= new DBEntityResolver(dbconn,
1819
                                                 (DBSAXHandler)chandler, dtd);
1820
      DTDHandler dtdhandler   = new DBDTDHandler(dbconn);
1821

    
1822
      // Get an instance of the parser
1823
      String parserName = MetaCatUtil.getOption("saxparser");
1824
      parser = XMLReaderFactory.createXMLReader(parserName);
1825

    
1826
      // Turn on validation
1827
      parser.setFeature("http://xml.org/sax/features/validation", validate);
1828
      // Turn off Including all external parameter entities
1829
      // (the external DTD subset also)
1830
      // Doesn't work well, probably the feature name is not correct
1831
      // parser.setFeature(
1832
      //  "http://xml.org/sax/features/external-parameter-entities", false);
1833
      
1834
      // Set Handlers in the parser
1835
      parser.setProperty("http://xml.org/sax/properties/declaration-handler",
1836
                         chandler);
1837
      parser.setProperty("http://xml.org/sax/properties/lexical-handler",
1838
                         chandler);
1839
      parser.setContentHandler((ContentHandler)chandler);
1840
      parser.setEntityResolver((EntityResolver)eresolver);
1841
      parser.setDTDHandler((DTDHandler)dtdhandler);
1842
      parser.setErrorHandler((ErrorHandler)chandler);
1843

    
1844
    } catch (Exception e) {
1845
      throw e;
1846
    }
1847
    //finally
1848
    //{
1849
      //DBConnectionPool.returnDBConnection(conn, serialNumber);
1850
    //}
1851

    
1852
    return parser;
1853
  }
1854

    
1855
  /**
1856
   * Save a document entry in the xml_revisions table 
1857
   * Connection use as a paramter is in order to rollback feature
1858
   */
1859
  private static void archiveDocRevision(DBConnection dbconn, String docid, 
1860
                                                    String user) 
1861
 {
1862
    String sysdate = dbAdapter.getDateTimeFunction();
1863
    //DBConnection conn = null;
1864
    //int serialNumber = -1;
1865
    PreparedStatement pstmt = null;
1866
    
1867
    // create a record in xml_revisions table 
1868
    // for that document as selected from xml_documents
1869
   
1870
   try
1871
   {
1872
     //check out DBConnection
1873
     /*conn=DBConnectionPool.
1874
                    getDBConnection("DocumentImpl.archiveDocRevision");
1875
     serialNumber=conn.getCheckOutSerialNumber();*/
1876
     pstmt = dbconn.prepareStatement(
1877
      "INSERT INTO xml_revisions " +
1878
        "(docid, rootnodeid, docname, doctype, " +
1879
        "user_owner, user_updated, date_created, date_updated, " +
1880
        "server_location, rev, public_access, catalog_id) " +
1881
      "SELECT ?, rootnodeid, docname, doctype, " + 
1882
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
1883
        "server_location, rev, public_access, catalog_id " +
1884
      "FROM xml_documents " +
1885
      "WHERE docid = ?");
1886
      // Increase dbconnection usage count
1887
      dbconn.increaseUsageCount(1);
1888
      // Bind the values to the query and execute it
1889
      pstmt.setString(1, docid);
1890
      pstmt.setString(2, user);
1891
      pstmt.setString(3, docid);
1892
      pstmt.execute();
1893
      pstmt.close();
1894
   }//try
1895
   catch (SQLException e)
1896
   {
1897
     MetaCatUtil.debugMessage("Error in DocumentImpl.archiveDocRevision : "+
1898
                                e.getMessage(), 30);
1899
   }//catch
1900
   finally
1901
   {
1902
     try
1903
     {
1904
       pstmt.close();
1905
     }//try
1906
     catch (SQLException ee)
1907
     {
1908
       MetaCatUtil.debugMessage("Error in DocumnetImpl.archiveDocRevision: "+
1909
                                  ee.getMessage(), 50);
1910
     }//catch
1911
     //finally
1912
     //{
1913
       
1914
       //check in DBConnection
1915
       //DBConnectionPool.returnDBConnection(conn, serialNumber);
1916
     //}//finally
1917
   }//finnally
1918
                                  
1919

    
1920
  }//achiveDocRevision
1921
  
1922
  /** Save a document entry in the xml_revisions table */
1923
  private static void archiveDocRevision(String docid, String user) 
1924
 {
1925
    String sysdate = dbAdapter.getDateTimeFunction();
1926
    DBConnection conn = null;
1927
    int serialNumber = -1;
1928
    PreparedStatement pstmt = null;
1929
    
1930
    // create a record in xml_revisions table 
1931
    // for that document as selected from xml_documents
1932
   
1933
   try
1934
   {
1935
     //check out DBConnection
1936
     conn=DBConnectionPool.
1937
                    getDBConnection("DocumentImpl.archiveDocRevision");
1938
     serialNumber=conn.getCheckOutSerialNumber();
1939
     pstmt = conn.prepareStatement(
1940
      "INSERT INTO xml_revisions " +
1941
        "(docid, rootnodeid, docname, doctype, " +
1942
        "user_owner, user_updated, date_created, date_updated, " +
1943
        "server_location, rev, public_access, catalog_id) " +
1944
      "SELECT ?, rootnodeid, docname, doctype, " + 
1945
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
1946
        "server_location, rev, public_access, catalog_id " +
1947
      "FROM xml_documents " +
1948
      "WHERE docid = ?");
1949
      // Bind the values to the query and execute it
1950
      pstmt.setString(1, docid);
1951
      pstmt.setString(2, user);
1952
      pstmt.setString(3, docid);
1953
      pstmt.execute();
1954
      pstmt.close();
1955
   }//try
1956
   catch (SQLException e)
1957
   {
1958
     MetaCatUtil.debugMessage("Error in DocumentImpl.archiveDocRevision : "+
1959
                                e.getMessage(), 30);
1960
   }//catch
1961
   finally
1962
   {
1963
     try
1964
     {
1965
       pstmt.close();
1966
     }//try
1967
     catch (SQLException ee)
1968
     {
1969
       MetaCatUtil.debugMessage("Error in DocumnetImpl.archiveDocRevision: "+
1970
                                  ee.getMessage(), 50);
1971
     }//catch
1972
     finally
1973
     {
1974
       //check in DBConnection
1975
       DBConnectionPool.returnDBConnection(conn, serialNumber);
1976
     }//finally
1977
   }//finnally
1978
                                  
1979

    
1980
  }//achiveDocRevision
1981
  
1982
  /**
1983
    * delete a entry in xml_table for given docid
1984
    * @param docId, the id of the document need to be delete
1985
    */
1986
  private static void deleteXMLDocuments(String docId) 
1987
                                         throws SQLException 
1988
  {
1989
    DBConnection conn = null;
1990
    int serialNumber = -1;
1991
    PreparedStatement pStmt = null;
1992
    try
1993
    {
1994
      //check out DBConnection
1995
      conn=DBConnectionPool.
1996
                    getDBConnection("DocumentImpl.deleteXMLDocuments");
1997
      serialNumber=conn.getCheckOutSerialNumber();
1998
      //delete a record 
1999
      pStmt = 
2000
             conn.prepareStatement("DELETE FROM xml_documents WHERE docid = '" 
2001
                                              + docId + "'");
2002
    pStmt.execute();
2003
    }//try
2004
    finally
2005
    {
2006
      try
2007
      {
2008
        pStmt.close();
2009
      }//try
2010
      catch (SQLException e)
2011
      {
2012
        MetaCatUtil.debugMessage("error in DocumentImpl.deleteXMLDocuments: "+
2013
                                  e.getMessage(), 50);
2014
      }//catch
2015
      finally
2016
      {
2017
        //return back DBconnection
2018
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2019
      }//finally
2020
    }//finally
2021
      
2022

    
2023
  }//deleteXMLDocuments
2024
  
2025
  /**
2026
    * Get last revision number from database for a docid
2027
    * If couldn't find an entry,  -1 will return
2028
    * The return value is integer because we want compare it to there new one
2029
    * @param docid <sitecode>.<uniqueid> part of Accession Number
2030
    */
2031
  private static int getLatestRevisionNumber(String docId)
2032
                                      throws SQLException
2033
  {
2034
    int rev = 1;
2035
    PreparedStatement pStmt = null;
2036
    DBConnection dbConn = null;
2037
    int serialNumber = -1;
2038
    
2039
    try
2040
    {
2041
      //check out DBConnection
2042
      dbConn=DBConnectionPool.
2043
                    getDBConnection("DocumentImpl.getLatestRevisionNumber");
2044
      serialNumber=dbConn.getCheckOutSerialNumber();
2045
     
2046
      pStmt = dbConn.prepareStatement
2047
              ("SELECT rev FROM xml_documents WHERE docid='" + docId + "'");
2048
      pStmt.execute();
2049

    
2050
      ResultSet rs = pStmt.getResultSet();
2051
      boolean hasRow = rs.next();
2052
      if (hasRow)
2053
      {
2054
        rev = rs.getInt(1);
2055
        pStmt.close();
2056
      }
2057
      else
2058
      {
2059
        rev=-1;
2060
        pStmt.close();
2061
      }
2062
    }//try
2063
    finally
2064
    {
2065
      try
2066
      {
2067
        pStmt.close();
2068
      }
2069
      catch (Exception ee)
2070
      {
2071
        MetaCatUtil.debugMessage("Error in DocumentImpl."+
2072
                        "getLatestRevisionNumber: "+ee.getMessage(), 50);
2073
      }
2074
      finally
2075
      {
2076
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2077
      }
2078
    }//finally  
2079
      
2080
    return rev;
2081
  }//getLatestRevisionNumber
2082
  
2083
  /**
2084
   * Get server location form database for a accNum
2085
   * 
2086
   * @param accum <sitecode>.<uniqueid>.<rev>
2087
   */
2088
  private static int getServerLocationNumber(String accNum)
2089
                                            throws SQLException
2090
  {
2091
    //get rid of revNum part
2092
    String docId=MetaCatUtil.getDocIdFromString(accNum);
2093
    PreparedStatement pStmt = null;
2094
    int serverLocation = 1;
2095
    DBConnection conn = null;
2096
    int serialNumber = -1;
2097
    
2098
    try
2099
    {
2100
      //check out DBConnection
2101
      conn=DBConnectionPool.
2102
                    getDBConnection("DocumentImpl.getServerLocationNumber");
2103
      serialNumber=conn.getCheckOutSerialNumber();
2104
     
2105
      pStmt = conn.prepareStatement
2106
      ("SELECT server_location FROM xml_documents WHERE docid='" + docId + "'");
2107
      pStmt.execute();
2108

    
2109
      ResultSet rs = pStmt.getResultSet();
2110
      boolean hasRow = rs.next();
2111
      //if there is entry in xml_documents, get the serverlocation
2112
      if (hasRow)
2113
      {
2114
        serverLocation = rs.getInt(1);
2115
        pStmt.close();
2116
      }
2117
      else
2118
      {
2119
        //if htere is no entry in xml_documents, we consider it is new document
2120
        //the server location is local host and value is 1
2121
        serverLocation=1;
2122
        pStmt.close();
2123
      }
2124
    }//try
2125
    finally
2126
    {
2127
      try
2128
      {
2129
        pStmt.close();
2130
      }//try
2131
      catch (Exception ee)
2132
      {
2133
        MetaCatUtil.debugMessage("Error in DocumentImpl.getServerLocationNu(): "
2134
                                    +ee.getMessage(), 50);
2135
      }//catch
2136
      finally
2137
      {
2138
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2139
      }//finally
2140
    }//finally
2141
      
2142
    return serverLocation;
2143
  }
2144
  
2145
  /**
2146
   * Given a server name, return its servercode in xml_replication table.
2147
   * If no server is found, -1 will return
2148
   * @param serverName, 
2149
   */
2150
  private static int getServerCode(String serverName) 
2151
  {
2152
    PreparedStatement pStmt=null;
2153
    int serverLocation=-2;
2154
    DBConnection dbConn = null;
2155
    int serialNumber = -1;
2156
    //MetaCatUtil util = new MetaCatUtil();
2157
    
2158
    
2159
    //we should consider about local host too
2160
    if (serverName.equals(MetaCatUtil.getLocalReplicationServerName()))
2161
    { 
2162
      serverLocation=1;
2163
      return serverLocation;
2164
    }
2165
    
2166
   
2167
    try
2168
    {
2169
      //check xml_replication table
2170
      //dbConn=util.openDBConnection();
2171
      //check out DBConnection
2172
      dbConn=DBConnectionPool.getDBConnection("DocumentImpl.getServerCode");
2173
      serialNumber=dbConn.getCheckOutSerialNumber();
2174
      pStmt = dbConn.prepareStatement
2175
      ("SELECT serverid FROM xml_replication WHERE server='" + serverName +"'");
2176
      pStmt.execute();
2177

    
2178
      ResultSet rs = pStmt.getResultSet();
2179
      boolean hasRow = rs.next();
2180
      //if there is entry in xml_replication, get the serverid
2181
      if (hasRow)
2182
      {
2183
        serverLocation = rs.getInt(1);
2184
        pStmt.close();
2185
      }
2186
      else
2187
      {
2188
        // if htere is no entry in xml_replication, -1 will return
2189
        serverLocation=-1;
2190
        pStmt.close();
2191
      }
2192
    }
2193
    catch (Exception e)
2194
    {
2195
      MetaCatUtil.debugMessage("Error in DocumentImpl.getServerCode(): "
2196
                                    +e.getMessage(), 30);
2197
    }
2198
    finally
2199
    {
2200
      try
2201
      {
2202
        pStmt.close();
2203
      }
2204
      catch (Exception ee)
2205
      {
2206
        MetaCatUtil.debugMessage("Error in DocumentImpl.getServerCode(): "
2207
                                    +ee.getMessage(), 50);
2208
      }
2209
      finally
2210
      {
2211
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2212
      }
2213
    }
2214
                 
2215
      
2216
    return serverLocation;
2217
  }
2218
  
2219
  /**
2220
   * Insert a server into xml_replcation table
2221
   * @param server, the name of server 
2222
   */
2223
  private static void  insertServerIntoReplicationTable(String server)
2224
  {
2225
    PreparedStatement pStmt=null;
2226
    DBConnection dbConn = null;
2227
    int serialNumber = -1;
2228
    int replicate = 1;
2229
    //MetaCatUtil util = new MetaCatUtil();
2230
    try
2231
    {
2232
       //dbConn=util.openDBConnection();
2233
       //check out DBConnection
2234
       dbConn=DBConnectionPool.
2235
                getDBConnection("DocumentImpl.insertServIntoReplicationTable");
2236
       serialNumber=dbConn.getCheckOutSerialNumber();
2237
       pStmt = dbConn.prepareStatement("INSERT INTO xml_replication " +
2238
                                      "(server, last_checked, replicate) " +
2239
                                      "VALUES ('" + server + "', to_date(" +
2240
                                      "'01/01/00', 'MM/DD/YY'), '" +
2241
                                      replicate + "')");
2242
        pStmt.execute();
2243
        pStmt.close();
2244
        dbConn.commit();
2245
    }//try
2246
    catch (Exception e)
2247
    {
2248
      MetaCatUtil.debugMessage("Error in DocumentImpl.insertServerIntoRepli(): "
2249
                                    +e.getMessage(), 30);
2250
    }//catch
2251
    finally
2252
    {
2253
     
2254
      try
2255
      {
2256
        pStmt.close();
2257
      }//try
2258
      catch (Exception ee)
2259
      {
2260
        MetaCatUtil.debugMessage("Error in DocumentImpl.insetServerIntoRepl(): "
2261
                                    +ee.getMessage(), 50);
2262
      }//catch
2263
      finally
2264
      {
2265
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2266
      }
2267
    
2268
    }//finally
2269

    
2270
  }
2271
  
2272
  
2273
  /**
2274
   * the main routine used to test the DBWriter utility.
2275
   * <p>
2276
   * Usage: java DocumentImpl <-f filename -a action -d docid>
2277
   *
2278
   * @param filename the filename to be loaded into the database
2279
   * @param action the action to perform (READ, INSERT, UPDATE, DELETE)
2280
   * @param docid the id of the document to process
2281
   */
2282
  static public void main(String[] args) {
2283
    DBConnection dbconn = null;
2284
    int serialNumber = -1;
2285
    try {
2286
      String filename    = null;
2287
      String dtdfilename = null;
2288
      String action      = null;
2289
      String docid       = null;
2290
      boolean showRuntime = false;
2291
      boolean useOldReadAlgorithm = false;
2292

    
2293
      // Parse the command line arguments
2294
      for ( int i=0 ; i < args.length; ++i ) {
2295
        if ( args[i].equals( "-f" ) ) {
2296
          filename =  args[++i];
2297
        } else if ( args[i].equals( "-r" ) ) {
2298
          dtdfilename =  args[++i];
2299
        } else if ( args[i].equals( "-a" ) ) {
2300
          action =  args[++i];
2301
        } else if ( args[i].equals( "-d" ) ) {
2302
          docid =  args[++i];
2303
        } else if ( args[i].equals( "-t" ) ) {
2304
          showRuntime = true;
2305
        } else if ( args[i].equals( "-old" ) ) {
2306
          useOldReadAlgorithm = true;
2307
        } else {
2308
          System.err.println
2309
            ( "   args[" +i+ "] '" +args[i]+ "' ignored." );
2310
        }
2311
      }
2312
      
2313
      // Check if the required arguments are provided
2314
      boolean argsAreValid = false;
2315
      if (action != null) {
2316
        if (action.equals("INSERT")) {
2317
          if (filename != null) {
2318
            argsAreValid = true;
2319
          } 
2320
        } else if (action.equals("UPDATE")) {
2321
          if ((filename != null) && (docid != null)) {
2322
            argsAreValid = true;
2323
          } 
2324
        } else if (action.equals("DELETE")) {
2325
          if (docid != null) {
2326
            argsAreValid = true;
2327
          } 
2328
        } else if (action.equals("READ")) {
2329
          if (docid != null) {
2330
            argsAreValid = true;
2331
          } 
2332
        } 
2333
      } 
2334

    
2335
      // Print usage message if the arguments are not valid
2336
      if (!argsAreValid) {
2337
        System.err.println("Wrong number of arguments!!!");
2338
        System.err.println(
2339
          "USAGE: java DocumentImpl [-t] <-a INSERT> [-d docid] <-f filename> "+
2340
          "[-r dtdfilename]");
2341
        System.err.println(
2342
          "   OR: java DocumentImpl [-t] <-a UPDATE -d docid -f filename> " +
2343
          "[-r dtdfilename]");
2344
        System.err.println(
2345
          "   OR: java DocumentImpl [-t] <-a DELETE -d docid>");
2346
        System.err.println(
2347
          "   OR: java DocumentImpl [-t] [-old] <-a READ -d docid>");
2348
        return;
2349
      }
2350
      
2351
      // Time the request if asked for
2352
      double startTime = System.currentTimeMillis();
2353
      
2354
      // Open a connection to the database
2355
      MetaCatUtil util = new MetaCatUtil();
2356
     
2357
      dbconn=DBConnectionPool.getDBConnection("DocumentImpl.main");
2358
      serialNumber=dbconn.getCheckOutSerialNumber();
2359

    
2360
      double connTime = System.currentTimeMillis();
2361
      // Execute the action requested (READ, INSERT, UPDATE, DELETE)
2362
      if (action.equals("READ")) {
2363
          DocumentImpl xmldoc = new DocumentImpl(docid );
2364
          if (useOldReadAlgorithm) {
2365
            System.out.println(xmldoc.readUsingSlowAlgorithm());
2366
          } else {
2367
            xmldoc.toXml(new PrintWriter(System.out));
2368
          }
2369
      } else if (action.equals("DELETE")) {
2370
        DocumentImpl.delete(docid, null, null);
2371
        System.out.println("Document deleted: " + docid);
2372
      } else {
2373
        String newdocid = DocumentImpl.write(dbconn, filename, null,
2374
                                             dtdfilename, action, docid,
2375
                                             null, null);
2376
        if ((docid != null) && (!docid.equals(newdocid))) {
2377
          if (action.equals("INSERT")) {
2378
            System.out.println("New document ID generated!!! ");
2379
          } else if (action.equals("UPDATE")) {
2380
            System.out.println("ERROR: Couldn't update document!!! ");
2381
          }
2382
        } else if ((docid == null) && (action.equals("UPDATE"))) {
2383
          System.out.println("ERROR: Couldn't update document!!! ");
2384
        }
2385
        System.out.println("Document processing finished for: " + filename
2386
              + " (" + newdocid + ")");
2387
      }
2388

    
2389
      double stopTime = System.currentTimeMillis();
2390
      double dbOpenTime = (connTime - startTime)/1000;
2391
      double insertTime = (stopTime - connTime)/1000;
2392
      double executionTime = (stopTime - startTime)/1000;
2393
      if (showRuntime) {
2394
        System.out.println("\n\nTotal Execution time was: " + 
2395
                           executionTime + " seconds.");
2396
        System.out.println("Time to open DB connection was: " + dbOpenTime + 
2397
                           " seconds.");
2398
        System.out.println("Time to insert document was: " + insertTime +
2399
                           " seconds.");
2400
      }
2401
      dbconn.close();
2402
    } catch (McdbException me) {
2403
      me.toXml(new PrintWriter(System.err));
2404
    } catch (AccessionNumberException ane) {
2405
      System.out.println(ane.getMessage());
2406
    } catch (Exception e) {
2407
      System.err.println("EXCEPTION HANDLING REQUIRED");
2408
      System.err.println(e.getMessage());
2409
      e.printStackTrace(System.err);
2410
    }
2411
    finally
2412
    {
2413
      // Return db connection
2414
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
2415
    }
2416
  }
2417
}
(26-26/43)