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: 2003-02-14 16:56:38 -0800 (Fri, 14 Feb 2003) $'
11
 * '$Revision: 1407 $'
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
   /* Constants */
71
   public static final String SCHEMA                 = "schema";
72
   public static final String DTD                    = "dtd";
73
   public static final String EML2                   = "eml2";
74
   public static final String EXTERNALSCHEMALOCATIONPROPERTY = 
75
              "http://apache.org/xml/properties/schema/external-schemaLocation";
76
   /*public static final String EXTERNALSCHEMALOCATION = 
77
     "eml://ecoinformatics.org/eml-2.0.0 http://dev.nceas.ucsb.edu/tao/schema/eml.xsd"+
78
      " http://www.xml-cml.org/schema/stmml http://dev.nceas.ucsb.edu/tao/schema/stmml.xsd";*/
79
   public static final String DECLARATIONHANDLERPROPERTY =
80
                            "http://xml.org/sax/properties/declaration-handler";
81
   public static final String LEXICALPROPERTY =
82
                             "http://xml.org/sax/properties/lexical-handler";
83
   public static final String VALIDATIONFEATURE = 
84
                             "http://xml.org/sax/features/validation";
85
   public static final String SCHEMAVALIDATIONFEATURE = 
86
                             "http://apache.org/xml/features/validation/schema";
87
   public static final String NAMESPACEFEATURE = 
88
                              "http://xml.org/sax/features/namespaces";
89
   public static final String NAMESPACEPREFIXESFEATURE = 
90
                              "http://xml.org/sax/features/namespace-prefixes";
91
  
92
  
93
  static final int ALL = 1;
94
  static final int WRITE = 2;
95
  static final int READ = 4;
96
  private static final AbstractDatabase dbAdapter = MetaCatUtil.dbAdapter;
97

    
98
  private DBConnection connection = null;
99
  private String docid = null;
100
  private String updatedVersion=null;
101
  private String docname = null;
102
  private String doctype = null;
103
// DOCTITLE attr cleared from the db
104
//  private String doctitle = null;
105
  private String createdate = null;
106
  private String updatedate = null;
107
  private String system_id = null;
108
  private String userowner = null;
109
  private String userupdated = null;
110
  private int rev;
111
  private int serverlocation;
112
  private String docHomeServer;
113
  private String publicaccess; 
114
  private long rootnodeid;
115
  private ElementNode rootNode = null;
116
  private TreeSet nodeRecordList = null;
117
  //private static 
118
  //ReplicationServerList serverList = new ReplicationServerList();
119
  
120
  /**
121
   * Constructor used to create a document and read the document information
122
   * from the database.  If readNodes is false, then the node data is not 
123
   * read at this time, but is deferred until it is needed (such as when a 
124
   * call to toXml() is made).  
125
   *
126
   * @param conn the database connection from which to read the document
127
   * @param docid the identifier of the document to be created
128
   * @param readNodes flag indicating whether the xmlnodes should be read
129
   */
130
  public DocumentImpl(String docid, boolean readNodes) 
131
         throws McdbException 
132
  {
133
    try {
134
      //this.conn = conn;
135
      this.docid = docid;
136
      
137
      // Look up the document information
138
      getDocumentInfo(docid);
139
      
140
      if (readNodes) {
141
        // Download all of the document nodes using a single SQL query
142
        // The sort order of the records is determined by the NodeComparator
143
        // class, and needs to represent a depth-first traversal for the
144
        // toXml() method to work properly
145
        nodeRecordList = getNodeRecordList(rootnodeid);
146
        
147
      }
148
    
149
    } catch (McdbException ex) {
150
      throw ex;
151
    } catch (Throwable t) {
152
      throw new McdbException("Error reading document from " +
153
                              "DocumentImpl.DocumentImpl: " + docid);
154
    }
155
  }
156

    
157
  /**
158
   * Constructor, creates document from database connection, used 
159
   * for reading the document
160
   *
161
   * @param conn the database connection from which to read the document
162
   * @param docid the identifier of the document to be created
163
   */
164
  public DocumentImpl(String docid) throws McdbException 
165
  {
166
    this(docid, true);
167
  }
168

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

    
551
    BufferedInputStream bis = null;
552
    bis = new BufferedInputStream(input);
553
    byte[] buf = new byte[4 * 1024]; // 4K buffer
554
    int b = bis.read(buf);
555
       
556
    while (b != -1) 
557
    {
558
        outPut.write(buf, 0, b);
559
        b = bis.read(buf);
560
    }
561
    bis.close();
562
	  outPut.close();
563
	  fos.close();
564
      
565
    // Force replicate data file
566
    ForceReplicationHandler forceReplication = new ForceReplicationHandler
567
                                    (accnum, false, notificationServer);
568
  
569
 }
570
  
571

    
572
  
573
  public static boolean getDataFileLockGrant(String accnum) 
574
                                                  throws Exception
575
  { 
576
    
577
    try
578
    {
579
      
580
      int serverLocation=getServerLocationNumber(accnum);
581
    
582
      return getDataFileLockGrant(accnum,serverLocation);
583
    }
584
    catch (Exception e)
585
    {
586
     
587
      throw e;
588
    }
589
  }
590
    
591
  /**
592
   * The method will check if metacat can get data file lock grant
593
   * If server code is 1, it get.
594
   * If server code is not 1 but call replication getlock successfully,
595
   * it get
596
   * else, it didn't get
597
   * @param accnum, the ID of the document 
598
   * @param action, the action to the document
599
   * @param serverCode, the server location code
600
   */
601
  public static boolean getDataFileLockGrant(String accnum, int serverCode)
602
                                          throws Exception 
603
  {
604
    boolean flag=true;
605
    //MetaCatUtil util = new MetaCatUtil();
606
    String docid = MetaCatUtil.getDocIdFromString(accnum);
607
    int rev = MetaCatUtil.getVersionFromString(accnum);
608
    
609
    if (serverCode == 1)
610
    {
611
      flag=true;
612
      return flag;
613
    }
614
    
615
    //if((serverCode != 1 && action.equals("UPDATE")) )
616
    if (serverCode != 1)
617
    { //if this document being written is not a resident of this server then
618
      //we need to try to get a lock from it's resident server.  If the
619
      //resident server will not give a lock then we send the user a message
620
      //saying that he/she needs to download a new copy of the file and
621
      //merge the differences manually.
622
      
623
      String server=MetacatReplication.getServerNameForServerCode(serverCode);
624
      MetacatReplication.replLog("attempting to lock " + accnum);
625
      URL u = new URL("https://" + server + "?server=" +
626
        MetaCatUtil.getLocalReplicationServerName()+"&action=getlock&updaterev=" 
627
           +rev + "&docid=" + docid);
628
      //System.out.println("sending message: " + u.toString());
629
      String serverResStr = MetacatReplication.getURLContent(u);
630
      String openingtag =serverResStr.substring(0, serverResStr.indexOf(">")+1);
631
      if(openingtag.equals("<lockgranted>"))
632
      {
633
        //the lock was granted go ahead with the insert
634
        //System.out.println("In lockgranted");
635
        MetacatReplication.replLog("lock granted for " + accnum + " from " +
636
                                      server);
637
        flag=true;  
638
        return flag;
639
      }//if
640

    
641
      else if(openingtag.equals("<filelocked>"))
642
      {//the file is currently locked by another user
643
       //notify our user to wait a few minutes, check out a new copy and try
644
       //again.
645
        //System.out.println("file locked");
646
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
647
                                   server + " reason: file already locked");
648
        throw new Exception("The file specified is already locked by another " +
649
                            "user.  Please wait 30 seconds, checkout the " +
650
                            "newer document, merge your changes and try " +
651
                            "again.");
652
      }
653
      else if(openingtag.equals("<outdatedfile>"))
654
      {//our file is outdated.  notify our user to check out a new copy of the
655
       //file and merge his version with the new version.
656
        //System.out.println("outdated file");
657
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
658
                                    server + " reason: local file outdated");
659
        throw new Exception("The file you are trying to update is an outdated" +
660
                            " version.  Please checkout the newest document, " +
661
                            "merge your changes and try again.");
662
      }//else if
663
    }//if
664
    
665
   return flag;
666
   
667
  }//getDataFileLockGrant
668
  
669
  /**
670
   * get the document name
671
   */
672
  public String getDocname() {
673
    return docname;
674
  }
675

    
676
  /**
677
   * get the document type (which is the PublicID)
678
   */
679
  public String getDoctype() {
680
    return doctype;
681
  }
682

    
683
  /**
684
   * get the system identifier
685
   */
686
  public String getSystemID() {
687
    return system_id;
688
  }
689

    
690
  /**
691
   * get the root node identifier
692
   */
693
  public long getRootNodeID() {
694
    return rootnodeid;
695
  }
696
  
697
  /**
698
   * get the creation date
699
   */
700
  public String getCreateDate() {
701
    return createdate;
702
  }
703
  
704
  /**
705
   * get the update date
706
   */
707
  public String getUpdateDate() {
708
    return updatedate;
709
  }
710

    
711
  /** 
712
   * Get the document identifier (docid)
713
   */
714
  public String getDocID() {
715
    return docid;
716
  }
717
  
718
// DOCTITLE attr cleared from the db
719
//  /**
720
//   *get the document title
721
//   */
722
//  public String getDocTitle() {
723
//    return doctitle;
724
//  }
725
  
726
  public String getUserowner() {
727
    return userowner;
728
  }
729
  
730
  public String getUserupdated() {
731
    return userupdated;
732
  }
733
  
734
  public int getServerlocation() {
735
    return serverlocation;
736
  }
737
  
738
  public String getDocHomeServer() {
739
    return docHomeServer;
740
  }
741
  
742
 
743
 
744
  public String getPublicaccess() {
745
    return publicaccess;
746
  }
747
  
748
  public int getRev() {
749
    return rev;
750
  }
751
  
752
   /**
753
   * Print a string representation of the XML document
754
   */
755
  public String toString()
756
  {
757
    StringWriter docwriter = new StringWriter();
758
    try {
759
      this.toXml(docwriter);
760
    } catch (McdbException mcdbe) {
761
      return null;
762
    }
763
    String document = docwriter.toString();
764
    return document;
765
  }
766

    
767
  /**
768
   * Get a text representation of the XML document as a string
769
   * This older algorithm uses a recursive tree of Objects to represent the
770
   * nodes of the tree.  Each object is passed the data for the document 
771
   * and searches all of the document data to find its children nodes and
772
   * recursively build.  Thus, because each node reads the whole document,
773
   * this algorithm is extremely slow for larger documents, and the time
774
   * to completion is O(N^N) wrt the number of nodes.  See toXml() for a
775
   * better algorithm.
776
   */
777
  public String readUsingSlowAlgorithm() throws McdbException
778
  {
779
    StringBuffer doc = new StringBuffer();
780

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

    
786
    // Create the elements from the downloaded data in the TreeSet
787
    rootNode = new ElementNode(nodeRecordList, rootnodeid);
788

    
789
    // Append the resulting document to the StringBuffer and return it
790
    doc.append("<?xml version=\"1.0\"?>\n");
791
      
792
    if (docname != null) {
793
      if ((doctype != null) && (system_id != null)) {
794
        doc.append("<!DOCTYPE " + docname + " PUBLIC \"" + doctype + 
795
                   "\" \"" + system_id + "\">\n");
796
      } else {
797
        doc.append("<!DOCTYPE " + docname + ">\n");
798
      }
799
    }
800
    doc.append(rootNode.toString());
801
  
802
    return (doc.toString());
803
  }
804

    
805
  /**
806
   * Print a text representation of the XML document to a Writer
807
   *
808
   * @param pw the Writer to which we print the document
809
   */
810
  public void toXml(Writer pw) throws McdbException
811
  {
812
    PrintWriter out = null;
813
    if (pw instanceof PrintWriter) {
814
      out = (PrintWriter)pw;
815
    } else {
816
      out = new PrintWriter(pw);
817
    }
818

    
819
    MetaCatUtil util = new MetaCatUtil();
820
    
821
    // First, check that we have the needed node data, and get it if not
822
    if (nodeRecordList == null) {
823
      nodeRecordList = getNodeRecordList(rootnodeid);
824
    }
825

    
826
    Stack openElements = new Stack();
827
    boolean atRootElement = true;
828
    boolean previousNodeWasElement = false;
829

    
830
    // Step through all of the node records we were given
831
    Iterator it = nodeRecordList.iterator();
832
    while (it.hasNext()) {
833
      NodeRecord currentNode = (NodeRecord)it.next();
834
      //util.debugMessage("[Got Node ID: " + currentNode.nodeid +
835
                          //" (" + currentNode.parentnodeid +
836
                          //", " + currentNode.nodeindex + 
837
                          //", " + currentNode.nodetype + 
838
                          //", " + currentNode.nodename + 
839
                          //", " + currentNode.nodedata + ")]");
840
      // Print the end tag for the previous node if needed
841
      //
842
      // This is determined by inspecting the parent nodeid for the
843
      // currentNode.  If it is the same as the nodeid of the last element
844
      // that was pushed onto the stack, then we are still in that previous
845
      // parent element, and we do nothing.  However, if it differs, then we
846
      // have returned to a level above the previous parent, so we go into
847
      // a loop and pop off nodes and print out their end tags until we get
848
      // the node on the stack to match the currentNode parentnodeid
849
      //
850
      // So, this of course means that we rely on the list of elements
851
      // having been sorted in a depth first traversal of the nodes, which
852
      // is handled by the NodeComparator class used by the TreeSet
853
      if (!atRootElement) {
854
        NodeRecord currentElement = (NodeRecord)openElements.peek();
855
        if ( currentNode.parentnodeid != currentElement.nodeid ) {
856
          while ( currentNode.parentnodeid != currentElement.nodeid ) {
857
            currentElement = (NodeRecord)openElements.pop();
858
            util.debugMessage("\n POPPED: " + currentElement.nodename);
859
            if (previousNodeWasElement) {
860
              out.print(">");
861
              previousNodeWasElement = false;
862
            }  
863
            if ( currentElement.nodeprefix != null ) {
864
              out.print("</" + currentElement.nodeprefix + ":" + 
865
                        currentElement.nodename + ">" );
866
            } else {
867
              out.print("</" + currentElement.nodename + ">" );
868
            }
869
            currentElement = (NodeRecord)openElements.peek();
870
          }
871
        }
872
      }
873

    
874
      // Handle the DOCUMENT node
875
      if (currentNode.nodetype.equals("DOCUMENT")) {
876
        out.println("<?xml version=\"1.0\"?>");
877
      
878
        if (docname != null) {
879
          if ((doctype != null) && (system_id != null)) {
880
            out.println("<!DOCTYPE " + docname + " PUBLIC \"" + doctype + 
881
                       "\" \"" + system_id + "\">");
882
          } else {
883
            out.println("<!DOCTYPE " + docname + ">");
884
          }
885
        }
886

    
887
      // Handle the ELEMENT nodes
888
      } else if (currentNode.nodetype.equals("ELEMENT")) {
889
        if (atRootElement) {
890
          atRootElement = false;
891
        } else {
892
          if (previousNodeWasElement) {
893
            out.print(">");
894
          }
895
        }
896
        openElements.push(currentNode);
897
        util.debugMessage("\n PUSHED: " + currentNode.nodename);
898
        previousNodeWasElement = true;
899
        if ( currentNode.nodeprefix != null ) {
900
          out.print("<" + currentNode.nodeprefix + ":" + currentNode.nodename);
901
        } else {
902
          out.print("<" + currentNode.nodename);
903
        }
904

    
905
      // Handle the ATTRIBUTE nodes
906
      } else if (currentNode.nodetype.equals("ATTRIBUTE")) {
907
        if ( currentNode.nodeprefix != null ) {
908
          out.print(" " + currentNode.nodeprefix + ":" + currentNode.nodename +
909
                    "=\"" + currentNode.nodedata + "\"");
910
        } else {
911
          out.print(" " + currentNode.nodename + "=\"" +
912
                    currentNode.nodedata + "\"");
913
        }
914

    
915
      // Handle the NAMESPACE nodes
916
      } else if (currentNode.nodetype.equals("NAMESPACE")) {
917
        out.print(" xmlns:" + currentNode.nodename + "=\""
918
                 + currentNode.nodedata + "\"");
919

    
920
      // Handle the TEXT nodes
921
      } else if (currentNode.nodetype.equals("TEXT")) {
922
        if (previousNodeWasElement) {
923
          out.print(">");
924
        }
925
        out.print(currentNode.nodedata);
926
        previousNodeWasElement = false;
927

    
928
      // Handle the COMMENT nodes
929
      } else if (currentNode.nodetype.equals("COMMENT")) {
930
        if (previousNodeWasElement) {
931
          out.print(">");
932
        }
933
        out.print("<!--" + currentNode.nodedata + "-->");
934
        previousNodeWasElement = false;
935

    
936
      // Handle the PI nodes
937
      } else if (currentNode.nodetype.equals("PI")) {
938
        if (previousNodeWasElement) {
939
          out.print(">");
940
        }
941
        out.print("<?" + currentNode.nodename + " " +
942
                        currentNode.nodedata + "?>");
943
        previousNodeWasElement = false;
944

    
945
      // Handle any other node type (do nothing)
946
      } else {
947
        // Any other types of nodes are not handled.
948
        // Probably should throw an exception here to indicate this
949
      }
950
      out.flush();
951
    }
952

    
953
    // Print the final end tag for the root element
954
    while(!openElements.empty())
955
    {
956
      NodeRecord currentElement = (NodeRecord)openElements.pop();
957
      util.debugMessage("\n POPPED: " + currentElement.nodename);
958
      if ( currentElement.nodeprefix != null ) {
959
        out.print("</" + currentElement.nodeprefix + ":" + 
960
                  currentElement.nodename + ">" );
961
      } else {
962
        out.print("</" + currentElement.nodename + ">" );
963
      }
964
    }
965
    out.flush();
966
  }
967
  
968
  private boolean isRevisionOnly(DocumentIdentifier docid) throws Exception
969
  {
970
    //System.out.println("inRevisionOnly");
971
    DBConnection dbconn = null;
972
    int serialNumber = -1;
973
    PreparedStatement pstmt =null;
974
    String rev = docid.getRev();
975
    String newid = docid.getIdentifier();
976
    try
977
    {
978
      dbconn=DBConnectionPool.
979
                    getDBConnection("DocumentImpl.isRevisionOnly");
980
      serialNumber=dbconn.getCheckOutSerialNumber();
981
      pstmt = dbconn.prepareStatement("select rev from xml_documents " +
982
                                  "where docid like '" + newid + "'");
983
      pstmt.execute();
984
      ResultSet rs = pstmt.getResultSet();
985
      boolean tablehasrows = rs.next();
986
      if(rev.equals("newest") || rev.equals("all"))
987
      {
988
        return false;
989
      }
990
    
991
      if(tablehasrows)
992
      {
993
        int r = rs.getInt(1);
994
        pstmt.close();
995
        if(new Integer(rev).intValue() == r)
996
        { //the current revision in in xml_documents
997
          //System.out.println("returning false");
998
          return false;
999
        }
1000
        else if(new Integer(rev).intValue() < r)
1001
        { //the current revision is in xml_revisions.
1002
          //System.out.println("returning true");
1003
          return true;
1004
        }
1005
        else if(new Integer(rev).intValue() > r)
1006
        { //error, rev cannot be greater than r
1007
          throw new Exception("requested revision cannot be greater than " +
1008
                            "the latest revision number.");
1009
        }
1010
      }
1011
      // Get miss docid and rev, throw to McdDocNotFoundException
1012
      String missDocId = MetaCatUtil.getDocIdFromString(docid.toString());
1013
      String missRevision = 
1014
                  MetaCatUtil.getRevisionStringFromString(docid.toString());
1015
      throw new McdbDocNotFoundException("the requested docid '" + 
1016
                docid.toString() + "' does not exist", missDocId, missRevision);
1017
    }//try
1018
    finally
1019
    {
1020
      pstmt.close();
1021
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1022
    }//finally
1023
  }
1024

    
1025
  private void getDocumentInfo(String docid) throws McdbException, 
1026
                                        AccessionNumberException, Exception
1027
  {
1028
    getDocumentInfo(new DocumentIdentifier(docid));
1029
  }
1030
  
1031
  /**
1032
   * Look up the document type information from the database
1033
   *
1034
   * @param docid the id of the document to look up
1035
   */
1036
  private void getDocumentInfo(DocumentIdentifier docid) throws McdbException
1037
                                                          , Exception
1038
  {
1039
    DBConnection dbconn = null;
1040
    int serialNumber = -1;
1041
    PreparedStatement pstmt = null;
1042
    String table = "xml_documents";
1043
        
1044
    try
1045
    {
1046
      if(isRevisionOnly(docid))
1047
      { //pull the document from xml_revisions instead of from xml_documents;
1048
        table = "xml_revisions";
1049
      }
1050
    }
1051
    // catch a McdbDocNotFoundException throw it
1052
    catch (McdbDocNotFoundException notFound)
1053
    {
1054
      throw notFound;
1055
    }
1056
    catch(Exception e)
1057
    {
1058
      
1059
      MetaCatUtil.debugMessage("error in DocumentImpl.getDocumentInfo: " + 
1060
                          e.getMessage(), 30);
1061
      throw e;
1062
    }
1063
    
1064

    
1065
    
1066
    try 
1067
    {
1068
      dbconn=DBConnectionPool.getDBConnection("DocumentImpl.getDocumentInfo");
1069
      serialNumber=dbconn.getCheckOutSerialNumber();
1070
      StringBuffer sql = new StringBuffer();
1071
// DOCTITLE attr cleared from the db
1072
//      sql.append("SELECT docname, doctype, rootnodeid, doctitle, ");
1073
      sql.append("SELECT docname, doctype, rootnodeid, ");
1074
      sql.append("date_created, date_updated, user_owner, user_updated, ");
1075
      sql.append("server_location, public_access, rev");
1076
      sql.append(" FROM ").append(table);
1077
      sql.append(" WHERE docid LIKE '").append(docid.getIdentifier());
1078
      sql.append("' and rev like '").append(docid.getRev()).append("'");
1079
      //System.out.println(sql.toString());
1080
      pstmt =
1081
        dbconn.prepareStatement(sql.toString());
1082
      // Bind the values to the query
1083
      //pstmt.setString(1, docid.getIdentifier());
1084
      //pstmt.setString(2, docid.getRev());
1085

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

    
1174
    if (this.docname == null) {
1175
      throw new McdbDocNotFoundException("Document not found: " + docid,
1176
                                 docid.getIdentifier(), docid.getRev());
1177
    }
1178
  }
1179

    
1180
  /**
1181
   * Look up the node data from the database
1182
   *
1183
   * @param rootnodeid the id of the root node of the node tree to look up
1184
   */
1185
  private TreeSet getNodeRecordList(long rootnodeid) throws McdbException
1186
  {
1187
    PreparedStatement pstmt = null;
1188
    DBConnection dbconn = null;
1189
    int serialNumber = -1;
1190
    TreeSet nodeRecordList = new TreeSet(new NodeComparator());
1191
    long nodeid = 0;
1192
    long parentnodeid = 0;
1193
    long nodeindex = 0;
1194
    String nodetype = null;
1195
    String nodename = null;
1196
    String nodeprefix = null;
1197
    String nodedata = null;
1198
    String quotechar = dbAdapter.getStringDelimiter();
1199

    
1200
    try {
1201
      dbconn=DBConnectionPool.
1202
                    getDBConnection("DocumentImpl.getNodeRecordList");
1203
      serialNumber=dbconn.getCheckOutSerialNumber();
1204
      pstmt =
1205
      dbconn.prepareStatement("SELECT nodeid,parentnodeid,nodeindex, " +
1206
           "nodetype,nodename,nodeprefix,nodedata " +               
1207
           "FROM xml_nodes WHERE rootnodeid = ?");
1208

    
1209
      // Bind the values to the query
1210
      pstmt.setLong(1, rootnodeid);
1211

    
1212
      pstmt.execute();
1213
      ResultSet rs = pstmt.getResultSet();
1214
      boolean tableHasRows = rs.next();
1215
      while (tableHasRows) {
1216
        nodeid = rs.getLong(1);
1217
        parentnodeid = rs.getLong(2);
1218
        nodeindex = rs.getLong(3);
1219
        nodetype = rs.getString(4);
1220
        nodename = rs.getString(5);
1221
        nodeprefix = rs.getString(6);
1222
        nodedata = rs.getString(7);
1223
        nodedata = MetaCatUtil.normalize(nodedata);
1224
        // add the data to the node record list hashtable
1225
        NodeRecord currentRecord = new NodeRecord(nodeid,parentnodeid,nodeindex,
1226
                                      nodetype, nodename, nodeprefix, nodedata);
1227
        nodeRecordList.add(currentRecord);
1228

    
1229
        // Advance to the next node
1230
        tableHasRows = rs.next();
1231
      } 
1232
      pstmt.close();
1233

    
1234
    } catch (SQLException e) {
1235
      throw new McdbException("Error in DocumentImpl.getNodeRecordList " +
1236
                              e.getMessage());
1237
    }
1238
    finally
1239
    {
1240
      try
1241
      {
1242
        pstmt.close();
1243
      }
1244
      catch (SQLException ee)
1245
      {
1246
        MetaCatUtil.debugMessage("error in DocumentImpl.getNodeRecordList: "
1247
                                    +ee.getMessage(), 30);
1248
      }
1249
      finally
1250
      {
1251
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1252
      }
1253
    }
1254
      
1255

    
1256
    if (nodeRecordList != null) {
1257
      return nodeRecordList;
1258
    } else {
1259
      throw new McdbException("Error getting node data: " + docid);
1260
    }
1261
  }
1262
  
1263
// NOT USED ANY MORE
1264
//  /** creates SQL code and inserts new document into DB connection 
1265
//   default serverCode of 1*/
1266
//  private void writeDocumentToDB(String action, String user)
1267
//               throws SQLException, Exception
1268
//  {
1269
//    writeDocumentToDB(action, user, null, 1);
1270
//  }
1271

    
1272
 /** creates SQL code and inserts new document into DB connection */
1273
  private void writeDocumentToDB(String action, String user, String pub, 
1274
                                 String catalogid, int serverCode) 
1275
               throws SQLException, Exception {
1276
    String sysdate = dbAdapter.getDateTimeFunction();
1277

    
1278
    try {
1279
      PreparedStatement pstmt = null;
1280

    
1281
      if (action.equals("INSERT")) {
1282
        //AccessionNumber ac = new AccessionNumber();
1283
        //this.docid = ac.generate(docid, "INSERT");
1284
        
1285
        pstmt = connection.prepareStatement(
1286
                "INSERT INTO xml_documents " +
1287
                "(docid, rootnodeid, docname, doctype, " + 
1288
                "user_owner, user_updated, date_created, date_updated, " + 
1289
                "public_access, catalog_id, server_location, rev) " +
1290
                "VALUES (?, ?, ?, ?, ?, ?, " + sysdate + ", " + sysdate + 
1291
                ", ?, ?, ?, ?)");
1292
        // Increase dbconnection usage count
1293
        connection.increaseUsageCount(1);
1294
        
1295
        //note that the server_location is set to 1. 
1296
        //this means that "localhost" in the xml_replication table must
1297
        //always be the first entry!!!!!
1298
        
1299
        // Bind the values to the query
1300
        pstmt.setString(1, this.docid);
1301
        pstmt.setLong(2, rootnodeid);
1302
        pstmt.setString(3, docname);
1303
        pstmt.setString(4, doctype);
1304
        pstmt.setString(5, user);
1305
        pstmt.setString(6, user);
1306
        //public access is usefulless, so set it to null
1307
        pstmt.setString(7, null);
1308
        /*if ( pub == null ) {
1309
          pstmt.setString(7, null);
1310
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
1311
          pstmt.setInt(7, 1);
1312
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
1313
          pstmt.setInt(7, 0);
1314
        }*/
1315
        pstmt.setString(8, catalogid);
1316
        pstmt.setInt(9, serverCode);
1317
        pstmt.setInt(10, Integer.parseInt(updatedVersion)); 
1318
      } else if (action.equals("UPDATE")) {
1319

    
1320
        // Save the old document publicaccessentry in a backup table
1321
        DocumentImpl.archiveDocRevision(connection, docid, user );
1322
        DocumentImpl thisdoc = new DocumentImpl(docid, false);
1323
        int thisrev = thisdoc.getRev();
1324
        
1325
        //if the updated vesion is not greater than current one,
1326
        //throw it into a exception
1327
        if (Integer.parseInt(updatedVersion)<=thisrev)
1328
        {
1329
          throw new Exception("Next revision number couldn't be less"
1330
                               +" than or equal "+ thisrev);
1331
        }
1332
        else
1333
        {
1334
          //set the user specified revision 
1335
          thisrev=Integer.parseInt(updatedVersion);
1336
        }
1337
        
1338
        // Delete index for the old version of docid
1339
        // The new index is inserting on the next calls to DBSAXNode
1340
        pstmt = connection.prepareStatement(
1341
                "DELETE FROM xml_index WHERE docid='" + this.docid + "'");
1342
        // Increase dbconnection usage count
1343
        connection.increaseUsageCount(1);
1344
        
1345
        pstmt.execute();
1346
        pstmt.close();
1347

    
1348
        // Update the new document to reflect the new node tree
1349
        pstmt = connection.prepareStatement(
1350
            "UPDATE xml_documents " +
1351
            "SET rootnodeid = ?, docname = ?, doctype = ?, " +
1352
            "user_updated = ?, date_updated = " + sysdate + ", " +
1353
            "server_location = ?, rev = ?, public_access = ?, catalog_id = ? " +
1354
            "WHERE docid = ?");
1355
        // Increase dbconnection usage count
1356
        connection.increaseUsageCount(1);
1357
        // Bind the values to the query
1358
        pstmt.setLong(1, rootnodeid);
1359
        pstmt.setString(2, docname);
1360
        pstmt.setString(3, doctype);
1361
        pstmt.setString(4, user);
1362
        pstmt.setInt(5, serverCode);
1363
        pstmt.setInt(6, thisrev);
1364
        pstmt.setString(7, null);
1365
        /*if ( pub == null ) {
1366
          pstmt.setString(7, null);
1367
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
1368
          pstmt .setInt(7, 1);
1369
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
1370
          pstmt.setInt(7, 0);
1371
        }*/
1372
        pstmt.setString(8, catalogid);
1373
        pstmt.setString(9, this.docid);
1374

    
1375
      } else {
1376
        System.err.println("Action not supported: " + action);
1377
      }
1378

    
1379
      // Do the insertion
1380
      pstmt.execute();
1381
      
1382
      pstmt.close();
1383

    
1384
    } catch (SQLException sqle) {
1385
      throw sqle;
1386
    } catch (Exception e) {
1387
      throw e;
1388
    }
1389
  }
1390

    
1391
  /**
1392
   * Write an XML file to the database, given a filename
1393
   *
1394
   * @param conn the JDBC connection to the database
1395
   * @param filename the filename to be loaded into the database
1396
   * @param pub flag for public "read" access on document
1397
   * @param dtdfilename the dtd to be uploaded on server's file system
1398
   * @param action the action to be performed (INSERT OR UPDATE)
1399
   * @param docid the docid to use for the INSERT OR UPDATE
1400
   * @param user the user that owns the document
1401
   * @param groups the groups to which user belongs
1402
   */
1403
  /*public static String write(DBConnection conn,String filename,
1404
                             String pub, String dtdfilename,
1405
                             String action, String docid, String user,
1406
                             String[] groups )
1407
                throws Exception {
1408
                  
1409
    Reader dtd = null;
1410
    if ( dtdfilename != null ) {
1411
      dtd = new FileReader(new File(dtdfilename).toString());
1412
    }
1413
    return write ( conn, new FileReader(new File(filename).toString()),
1414
                   pub, dtd, action, docid, user, groups, false);
1415
  }*/
1416

    
1417
  public static String write(DBConnection conn,Reader xml,String pub,Reader dtd,
1418
                             String action, String docid, String user,
1419
                             String[] groups, String ruleBase, 
1420
                             boolean needValidation)
1421
                throws Exception {
1422
    //this method will be called in handleUpdateOrInsert method 
1423
    //in MetacatServlet class and now is wrapper into documentImple
1424
    // get server location for this doc
1425
    int serverLocation=getServerLocationNumber(docid);
1426
    return write(conn,xml,pub,dtd,action,docid,user,groups,serverLocation,false,
1427
                 ruleBase, needValidation);
1428
  }
1429

    
1430
 
1431
  
1432
  /**
1433
   * Write an XML file to the database, given a Reader
1434
   *
1435
   * @param conn the JDBC connection to the database
1436
   * @param xml the xml stream to be loaded into the database
1437
   * @param pub flag for public "read" access on xml document
1438
   * @param dtd the dtd to be uploaded on server's file system
1439
   * @param action the action to be performed (INSERT or UPDATE)
1440
   * @param accnum the docid + rev# to use on INSERT or UPDATE
1441
   * @param user the user that owns the document
1442
   * @param groups the groups to which user belongs
1443
   * @param serverCode the serverid from xml_replication on which this document
1444
   *        resides.
1445
   * @param override flag to stop insert replication checking.
1446
   *        if override = true then a document not belonging to the local server
1447
   *        will not be checked upon update for a file lock.
1448
   *        if override = false then a document not from this server, upon 
1449
   *        update will be locked and version checked.
1450
   */
1451

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

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

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

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

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

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

    
1698
    return(accnum);
1699
  }
1700

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

    
1731
      // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1732
      AccessionNumber ac = new AccessionNumber(accnum, "DELETE");
1733
      String docid = ac.getDocid();
1734
      String rev = ac.getRev();
1735
    
1736

    
1737
    // check for 'write' permission for 'user' to delete this document
1738
      if ( !hasPermission(user, groups, docid) ) {
1739
        throw new Exception("User " + user + 
1740
              " does not have permission to delete XML Document #" + accnum);
1741
      }
1742

    
1743
      conn.setAutoCommit(false);
1744
      // Copy the record to the xml_revisions table
1745
      DocumentImpl.archiveDocRevision(conn, docid, user );
1746

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

    
1804
  /** 
1805
    * Check for "WRITE" permission on @docid for @user and/or @groups 
1806
    * from DB connection 
1807
    */
1808
  private static boolean hasPermission (String user,
1809
                                  String[] groups, String docid ) 
1810
                  throws SQLException, Exception
1811
  {
1812
    // Check for WRITE permission on @docid for @user and/or @groups
1813
    //AccessControlList aclobj = new AccessControlList(dbconn);
1814
    return AccessControlList.hasPermission("WRITE", user, groups, docid);
1815
    //return aclobj.hasPermission("WRITE", user, groups, docid);
1816
  }
1817

    
1818
  /** 
1819
    * Check for "READ" permission base on docid, user and group
1820
    *@docid, the document
1821
    *@user, user name
1822
    *@group, user's group
1823
    * 
1824
    */
1825
  public static boolean hasReadPermission (String user,
1826
                                  String[] groups, String docId ) 
1827
                  throws SQLException, Exception
1828
  {
1829
    // Check for READ permission on @docid for @user and/or @groups
1830
    //AccessControlList aclObj = new AccessControlList(conn);
1831
    //return aclObj.hasPermission("READ", user, groups, docId);
1832
    return AccessControlList.hasPermission("READ", user, groups, docId);
1833
  }  
1834

    
1835
  
1836
   /**
1837
   * Set up the parser handlers for writing the document to the database
1838
   */
1839
  private static XMLReader initializeParser(DBConnection dbconn, String action,
1840
                                            String docid, String rev, 
1841
                                            String user, 
1842
                                            String[] groups, String pub, 
1843
                                            int serverCode, Reader dtd,
1844
                                            String ruleBase, 
1845
                                            boolean needValidation) 
1846
                                            throws Exception 
1847
  {
1848
    XMLReader parser = null;
1849
    try 
1850
    {
1851
      // handler
1852
      ContentHandler chandler;
1853
      EntityResolver eresolver;
1854
      DTDHandler dtdhandler;  
1855
      // Get an instance of the parser
1856
      String parserName = MetaCatUtil.getOption("saxparser");
1857
      parser = XMLReaderFactory.createXMLReader(parserName);
1858
      if (ruleBase != null && ruleBase.equals(EML2))
1859
      {
1860
        MetaCatUtil.debugMessage("eml 2 parser", 20);
1861
        chandler = new EmlSAXHandler(dbconn, action, 
1862
                                    docid, rev, user, groups, pub, serverCode);
1863
        parser.setContentHandler((ContentHandler)chandler);
1864
        parser.setErrorHandler((ErrorHandler)chandler);
1865
        parser.setProperty(DECLARATIONHANDLERPROPERTY, chandler);
1866
        parser.setProperty(LEXICALPROPERTY, chandler);
1867
        // turn on schema validation feature
1868
        parser.setFeature(VALIDATIONFEATURE, true);
1869
        parser.setFeature(NAMESPACEFEATURE, true);
1870
        parser.setFeature(NAMESPACEPREFIXESFEATURE, true);
1871
        parser.setFeature(SCHEMAVALIDATIONFEATURE, true);
1872
        // From DB to find the register external schema location
1873
        String externalSchemaLocation = null;
1874
        SchemaLocationResolver resolver = new SchemaLocationResolver();
1875
        externalSchemaLocation = resolver.getNameSpaceAndLocationString();
1876
        // Set external schemalocation.
1877
        if (externalSchemaLocation != null && 
1878
            !(externalSchemaLocation.trim()).equals(""))
1879
        {
1880
            parser.setProperty(EXTERNALSCHEMALOCATIONPROPERTY,
1881
                             externalSchemaLocation);
1882
        }
1883
      }
1884
      else
1885
      {
1886
        //create a DBSAXHandler object which has the revision specification
1887
        chandler = new DBSAXHandler(dbconn, action, 
1888
                                    docid, rev, user, groups, pub, serverCode);
1889
        parser.setContentHandler((ContentHandler)chandler);
1890
        parser.setErrorHandler((ErrorHandler)chandler);
1891
        parser.setProperty(DECLARATIONHANDLERPROPERTY, chandler);
1892
        parser.setProperty(LEXICALPROPERTY, chandler);
1893
      
1894
        if (ruleBase != null && ruleBase.equals(SCHEMA) && needValidation)
1895
        {
1896
          MetaCatUtil.debugMessage("General schema parser", 20);
1897
          // turn on schema validation feature
1898
          parser.setFeature(VALIDATIONFEATURE, true);
1899
          parser.setFeature(NAMESPACEFEATURE, true);
1900
          parser.setFeature(NAMESPACEPREFIXESFEATURE, true);
1901
          parser.setFeature(SCHEMAVALIDATIONFEATURE, true);
1902
          // From DB to find the register external schema location
1903
          String externalSchemaLocation = null;
1904
          SchemaLocationResolver resolver = new SchemaLocationResolver();
1905
          externalSchemaLocation = resolver.getNameSpaceAndLocationString();
1906
          // Set external schemalocation.
1907
          if (externalSchemaLocation != null && 
1908
            !(externalSchemaLocation.trim()).equals(""))
1909
          {
1910
            parser.setProperty(EXTERNALSCHEMALOCATIONPROPERTY,
1911
                             externalSchemaLocation);
1912
          }
1913
     
1914
        }
1915
        else if (ruleBase != null && ruleBase.equals(DTD) && needValidation)
1916
        {
1917
          MetaCatUtil.debugMessage("dtd parser", 20);
1918
          // turn on dtd validaton feature
1919
          parser.setFeature(VALIDATIONFEATURE, true);
1920
          eresolver= new DBEntityResolver(dbconn, (DBSAXHandler)chandler, dtd);
1921
          dtdhandler = new DBDTDHandler(dbconn);
1922
          parser.setEntityResolver((EntityResolver)eresolver);
1923
          parser.setDTDHandler((DTDHandler)dtdhandler);
1924
        }
1925
        else
1926
        {
1927
          MetaCatUtil.debugMessage("other parser", 20);
1928
          // non validation
1929
          parser.setFeature(VALIDATIONFEATURE, false);
1930
          eresolver= new DBEntityResolver(dbconn, (DBSAXHandler)chandler, dtd);
1931
          dtdhandler = new DBDTDHandler(dbconn);
1932
          parser.setEntityResolver((EntityResolver)eresolver);
1933
          parser.setDTDHandler((DTDHandler)dtdhandler);
1934
        }
1935
      }//else
1936
    } 
1937
    catch (Exception e) 
1938
    {
1939
      throw e;
1940
    }
1941
    return parser;
1942
  }
1943

    
1944
  
1945
  /**
1946
   * Set up the parser handlers for writing the document to the database
1947
   */
1948
  /*private static XMLReader initializeParser(DBConnection dbconn, String action,
1949
                               String docid, String rev, boolean validate, 
1950
                                   String user, String[] groups, String pub, 
1951
                                   int serverCode, Reader dtd) 
1952
                           throws Exception 
1953
  {
1954
    XMLReader parser = null;
1955
    //DBConnection conn = null;
1956
    //int serialNumber = -1;
1957
    //
1958
    // Set up the SAX document handlers for parsing
1959
    //
1960
    try {
1961
       //check out DBConnection
1962
     
1963
      //create a DBSAXHandler object which has the revision specification
1964
      ContentHandler chandler = new DBSAXHandler(dbconn, action, 
1965
                                    docid, rev, user, groups, pub, serverCode);
1966
      EntityResolver eresolver= new DBEntityResolver(dbconn,
1967
                                                 (DBSAXHandler)chandler, dtd);
1968
      DTDHandler dtdhandler   = new DBDTDHandler(dbconn);
1969

    
1970
      // Get an instance of the parser
1971
      String parserName = MetaCatUtil.getOption("saxparser");
1972
      parser = XMLReaderFactory.createXMLReader(parserName);
1973

    
1974
      // Turn on validation
1975
      parser.setFeature("http://xml.org/sax/features/validation", validate);
1976
      // Turn off Including all external parameter entities
1977
      // (the external DTD subset also)
1978
      // Doesn't work well, probably the feature name is not correct
1979
      // parser.setFeature(
1980
      //  "http://xml.org/sax/features/external-parameter-entities", false);
1981
      
1982
      // Set Handlers in the parser
1983
      parser.setProperty("http://xml.org/sax/properties/declaration-handler",
1984
                         chandler);
1985
      parser.setProperty("http://xml.org/sax/properties/lexical-handler",
1986
                         chandler);
1987
      parser.setContentHandler((ContentHandler)chandler);
1988
      parser.setEntityResolver((EntityResolver)eresolver);
1989
      parser.setDTDHandler((DTDHandler)dtdhandler);
1990
      parser.setErrorHandler((ErrorHandler)chandler);
1991

    
1992
    } catch (Exception e) {
1993
      throw e;
1994
    }
1995
    //finally
1996
    //{
1997
      //DBConnectionPool.returnDBConnection(conn, serialNumber);
1998
    //}
1999

    
2000
    return parser;
2001
  }*/
2002

    
2003
  /**
2004
   * Save a document entry in the xml_revisions table 
2005
   * Connection use as a paramter is in order to rollback feature
2006
   */
2007
  private static void archiveDocRevision(DBConnection dbconn, String docid, 
2008
                                                    String user) 
2009
 {
2010
    String sysdate = dbAdapter.getDateTimeFunction();
2011
    //DBConnection conn = null;
2012
    //int serialNumber = -1;
2013
    PreparedStatement pstmt = null;
2014
    
2015
    // create a record in xml_revisions table 
2016
    // for that document as selected from xml_documents
2017
   
2018
   try
2019
   {
2020
     //check out DBConnection
2021
     /*conn=DBConnectionPool.
2022
                    getDBConnection("DocumentImpl.archiveDocRevision");
2023
     serialNumber=conn.getCheckOutSerialNumber();*/
2024
     pstmt = dbconn.prepareStatement(
2025
      "INSERT INTO xml_revisions " +
2026
        "(docid, rootnodeid, docname, doctype, " +
2027
        "user_owner, user_updated, date_created, date_updated, " +
2028
        "server_location, rev, public_access, catalog_id) " +
2029
      "SELECT ?, rootnodeid, docname, doctype, " + 
2030
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
2031
        "server_location, rev, public_access, catalog_id " +
2032
      "FROM xml_documents " +
2033
      "WHERE docid = ?");
2034
      // Increase dbconnection usage count
2035
      dbconn.increaseUsageCount(1);
2036
      // Bind the values to the query and execute it
2037
      pstmt.setString(1, docid);
2038
      pstmt.setString(2, user);
2039
      pstmt.setString(3, docid);
2040
      pstmt.execute();
2041
      pstmt.close();
2042
   }//try
2043
   catch (SQLException e)
2044
   {
2045
     MetaCatUtil.debugMessage("Error in DocumentImpl.archiveDocRevision : "+
2046
                                e.getMessage(), 30);
2047
   }//catch
2048
   finally
2049
   {
2050
     try
2051
     {
2052
       pstmt.close();
2053
     }//try
2054
     catch (SQLException ee)
2055
     {
2056
       MetaCatUtil.debugMessage("Error in DocumnetImpl.archiveDocRevision: "+
2057
                                  ee.getMessage(), 50);
2058
     }//catch
2059
     //finally
2060
     //{
2061
       
2062
       //check in DBConnection
2063
       //DBConnectionPool.returnDBConnection(conn, serialNumber);
2064
     //}//finally
2065
   }//finnally
2066
                                  
2067

    
2068
  }//achiveDocRevision
2069
  
2070
  /** Save a document entry in the xml_revisions table */
2071
  private static void archiveDocRevision(String docid, String user) 
2072
 {
2073
    String sysdate = dbAdapter.getDateTimeFunction();
2074
    DBConnection conn = null;
2075
    int serialNumber = -1;
2076
    PreparedStatement pstmt = null;
2077
    
2078
    // create a record in xml_revisions table 
2079
    // for that document as selected from xml_documents
2080
   
2081
   try
2082
   {
2083
     //check out DBConnection
2084
     conn=DBConnectionPool.
2085
                    getDBConnection("DocumentImpl.archiveDocRevision");
2086
     serialNumber=conn.getCheckOutSerialNumber();
2087
     pstmt = conn.prepareStatement(
2088
      "INSERT INTO xml_revisions " +
2089
        "(docid, rootnodeid, docname, doctype, " +
2090
        "user_owner, user_updated, date_created, date_updated, " +
2091
        "server_location, rev, public_access, catalog_id) " +
2092
      "SELECT ?, rootnodeid, docname, doctype, " + 
2093
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
2094
        "server_location, rev, public_access, catalog_id " +
2095
      "FROM xml_documents " +
2096
      "WHERE docid = ?");
2097
      // Bind the values to the query and execute it
2098
      pstmt.setString(1, docid);
2099
      pstmt.setString(2, user);
2100
      pstmt.setString(3, docid);
2101
      pstmt.execute();
2102
      pstmt.close();
2103
   }//try
2104
   catch (SQLException e)
2105
   {
2106
     MetaCatUtil.debugMessage("Error in DocumentImpl.archiveDocRevision : "+
2107
                                e.getMessage(), 30);
2108
   }//catch
2109
   finally
2110
   {
2111
     try
2112
     {
2113
       pstmt.close();
2114
     }//try
2115
     catch (SQLException ee)
2116
     {
2117
       MetaCatUtil.debugMessage("Error in DocumnetImpl.archiveDocRevision: "+
2118
                                  ee.getMessage(), 50);
2119
     }//catch
2120
     finally
2121
     {
2122
       //check in DBConnection
2123
       DBConnectionPool.returnDBConnection(conn, serialNumber);
2124
     }//finally
2125
   }//finnally
2126
                                  
2127

    
2128
  }//achiveDocRevision
2129
  
2130
  /**
2131
    * delete a entry in xml_table for given docid
2132
    * @param docId, the id of the document need to be delete
2133
    */
2134
  private static void deleteXMLDocuments(String docId) 
2135
                                         throws SQLException 
2136
  {
2137
    DBConnection conn = null;
2138
    int serialNumber = -1;
2139
    PreparedStatement pStmt = null;
2140
    try
2141
    {
2142
      //check out DBConnection
2143
      conn=DBConnectionPool.
2144
                    getDBConnection("DocumentImpl.deleteXMLDocuments");
2145
      serialNumber=conn.getCheckOutSerialNumber();
2146
      //delete a record 
2147
      pStmt = 
2148
             conn.prepareStatement("DELETE FROM xml_documents WHERE docid = '" 
2149
                                              + docId + "'");
2150
    pStmt.execute();
2151
    }//try
2152
    finally
2153
    {
2154
      try
2155
      {
2156
        pStmt.close();
2157
      }//try
2158
      catch (SQLException e)
2159
      {
2160
        MetaCatUtil.debugMessage("error in DocumentImpl.deleteXMLDocuments: "+
2161
                                  e.getMessage(), 50);
2162
      }//catch
2163
      finally
2164
      {
2165
        //return back DBconnection
2166
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2167
      }//finally
2168
    }//finally
2169
      
2170

    
2171
  }//deleteXMLDocuments
2172
  
2173
  /**
2174
    * Get last revision number from database for a docid
2175
    * If couldn't find an entry,  -1 will return
2176
    * The return value is integer because we want compare it to there new one
2177
    * @param docid <sitecode>.<uniqueid> part of Accession Number
2178
    */
2179
  private static int getLatestRevisionNumber(String docId)
2180
                                      throws SQLException
2181
  {
2182
    int rev = 1;
2183
    PreparedStatement pStmt = null;
2184
    DBConnection dbConn = null;
2185
    int serialNumber = -1;
2186
    
2187
    try
2188
    {
2189
      //check out DBConnection
2190
      dbConn=DBConnectionPool.
2191
                    getDBConnection("DocumentImpl.getLatestRevisionNumber");
2192
      serialNumber=dbConn.getCheckOutSerialNumber();
2193
     
2194
      pStmt = dbConn.prepareStatement
2195
              ("SELECT rev FROM xml_documents WHERE docid='" + docId + "'");
2196
      pStmt.execute();
2197

    
2198
      ResultSet rs = pStmt.getResultSet();
2199
      boolean hasRow = rs.next();
2200
      if (hasRow)
2201
      {
2202
        rev = rs.getInt(1);
2203
        pStmt.close();
2204
      }
2205
      else
2206
      {
2207
        rev=-1;
2208
        pStmt.close();
2209
      }
2210
    }//try
2211
    finally
2212
    {
2213
      try
2214
      {
2215
        pStmt.close();
2216
      }
2217
      catch (Exception ee)
2218
      {
2219
        MetaCatUtil.debugMessage("Error in DocumentImpl."+
2220
                        "getLatestRevisionNumber: "+ee.getMessage(), 50);
2221
      }
2222
      finally
2223
      {
2224
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2225
      }
2226
    }//finally  
2227
      
2228
    return rev;
2229
  }//getLatestRevisionNumber
2230
  
2231
  /**
2232
   * Get server location form database for a accNum
2233
   * 
2234
   * @param accum <sitecode>.<uniqueid>.<rev>
2235
   */
2236
  private static int getServerLocationNumber(String accNum)
2237
                                            throws SQLException
2238
  {
2239
    //get rid of revNum part
2240
    String docId=MetaCatUtil.getDocIdFromString(accNum);
2241
    PreparedStatement pStmt = null;
2242
    int serverLocation = 1;
2243
    DBConnection conn = null;
2244
    int serialNumber = -1;
2245
    
2246
    try
2247
    {
2248
      //check out DBConnection
2249
      conn=DBConnectionPool.
2250
                    getDBConnection("DocumentImpl.getServerLocationNumber");
2251
      serialNumber=conn.getCheckOutSerialNumber();
2252
     
2253
      pStmt = conn.prepareStatement
2254
      ("SELECT server_location FROM xml_documents WHERE docid='" + docId + "'");
2255
      pStmt.execute();
2256

    
2257
      ResultSet rs = pStmt.getResultSet();
2258
      boolean hasRow = rs.next();
2259
      //if there is entry in xml_documents, get the serverlocation
2260
      if (hasRow)
2261
      {
2262
        serverLocation = rs.getInt(1);
2263
        pStmt.close();
2264
      }
2265
      else
2266
      {
2267
        //if htere is no entry in xml_documents, we consider it is new document
2268
        //the server location is local host and value is 1
2269
        serverLocation=1;
2270
        pStmt.close();
2271
      }
2272
    }//try
2273
    finally
2274
    {
2275
      try
2276
      {
2277
        pStmt.close();
2278
      }//try
2279
      catch (Exception ee)
2280
      {
2281
        MetaCatUtil.debugMessage("Error in DocumentImpl.getServerLocationNu(): "
2282
                                    +ee.getMessage(), 50);
2283
      }//catch
2284
      finally
2285
      {
2286
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2287
      }//finally
2288
    }//finally
2289
      
2290
    return serverLocation;
2291
  }
2292
  
2293
  /**
2294
   * Given a server name, return its servercode in xml_replication table.
2295
   * If no server is found, -1 will return
2296
   * @param serverName, 
2297
   */
2298
  private static int getServerCode(String serverName) 
2299
  {
2300
    PreparedStatement pStmt=null;
2301
    int serverLocation=-2;
2302
    DBConnection dbConn = null;
2303
    int serialNumber = -1;
2304
    //MetaCatUtil util = new MetaCatUtil();
2305
    
2306
    
2307
    //we should consider about local host too
2308
    if (serverName.equals(MetaCatUtil.getLocalReplicationServerName()))
2309
    { 
2310
      serverLocation=1;
2311
      return serverLocation;
2312
    }
2313
    
2314
   
2315
    try
2316
    {
2317
      //check xml_replication table
2318
      //dbConn=util.openDBConnection();
2319
      //check out DBConnection
2320
      dbConn=DBConnectionPool.getDBConnection("DocumentImpl.getServerCode");
2321
      serialNumber=dbConn.getCheckOutSerialNumber();
2322
      pStmt = dbConn.prepareStatement
2323
      ("SELECT serverid FROM xml_replication WHERE server='" + serverName +"'");
2324
      pStmt.execute();
2325

    
2326
      ResultSet rs = pStmt.getResultSet();
2327
      boolean hasRow = rs.next();
2328
      //if there is entry in xml_replication, get the serverid
2329
      if (hasRow)
2330
      {
2331
        serverLocation = rs.getInt(1);
2332
        pStmt.close();
2333
      }
2334
      else
2335
      {
2336
        // if htere is no entry in xml_replication, -1 will return
2337
        serverLocation=-1;
2338
        pStmt.close();
2339
      }
2340
    }
2341
    catch (Exception e)
2342
    {
2343
      MetaCatUtil.debugMessage("Error in DocumentImpl.getServerCode(): "
2344
                                    +e.getMessage(), 30);
2345
    }
2346
    finally
2347
    {
2348
      try
2349
      {
2350
        pStmt.close();
2351
      }
2352
      catch (Exception ee)
2353
      {
2354
        MetaCatUtil.debugMessage("Error in DocumentImpl.getServerCode(): "
2355
                                    +ee.getMessage(), 50);
2356
      }
2357
      finally
2358
      {
2359
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2360
      }
2361
    }
2362
                 
2363
      
2364
    return serverLocation;
2365
  }
2366
  
2367
  /**
2368
   * Insert a server into xml_replcation table
2369
   * @param server, the name of server 
2370
   */
2371
  private static synchronized void 
2372
                                insertServerIntoReplicationTable(String server)
2373
  {
2374
    PreparedStatement pStmt=null;
2375
    DBConnection dbConn = null;
2376
    int serialNumber = -1;
2377
    
2378
    // Initial value for the server
2379
    int replicate = 0;
2380
    int dataReplicate = 0;
2381
    int hub = 0;
2382
   
2383
    try
2384
    {
2385
       // Get DBConnection
2386
       dbConn=DBConnectionPool.
2387
                getDBConnection("DocumentImpl.insertServIntoReplicationTable");
2388
       serialNumber=dbConn.getCheckOutSerialNumber();
2389
      
2390
      // Compare the server to dabase
2391
      pStmt = dbConn.prepareStatement
2392
      ("SELECT serverid FROM xml_replication WHERE server='" + server +"'");
2393
      pStmt.execute();
2394
      ResultSet rs = pStmt.getResultSet();
2395
      boolean hasRow = rs.next();
2396
      // Close preparedstatement and result set
2397
      pStmt.close();
2398
      rs.close();
2399
      
2400
      // If the server is not in the table, and server is not local host,
2401
      // insert it
2402
      if ( !hasRow 
2403
         && !server.equals(MetaCatUtil.getLocalReplicationServerName()))
2404
      {
2405
        // Set auto commit false
2406
        dbConn.setAutoCommit(false);
2407
        pStmt = dbConn.prepareStatement("INSERT INTO xml_replication " +
2408
                      "(server, last_checked, replicate, datareplicate, hub) " +
2409
                       "VALUES ('" + server + "', to_date(" +
2410
                       "'01/01/00', 'MM/DD/YY'), '" +
2411
                       replicate +"', '"+dataReplicate+"','"+ hub + "')");
2412
        pStmt.execute();
2413
        dbConn.commit();
2414
        // Increase usage number
2415
        dbConn.increaseUsageCount(1);
2416
        pStmt.close();
2417
        
2418
      }
2419
    }//try
2420
    catch (Exception e)
2421
    {
2422
      MetaCatUtil.debugMessage("Error in DocumentImpl.insertServerIntoRepli(): "
2423
                                    +e.getMessage(), 30);
2424
    }//catch
2425
    finally
2426
    {
2427
     
2428
      try
2429
      {
2430
        // Set auto commit true
2431
        dbConn.setAutoCommit(true);
2432
        pStmt.close();
2433
        
2434
      }//try
2435
      catch (Exception ee)
2436
      {
2437
        MetaCatUtil.debugMessage("Error in DocumentImpl.insetServerIntoRepl(): "
2438
                                    +ee.getMessage(), 50);
2439
      }//catch
2440
      finally
2441
      {
2442
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2443
      }
2444
    
2445
    }//finally
2446

    
2447
  }
2448
  
2449
  
2450
  /**
2451
   * the main routine used to test the DBWriter utility.
2452
   * <p>
2453
   * Usage: java DocumentImpl <-f filename -a action -d docid>
2454
   *
2455
   * @param filename the filename to be loaded into the database
2456
   * @param action the action to perform (READ, INSERT, UPDATE, DELETE)
2457
   * @param docid the id of the document to process
2458
   */
2459
  static public void main(String[] args) {
2460
    DBConnection dbconn = null;
2461
    int serialNumber = -1;
2462
    try {
2463
      String filename    = null;
2464
      String dtdfilename = null;
2465
      String action      = null;
2466
      String docid       = null;
2467
      boolean showRuntime = false;
2468
      boolean useOldReadAlgorithm = false;
2469

    
2470
      // Parse the command line arguments
2471
      for ( int i=0 ; i < args.length; ++i ) {
2472
        if ( args[i].equals( "-f" ) ) {
2473
          filename =  args[++i];
2474
        } else if ( args[i].equals( "-r" ) ) {
2475
          dtdfilename =  args[++i];
2476
        } else if ( args[i].equals( "-a" ) ) {
2477
          action =  args[++i];
2478
        } else if ( args[i].equals( "-d" ) ) {
2479
          docid =  args[++i];
2480
        } else if ( args[i].equals( "-t" ) ) {
2481
          showRuntime = true;
2482
        } else if ( args[i].equals( "-old" ) ) {
2483
          useOldReadAlgorithm = true;
2484
        } else {
2485
          System.err.println
2486
            ( "   args[" +i+ "] '" +args[i]+ "' ignored." );
2487
        }
2488
      }
2489
      
2490
      // Check if the required arguments are provided
2491
      boolean argsAreValid = false;
2492
      if (action != null) {
2493
        if (action.equals("INSERT")) {
2494
          if (filename != null) {
2495
            argsAreValid = true;
2496
          } 
2497
        } else if (action.equals("UPDATE")) {
2498
          if ((filename != null) && (docid != null)) {
2499
            argsAreValid = true;
2500
          } 
2501
        } else if (action.equals("DELETE")) {
2502
          if (docid != null) {
2503
            argsAreValid = true;
2504
          } 
2505
        } else if (action.equals("READ")) {
2506
          if (docid != null) {
2507
            argsAreValid = true;
2508
          } 
2509
        } 
2510
      } 
2511

    
2512
      // Print usage message if the arguments are not valid
2513
      if (!argsAreValid) {
2514
        System.err.println("Wrong number of arguments!!!");
2515
        System.err.println(
2516
          "USAGE: java DocumentImpl [-t] <-a INSERT> [-d docid] <-f filename> "+
2517
          "[-r dtdfilename]");
2518
        System.err.println(
2519
          "   OR: java DocumentImpl [-t] <-a UPDATE -d docid -f filename> " +
2520
          "[-r dtdfilename]");
2521
        System.err.println(
2522
          "   OR: java DocumentImpl [-t] <-a DELETE -d docid>");
2523
        System.err.println(
2524
          "   OR: java DocumentImpl [-t] [-old] <-a READ -d docid>");
2525
        return;
2526
      }
2527
      
2528
      // Time the request if asked for
2529
      double startTime = System.currentTimeMillis();
2530
      
2531
      // Open a connection to the database
2532
      MetaCatUtil util = new MetaCatUtil();
2533
     
2534
      dbconn=DBConnectionPool.getDBConnection("DocumentImpl.main");
2535
      serialNumber=dbconn.getCheckOutSerialNumber();
2536

    
2537
      double connTime = System.currentTimeMillis();
2538
      // Execute the action requested (READ, INSERT, UPDATE, DELETE)
2539
      if (action.equals("READ")) {
2540
          DocumentImpl xmldoc = new DocumentImpl(docid );
2541
          if (useOldReadAlgorithm) {
2542
            System.out.println(xmldoc.readUsingSlowAlgorithm());
2543
          } else {
2544
            xmldoc.toXml(new PrintWriter(System.out));
2545
          }
2546
      } else if (action.equals("DELETE")) {
2547
        DocumentImpl.delete(docid, null, null);
2548
        System.out.println("Document deleted: " + docid);
2549
      } else {
2550
        /*String newdocid = DocumentImpl.write(dbconn, filename, null,
2551
                                             dtdfilename, action, docid,
2552
                                             null, null);
2553
        if ((docid != null) && (!docid.equals(newdocid))) {
2554
          if (action.equals("INSERT")) {
2555
            System.out.println("New document ID generated!!! ");
2556
          } else if (action.equals("UPDATE")) {
2557
            System.out.println("ERROR: Couldn't update document!!! ");
2558
          }
2559
        } else if ((docid == null) && (action.equals("UPDATE"))) {
2560
          System.out.println("ERROR: Couldn't update document!!! ");
2561
        }
2562
        System.out.println("Document processing finished for: " + filename
2563
              + " (" + newdocid + ")");*/
2564
      }
2565

    
2566
      double stopTime = System.currentTimeMillis();
2567
      double dbOpenTime = (connTime - startTime)/1000;
2568
      double insertTime = (stopTime - connTime)/1000;
2569
      double executionTime = (stopTime - startTime)/1000;
2570
      if (showRuntime) {
2571
        System.out.println("\n\nTotal Execution time was: " + 
2572
                           executionTime + " seconds.");
2573
        System.out.println("Time to open DB connection was: " + dbOpenTime + 
2574
                           " seconds.");
2575
        System.out.println("Time to insert document was: " + insertTime +
2576
                           " seconds.");
2577
      }
2578
      dbconn.close();
2579
    } catch (McdbException me) {
2580
      me.toXml(new PrintWriter(System.err));
2581
    } catch (AccessionNumberException ane) {
2582
      System.out.println(ane.getMessage());
2583
    } catch (Exception e) {
2584
      System.err.println("EXCEPTION HANDLING REQUIRED");
2585
      System.err.println(e.getMessage());
2586
      e.printStackTrace(System.err);
2587
    }
2588
    finally
2589
    {
2590
      // Return db connection
2591
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
2592
    }
2593
  }
2594
}
(29-29/52)