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-07-14 12:33:25 -0700 (Sun, 14 Jul 2002) $'
11
 * '$Revision: 1292 $'
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
  //private static 
95
  //ReplicationServerList serverList = new ReplicationServerList();
96
  
97
  /**
98
   * Constructor used to create a document and read the document information
99
   * from the database.  If readNodes is false, then the node data is not 
100
   * read at this time, but is deferred until it is needed (such as when a 
101
   * call to toXml() is made).  
102
   *
103
   * @param conn the database connection from which to read the document
104
   * @param docid the identifier of the document to be created
105
   * @param readNodes flag indicating whether the xmlnodes should be read
106
   */
107
  public DocumentImpl(String docid, boolean readNodes) 
108
         throws McdbException 
109
  {
110
    try {
111
      //this.conn = conn;
112
      this.docid = docid;
113
      
114
      // Look up the document information
115
      getDocumentInfo(docid);
116
      
117
      if (readNodes) {
118
        // Download all of the document nodes using a single SQL query
119
        // The sort order of the records is determined by the NodeComparator
120
        // class, and needs to represent a depth-first traversal for the
121
        // toXml() method to work properly
122
        nodeRecordList = getNodeRecordList(rootnodeid);
123
        
124
      }
125
    
126
    } catch (McdbException ex) {
127
      throw ex;
128
    } catch (Throwable t) {
129
      throw new McdbException("Error reading document from " +
130
                              "DocumentImpl.DocumentImpl: " + docid);
131
    }
132
  }
133

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

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

    
528
    BufferedInputStream bis = null;
529
    bis = new BufferedInputStream(input);
530
    byte[] buf = new byte[4 * 1024]; // 4K buffer
531
    int b = bis.read(buf);
532
       
533
    while (b != -1) 
534
    {
535
        outPut.write(buf, 0, b);
536
        b = bis.read(buf);
537
    }
538
    bis.close();
539
	  outPut.close();
540
	  fos.close();
541
      
542
    // Force replicate data file
543
    ForceReplicationHandler forceReplication = new ForceReplicationHandler
544
                                    (accnum, false, notificationServer);
545
  
546
 }
547
  
548

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

    
618
      else if(openingtag.equals("<filelocked>"))
619
      {//the file is currently locked by another user
620
       //notify our user to wait a few minutes, check out a new copy and try
621
       //again.
622
        //System.out.println("file locked");
623
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
624
                                   server + " reason: file already locked");
625
        throw new Exception("The file specified is already locked by another " +
626
                            "user.  Please wait 30 seconds, checkout the " +
627
                            "newer document, merge your changes and try " +
628
                            "again.");
629
      }
630
      else if(openingtag.equals("<outdatedfile>"))
631
      {//our file is outdated.  notify our user to check out a new copy of the
632
       //file and merge his version with the new version.
633
        //System.out.println("outdated file");
634
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
635
                                    server + " reason: local file outdated");
636
        throw new Exception("The file you are trying to update is an outdated" +
637
                            " version.  Please checkout the newest document, " +
638
                            "merge your changes and try again.");
639
      }//else if
640
    }//if
641
    
642
   return flag;
643
   
644
  }//getDataFileLockGrant
645
  
646
  /**
647
   * get the document name
648
   */
649
  public String getDocname() {
650
    return docname;
651
  }
652

    
653
  /**
654
   * get the document type (which is the PublicID)
655
   */
656
  public String getDoctype() {
657
    return doctype;
658
  }
659

    
660
  /**
661
   * get the system identifier
662
   */
663
  public String getSystemID() {
664
    return system_id;
665
  }
666

    
667
  /**
668
   * get the root node identifier
669
   */
670
  public long getRootNodeID() {
671
    return rootnodeid;
672
  }
673
  
674
  /**
675
   * get the creation date
676
   */
677
  public String getCreateDate() {
678
    return createdate;
679
  }
680
  
681
  /**
682
   * get the update date
683
   */
684
  public String getUpdateDate() {
685
    return updatedate;
686
  }
687

    
688
  /** 
689
   * Get the document identifier (docid)
690
   */
691
  public String getDocID() {
692
    return docid;
693
  }
694
  
695
// DOCTITLE attr cleared from the db
696
//  /**
697
//   *get the document title
698
//   */
699
//  public String getDocTitle() {
700
//    return doctitle;
701
//  }
702
  
703
  public String getUserowner() {
704
    return userowner;
705
  }
706
  
707
  public String getUserupdated() {
708
    return userupdated;
709
  }
710
  
711
  public int getServerlocation() {
712
    return serverlocation;
713
  }
714
  
715
  public String getDocHomeServer() {
716
    return docHomeServer;
717
  }
718
  
719
 
720
 
721
  public String getPublicaccess() {
722
    return publicaccess;
723
  }
724
  
725
  public int getRev() {
726
    return rev;
727
  }
728
  
729
   /**
730
   * Print a string representation of the XML document
731
   */
732
  public String toString()
733
  {
734
    StringWriter docwriter = new StringWriter();
735
    try {
736
      this.toXml(docwriter);
737
    } catch (McdbException mcdbe) {
738
      return null;
739
    }
740
    String document = docwriter.toString();
741
    return document;
742
  }
743

    
744
  /**
745
   * Get a text representation of the XML document as a string
746
   * This older algorithm uses a recursive tree of Objects to represent the
747
   * nodes of the tree.  Each object is passed the data for the document 
748
   * and searches all of the document data to find its children nodes and
749
   * recursively build.  Thus, because each node reads the whole document,
750
   * this algorithm is extremely slow for larger documents, and the time
751
   * to completion is O(N^N) wrt the number of nodes.  See toXml() for a
752
   * better algorithm.
753
   */
754
  public String readUsingSlowAlgorithm() throws McdbException
755
  {
756
    StringBuffer doc = new StringBuffer();
757

    
758
    // First, check that we have the needed node data, and get it if not
759
    if (nodeRecordList == null) {
760
      nodeRecordList = getNodeRecordList(rootnodeid);
761
    }
762

    
763
    // Create the elements from the downloaded data in the TreeSet
764
    rootNode = new ElementNode(nodeRecordList, rootnodeid);
765

    
766
    // Append the resulting document to the StringBuffer and return it
767
    doc.append("<?xml version=\"1.0\"?>\n");
768
      
769
    if (docname != null) {
770
      if ((doctype != null) && (system_id != null)) {
771
        doc.append("<!DOCTYPE " + docname + " PUBLIC \"" + doctype + 
772
                   "\" \"" + system_id + "\">\n");
773
      } else {
774
        doc.append("<!DOCTYPE " + docname + ">\n");
775
      }
776
    }
777
    doc.append(rootNode.toString());
778
  
779
    return (doc.toString());
780
  }
781

    
782
  /**
783
   * Print a text representation of the XML document to a Writer
784
   *
785
   * @param pw the Writer to which we print the document
786
   */
787
  public void toXml(Writer pw) throws McdbException
788
  {
789
    PrintWriter out = null;
790
    if (pw instanceof PrintWriter) {
791
      out = (PrintWriter)pw;
792
    } else {
793
      out = new PrintWriter(pw);
794
    }
795

    
796
    MetaCatUtil util = new MetaCatUtil();
797
    
798
    // First, check that we have the needed node data, and get it if not
799
    if (nodeRecordList == null) {
800
      nodeRecordList = getNodeRecordList(rootnodeid);
801
    }
802

    
803
    Stack openElements = new Stack();
804
    boolean atRootElement = true;
805
    boolean previousNodeWasElement = false;
806

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

    
851
      // Handle the DOCUMENT node
852
      if (currentNode.nodetype.equals("DOCUMENT")) {
853
        out.println("<?xml version=\"1.0\"?>");
854
      
855
        if (docname != null) {
856
          if ((doctype != null) && (system_id != null)) {
857
            out.println("<!DOCTYPE " + docname + " PUBLIC \"" + doctype + 
858
                       "\" \"" + system_id + "\">");
859
          } else {
860
            out.println("<!DOCTYPE " + docname + ">");
861
          }
862
        }
863

    
864
      // Handle the ELEMENT nodes
865
      } else if (currentNode.nodetype.equals("ELEMENT")) {
866
        if (atRootElement) {
867
          atRootElement = false;
868
        } else {
869
          if (previousNodeWasElement) {
870
            out.print(">");
871
          }
872
        }
873
        openElements.push(currentNode);
874
        util.debugMessage("\n PUSHED: " + currentNode.nodename);
875
        previousNodeWasElement = true;
876
        if ( currentNode.nodeprefix != null ) {
877
          out.print("<" + currentNode.nodeprefix + ":" + currentNode.nodename);
878
        } else {
879
          out.print("<" + currentNode.nodename);
880
        }
881

    
882
      // Handle the ATTRIBUTE nodes
883
      } else if (currentNode.nodetype.equals("ATTRIBUTE")) {
884
        if ( currentNode.nodeprefix != null ) {
885
          out.print(" " + currentNode.nodeprefix + ":" + currentNode.nodename +
886
                    "=\"" + currentNode.nodedata + "\"");
887
        } else {
888
          out.print(" " + currentNode.nodename + "=\"" +
889
                    currentNode.nodedata + "\"");
890
        }
891

    
892
      // Handle the NAMESPACE nodes
893
      } else if (currentNode.nodetype.equals("NAMESPACE")) {
894
        out.print(" xmlns:" + currentNode.nodename + "=\""
895
                 + currentNode.nodedata + "\"");
896

    
897
      // Handle the TEXT nodes
898
      } else if (currentNode.nodetype.equals("TEXT")) {
899
        if (previousNodeWasElement) {
900
          out.print(">");
901
        }
902
        out.print(currentNode.nodedata);
903
        previousNodeWasElement = false;
904

    
905
      // Handle the COMMENT nodes
906
      } else if (currentNode.nodetype.equals("COMMENT")) {
907
        if (previousNodeWasElement) {
908
          out.print(">");
909
        }
910
        out.print("<!--" + currentNode.nodedata + "-->");
911
        previousNodeWasElement = false;
912

    
913
      // Handle the PI nodes
914
      } else if (currentNode.nodetype.equals("PI")) {
915
        if (previousNodeWasElement) {
916
          out.print(">");
917
        }
918
        out.print("<?" + currentNode.nodename + " " +
919
                        currentNode.nodedata + "?>");
920
        previousNodeWasElement = false;
921

    
922
      // Handle any other node type (do nothing)
923
      } else {
924
        // Any other types of nodes are not handled.
925
        // Probably should throw an exception here to indicate this
926
      }
927
      out.flush();
928
    }
929

    
930
    // Print the final end tag for the root element
931
    while(!openElements.empty())
932
    {
933
      NodeRecord currentElement = (NodeRecord)openElements.pop();
934
      util.debugMessage("\n POPPED: " + currentElement.nodename);
935
      if ( currentElement.nodeprefix != null ) {
936
        out.print("</" + currentElement.nodeprefix + ":" + 
937
                  currentElement.nodename + ">" );
938
      } else {
939
        out.print("</" + currentElement.nodename + ">" );
940
      }
941
    }
942
    out.flush();
943
  }
944
  
945
  private boolean isRevisionOnly(DocumentIdentifier docid) throws Exception
946
  {
947
    //System.out.println("inRevisionOnly");
948
    DBConnection dbconn = null;
949
    int serialNumber = -1;
950
    PreparedStatement pstmt =null;
951
    String rev = docid.getRev();
952
    String newid = docid.getIdentifier();
953
    try
954
    {
955
      dbconn=DBConnectionPool.
956
                    getDBConnection("DocumentImpl.isRevisionOnly");
957
      serialNumber=dbconn.getCheckOutSerialNumber();
958
      pstmt = dbconn.prepareStatement("select rev from xml_documents " +
959
                                  "where docid like '" + newid + "'");
960
      pstmt.execute();
961
      ResultSet rs = pstmt.getResultSet();
962
      boolean tablehasrows = rs.next();
963
      if(rev.equals("newest") || rev.equals("all"))
964
      {
965
        return false;
966
      }
967
    
968
      if(tablehasrows)
969
      {
970
        int r = rs.getInt(1);
971
        pstmt.close();
972
        if(new Integer(rev).intValue() == r)
973
        { //the current revision in in xml_documents
974
          //System.out.println("returning false");
975
          return false;
976
        }
977
        else if(new Integer(rev).intValue() < r)
978
        { //the current revision is in xml_revisions.
979
          //System.out.println("returning true");
980
          return true;
981
        }
982
        else if(new Integer(rev).intValue() > r)
983
        { //error, rev cannot be greater than r
984
          throw new Exception("requested revision cannot be greater than " +
985
                            "the latest revision number.");
986
        }
987
      }
988
      // Get miss docid and rev, throw to McdDocNotFoundException
989
      String missDocId = MetaCatUtil.getDocIdFromString(docid.toString());
990
      String missRevision = 
991
                  MetaCatUtil.getRevisionStringFromString(docid.toString());
992
      throw new McdbDocNotFoundException("the requested docid '" + 
993
                docid.toString() + "' does not exist", missDocId, missRevision);
994
    }//try
995
    finally
996
    {
997
      pstmt.close();
998
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
999
    }//finally
1000
  }
1001

    
1002
  private void getDocumentInfo(String docid) throws McdbException, 
1003
                                        AccessionNumberException, Exception
1004
  {
1005
    getDocumentInfo(new DocumentIdentifier(docid));
1006
  }
1007
  
1008
  /**
1009
   * Look up the document type information from the database
1010
   *
1011
   * @param docid the id of the document to look up
1012
   */
1013
  private void getDocumentInfo(DocumentIdentifier docid) throws McdbException
1014
                                                          , Exception
1015
  {
1016
    DBConnection dbconn = null;
1017
    int serialNumber = -1;
1018
    PreparedStatement pstmt = null;
1019
    String table = "xml_documents";
1020
        
1021
    try
1022
    {
1023
      if(isRevisionOnly(docid))
1024
      { //pull the document from xml_revisions instead of from xml_documents;
1025
        table = "xml_revisions";
1026
      }
1027
    }
1028
    // catch a McdbDocNotFoundException throw it
1029
    catch (McdbDocNotFoundException notFound)
1030
    {
1031
      throw notFound;
1032
    }
1033
    catch(Exception e)
1034
    {
1035
      
1036
      MetaCatUtil.debugMessage("error in DocumentImpl.getDocumentInfo: " + 
1037
                          e.getMessage(), 30);
1038
      throw e;
1039
    }
1040
    
1041

    
1042
    
1043
    try 
1044
    {
1045
      dbconn=DBConnectionPool.getDBConnection("DocumentImpl.getDocumentInfo");
1046
      serialNumber=dbconn.getCheckOutSerialNumber();
1047
      StringBuffer sql = new StringBuffer();
1048
// DOCTITLE attr cleared from the db
1049
//      sql.append("SELECT docname, doctype, rootnodeid, doctitle, ");
1050
      sql.append("SELECT docname, doctype, rootnodeid, ");
1051
      sql.append("date_created, date_updated, user_owner, user_updated, ");
1052
      sql.append("server_location, public_access, rev");
1053
      sql.append(" FROM ").append(table);
1054
      sql.append(" WHERE docid LIKE '").append(docid.getIdentifier());
1055
      sql.append("' and rev like '").append(docid.getRev()).append("'");
1056
      //System.out.println(sql.toString());
1057
      pstmt =
1058
        dbconn.prepareStatement(sql.toString());
1059
      // Bind the values to the query
1060
      //pstmt.setString(1, docid.getIdentifier());
1061
      //pstmt.setString(2, docid.getRev());
1062

    
1063
      pstmt.execute();
1064
      ResultSet rs = pstmt.getResultSet();
1065
      boolean tableHasRows = rs.next();
1066
      if (tableHasRows) {
1067
        this.docname        = rs.getString(1);
1068
        this.doctype        = rs.getString(2);
1069
        this.rootnodeid     = rs.getLong(3);
1070
// DOCTITLE attr cleared from the db
1071
//        this.doctitle       = rs.getString(4);
1072
        this.createdate     = rs.getString(4);
1073
        this.updatedate     = rs.getString(5);
1074
        this.userowner      = rs.getString(6);
1075
        this.userupdated    = rs.getString(7);
1076
        this.serverlocation = rs.getInt(8);
1077
        this.publicaccess   = rs.getString(9);
1078
        this.rev            = rs.getInt(10);
1079
      } 
1080
      pstmt.close();
1081
      
1082
      //get doc  home server name
1083
      
1084
      pstmt = dbconn.prepareStatement("select server " +
1085
                        "from xml_replication where serverid = ?");
1086
      //because connection use twise here, so we need to increase one
1087
      dbconn.increaseUsageCount(1);
1088
      pstmt.setInt(1, serverlocation);
1089
      pstmt.execute();
1090
      rs = pstmt.getResultSet();
1091
      tableHasRows = rs.next();
1092
      if (tableHasRows)
1093
      {
1094
        
1095
          String server = rs.getString(1);
1096
          //get homeserver name
1097
          if(!server.equals("localhost"))
1098
          {
1099
            this.docHomeServer=server;
1100
          }
1101
          else
1102
          {
1103
            this.docHomeServer=MetaCatUtil.getLocalReplicationServerName();
1104
          }
1105
          MetaCatUtil.debugMessage("server: "+docHomeServer, 50);
1106
        
1107
      }
1108
      pstmt.close();
1109
      if (this.doctype != null) {
1110
        pstmt =
1111
          dbconn.prepareStatement("SELECT system_id " +
1112
                                  "FROM xml_catalog " +
1113
                                 "WHERE public_id = ?");
1114
        //should increase usage count again
1115
        dbconn.increaseUsageCount(1);
1116
        // Bind the values to the query
1117
        pstmt.setString(1, doctype);
1118
  
1119
        pstmt.execute();
1120
        rs = pstmt.getResultSet();
1121
        tableHasRows = rs.next();
1122
        if (tableHasRows) {
1123
          this.system_id  = rs.getString(1);
1124
        } 
1125
        pstmt.close();
1126
      }
1127
    } catch (SQLException e) {
1128
      System.out.println("error in DocumentImpl.getDocumentInfo: " + 
1129
                          e.getMessage());
1130
      e.printStackTrace(System.out);
1131
      throw new McdbException("Error accessing database connection in " +
1132
                              "DocumentImpl.getDocumentInfo: ", e);
1133
    }
1134
    finally
1135
    {
1136
      try
1137
      {
1138
        pstmt.close();
1139
      }
1140
      catch (SQLException ee)
1141
      {
1142
        MetaCatUtil.debugMessage("error in DocumentImple.getDocumentInfo: "
1143
                                    +ee.getMessage(), 30);
1144
      }//catch
1145
      finally
1146
      {
1147
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1148
      }
1149
    }
1150

    
1151
    if (this.docname == null) {
1152
      throw new McdbDocNotFoundException("Document not found: " + docid,
1153
                                 docid.getIdentifier(), docid.getRev());
1154
    }
1155
  }
1156

    
1157
  /**
1158
   * Look up the node data from the database
1159
   *
1160
   * @param rootnodeid the id of the root node of the node tree to look up
1161
   */
1162
  private TreeSet getNodeRecordList(long rootnodeid) throws McdbException
1163
  {
1164
    PreparedStatement pstmt = null;
1165
    DBConnection dbconn = null;
1166
    int serialNumber = -1;
1167
    TreeSet nodeRecordList = new TreeSet(new NodeComparator());
1168
    long nodeid = 0;
1169
    long parentnodeid = 0;
1170
    long nodeindex = 0;
1171
    String nodetype = null;
1172
    String nodename = null;
1173
    String nodeprefix = null;
1174
    String nodedata = null;
1175
    String quotechar = dbAdapter.getStringDelimiter();
1176

    
1177
    try {
1178
      dbconn=DBConnectionPool.
1179
                    getDBConnection("DocumentImpl.getNodeRecordList");
1180
      serialNumber=dbconn.getCheckOutSerialNumber();
1181
      pstmt =
1182
      dbconn.prepareStatement("SELECT nodeid,parentnodeid,nodeindex, " +
1183
           "nodetype,nodename,nodeprefix,nodedata " +               
1184
           "FROM xml_nodes WHERE rootnodeid = ?");
1185

    
1186
      // Bind the values to the query
1187
      pstmt.setLong(1, rootnodeid);
1188

    
1189
      pstmt.execute();
1190
      ResultSet rs = pstmt.getResultSet();
1191
      boolean tableHasRows = rs.next();
1192
      while (tableHasRows) {
1193
        nodeid = rs.getLong(1);
1194
        parentnodeid = rs.getLong(2);
1195
        nodeindex = rs.getLong(3);
1196
        nodetype = rs.getString(4);
1197
        nodename = rs.getString(5);
1198
        nodeprefix = rs.getString(6);
1199
        nodedata = rs.getString(7);
1200
        nodedata = MetaCatUtil.normalize(nodedata);
1201
        // add the data to the node record list hashtable
1202
        NodeRecord currentRecord = new NodeRecord(nodeid,parentnodeid,nodeindex,
1203
                                      nodetype, nodename, nodeprefix, nodedata);
1204
        nodeRecordList.add(currentRecord);
1205

    
1206
        // Advance to the next node
1207
        tableHasRows = rs.next();
1208
      } 
1209
      pstmt.close();
1210

    
1211
    } catch (SQLException e) {
1212
      throw new McdbException("Error in DocumentImpl.getNodeRecordList " +
1213
                              e.getMessage());
1214
    }
1215
    finally
1216
    {
1217
      try
1218
      {
1219
        pstmt.close();
1220
      }
1221
      catch (SQLException ee)
1222
      {
1223
        MetaCatUtil.debugMessage("error in DocumentImpl.getNodeRecordList: "
1224
                                    +ee.getMessage(), 30);
1225
      }
1226
      finally
1227
      {
1228
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1229
      }
1230
    }
1231
      
1232

    
1233
    if (nodeRecordList != null) {
1234
      return nodeRecordList;
1235
    } else {
1236
      throw new McdbException("Error getting node data: " + docid);
1237
    }
1238
  }
1239
  
1240
// NOT USED ANY MORE
1241
//  /** creates SQL code and inserts new document into DB connection 
1242
//   default serverCode of 1*/
1243
//  private void writeDocumentToDB(String action, String user)
1244
//               throws SQLException, Exception
1245
//  {
1246
//    writeDocumentToDB(action, user, null, 1);
1247
//  }
1248

    
1249
 /** creates SQL code and inserts new document into DB connection */
1250
  private void writeDocumentToDB(String action, String user, String pub, 
1251
                                 String catalogid, int serverCode) 
1252
               throws SQLException, Exception {
1253
    String sysdate = dbAdapter.getDateTimeFunction();
1254

    
1255
    try {
1256
      PreparedStatement pstmt = null;
1257

    
1258
      if (action.equals("INSERT")) {
1259
        //AccessionNumber ac = new AccessionNumber();
1260
        //this.docid = ac.generate(docid, "INSERT");
1261
        
1262
        pstmt = connection.prepareStatement(
1263
                "INSERT INTO xml_documents " +
1264
                "(docid, rootnodeid, docname, doctype, " + 
1265
                "user_owner, user_updated, date_created, date_updated, " + 
1266
                "public_access, catalog_id, server_location, rev) " +
1267
                "VALUES (?, ?, ?, ?, ?, ?, " + sysdate + ", " + sysdate + 
1268
                ", ?, ?, ?, ?)");
1269
        // Increase dbconnection usage count
1270
        connection.increaseUsageCount(1);
1271
        
1272
        //note that the server_location is set to 1. 
1273
        //this means that "localhost" in the xml_replication table must
1274
        //always be the first entry!!!!!
1275
        
1276
        // Bind the values to the query
1277
        pstmt.setString(1, this.docid);
1278
        pstmt.setLong(2, rootnodeid);
1279
        pstmt.setString(3, docname);
1280
        pstmt.setString(4, doctype);
1281
        pstmt.setString(5, user);
1282
        pstmt.setString(6, user);
1283
        //public access is usefulless, so set it to null
1284
        pstmt.setString(7, null);
1285
        /*if ( pub == null ) {
1286
          pstmt.setString(7, null);
1287
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
1288
          pstmt.setInt(7, 1);
1289
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
1290
          pstmt.setInt(7, 0);
1291
        }*/
1292
        pstmt.setString(8, catalogid);
1293
        pstmt.setInt(9, serverCode);
1294
        pstmt.setInt(10, Integer.parseInt(updatedVersion)); 
1295
      } else if (action.equals("UPDATE")) {
1296

    
1297
        // Save the old document publicaccessentry in a backup table
1298
        DocumentImpl.archiveDocRevision(connection, docid, user );
1299
        DocumentImpl thisdoc = new DocumentImpl(docid, false);
1300
        int thisrev = thisdoc.getRev();
1301
        
1302
        //if the updated vesion is not greater than current one,
1303
        //throw it into a exception
1304
        if (Integer.parseInt(updatedVersion)<=thisrev)
1305
        {
1306
          throw new Exception("Next revision number couldn't be less"
1307
                               +" than or equal "+ thisrev);
1308
        }
1309
        else
1310
        {
1311
          //set the user specified revision 
1312
          thisrev=Integer.parseInt(updatedVersion);
1313
        }
1314
        
1315
        // Delete index for the old version of docid
1316
        // The new index is inserting on the next calls to DBSAXNode
1317
        pstmt = connection.prepareStatement(
1318
                "DELETE FROM xml_index WHERE docid='" + this.docid + "'");
1319
        // Increase dbconnection usage count
1320
        connection.increaseUsageCount(1);
1321
        
1322
        pstmt.execute();
1323
        pstmt.close();
1324

    
1325
        // Update the new document to reflect the new node tree
1326
        pstmt = connection.prepareStatement(
1327
            "UPDATE xml_documents " +
1328
            "SET rootnodeid = ?, docname = ?, doctype = ?, " +
1329
            "user_updated = ?, date_updated = " + sysdate + ", " +
1330
            "server_location = ?, rev = ?, public_access = ?, catalog_id = ? " +
1331
            "WHERE docid = ?");
1332
        // Increase dbconnection usage count
1333
        connection.increaseUsageCount(1);
1334
        // Bind the values to the query
1335
        pstmt.setLong(1, rootnodeid);
1336
        pstmt.setString(2, docname);
1337
        pstmt.setString(3, doctype);
1338
        pstmt.setString(4, user);
1339
        pstmt.setInt(5, serverCode);
1340
        pstmt.setInt(6, thisrev);
1341
        pstmt.setString(7, null);
1342
        /*if ( pub == null ) {
1343
          pstmt.setString(7, null);
1344
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
1345
          pstmt .setInt(7, 1);
1346
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
1347
          pstmt.setInt(7, 0);
1348
        }*/
1349
        pstmt.setString(8, catalogid);
1350
        pstmt.setString(9, this.docid);
1351

    
1352
      } else {
1353
        System.err.println("Action not supported: " + action);
1354
      }
1355

    
1356
      // Do the insertion
1357
      pstmt.execute();
1358
      
1359
      pstmt.close();
1360

    
1361
    } catch (SQLException sqle) {
1362
      throw sqle;
1363
    } catch (Exception e) {
1364
      throw e;
1365
    }
1366
  }
1367

    
1368
  /**
1369
   * Write an XML file to the database, given a filename
1370
   *
1371
   * @param conn the JDBC connection to the database
1372
   * @param filename the filename to be loaded into the database
1373
   * @param pub flag for public "read" access on document
1374
   * @param dtdfilename the dtd to be uploaded on server's file system
1375
   * @param action the action to be performed (INSERT OR UPDATE)
1376
   * @param docid the docid to use for the INSERT OR UPDATE
1377
   * @param user the user that owns the document
1378
   * @param groups the groups to which user belongs
1379
   */
1380
  public static String write(DBConnection conn,String filename,
1381
                             String pub, String dtdfilename,
1382
                             String action, String docid, String user,
1383
                             String[] groups )
1384
                throws Exception {
1385
                  
1386
    Reader dtd = null;
1387
    if ( dtdfilename != null ) {
1388
      dtd = new FileReader(new File(dtdfilename).toString());
1389
    }
1390
    return write ( conn, new FileReader(new File(filename).toString()),
1391
                   pub, dtd, action, docid, user, groups, false);
1392
  }
1393

    
1394
  public static String write(DBConnection conn,Reader xml,String pub,Reader dtd,
1395
                             String action, String docid, String user,
1396
                             String[] groups, boolean validate)
1397
                throws Exception {
1398
    //this method will be called in handleUpdateOrInsert method 
1399
    //in MetacatServlet class
1400
    // get server location for this doc
1401
    int serverLocation=getServerLocationNumber(docid);
1402
    //System.out.println("server location: "+serverLocation);
1403
    return write(conn,xml,pub,dtd,action,docid,user,groups,serverLocation,false,
1404
                 validate);
1405
  }
1406

    
1407
  public static String write(DBConnection conn, Reader xml, String pub,
1408
                             String action, String docid, String user,
1409
                             String[] groups )
1410
                throws Exception {
1411
    if(action.equals("UPDATE"))
1412
    {//if the document is being updated then use the servercode from the 
1413
     //originally inserted document.
1414
      DocumentImpl doc = new DocumentImpl(docid);
1415
      int servercode = doc.getServerlocation();
1416
      return write(conn, xml, pub, action, docid, user, groups, servercode);
1417
    }
1418
    else
1419
    {//if the file is being inserted then the servercode is always 1
1420
      return write(conn, xml, pub, action, docid, user, groups, 1);
1421
    }
1422
  }
1423
  
1424
  public static String write(DBConnection conn, Reader xml,
1425
                              String action, String docid, String user,
1426
                              String[] groups, int serverCode )
1427
                throws Exception
1428
  {
1429
    return write(conn,xml,null,action,docid,user,groups,serverCode);
1430
  }
1431
  
1432
  public static String write(DBConnection conn, Reader xml, String pub,
1433
                              String action, String docid, String user,
1434
                              String[] groups, int serverCode) 
1435
                throws Exception
1436
  {
1437
    return write(conn,xml,pub,null,action,docid,user,groups,
1438
                 serverCode,false,false);
1439
  }
1440
  
1441
  public static String write(DBConnection conn, Reader xml, String pub,
1442
                              String action, String docid, String user,
1443
                              String[] groups, int serverCode, boolean override)
1444
                throws Exception
1445
  {
1446
    return write(conn,xml,pub,null,action,docid,user,groups,
1447
                 serverCode,override,false);
1448
  }
1449
  
1450
  /**
1451
   * Write an XML file to the database, given a Reader
1452
   *
1453
   * @param conn the JDBC connection to the database
1454
   * @param xml the xml stream to be loaded into the database
1455
   * @param pub flag for public "read" access on xml document
1456
   * @param dtd the dtd to be uploaded on server's file system
1457
   * @param action the action to be performed (INSERT or UPDATE)
1458
   * @param accnum the docid + rev# to use on INSERT or UPDATE
1459
   * @param user the user that owns the document
1460
   * @param groups the groups to which user belongs
1461
   * @param serverCode the serverid from xml_replication on which this document
1462
   *        resides.
1463
   * @param override flag to stop insert replication checking.
1464
   *        if override = true then a document not belonging to the local server
1465
   *        will not be checked upon update for a file lock.
1466
   *        if override = false then a document not from this server, upon 
1467
   *        update will be locked and version checked.
1468
   */
1469

    
1470
  public static String write(DBConnection conn, Reader xml,String pub,
1471
                         Reader dtd, String action, String accnum, String user,
1472
                         String[] groups, int serverCode, boolean override,
1473
                         boolean validate)
1474
                throws Exception
1475
  {
1476
    // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1477
    //MetaCatUtil util = new MetaCatUtil();
1478
    MetaCatUtil.debugMessage("conn usage count before writting: "
1479
                                      +conn.getUsageCount(), 50);
1480
    AccessionNumber ac = new AccessionNumber(accnum, action);
1481
    String docid = ac.getDocid();
1482
    String rev = ac.getRev();
1483
    MetaCatUtil.debugMessage("action: " + action + " servercode: " + 
1484
                             serverCode + " override: " + override, 10);
1485
                        
1486
    if((serverCode != 1 && action.equals("UPDATE")) && !override)
1487
    { //if this document being written is not a resident of this server then
1488
      //we need to try to get a lock from it's resident server.  If the
1489
      //resident server will not give a lock then we send the user a message
1490
      //saying that he/she needs to download a new copy of the file and
1491
      //merge the differences manually.
1492
      int istreamInt; 
1493
      char istreamChar;
1494
     
1495
      // check for 'write' permission for 'user' to update this document
1496
      if ( !hasPermission(user, groups, docid) ) {
1497
        throw new Exception("User " + user + 
1498
              " does not have permission to update XML Document #" + accnum);
1499
      }        
1500
  
1501
      DocumentIdentifier id = new DocumentIdentifier(accnum);
1502
      String updaterev = id.getRev();
1503
      String server=MetacatReplication.getServerNameForServerCode(serverCode);
1504
      MetacatReplication.replLog("attempting to lock " + accnum);
1505
      URL u = new URL("https://" + server + "?server="+
1506
        MetaCatUtil.getLocalReplicationServerName()+"&action=getlock&updaterev=" 
1507
           +updaterev + "&docid=" + docid);
1508
      //System.out.println("sending message: " + u.toString());
1509
      String serverResStr = MetacatReplication.getURLContent(u);
1510
      String openingtag =serverResStr.substring(0, serverResStr.indexOf(">")+1);
1511
      if(openingtag.equals("<lockgranted>"))
1512
      {//the lock was granted go ahead with the insert
1513
        try 
1514
        {
1515
          //System.out.println("In lockgranted");
1516
          MetacatReplication.replLog("lock granted for " + accnum + " from " +
1517
                                      server);
1518
          XMLReader parser = initializeParser(conn, action, docid, updaterev,
1519
                                  validate, user, groups, pub, serverCode, dtd);
1520
          conn.setAutoCommit(false);
1521
          parser.parse(new InputSource(xml)); 
1522
          conn.commit();
1523
          conn.setAutoCommit(true);
1524
        } 
1525
        catch (Exception e) 
1526
        {
1527
          conn.rollback();
1528
          conn.setAutoCommit(true);
1529
          throw e;
1530
        }
1531
                
1532
        
1533
        
1534
        // Force replication the docid
1535
        ForceReplicationHandler frh = new ForceReplicationHandler
1536
                                                          (accnum, true, null);
1537
        return(accnum);
1538
   
1539
      }
1540

    
1541
      else if(openingtag.equals("<filelocked>"))
1542
      {//the file is currently locked by another user
1543
       //notify our user to wait a few minutes, check out a new copy and try
1544
       //again.
1545
        //System.out.println("file locked");
1546
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1547
                                   server + " reason: file already locked");
1548
        throw new Exception("The file specified is already locked by another " +
1549
                            "user.  Please wait 30 seconds, checkout the " +
1550
                            "newer document, merge your changes and try " +
1551
                            "again.");
1552
      }
1553
      else if(openingtag.equals("<outdatedfile>"))
1554
      {//our file is outdated.  notify our user to check out a new copy of the
1555
       //file and merge his version with the new version.
1556
        //System.out.println("outdated file");
1557
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1558
                                    server + " reason: local file outdated");
1559
        throw new Exception("The file you are trying to update is an outdated" +
1560
                            " version.  Please checkout the newest document, " +
1561
                            "merge your changes and try again.");
1562
      }
1563
    }
1564
    
1565
    if ( action.equals("UPDATE") ) {
1566
      // check for 'write' permission for 'user' to update this document
1567

    
1568
      if ( !hasPermission(user, groups, docid) ) {
1569
        throw new Exception("User " + user + 
1570
              " does not have permission to update XML Document #" + accnum);
1571
      }          
1572
    }
1573

    
1574
    try 
1575
    { 
1576
      
1577
      XMLReader parser = initializeParser(conn, action, docid, rev, validate,
1578
                                          user, groups, pub, serverCode, dtd);
1579
   
1580
      conn.setAutoCommit(false);
1581
      parser.parse(new InputSource(xml));
1582
      conn.commit();
1583
      conn.setAutoCommit(true);
1584
    } 
1585
    catch (Exception e) 
1586
    {
1587
      conn.rollback();
1588
      conn.setAutoCommit(true);
1589
      throw e;
1590
    }
1591
    
1592
    // Force replicate out the new document to each server in our server list.
1593
    // Start the thread to replicate this new document out to the other servers
1594
    // true mean it is xml document
1595
    // null is because no metacat notify the force replication.
1596
    ForceReplicationHandler frh = new ForceReplicationHandler
1597
                                                  (accnum, action, true, null);
1598
      
1599
   
1600
    MetaCatUtil.debugMessage("Conn Usage count after writting: "
1601
                                                      +conn.getUsageCount(),50); 
1602
    return(accnum);
1603
  }
1604

    
1605
  /**
1606
   * Write an XML file to the database during replication
1607
   *
1608
   * @param conn the JDBC connection to the database
1609
   * @param xml the xml stream to be loaded into the database
1610
   * @param pub flag for public "read" access on xml document
1611
   * @param dtd the dtd to be uploaded on server's file system
1612
   * @param action the action to be performed (INSERT or UPDATE)
1613
   * @param accnum the docid + rev# to use on INSERT or UPDATE
1614
   * @param user the user that owns the document
1615
   * @param groups the groups to which user belongs
1616
   * @param homeServer the name of server which the document origanlly create
1617
   * @param validate, if the xml document is valid or not
1618
   * @param notifyServer, the server which notify local server the force 
1619
   *                       replication command
1620
   */
1621

    
1622
  public static String writeReplication(DBConnection conn, Reader xml, 
1623
            String pub, Reader dtd, String action, String accnum, String user,
1624
     String[] groups,String homeServer, boolean validate, String notifyServer)
1625
                throws Exception
1626
  {
1627
    // Docid without revision
1628
    String docid=MetaCatUtil.getDocIdFromString(accnum);
1629
    // Revision specified by user (int)
1630
    int userSpecifyRev=MetaCatUtil.getVersionFromString(accnum);
1631
    // Revision for this docid in current database
1632
    int revInDataBase=getLatestRevisionNumber(docid);
1633
    // String to store the revision
1634
    String rev = null;
1635
   
1636
    
1637
    //revIndataBase=-1, there is no record in xml_documents table
1638
    //the document is a new one for local server, inert it into table
1639
    //user specified rev should be great than 0
1640
    if (revInDataBase==-1 && userSpecifyRev>0 )
1641
    {
1642
        // rev equals user specified
1643
        rev=(new Integer(userSpecifyRev)).toString();
1644
        // action should be INSERT
1645
        action = "INSERT";
1646
    }
1647
    //rev is greater the last revsion number and revInDataBase isn't -1
1648
    // it is a updated  file
1649
    else if (userSpecifyRev>revInDataBase && revInDataBase>0)
1650
    {
1651
       // rev equals user specified
1652
       rev=(new Integer(userSpecifyRev)).toString();
1653
       // action should be update
1654
       action = "UPDATE";
1655
    }
1656
    // local server has newer version, then notify the remote server
1657
    else if ( userSpecifyRev < revInDataBase && revInDataBase > 0)
1658
    {
1659
      throw new Exception("Local server: "+MetaCatUtil.getOption("server")+
1660
                " has newer revision of doc: "+docid+"."+revInDataBase
1661
                 +". Please notify it.");
1662
    }
1663
    //other situation
1664
    else
1665
    {
1666
        
1667
        throw new Exception("The docid"+docid+"'s revision number couldn't be "
1668
                    +userSpecifyRev);
1669
    }
1670
    // Variable to store homeserver code
1671
    int serverCode=-2;
1672
    
1673
     // If server is not int the xml replication talbe, insert it into
1674
    // xml_replication table
1675
    //serverList.addToServerListIfItIsNot(homeServer);
1676
    insertServerIntoReplicationTable(homeServer);
1677
    // Get server code again
1678
    serverCode = getServerCode(homeServer);
1679
    
1680
    
1681
    MetaCatUtil.debugMessage("Document "+docid+"."+rev+" "+action+ " into local"
1682
                               +" metacat with servercode: "+ serverCode, 10);
1683
                        
1684
  
1685
    // insert into xml_nodes and xml_index table
1686
    try 
1687
    { 
1688
      
1689
      XMLReader parser = initializeParser(conn, action, docid, rev, validate,
1690
                                          user, groups, pub, serverCode, dtd);
1691
      conn.setAutoCommit(false);
1692
      parser.parse(new InputSource(xml));
1693
      conn.commit();
1694
      conn.setAutoCommit(true);
1695
    } 
1696
    catch (Exception e) 
1697
    {
1698
      conn.rollback();
1699
      conn.setAutoCommit(true);
1700
      throw e;
1701
    }
1702
    
1703
    //Force replication to other server
1704
    ForceReplicationHandler forceReplication = new ForceReplicationHandler
1705
                                  (accnum, action, true, notifyServer);
1706
    
1707

    
1708
    return(accnum);
1709
  }
1710

    
1711
  
1712
  /**
1713
   * Delete an XML file from the database (actually, just make it a revision
1714
   * in the xml_revisions table)
1715
   *
1716
   * @param docid the ID of the document to be deleted from the database
1717
   */
1718
  public static void delete(String accnum,
1719
                                 String user, String[] groups )
1720
                throws Exception 
1721
  {
1722
    // OLD
1723
    //DocumentIdentifier id = new DocumentIdentifier(accnum);
1724
    //String docid = id.getIdentifier();
1725
    //String rev = id.getRev();
1726
    
1727
    // OLD
1728
    // Determine if the docid,rev are OK for DELETE
1729
    //AccessionNumber ac = new AccessionNumber(conn);
1730
    //docid = ac.generate(docid, rev, "DELETE");
1731
    DBConnection conn = null;
1732
    int serialNumber = -1;
1733
    PreparedStatement pstmt =null;
1734
    try
1735
    {
1736
      //check out DBConnection
1737
      conn=DBConnectionPool.
1738
                    getDBConnection("DocumentImpl.delete");
1739
      serialNumber=conn.getCheckOutSerialNumber();
1740

    
1741
      // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1742
      AccessionNumber ac = new AccessionNumber(accnum, "DELETE");
1743
      String docid = ac.getDocid();
1744
      String rev = ac.getRev();
1745
    
1746

    
1747
    // check for 'write' permission for 'user' to delete this document
1748
      if ( !hasPermission(user, groups, docid) ) {
1749
        throw new Exception("User " + user + 
1750
              " does not have permission to delete XML Document #" + accnum);
1751
      }
1752

    
1753
      conn.setAutoCommit(false);
1754
      // Copy the record to the xml_revisions table
1755
      DocumentImpl.archiveDocRevision(conn, docid, user );
1756

    
1757
      // Now delete it from the xml_index table
1758
      pstmt = conn.prepareStatement("DELETE FROM xml_index WHERE docid = ?");
1759
      pstmt.setString(1,docid);
1760
      pstmt.execute();
1761
      pstmt.close();
1762
      conn.increaseUsageCount(1);
1763
      
1764
      //stmt.execute("DELETE FROM xml_access WHERE docid = '" + docid + "'");
1765
      // Now delete it from xml_access table
1766
      pstmt = conn.
1767
              prepareStatement("DELETE FROM xml_access WHERE accessfileid = ?");
1768
      pstmt.setString(1, docid);
1769
      pstmt.execute();
1770
      pstmt.close();
1771
      conn.increaseUsageCount(1);
1772
      
1773
      // Delete it from relation table
1774
      pstmt = conn.
1775
               prepareStatement("DELETE FROM xml_relation WHERE docid = ?");
1776
      //increase usage count
1777
      conn.increaseUsageCount(1);
1778
      pstmt.setString(1, docid);
1779
      pstmt.execute();
1780
      pstmt.close();
1781
      
1782
      // Delete it from xml_doucments table
1783
      pstmt =conn.prepareStatement("DELETE FROM xml_documents WHERE docid = ?");
1784
      pstmt.setString(1, docid);
1785
      pstmt.execute();
1786
      pstmt.close();
1787
      //Usaga count increase 1
1788
      conn.increaseUsageCount(1);
1789
      
1790
      conn.commit();
1791
      conn.setAutoCommit(true);
1792
    }//try
1793
    finally
1794
    {
1795
      
1796
      try
1797
      {
1798
        // close preparedStatement
1799
        pstmt.close();
1800
      }//try
1801
      finally
1802
      {
1803
        //check in DBonnection
1804
        DBConnectionPool.returnDBConnection(conn, serialNumber);
1805
      }//finally
1806
    }//finally
1807
    //IF this is a package document:
1808
    //delete all of the relations that this document created.
1809
    //if the deleted document is a package document its relations should 
1810
    //no longer be active if it has been deleted from the system.
1811
    
1812
  }
1813

    
1814
  /** 
1815
    * Check for "WRITE" permission on @docid for @user and/or @groups 
1816
    * from DB connection 
1817
    */
1818
  private static boolean hasPermission (String user,
1819
                                  String[] groups, String docid ) 
1820
                  throws SQLException, Exception
1821
  {
1822
    // Check for WRITE permission on @docid for @user and/or @groups
1823
    //AccessControlList aclobj = new AccessControlList(dbconn);
1824
    return AccessControlList.hasPermission("WRITE", user, groups, docid);
1825
    //return aclobj.hasPermission("WRITE", user, groups, docid);
1826
  }
1827

    
1828
  /** 
1829
    * Check for "READ" permission base on docid, user and group
1830
    *@docid, the document
1831
    *@user, user name
1832
    *@group, user's group
1833
    * 
1834
    */
1835
  public static boolean hasReadPermission (String user,
1836
                                  String[] groups, String docId ) 
1837
                  throws SQLException, Exception
1838
  {
1839
    // Check for READ permission on @docid for @user and/or @groups
1840
    //AccessControlList aclObj = new AccessControlList(conn);
1841
    //return aclObj.hasPermission("READ", user, groups, docId);
1842
    return AccessControlList.hasPermission("READ", user, groups, docId);
1843
  }  
1844

    
1845
  /**
1846
   * Set up the parser handlers for writing the document to the database
1847
   */
1848
  private static XMLReader initializeParser(DBConnection dbconn, String action,
1849
                               String docid, String rev, boolean validate, 
1850
                                   String user, String[] groups, String pub, 
1851
                                   int serverCode, Reader dtd) 
1852
                           throws Exception 
1853
  {
1854
    XMLReader parser = null;
1855
    //DBConnection conn = null;
1856
    //int serialNumber = -1;
1857
    //
1858
    // Set up the SAX document handlers for parsing
1859
    //
1860
    try {
1861
       //check out DBConnection
1862
      /*conn=DBConnectionPool.
1863
                    getDBConnection("DocumentImpl.initializeParse");
1864
      serialNumber=conn.getCheckOutSerialNumber();*/
1865
      
1866
      //create a DBSAXHandler object which has the revision specification
1867
      ContentHandler chandler = new DBSAXHandler(dbconn, action, 
1868
                                    docid, rev, user, groups, pub, serverCode);
1869
      EntityResolver eresolver= new DBEntityResolver(dbconn,
1870
                                                 (DBSAXHandler)chandler, dtd);
1871
      DTDHandler dtdhandler   = new DBDTDHandler(dbconn);
1872

    
1873
      // Get an instance of the parser
1874
      String parserName = MetaCatUtil.getOption("saxparser");
1875
      parser = XMLReaderFactory.createXMLReader(parserName);
1876

    
1877
      // Turn on validation
1878
      parser.setFeature("http://xml.org/sax/features/validation", validate);
1879
      // Turn off Including all external parameter entities
1880
      // (the external DTD subset also)
1881
      // Doesn't work well, probably the feature name is not correct
1882
      // parser.setFeature(
1883
      //  "http://xml.org/sax/features/external-parameter-entities", false);
1884
      
1885
      // Set Handlers in the parser
1886
      parser.setProperty("http://xml.org/sax/properties/declaration-handler",
1887
                         chandler);
1888
      parser.setProperty("http://xml.org/sax/properties/lexical-handler",
1889
                         chandler);
1890
      parser.setContentHandler((ContentHandler)chandler);
1891
      parser.setEntityResolver((EntityResolver)eresolver);
1892
      parser.setDTDHandler((DTDHandler)dtdhandler);
1893
      parser.setErrorHandler((ErrorHandler)chandler);
1894

    
1895
    } catch (Exception e) {
1896
      throw e;
1897
    }
1898
    //finally
1899
    //{
1900
      //DBConnectionPool.returnDBConnection(conn, serialNumber);
1901
    //}
1902

    
1903
    return parser;
1904
  }
1905

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

    
1971
  }//achiveDocRevision
1972
  
1973
  /** Save a document entry in the xml_revisions table */
1974
  private static void archiveDocRevision(String docid, String user) 
1975
 {
1976
    String sysdate = dbAdapter.getDateTimeFunction();
1977
    DBConnection conn = null;
1978
    int serialNumber = -1;
1979
    PreparedStatement pstmt = null;
1980
    
1981
    // create a record in xml_revisions table 
1982
    // for that document as selected from xml_documents
1983
   
1984
   try
1985
   {
1986
     //check out DBConnection
1987
     conn=DBConnectionPool.
1988
                    getDBConnection("DocumentImpl.archiveDocRevision");
1989
     serialNumber=conn.getCheckOutSerialNumber();
1990
     pstmt = conn.prepareStatement(
1991
      "INSERT INTO xml_revisions " +
1992
        "(docid, rootnodeid, docname, doctype, " +
1993
        "user_owner, user_updated, date_created, date_updated, " +
1994
        "server_location, rev, public_access, catalog_id) " +
1995
      "SELECT ?, rootnodeid, docname, doctype, " + 
1996
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
1997
        "server_location, rev, public_access, catalog_id " +
1998
      "FROM xml_documents " +
1999
      "WHERE docid = ?");
2000
      // Bind the values to the query and execute it
2001
      pstmt.setString(1, docid);
2002
      pstmt.setString(2, user);
2003
      pstmt.setString(3, docid);
2004
      pstmt.execute();
2005
      pstmt.close();
2006
   }//try
2007
   catch (SQLException e)
2008
   {
2009
     MetaCatUtil.debugMessage("Error in DocumentImpl.archiveDocRevision : "+
2010
                                e.getMessage(), 30);
2011
   }//catch
2012
   finally
2013
   {
2014
     try
2015
     {
2016
       pstmt.close();
2017
     }//try
2018
     catch (SQLException ee)
2019
     {
2020
       MetaCatUtil.debugMessage("Error in DocumnetImpl.archiveDocRevision: "+
2021
                                  ee.getMessage(), 50);
2022
     }//catch
2023
     finally
2024
     {
2025
       //check in DBConnection
2026
       DBConnectionPool.returnDBConnection(conn, serialNumber);
2027
     }//finally
2028
   }//finnally
2029
                                  
2030

    
2031
  }//achiveDocRevision
2032
  
2033
  /**
2034
    * delete a entry in xml_table for given docid
2035
    * @param docId, the id of the document need to be delete
2036
    */
2037
  private static void deleteXMLDocuments(String docId) 
2038
                                         throws SQLException 
2039
  {
2040
    DBConnection conn = null;
2041
    int serialNumber = -1;
2042
    PreparedStatement pStmt = null;
2043
    try
2044
    {
2045
      //check out DBConnection
2046
      conn=DBConnectionPool.
2047
                    getDBConnection("DocumentImpl.deleteXMLDocuments");
2048
      serialNumber=conn.getCheckOutSerialNumber();
2049
      //delete a record 
2050
      pStmt = 
2051
             conn.prepareStatement("DELETE FROM xml_documents WHERE docid = '" 
2052
                                              + docId + "'");
2053
    pStmt.execute();
2054
    }//try
2055
    finally
2056
    {
2057
      try
2058
      {
2059
        pStmt.close();
2060
      }//try
2061
      catch (SQLException e)
2062
      {
2063
        MetaCatUtil.debugMessage("error in DocumentImpl.deleteXMLDocuments: "+
2064
                                  e.getMessage(), 50);
2065
      }//catch
2066
      finally
2067
      {
2068
        //return back DBconnection
2069
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2070
      }//finally
2071
    }//finally
2072
      
2073

    
2074
  }//deleteXMLDocuments
2075
  
2076
  /**
2077
    * Get last revision number from database for a docid
2078
    * If couldn't find an entry,  -1 will return
2079
    * The return value is integer because we want compare it to there new one
2080
    * @param docid <sitecode>.<uniqueid> part of Accession Number
2081
    */
2082
  private static int getLatestRevisionNumber(String docId)
2083
                                      throws SQLException
2084
  {
2085
    int rev = 1;
2086
    PreparedStatement pStmt = null;
2087
    DBConnection dbConn = null;
2088
    int serialNumber = -1;
2089
    
2090
    try
2091
    {
2092
      //check out DBConnection
2093
      dbConn=DBConnectionPool.
2094
                    getDBConnection("DocumentImpl.getLatestRevisionNumber");
2095
      serialNumber=dbConn.getCheckOutSerialNumber();
2096
     
2097
      pStmt = dbConn.prepareStatement
2098
              ("SELECT rev FROM xml_documents WHERE docid='" + docId + "'");
2099
      pStmt.execute();
2100

    
2101
      ResultSet rs = pStmt.getResultSet();
2102
      boolean hasRow = rs.next();
2103
      if (hasRow)
2104
      {
2105
        rev = rs.getInt(1);
2106
        pStmt.close();
2107
      }
2108
      else
2109
      {
2110
        rev=-1;
2111
        pStmt.close();
2112
      }
2113
    }//try
2114
    finally
2115
    {
2116
      try
2117
      {
2118
        pStmt.close();
2119
      }
2120
      catch (Exception ee)
2121
      {
2122
        MetaCatUtil.debugMessage("Error in DocumentImpl."+
2123
                        "getLatestRevisionNumber: "+ee.getMessage(), 50);
2124
      }
2125
      finally
2126
      {
2127
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2128
      }
2129
    }//finally  
2130
      
2131
    return rev;
2132
  }//getLatestRevisionNumber
2133
  
2134
  /**
2135
   * Get server location form database for a accNum
2136
   * 
2137
   * @param accum <sitecode>.<uniqueid>.<rev>
2138
   */
2139
  private static int getServerLocationNumber(String accNum)
2140
                                            throws SQLException
2141
  {
2142
    //get rid of revNum part
2143
    String docId=MetaCatUtil.getDocIdFromString(accNum);
2144
    PreparedStatement pStmt = null;
2145
    int serverLocation = 1;
2146
    DBConnection conn = null;
2147
    int serialNumber = -1;
2148
    
2149
    try
2150
    {
2151
      //check out DBConnection
2152
      conn=DBConnectionPool.
2153
                    getDBConnection("DocumentImpl.getServerLocationNumber");
2154
      serialNumber=conn.getCheckOutSerialNumber();
2155
     
2156
      pStmt = conn.prepareStatement
2157
      ("SELECT server_location FROM xml_documents WHERE docid='" + docId + "'");
2158
      pStmt.execute();
2159

    
2160
      ResultSet rs = pStmt.getResultSet();
2161
      boolean hasRow = rs.next();
2162
      //if there is entry in xml_documents, get the serverlocation
2163
      if (hasRow)
2164
      {
2165
        serverLocation = rs.getInt(1);
2166
        pStmt.close();
2167
      }
2168
      else
2169
      {
2170
        //if htere is no entry in xml_documents, we consider it is new document
2171
        //the server location is local host and value is 1
2172
        serverLocation=1;
2173
        pStmt.close();
2174
      }
2175
    }//try
2176
    finally
2177
    {
2178
      try
2179
      {
2180
        pStmt.close();
2181
      }//try
2182
      catch (Exception ee)
2183
      {
2184
        MetaCatUtil.debugMessage("Error in DocumentImpl.getServerLocationNu(): "
2185
                                    +ee.getMessage(), 50);
2186
      }//catch
2187
      finally
2188
      {
2189
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2190
      }//finally
2191
    }//finally
2192
      
2193
    return serverLocation;
2194
  }
2195
  
2196
  /**
2197
   * Given a server name, return its servercode in xml_replication table.
2198
   * If no server is found, -1 will return
2199
   * @param serverName, 
2200
   */
2201
  private static int getServerCode(String serverName) 
2202
  {
2203
    PreparedStatement pStmt=null;
2204
    int serverLocation=-2;
2205
    DBConnection dbConn = null;
2206
    int serialNumber = -1;
2207
    //MetaCatUtil util = new MetaCatUtil();
2208
    
2209
    
2210
    //we should consider about local host too
2211
    if (serverName.equals(MetaCatUtil.getLocalReplicationServerName()))
2212
    { 
2213
      serverLocation=1;
2214
      return serverLocation;
2215
    }
2216
    
2217
   
2218
    try
2219
    {
2220
      //check xml_replication table
2221
      //dbConn=util.openDBConnection();
2222
      //check out DBConnection
2223
      dbConn=DBConnectionPool.getDBConnection("DocumentImpl.getServerCode");
2224
      serialNumber=dbConn.getCheckOutSerialNumber();
2225
      pStmt = dbConn.prepareStatement
2226
      ("SELECT serverid FROM xml_replication WHERE server='" + serverName +"'");
2227
      pStmt.execute();
2228

    
2229
      ResultSet rs = pStmt.getResultSet();
2230
      boolean hasRow = rs.next();
2231
      //if there is entry in xml_replication, get the serverid
2232
      if (hasRow)
2233
      {
2234
        serverLocation = rs.getInt(1);
2235
        pStmt.close();
2236
      }
2237
      else
2238
      {
2239
        // if htere is no entry in xml_replication, -1 will return
2240
        serverLocation=-1;
2241
        pStmt.close();
2242
      }
2243
    }
2244
    catch (Exception e)
2245
    {
2246
      MetaCatUtil.debugMessage("Error in DocumentImpl.getServerCode(): "
2247
                                    +e.getMessage(), 30);
2248
    }
2249
    finally
2250
    {
2251
      try
2252
      {
2253
        pStmt.close();
2254
      }
2255
      catch (Exception ee)
2256
      {
2257
        MetaCatUtil.debugMessage("Error in DocumentImpl.getServerCode(): "
2258
                                    +ee.getMessage(), 50);
2259
      }
2260
      finally
2261
      {
2262
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2263
      }
2264
    }
2265
                 
2266
      
2267
    return serverLocation;
2268
  }
2269
  
2270
  /**
2271
   * Insert a server into xml_replcation table
2272
   * @param server, the name of server 
2273
   */
2274
  private static synchronized void 
2275
                                insertServerIntoReplicationTable(String server)
2276
  {
2277
    PreparedStatement pStmt=null;
2278
    DBConnection dbConn = null;
2279
    int serialNumber = -1;
2280
    
2281
    // Initial value for the server
2282
    int replicate = 0;
2283
    int dataReplicate = 0;
2284
    int hub = 0;
2285
   
2286
    try
2287
    {
2288
       // Get DBConnection
2289
       dbConn=DBConnectionPool.
2290
                getDBConnection("DocumentImpl.insertServIntoReplicationTable");
2291
       serialNumber=dbConn.getCheckOutSerialNumber();
2292
      
2293
      // Compare the server to dabase
2294
      pStmt = dbConn.prepareStatement
2295
      ("SELECT serverid FROM xml_replication WHERE server='" + server +"'");
2296
      pStmt.execute();
2297
      ResultSet rs = pStmt.getResultSet();
2298
      boolean hasRow = rs.next();
2299
      // Close preparedstatement and result set
2300
      pStmt.close();
2301
      rs.close();
2302
      
2303
      // If the server is not in the table, and server is not local host,
2304
      // insert it
2305
      if ( !hasRow 
2306
         && !server.equals(MetaCatUtil.getLocalReplicationServerName()))
2307
      {
2308
        // Set auto commit false
2309
        dbConn.setAutoCommit(false);
2310
        pStmt = dbConn.prepareStatement("INSERT INTO xml_replication " +
2311
                      "(server, last_checked, replicate, datareplicate, hub) " +
2312
                       "VALUES ('" + server + "', to_date(" +
2313
                       "'01/01/00', 'MM/DD/YY'), '" +
2314
                       replicate +"', '"+dataReplicate+"','"+ hub + "')");
2315
        pStmt.execute();
2316
        dbConn.commit();
2317
        // Increase usage number
2318
        dbConn.increaseUsageCount(1);
2319
        pStmt.close();
2320
        
2321
      }
2322
    }//try
2323
    catch (Exception e)
2324
    {
2325
      MetaCatUtil.debugMessage("Error in DocumentImpl.insertServerIntoRepli(): "
2326
                                    +e.getMessage(), 30);
2327
    }//catch
2328
    finally
2329
    {
2330
     
2331
      try
2332
      {
2333
        // Set auto commit true
2334
        dbConn.setAutoCommit(true);
2335
        pStmt.close();
2336
        
2337
      }//try
2338
      catch (Exception ee)
2339
      {
2340
        MetaCatUtil.debugMessage("Error in DocumentImpl.insetServerIntoRepl(): "
2341
                                    +ee.getMessage(), 50);
2342
      }//catch
2343
      finally
2344
      {
2345
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2346
      }
2347
    
2348
    }//finally
2349

    
2350
  }
2351
  
2352
  
2353
  /**
2354
   * the main routine used to test the DBWriter utility.
2355
   * <p>
2356
   * Usage: java DocumentImpl <-f filename -a action -d docid>
2357
   *
2358
   * @param filename the filename to be loaded into the database
2359
   * @param action the action to perform (READ, INSERT, UPDATE, DELETE)
2360
   * @param docid the id of the document to process
2361
   */
2362
  static public void main(String[] args) {
2363
    DBConnection dbconn = null;
2364
    int serialNumber = -1;
2365
    try {
2366
      String filename    = null;
2367
      String dtdfilename = null;
2368
      String action      = null;
2369
      String docid       = null;
2370
      boolean showRuntime = false;
2371
      boolean useOldReadAlgorithm = false;
2372

    
2373
      // Parse the command line arguments
2374
      for ( int i=0 ; i < args.length; ++i ) {
2375
        if ( args[i].equals( "-f" ) ) {
2376
          filename =  args[++i];
2377
        } else if ( args[i].equals( "-r" ) ) {
2378
          dtdfilename =  args[++i];
2379
        } else if ( args[i].equals( "-a" ) ) {
2380
          action =  args[++i];
2381
        } else if ( args[i].equals( "-d" ) ) {
2382
          docid =  args[++i];
2383
        } else if ( args[i].equals( "-t" ) ) {
2384
          showRuntime = true;
2385
        } else if ( args[i].equals( "-old" ) ) {
2386
          useOldReadAlgorithm = true;
2387
        } else {
2388
          System.err.println
2389
            ( "   args[" +i+ "] '" +args[i]+ "' ignored." );
2390
        }
2391
      }
2392
      
2393
      // Check if the required arguments are provided
2394
      boolean argsAreValid = false;
2395
      if (action != null) {
2396
        if (action.equals("INSERT")) {
2397
          if (filename != null) {
2398
            argsAreValid = true;
2399
          } 
2400
        } else if (action.equals("UPDATE")) {
2401
          if ((filename != null) && (docid != null)) {
2402
            argsAreValid = true;
2403
          } 
2404
        } else if (action.equals("DELETE")) {
2405
          if (docid != null) {
2406
            argsAreValid = true;
2407
          } 
2408
        } else if (action.equals("READ")) {
2409
          if (docid != null) {
2410
            argsAreValid = true;
2411
          } 
2412
        } 
2413
      } 
2414

    
2415
      // Print usage message if the arguments are not valid
2416
      if (!argsAreValid) {
2417
        System.err.println("Wrong number of arguments!!!");
2418
        System.err.println(
2419
          "USAGE: java DocumentImpl [-t] <-a INSERT> [-d docid] <-f filename> "+
2420
          "[-r dtdfilename]");
2421
        System.err.println(
2422
          "   OR: java DocumentImpl [-t] <-a UPDATE -d docid -f filename> " +
2423
          "[-r dtdfilename]");
2424
        System.err.println(
2425
          "   OR: java DocumentImpl [-t] <-a DELETE -d docid>");
2426
        System.err.println(
2427
          "   OR: java DocumentImpl [-t] [-old] <-a READ -d docid>");
2428
        return;
2429
      }
2430
      
2431
      // Time the request if asked for
2432
      double startTime = System.currentTimeMillis();
2433
      
2434
      // Open a connection to the database
2435
      MetaCatUtil util = new MetaCatUtil();
2436
     
2437
      dbconn=DBConnectionPool.getDBConnection("DocumentImpl.main");
2438
      serialNumber=dbconn.getCheckOutSerialNumber();
2439

    
2440
      double connTime = System.currentTimeMillis();
2441
      // Execute the action requested (READ, INSERT, UPDATE, DELETE)
2442
      if (action.equals("READ")) {
2443
          DocumentImpl xmldoc = new DocumentImpl(docid );
2444
          if (useOldReadAlgorithm) {
2445
            System.out.println(xmldoc.readUsingSlowAlgorithm());
2446
          } else {
2447
            xmldoc.toXml(new PrintWriter(System.out));
2448
          }
2449
      } else if (action.equals("DELETE")) {
2450
        DocumentImpl.delete(docid, null, null);
2451
        System.out.println("Document deleted: " + docid);
2452
      } else {
2453
        String newdocid = DocumentImpl.write(dbconn, filename, null,
2454
                                             dtdfilename, action, docid,
2455
                                             null, null);
2456
        if ((docid != null) && (!docid.equals(newdocid))) {
2457
          if (action.equals("INSERT")) {
2458
            System.out.println("New document ID generated!!! ");
2459
          } else if (action.equals("UPDATE")) {
2460
            System.out.println("ERROR: Couldn't update document!!! ");
2461
          }
2462
        } else if ((docid == null) && (action.equals("UPDATE"))) {
2463
          System.out.println("ERROR: Couldn't update document!!! ");
2464
        }
2465
        System.out.println("Document processing finished for: " + filename
2466
              + " (" + newdocid + ")");
2467
      }
2468

    
2469
      double stopTime = System.currentTimeMillis();
2470
      double dbOpenTime = (connTime - startTime)/1000;
2471
      double insertTime = (stopTime - connTime)/1000;
2472
      double executionTime = (stopTime - startTime)/1000;
2473
      if (showRuntime) {
2474
        System.out.println("\n\nTotal Execution time was: " + 
2475
                           executionTime + " seconds.");
2476
        System.out.println("Time to open DB connection was: " + dbOpenTime + 
2477
                           " seconds.");
2478
        System.out.println("Time to insert document was: " + insertTime +
2479
                           " seconds.");
2480
      }
2481
      dbconn.close();
2482
    } catch (McdbException me) {
2483
      me.toXml(new PrintWriter(System.err));
2484
    } catch (AccessionNumberException ane) {
2485
      System.out.println(ane.getMessage());
2486
    } catch (Exception e) {
2487
      System.err.println("EXCEPTION HANDLING REQUIRED");
2488
      System.err.println(e.getMessage());
2489
      e.printStackTrace(System.err);
2490
    }
2491
    finally
2492
    {
2493
      // Return db connection
2494
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
2495
    }
2496
  }
2497
}
(26-26/46)