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-07-25 08:13:51 -0700 (Fri, 25 Jul 2003) $'
11
 * '$Revision: 1757 $'
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.Hashtable;
44
import java.util.Iterator;
45
import java.util.Stack;
46
import java.util.TreeSet;
47
import java.util.Vector;
48
import java.util.Enumeration;
49

    
50
import org.xml.sax.AttributeList;
51
import org.xml.sax.ContentHandler;
52
import org.xml.sax.DTDHandler;
53
import org.xml.sax.EntityResolver;
54
import org.xml.sax.ErrorHandler;
55
import org.xml.sax.InputSource;
56
import org.xml.sax.XMLReader;
57
import org.xml.sax.SAXException;
58
import org.xml.sax.SAXParseException;
59
import org.xml.sax.helpers.XMLReaderFactory;
60

    
61
import java.net.URL;
62

    
63
import edu.ucsb.nceas.dbadapter.AbstractDatabase;
64

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

    
72
   /* Constants */
73
   public static final String SCHEMA                 = "Schema";
74
   public static final String DTD                    = "DTD";
75
   public static final String EML2                   = "eml2";
76
   public static final String EXTERNALSCHEMALOCATIONPROPERTY = 
77
              "http://apache.org/xml/properties/schema/external-schemaLocation";
78
   /*public static final String EXTERNALSCHEMALOCATION = 
79
     "eml://ecoinformatics.org/eml-2.0.0 http://dev.nceas.ucsb.edu/tao/schema/eml.xsd"+
80
      " http://www.xml-cml.org/schema/stmml http://dev.nceas.ucsb.edu/tao/schema/stmml.xsd";*/
81
   public static final String DECLARATIONHANDLERPROPERTY =
82
                            "http://xml.org/sax/properties/declaration-handler";
83
   public static final String LEXICALPROPERTY =
84
                             "http://xml.org/sax/properties/lexical-handler";
85
   public static final String VALIDATIONFEATURE = 
86
                             "http://xml.org/sax/features/validation";
87
   public static final String SCHEMAVALIDATIONFEATURE = 
88
                             "http://apache.org/xml/features/validation/schema";
89
   public static final String NAMESPACEFEATURE = 
90
                              "http://xml.org/sax/features/namespaces";
91
   public static final String NAMESPACEPREFIXESFEATURE = 
92
                              "http://xml.org/sax/features/namespace-prefixes";
93
   public static final String EMLNAMESPACE =
94
                                         MetaCatUtil.getOption("eml2namespace"); 
95
                                         // "eml://ecoinformatics.org/eml-2.0.0";
96
  
97
  
98
  static final int ALL = 1;
99
  static final int WRITE = 2;
100
  static final int READ = 4;
101
  private static final AbstractDatabase dbAdapter = MetaCatUtil.dbAdapter;
102

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

    
163
  /**
164
   * Constructor, creates document from database connection, used 
165
   * for reading the document
166
   *
167
   * @param conn the database connection from which to read the document
168
   * @param docid the identifier of the document to be created
169
   */
170
  public DocumentImpl(String docid) throws McdbException 
171
  {
172
    this(docid, true);
173
  }
174

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

    
563
    BufferedInputStream bis = null;
564
    bis = new BufferedInputStream(input);
565
    byte[] buf = new byte[4 * 1024]; // 4K buffer
566
    int b = bis.read(buf);
567
       
568
    while (b != -1) 
569
    {
570
        outPut.write(buf, 0, b);
571
        b = bis.read(buf);
572
    }
573
    bis.close();
574
	  outPut.close();
575
	  fos.close();
576
      
577
    // Force replicate data file
578
    ForceReplicationHandler forceReplication = new ForceReplicationHandler
579
                                    (accnum, false, notificationServer);
580
  
581
 }
582
  
583

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

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

    
688
  /**
689
   * get the document type (which is the PublicID)
690
   */
691
  public String getDoctype() {
692
    return doctype;
693
  }
694

    
695
  /**
696
   * get the system identifier
697
   */
698
  public String getSystemID() {
699
    return system_id;
700
  }
701

    
702
  /**
703
   * get the root node identifier
704
   */
705
  public long getRootNodeID() {
706
    return rootnodeid;
707
  }
708
  
709
  /**
710
   * get the creation date
711
   */
712
  public String getCreateDate() {
713
    return createdate;
714
  }
715
  
716
  /**
717
   * get the update date
718
   */
719
  public String getUpdateDate() {
720
    return updatedate;
721
  }
722

    
723
  /** 
724
   * Get the document identifier (docid)
725
   */
726
  public String getDocID() {
727
    return docid;
728
  }
729
  
730
// DOCTITLE attr cleared from the db
731
//  /**
732
//   *get the document title
733
//   */
734
//  public String getDocTitle() {
735
//    return doctitle;
736
//  }
737
  
738
  public String getUserowner() {
739
    return userowner;
740
  }
741
  
742
  public String getUserupdated() {
743
    return userupdated;
744
  }
745
  
746
  public int getServerlocation() {
747
    return serverlocation;
748
  }
749
  
750
  public String getDocHomeServer() {
751
    return docHomeServer;
752
  }
753
  
754
 
755
 
756
  public String getPublicaccess() {
757
    return publicaccess;
758
  }
759
  
760
  public int getRev() {
761
    return rev;
762
  }
763
  
764
  public String getValidateType()
765
  {
766
    return validateType;
767
  }
768
  
769
  /**
770
   * Print a string representation of the XML document
771
   */
772
  public String toString(String user, String[] groups, boolean withInlinedata)
773
  {
774
    StringWriter docwriter = new StringWriter();
775
    try 
776
    {
777
      this.toXml(docwriter, user, groups, withInlinedata);
778
    } 
779
    catch (McdbException mcdbe) 
780
    {
781
      return null;
782
    }
783
    String document = docwriter.toString();
784
    return document;
785
  }
786
  
787
   /**
788
   * Print a string representation of the XML document
789
   */
790
  public String toString()
791
  {
792
    StringWriter docwriter = new StringWriter();
793
    String userName = null;
794
    String[] groupNames = null;
795
    boolean withInlineData = false;
796
    try 
797
    {
798
      this.toXml(docwriter, userName, groupNames, withInlineData);
799
    } 
800
    catch (McdbException mcdbe) 
801
    {
802
      return null;
803
    }
804
    String document = docwriter.toString();
805
    return document;
806
  }
807

    
808
  /**
809
   * Get a text representation of the XML document as a string
810
   * This older algorithm uses a recursive tree of Objects to represent the
811
   * nodes of the tree.  Each object is passed the data for the document 
812
   * and searches all of the document data to find its children nodes and
813
   * recursively build.  Thus, because each node reads the whole document,
814
   * this algorithm is extremely slow for larger documents, and the time
815
   * to completion is O(N^N) wrt the number of nodes.  See toXml() for a
816
   * better algorithm.
817
   */
818
  public String readUsingSlowAlgorithm() throws McdbException
819
  {
820
    StringBuffer doc = new StringBuffer();
821

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

    
827
    // Create the elements from the downloaded data in the TreeSet
828
    rootNode = new ElementNode(nodeRecordList, rootnodeid);
829

    
830
    // Append the resulting document to the StringBuffer and return it
831
    doc.append("<?xml version=\"1.0\"?>\n");
832
      
833
    if (docname != null) {
834
      if ((doctype != null) && (system_id != null)) {
835
        doc.append("<!DOCTYPE " + docname + " PUBLIC \"" + doctype + 
836
                   "\" \"" + system_id + "\">\n");
837
      } else {
838
        doc.append("<!DOCTYPE " + docname + ">\n");
839
      }
840
    }
841
    doc.append(rootNode.toString());
842
  
843
    return (doc.toString());
844
  }
845

    
846
  /**
847
   * Print a text representation of the XML document to a Writer
848
   *
849
   * @param pw the Writer to which we print the document
850
   */
851
  public void toXml(Writer pw, String user, String[] groups, boolean withInLineData) 
852
                                                          throws McdbException
853
  {
854
    // flag for process  eml2
855
    boolean proccessEml2 = false;
856
    if (doctype != null && doctype.equals(EMLNAMESPACE))
857
    {
858
      proccessEml2 = true;
859
    }
860
    // flag for process inline data
861
    boolean prcocessInlineData = false;
862
    
863
    TreeSet nodeRecordLists = null;
864
    PrintWriter out = null;
865
    if (pw instanceof PrintWriter) {
866
      out = (PrintWriter)pw;
867
    } else {
868
      out = new PrintWriter(pw);
869
    }
870

    
871
    MetaCatUtil util = new MetaCatUtil();
872
    
873
    // Here add code to handle subtree access control
874
    PermissionController control = new PermissionController(docid);
875
    Hashtable unaccessableSubTree =control.hasUnaccessableSubTree(user, groups, 
876
                                             AccessControlInterface.READSTRING);
877
    
878
    if (!unaccessableSubTree.isEmpty())
879
    {
880
     
881
      nodeRecordLists = getPartNodeRecordList(rootnodeid, unaccessableSubTree);
882
      
883
    }
884
    else 
885
    {
886
      nodeRecordLists = getNodeRecordList(rootnodeid);
887
    }
888

    
889
    Stack openElements = new Stack();
890
    boolean atRootElement = true;
891
    boolean previousNodeWasElement = false;
892

    
893
    // Step through all of the node records we were given
894
   
895
    Iterator it = nodeRecordLists.iterator();
896
   
897
    while (it.hasNext()) 
898
    {
899
      
900
      NodeRecord currentNode = (NodeRecord)it.next();
901
      util.debugMessage("[Got Node ID: " + currentNode.nodeid +
902
                          " (" + currentNode.parentnodeid +
903
                          ", " + currentNode.nodeindex + 
904
                          ", " + currentNode.nodetype + 
905
                          ", " + currentNode.nodename + 
906
                          ", " + currentNode.nodedata + ")]", 50);
907
      // Print the end tag for the previous node if needed
908
      //
909
      // This is determined by inspecting the parent nodeid for the
910
      // currentNode.  If it is the same as the nodeid of the last element
911
      // that was pushed onto the stack, then we are still in that previous
912
      // parent element, and we do nothing.  However, if it differs, then we
913
      // have returned to a level above the previous parent, so we go into
914
      // a loop and pop off nodes and print out their end tags until we get
915
      // the node on the stack to match the currentNode parentnodeid
916
      //
917
      // So, this of course means that we rely on the list of elements
918
      // having been sorted in a depth first traversal of the nodes, which
919
      // is handled by the NodeComparator class used by the TreeSet
920
      if (!atRootElement) {
921
        NodeRecord currentElement = (NodeRecord)openElements.peek();
922
        if ( currentNode.parentnodeid != currentElement.nodeid ) {
923
          while ( currentNode.parentnodeid != currentElement.nodeid ) {
924
            currentElement = (NodeRecord)openElements.pop();
925
            util.debugMessage("\n POPPED: " + currentElement.nodename, 50);
926
            if (previousNodeWasElement) {
927
              out.print(">");
928
              previousNodeWasElement = false;
929
            }  
930
            if ( currentElement.nodeprefix != null ) {
931
              out.print("</" + currentElement.nodeprefix + ":" + 
932
                        currentElement.nodename + ">" );
933
            } else {
934
              out.print("</" + currentElement.nodename + ">" );
935
            }
936
            currentElement = (NodeRecord)openElements.peek();
937
          }
938
        }
939
      }
940

    
941
      // Handle the DOCUMENT node
942
      if (currentNode.nodetype.equals("DOCUMENT")) {
943
        out.println("<?xml version=\"1.0\"?>");
944
        if (docname != null && validateType != null && validateType.equals(DTD)) 
945
        {
946
          if ((doctype != null) && (system_id != null)) 
947
          {
948
            
949
            out.println("<!DOCTYPE " + docname + " PUBLIC \"" + doctype + 
950
                       "\" \"" + system_id + "\">");
951
          } 
952
          else 
953
          {
954
            
955
            out.println("<!DOCTYPE " + docname + ">");
956
          }
957
        }
958

    
959
      // Handle the ELEMENT nodes
960
      } else if (currentNode.nodetype.equals("ELEMENT")) {
961
        if (atRootElement) {
962
          atRootElement = false;
963
        } else {
964
          if (previousNodeWasElement) {
965
            out.print(">");
966
          }
967
        }
968
        openElements.push(currentNode);
969
        util.debugMessage("\n PUSHED: " + currentNode.nodename, 50);
970
        previousNodeWasElement = true;
971
        if ( currentNode.nodeprefix != null ) {
972
          out.print("<" + currentNode.nodeprefix + ":" + currentNode.nodename);
973
        } else {
974
          out.print("<" + currentNode.nodename);
975
        }
976
        
977
        // if currentNode is inline and handle eml2, set flag proccess in
978
        if (currentNode.nodename != null && 
979
            currentNode.nodename.equals(EmlSAXHandler.INLINE) && proccessEml2)
980
        {
981
          prcocessInlineData = true;
982
        }
983

    
984
      // Handle the ATTRIBUTE nodes
985
      } else if (currentNode.nodetype.equals("ATTRIBUTE")) {
986
        if ( currentNode.nodeprefix != null ) {
987
          out.print(" " + currentNode.nodeprefix + ":" + currentNode.nodename +
988
                    "=\"" + currentNode.nodedata + "\"");
989
        } else {
990
          out.print(" " + currentNode.nodename + "=\"" +
991
                    currentNode.nodedata + "\"");
992
        }
993

    
994
      // Handle the NAMESPACE nodes
995
      } else if (currentNode.nodetype.equals("NAMESPACE")) {
996
        out.print(" xmlns:" + currentNode.nodename + "=\""
997
                 + currentNode.nodedata + "\"");
998

    
999
      // Handle the TEXT nodes
1000
      } else if (currentNode.nodetype.equals("TEXT")) {
1001
        if (previousNodeWasElement) {
1002
          out.print(">");
1003
        }
1004
        if (!prcocessInlineData || !withInLineData)
1005
        {
1006
          // if it is not inline data just out put data or it is line data
1007
          // but user don't want it, just put local id in inlinedata
1008
          out.print(currentNode.nodedata);
1009
        }
1010
        else
1011
        {
1012
          // if it is inline data and user want to see it, pull out from 
1013
          // file system and output it
1014
          // for inline data, the data base only store the file name, so we
1015
          // can combine the file name and inline data file path, to get it
1016
          String fileName = currentNode.nodedata;
1017
          String content = EmlSAXHandler.readInlineDataFromFileSystem(fileName);
1018
          out.print(content);
1019
        }
1020
        // reset proccess inline data false
1021
        prcocessInlineData =false;
1022
        previousNodeWasElement = false;
1023

    
1024
      // Handle the COMMENT nodes
1025
      } else if (currentNode.nodetype.equals("COMMENT")) {
1026
        if (previousNodeWasElement) {
1027
          out.print(">");
1028
        }
1029
        out.print("<!--" + currentNode.nodedata + "-->");
1030
        previousNodeWasElement = false;
1031

    
1032
      // Handle the PI nodes
1033
      } else if (currentNode.nodetype.equals("PI")) {
1034
        if (previousNodeWasElement) {
1035
          out.print(">");
1036
        }
1037
        out.print("<?" + currentNode.nodename + " " +
1038
                        currentNode.nodedata + "?>");
1039
        previousNodeWasElement = false;
1040

    
1041
      // Handle any other node type (do nothing)
1042
      } else {
1043
        // Any other types of nodes are not handled.
1044
        // Probably should throw an exception here to indicate this
1045
      }
1046
      out.flush();
1047
    }
1048
    
1049
    // Print the final end tag for the root element
1050
    while(!openElements.empty())
1051
    {
1052
      NodeRecord currentElement = (NodeRecord)openElements.pop();
1053
      util.debugMessage("\n POPPED: " + currentElement.nodename, 50);
1054
      if ( currentElement.nodeprefix != null ) {
1055
        out.print("</" + currentElement.nodeprefix + ":" + 
1056
                  currentElement.nodename + ">" );
1057
      } else {
1058
        out.print("</" + currentElement.nodename + ">" );
1059
      }
1060
    }
1061
    out.flush();
1062
  }
1063
  
1064

    
1065
  
1066
  private boolean isRevisionOnly(DocumentIdentifier docid) throws Exception
1067
  {
1068
    //System.out.println("inRevisionOnly");
1069
    DBConnection dbconn = null;
1070
    int serialNumber = -1;
1071
    PreparedStatement pstmt =null;
1072
    String rev = docid.getRev();
1073
    String newid = docid.getIdentifier();
1074
    try
1075
    {
1076
      dbconn=DBConnectionPool.
1077
                    getDBConnection("DocumentImpl.isRevisionOnly");
1078
      serialNumber=dbconn.getCheckOutSerialNumber();
1079
      pstmt = dbconn.prepareStatement("select rev from xml_documents " +
1080
                                  "where docid like '" + newid + "'");
1081
      pstmt.execute();
1082
      ResultSet rs = pstmt.getResultSet();
1083
      boolean tablehasrows = rs.next();
1084
      if(rev.equals("newest") || rev.equals("all"))
1085
      {
1086
        return false;
1087
      }
1088
    
1089
      if(tablehasrows)
1090
      {
1091
        int r = rs.getInt(1);
1092
        pstmt.close();
1093
        if(new Integer(rev).intValue() == r)
1094
        { //the current revision in in xml_documents
1095
          //System.out.println("returning false");
1096
          return false;
1097
        }
1098
        else if(new Integer(rev).intValue() < r)
1099
        { //the current revision is in xml_revisions.
1100
          //System.out.println("returning true");
1101
          return true;
1102
        }
1103
        else if(new Integer(rev).intValue() > r)
1104
        { //error, rev cannot be greater than r
1105
          throw new Exception("requested revision cannot be greater than " +
1106
                            "the latest revision number.");
1107
        }
1108
      }
1109
      // Get miss docid and rev, throw to McdDocNotFoundException
1110
      String missDocId = MetaCatUtil.getDocIdFromString(docid.toString());
1111
      String missRevision = 
1112
                  MetaCatUtil.getRevisionStringFromString(docid.toString());
1113
      throw new McdbDocNotFoundException("the requested docid '" + 
1114
                docid.toString() + "' does not exist", missDocId, missRevision);
1115
    }//try
1116
    finally
1117
    {
1118
      pstmt.close();
1119
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1120
    }//finally
1121
  }
1122

    
1123
  private void getDocumentInfo(String docid) throws McdbException, 
1124
                                        AccessionNumberException, Exception
1125
  {
1126
    getDocumentInfo(new DocumentIdentifier(docid));
1127
  }
1128
  
1129
  /**
1130
   * Look up the document type information from the database
1131
   *
1132
   * @param docid the id of the document to look up
1133
   */
1134
  private void getDocumentInfo(DocumentIdentifier docid) throws McdbException
1135
                                                          , Exception
1136
  {
1137
    DBConnection dbconn = null;
1138
    int serialNumber = -1;
1139
    PreparedStatement pstmt = null;
1140
    String table = "xml_documents";
1141
        
1142
    try
1143
    {
1144
      if(isRevisionOnly(docid))
1145
      { //pull the document from xml_revisions instead of from xml_documents;
1146
        table = "xml_revisions";
1147
      }
1148
    }
1149
    // catch a McdbDocNotFoundException throw it
1150
    catch (McdbDocNotFoundException notFound)
1151
    {
1152
      throw notFound;
1153
    }
1154
    catch(Exception e)
1155
    {
1156
      
1157
      MetaCatUtil.debugMessage("error in DocumentImpl.getDocumentInfo: " + 
1158
                          e.getMessage(), 30);
1159
      throw e;
1160
    }
1161
    
1162

    
1163
    
1164
    try 
1165
    {
1166
      dbconn=DBConnectionPool.getDBConnection("DocumentImpl.getDocumentInfo");
1167
      serialNumber=dbconn.getCheckOutSerialNumber();
1168
      StringBuffer sql = new StringBuffer();
1169
// DOCTITLE attr cleared from the db
1170
//      sql.append("SELECT docname, doctype, rootnodeid, doctitle, ");
1171
      sql.append("SELECT docname, doctype, rootnodeid, ");
1172
      sql.append("date_created, date_updated, user_owner, user_updated, ");
1173
      sql.append("server_location, public_access, rev");
1174
      sql.append(" FROM ").append(table);
1175
      sql.append(" WHERE docid LIKE '").append(docid.getIdentifier());
1176
      sql.append("' and rev like '").append(docid.getRev()).append("'");
1177
      //System.out.println(sql.toString());
1178
      pstmt =
1179
        dbconn.prepareStatement(sql.toString());
1180
      // Bind the values to the query
1181
      //pstmt.setString(1, docid.getIdentifier());
1182
      //pstmt.setString(2, docid.getRev());
1183

    
1184
      pstmt.execute();
1185
      ResultSet rs = pstmt.getResultSet();
1186
      boolean tableHasRows = rs.next();
1187
      if (tableHasRows) {
1188
        this.docname        = rs.getString(1);
1189
        this.doctype        = rs.getString(2);
1190
        this.rootnodeid     = rs.getLong(3);
1191
// DOCTITLE attr cleared from the db
1192
//        this.doctitle       = rs.getString(4);
1193
        this.createdate     = rs.getString(4);
1194
        this.updatedate     = rs.getString(5);
1195
        this.userowner      = rs.getString(6);
1196
        this.userupdated    = rs.getString(7);
1197
        this.serverlocation = rs.getInt(8);
1198
        this.publicaccess   = rs.getString(9);
1199
        this.rev            = rs.getInt(10);
1200
      } 
1201
      pstmt.close();
1202
      
1203
      //get doc  home server name
1204
      
1205
      pstmt = dbconn.prepareStatement("select server " +
1206
                        "from xml_replication where serverid = ?");
1207
      //because connection use twise here, so we need to increase one
1208
      dbconn.increaseUsageCount(1);
1209
      pstmt.setInt(1, serverlocation);
1210
      pstmt.execute();
1211
      rs = pstmt.getResultSet();
1212
      tableHasRows = rs.next();
1213
      if (tableHasRows)
1214
      {
1215
        
1216
          String server = rs.getString(1);
1217
          //get homeserver name
1218
          if(!server.equals("localhost"))
1219
          {
1220
            this.docHomeServer=server;
1221
          }
1222
          else
1223
          {
1224
            this.docHomeServer=MetaCatUtil.getLocalReplicationServerName();
1225
          }
1226
          MetaCatUtil.debugMessage("server: "+docHomeServer, 50);
1227
        
1228
      }
1229
      pstmt.close();
1230
      if (this.doctype != null) {
1231
        pstmt =
1232
          dbconn.prepareStatement("SELECT system_id, entry_type " +
1233
                                  "FROM xml_catalog " +
1234
                                 "WHERE public_id = ?");
1235
        //should increase usage count again
1236
        dbconn.increaseUsageCount(1);
1237
        // Bind the values to the query
1238
        pstmt.setString(1, doctype);
1239
  
1240
        pstmt.execute();
1241
        rs = pstmt.getResultSet();
1242
        tableHasRows = rs.next();
1243
        if (tableHasRows) {
1244
          this.system_id  = rs.getString(1);
1245
          this.validateType = rs.getString(2);
1246
          
1247
        } 
1248
        pstmt.close();
1249
      }
1250
    } catch (SQLException e) {
1251
      System.out.println("error in DocumentImpl.getDocumentInfo: " + 
1252
                          e.getMessage());
1253
      e.printStackTrace(System.out);
1254
      throw new McdbException("Error accessing database connection in " +
1255
                              "DocumentImpl.getDocumentInfo: ", e);
1256
    }
1257
    finally
1258
    {
1259
      try
1260
      {
1261
        pstmt.close();
1262
      }
1263
      catch (SQLException ee)
1264
      {
1265
        MetaCatUtil.debugMessage("error in DocumentImple.getDocumentInfo: "
1266
                                    +ee.getMessage(), 30);
1267
      }//catch
1268
      finally
1269
      {
1270
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1271
      }
1272
    }
1273

    
1274
    if (this.docname == null) {
1275
      throw new McdbDocNotFoundException("Document not found: " + docid,
1276
                                 docid.getIdentifier(), docid.getRev());
1277
    }
1278
  }
1279
  
1280
  /**
1281
   * Look up the node data from the database, but some node would be shown
1282
   * because of access control
1283
   * @param rootnodeid the id of the root node of the node tree to look up
1284
   * @param accessControl  the hashtable has control info
1285
   */
1286
  private TreeSet getPartNodeRecordList(long rootnodeid, 
1287
                                        Hashtable accessControl) 
1288
                                        throws McdbException
1289
  {
1290
    PreparedStatement pstmt = null;
1291
    DBConnection dbconn = null;
1292
    int serialNumber = -1;
1293
    TreeSet nodeRecordList = new TreeSet(new NodeComparator());
1294
    long nodeid = 0;
1295
    long parentnodeid = 0;
1296
    long nodeindex = 0;
1297
    String nodetype = null;
1298
    String nodename = null;
1299
    String nodeprefix = null;
1300
    String nodedata = null;
1301
    String quotechar = dbAdapter.getStringDelimiter();
1302
    String sql = "SELECT nodeid,parentnodeid,nodeindex, " +
1303
                 "nodetype,nodename,nodeprefix,nodedata " +               
1304
                  "FROM xml_nodes WHERE rootnodeid = ?";
1305
                  
1306
    // go through the access control for some nodes
1307
     Enumeration en = accessControl.elements();
1308
     while (en.hasMoreElements())
1309
     {
1310
         SubTree tree = (SubTree)en.nextElement();
1311
         long startId = tree.getStartNodeId();
1312
         long endId  = tree.getEndNodeId();
1313
         sql = sql +" AND(nodeid < " + startId + " OR nodeid > " +endId +")";
1314
         
1315
     }
1316
     MetaCatUtil.debugMessage("The final query to select part node tree: " +
1317
                              sql, 25);
1318

    
1319
    try 
1320
    {
1321
      dbconn=DBConnectionPool.
1322
                    getDBConnection("DocumentImpl.getPartNodeRecordList");
1323
      serialNumber=dbconn.getCheckOutSerialNumber();
1324
      pstmt = dbconn.prepareStatement(sql);
1325

    
1326
      // Bind the values to the query
1327
      pstmt.setLong(1, rootnodeid);
1328
      pstmt.execute();
1329
      ResultSet rs = pstmt.getResultSet();
1330
      boolean tableHasRows = rs.next();
1331
      while (tableHasRows) 
1332
      {
1333
        nodeid = rs.getLong(1);
1334
        parentnodeid = rs.getLong(2);
1335
        nodeindex = rs.getLong(3);
1336
        nodetype = rs.getString(4);
1337
        nodename = rs.getString(5);
1338
        nodeprefix = rs.getString(6);
1339
        nodedata = rs.getString(7);
1340
        nodedata = MetaCatUtil.normalize(nodedata);
1341
        // add the data to the node record list hashtable
1342
        NodeRecord currentRecord = new NodeRecord(nodeid,parentnodeid,nodeindex,
1343
                                      nodetype, nodename, nodeprefix, nodedata);
1344
        nodeRecordList.add(currentRecord);
1345

    
1346
        // Advance to the next node
1347
        tableHasRows = rs.next();
1348
      } 
1349
      pstmt.close();
1350

    
1351
    } 
1352
    catch (SQLException e) 
1353
    {
1354
      throw new McdbException("Error in DocumentImpl.getPartNodeRecordList " +
1355
                              e.getMessage());
1356
    }
1357
    finally
1358
    {
1359
      try
1360
      {
1361
        pstmt.close();
1362
      }
1363
      catch (SQLException ee)
1364
      {
1365
        MetaCatUtil.debugMessage("error in DocumentImpl.getPartNodeRecordList: "
1366
                                    +ee.getMessage(), 30);
1367
      }
1368
      finally
1369
      {
1370
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1371
      }
1372
    }
1373
      
1374

    
1375
    if (!nodeRecordList.isEmpty()) 
1376
    {
1377
     
1378
      return nodeRecordList;
1379
    } 
1380
    else 
1381
    {
1382
      
1383
      throw new McdbException("Error getting node data: " + docid);
1384
    }
1385
  }
1386
  
1387
  /**
1388
   * Look up the node data from the database
1389
   *
1390
   * @param rootnodeid the id of the root node of the node tree to look up
1391
   */
1392
  private TreeSet getNodeRecordList(long rootnodeid) throws McdbException
1393
  {
1394
    PreparedStatement pstmt = null;
1395
    DBConnection dbconn = null;
1396
    int serialNumber = -1;
1397
    TreeSet nodeRecordList = new TreeSet(new NodeComparator());
1398
    long nodeid = 0;
1399
    long parentnodeid = 0;
1400
    long nodeindex = 0;
1401
    String nodetype = null;
1402
    String nodename = null;
1403
    String nodeprefix = null;
1404
    String nodedata = null;
1405
    String quotechar = dbAdapter.getStringDelimiter();
1406

    
1407
    try {
1408
      dbconn=DBConnectionPool.
1409
                    getDBConnection("DocumentImpl.getNodeRecordList");
1410
      serialNumber=dbconn.getCheckOutSerialNumber();
1411
      pstmt =
1412
      dbconn.prepareStatement("SELECT nodeid,parentnodeid,nodeindex, " +
1413
           "nodetype,nodename,nodeprefix,nodedata " +               
1414
           "FROM xml_nodes WHERE rootnodeid = ?");
1415

    
1416
      // Bind the values to the query
1417
      pstmt.setLong(1, rootnodeid);
1418

    
1419
      pstmt.execute();
1420
      ResultSet rs = pstmt.getResultSet();
1421
      boolean tableHasRows = rs.next();
1422
      while (tableHasRows) {
1423
        nodeid = rs.getLong(1);
1424
        parentnodeid = rs.getLong(2);
1425
        nodeindex = rs.getLong(3);
1426
        nodetype = rs.getString(4);
1427
        nodename = rs.getString(5);
1428
        nodeprefix = rs.getString(6);
1429
        nodedata = rs.getString(7);
1430
        nodedata = MetaCatUtil.normalize(nodedata);
1431
        // add the data to the node record list hashtable
1432
        NodeRecord currentRecord = new NodeRecord(nodeid,parentnodeid,nodeindex,
1433
                                      nodetype, nodename, nodeprefix, nodedata);
1434
        nodeRecordList.add(currentRecord);
1435

    
1436
        // Advance to the next node
1437
        tableHasRows = rs.next();
1438
      } 
1439
      pstmt.close();
1440

    
1441
    } catch (SQLException e) {
1442
      throw new McdbException("Error in DocumentImpl.getNodeRecordList " +
1443
                              e.getMessage());
1444
    }
1445
    finally
1446
    {
1447
      try
1448
      {
1449
        pstmt.close();
1450
      }
1451
      catch (SQLException ee)
1452
      {
1453
        MetaCatUtil.debugMessage("error in DocumentImpl.getNodeRecordList: "
1454
                                    +ee.getMessage(), 30);
1455
      }
1456
      finally
1457
      {
1458
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1459
      }
1460
    }
1461
  
1462
    return nodeRecordList;
1463
   
1464
  }
1465
  
1466
// NOT USED ANY MORE
1467
//  /** creates SQL code and inserts new document into DB connection 
1468
//   default serverCode of 1*/
1469
//  private void writeDocumentToDB(String action, String user)
1470
//               throws SQLException, Exception
1471
//  {
1472
//    writeDocumentToDB(action, user, null, 1);
1473
//  }
1474

    
1475
 /** creates SQL code and inserts new document into DB connection */
1476
  private void writeDocumentToDB(String action, String user, String pub, 
1477
                                 String catalogid, int serverCode) 
1478
               throws SQLException, Exception {
1479
    String sysdate = dbAdapter.getDateTimeFunction();
1480

    
1481
    try {
1482
      PreparedStatement pstmt = null;
1483

    
1484
      if (action.equals("INSERT")) {
1485
        //AccessionNumber ac = new AccessionNumber();
1486
        //this.docid = ac.generate(docid, "INSERT");
1487
        
1488
        pstmt = connection.prepareStatement(
1489
                "INSERT INTO xml_documents " +
1490
                "(docid, rootnodeid, docname, doctype, " + 
1491
                "user_owner, user_updated, date_created, date_updated, " + 
1492
                "public_access, catalog_id, server_location, rev) " +
1493
                "VALUES (?, ?, ?, ?, ?, ?, " + sysdate + ", " + sysdate + 
1494
                ", ?, ?, ?, ?)");
1495
        // Increase dbconnection usage count
1496
        connection.increaseUsageCount(1);
1497
        
1498
        //note that the server_location is set to 1. 
1499
        //this means that "localhost" in the xml_replication table must
1500
        //always be the first entry!!!!!
1501
        
1502
        // Bind the values to the query
1503
        pstmt.setString(1, this.docid);
1504
        pstmt.setLong(2, rootnodeid);
1505
        pstmt.setString(3, docname);
1506
        pstmt.setString(4, doctype);
1507
        pstmt.setString(5, user);
1508
        pstmt.setString(6, user);
1509
        //public access is usefulless, so set it to null
1510
        pstmt.setString(7, null);
1511
        /*if ( pub == null ) {
1512
          pstmt.setString(7, null);
1513
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
1514
          pstmt.setInt(7, 1);
1515
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
1516
          pstmt.setInt(7, 0);
1517
        }*/
1518
        pstmt.setString(8, catalogid);
1519
        pstmt.setInt(9, serverCode);
1520
        pstmt.setInt(10, Integer.parseInt(updatedVersion)); 
1521
      } else if (action.equals("UPDATE")) {
1522

    
1523
        // Save the old document publicaccessentry in a backup table
1524
        DocumentImpl.archiveDocRevision(connection, docid, user );
1525
        DocumentImpl thisdoc = new DocumentImpl(docid, false);
1526
        int thisrev = thisdoc.getRev();
1527
        
1528
        //if the updated vesion is not greater than current one,
1529
        //throw it into a exception
1530
        if (Integer.parseInt(updatedVersion)<=thisrev)
1531
        {
1532
          throw new Exception("Next revision number couldn't be less"
1533
                               +" than or equal "+ thisrev);
1534
        }
1535
        else
1536
        {
1537
          //set the user specified revision 
1538
          thisrev=Integer.parseInt(updatedVersion);
1539
        }
1540
        
1541
        // Delete index for the old version of docid
1542
        // The new index is inserting on the next calls to DBSAXNode
1543
        pstmt = connection.prepareStatement(
1544
                "DELETE FROM xml_index WHERE docid='" + this.docid + "'");
1545
        // Increase dbconnection usage count
1546
        connection.increaseUsageCount(1);
1547
        
1548
        pstmt.execute();
1549
        pstmt.close();
1550

    
1551
        // Update the new document to reflect the new node tree
1552
        pstmt = connection.prepareStatement(
1553
            "UPDATE xml_documents " +
1554
            "SET rootnodeid = ?, docname = ?, doctype = ?, " +
1555
            "user_updated = ?, date_updated = " + sysdate + ", " +
1556
            "server_location = ?, rev = ?, public_access = ?, catalog_id = ? " +
1557
            "WHERE docid = ?");
1558
        // Increase dbconnection usage count
1559
        connection.increaseUsageCount(1);
1560
        // Bind the values to the query
1561
        pstmt.setLong(1, rootnodeid);
1562
        pstmt.setString(2, docname);
1563
        pstmt.setString(3, doctype);
1564
        pstmt.setString(4, user);
1565
        pstmt.setInt(5, serverCode);
1566
        pstmt.setInt(6, thisrev);
1567
        pstmt.setString(7, null);
1568
        /*if ( pub == null ) {
1569
          pstmt.setString(7, null);
1570
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
1571
          pstmt .setInt(7, 1);
1572
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
1573
          pstmt.setInt(7, 0);
1574
        }*/
1575
        pstmt.setString(8, catalogid);
1576
        pstmt.setString(9, this.docid);
1577

    
1578
      } else {
1579
        System.err.println("Action not supported: " + action);
1580
      }
1581

    
1582
      // Do the insertion
1583
      pstmt.execute();
1584
      
1585
      pstmt.close();
1586

    
1587
    } catch (SQLException sqle) {
1588
      throw sqle;
1589
    } catch (Exception e) {
1590
      throw e;
1591
    }
1592
  }
1593

    
1594
  /**
1595
   * Write an XML file to the database, given a filename
1596
   *
1597
   * @param conn the JDBC connection to the database
1598
   * @param filename the filename to be loaded into the database
1599
   * @param pub flag for public "read" access on document
1600
   * @param dtdfilename the dtd to be uploaded on server's file system
1601
   * @param action the action to be performed (INSERT OR UPDATE)
1602
   * @param docid the docid to use for the INSERT OR UPDATE
1603
   * @param user the user that owns the document
1604
   * @param groups the groups to which user belongs
1605
   */
1606
  /*public static String write(DBConnection conn,String filename,
1607
                             String pub, String dtdfilename,
1608
                             String action, String docid, String user,
1609
                             String[] groups )
1610
                throws Exception {
1611
                  
1612
    Reader dtd = null;
1613
    if ( dtdfilename != null ) {
1614
      dtd = new FileReader(new File(dtdfilename).toString());
1615
    }
1616
    return write ( conn, new FileReader(new File(filename).toString()),
1617
                   pub, dtd, action, docid, user, groups, false);
1618
  }*/
1619

    
1620
  public static String write(DBConnection conn,Reader xml,String pub,Reader dtd,
1621
                             String action, String docid, String user,
1622
                             String[] groups, String ruleBase, 
1623
                             boolean needValidation)
1624
                throws Exception {
1625
    //this method will be called in handleUpdateOrInsert method 
1626
    //in MetacatServlet class and now is wrapper into documentImple
1627
    // get server location for this doc
1628
    int serverLocation=getServerLocationNumber(docid);
1629
    return write(conn,xml,pub,dtd,action,docid,user,groups,serverLocation,false,
1630
                 ruleBase, needValidation);
1631
  }
1632

    
1633
 
1634
  
1635
  /**
1636
   * Write an XML file to the database, given a Reader
1637
   *
1638
   * @param conn the JDBC connection to the database
1639
   * @param xml the xml stream to be loaded into the database
1640
   * @param pub flag for public "read" access on xml document
1641
   * @param dtd the dtd to be uploaded on server's file system
1642
   * @param action the action to be performed (INSERT or UPDATE)
1643
   * @param accnum the docid + rev# to use on INSERT or UPDATE
1644
   * @param user the user that owns the document
1645
   * @param groups the groups to which user belongs
1646
   * @param serverCode the serverid from xml_replication on which this document
1647
   *        resides.
1648
   * @param override flag to stop insert replication checking.
1649
   *        if override = true then a document not belonging to the local server
1650
   *        will not be checked upon update for a file lock.
1651
   *        if override = false then a document not from this server, upon 
1652
   *        update will be locked and version checked.
1653
   */
1654

    
1655
  public static String write(DBConnection conn, Reader xml,String pub,
1656
                         Reader dtd, String action, String accnum, String user,
1657
                         String[] groups, int serverCode, boolean override,
1658
                         String ruleBase, boolean needValidation)
1659
                throws Exception
1660
  {
1661
    // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1662
    //MetaCatUtil util = new MetaCatUtil();
1663
    MetaCatUtil.debugMessage("conn usage count before writting: "
1664
                                      +conn.getUsageCount(), 50);
1665
    AccessionNumber ac = new AccessionNumber(accnum, action);
1666
    String docid = ac.getDocid();
1667
    String rev = ac.getRev();
1668
    MetaCatUtil.debugMessage("action: " + action + " servercode: " + 
1669
                             serverCode + " override: " + override, 10);
1670
                     
1671
    if((serverCode != 1 && action.equals("UPDATE")) && !override)
1672
    { //if this document being written is not a resident of this server then
1673
      //we need to try to get a lock from it's resident server.  If the
1674
      //resident server will not give a lock then we send the user a message
1675
      //saying that he/she needs to download a new copy of the file and
1676
      //merge the differences manually.
1677
      int istreamInt; 
1678
      char istreamChar;
1679
     
1680
      // check for 'write' permission for 'user' to update this document
1681
      if ( !hasWritePermission(user, groups, docid) ) {
1682
        throw new Exception("User " + user + 
1683
              " does not have permission to update XML Document #" + accnum);
1684
      }        
1685
  
1686
      DocumentIdentifier id = new DocumentIdentifier(accnum);
1687
      String updaterev = id.getRev();
1688
      String server=MetacatReplication.getServerNameForServerCode(serverCode);
1689
      MetacatReplication.replLog("attempting to lock " + accnum);
1690
      URL u = new URL("https://" + server + "?server="+
1691
        MetaCatUtil.getLocalReplicationServerName()+"&action=getlock&updaterev=" 
1692
           +updaterev + "&docid=" + docid);
1693
      //System.out.println("sending message: " + u.toString());
1694
      String serverResStr = MetacatReplication.getURLContent(u);
1695
      String openingtag =serverResStr.substring(0, serverResStr.indexOf(">")+1);
1696
      if(openingtag.equals("<lockgranted>"))
1697
      {//the lock was granted go ahead with the insert
1698
        try 
1699
        {
1700
          //System.out.println("In lockgranted");
1701
          MetacatReplication.replLog("lock granted for " + accnum + " from " +
1702
                                      server);
1703
          /*XMLReader parser = initializeParser(conn, action, docid, updaterev,
1704
                               validate, user, groups, pub, serverCode, dtd);*/
1705
          XMLReader parser = initializeParser(conn, action, docid, updaterev,
1706
                                        user, groups, pub, serverCode, 
1707
                                        dtd,ruleBase, needValidation); 
1708
          conn.setAutoCommit(false);
1709
          parser.parse(new InputSource(xml)); 
1710
          conn.commit();
1711
          conn.setAutoCommit(true);
1712
        } 
1713
        catch (Exception e) 
1714
        {
1715
          conn.rollback();
1716
          conn.setAutoCommit(true);
1717
          throw e;
1718
        }
1719
        // run write into access db base one relation table and access object 
1720
        runRelationAndAccessHandler(accnum, user, groups, serverCode);
1721
        
1722
        // Force replication the docid
1723
        ForceReplicationHandler frh = new ForceReplicationHandler
1724
                                                          (accnum, true, null);
1725
        return(accnum);
1726
   
1727
      }
1728

    
1729
      else if(openingtag.equals("<filelocked>"))
1730
      {//the file is currently locked by another user
1731
       //notify our user to wait a few minutes, check out a new copy and try
1732
       //again.
1733
        //System.out.println("file locked");
1734
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1735
                                   server + " reason: file already locked");
1736
        throw new Exception("The file specified is already locked by another " +
1737
                            "user.  Please wait 30 seconds, checkout the " +
1738
                            "newer document, merge your changes and try " +
1739
                            "again.");
1740
      }
1741
      else if(openingtag.equals("<outdatedfile>"))
1742
      {//our file is outdated.  notify our user to check out a new copy of the
1743
       //file and merge his version with the new version.
1744
        //System.out.println("outdated file");
1745
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1746
                                    server + " reason: local file outdated");
1747
        throw new Exception("The file you are trying to update is an outdated" +
1748
                            " version.  Please checkout the newest document, " +
1749
                            "merge your changes and try again.");
1750
      }
1751
    }
1752
    
1753
    if ( action.equals("UPDATE") ) {
1754
      // check for 'write' permission for 'user' to update this document
1755

    
1756
      if ( !hasWritePermission(user, groups, docid) ) {
1757
        throw new Exception("User " + user + 
1758
              " does not have permission to update XML Document #" + accnum);
1759
      }          
1760
    }
1761

    
1762
    try 
1763
    { 
1764
      
1765
      XMLReader parser = initializeParser(conn, action, docid, rev, 
1766
                                          user, groups, pub, serverCode, 
1767
                                          dtd, ruleBase, needValidation);
1768
   
1769
      conn.setAutoCommit(false);
1770
      parser.parse(new InputSource(xml));
1771
      conn.commit();
1772
      conn.setAutoCommit(true);
1773
    } 
1774
    catch (Exception e) 
1775
    {
1776
      conn.rollback();
1777
      conn.setAutoCommit(true);
1778
      throw e;
1779
    }
1780
    
1781
    // run access db base on relation table and access object       
1782
    runRelationAndAccessHandler(accnum, user, groups, serverCode);
1783
    
1784
    // Force replicate out the new document to each server in our server list.
1785
    // Start the thread to replicate this new document out to the other servers
1786
    // true mean it is xml document
1787
    // null is because no metacat notify the force replication.
1788
    ForceReplicationHandler frh = new ForceReplicationHandler
1789
                                                  (accnum, action, true, null);
1790
      
1791
   
1792
    MetaCatUtil.debugMessage("Conn Usage count after writting: "
1793
                                                      +conn.getUsageCount(),50); 
1794
    return(accnum);
1795
  }
1796

    
1797
  /**
1798
   * Write an XML file to the database during replication
1799
   *
1800
   * @param conn the JDBC connection to the database
1801
   * @param xml the xml stream to be loaded into the database
1802
   * @param pub flag for public "read" access on xml document
1803
   * @param dtd the dtd to be uploaded on server's file system
1804
   * @param action the action to be performed (INSERT or UPDATE)
1805
   * @param accnum the docid + rev# to use on INSERT or UPDATE
1806
   * @param user the user that owns the document
1807
   * @param groups the groups to which user belongs
1808
   * @param homeServer the name of server which the document origanlly create
1809
   * @param validate, if the xml document is valid or not
1810
   * @param notifyServer, the server which notify local server the force 
1811
   *                       replication command
1812
   */
1813

    
1814
  public static String writeReplication(DBConnection conn, Reader xml, 
1815
                                        String pub, Reader dtd, String action, 
1816
                                        String accnum, String user,
1817
                                        String[] groups,String homeServer, 
1818
                                        String notifyServer,
1819
                                        String ruleBase, boolean needValidation)
1820
                                        throws Exception
1821
  {
1822
    // Docid without revision
1823
    String docid=MetaCatUtil.getDocIdFromString(accnum);
1824
    // Revision specified by user (int)
1825
    int userSpecifyRev=MetaCatUtil.getVersionFromString(accnum);
1826
    // Revision for this docid in current database
1827
    int revInDataBase=getLatestRevisionNumber(docid);
1828
    // String to store the revision
1829
    String rev = null;
1830
   
1831
    
1832
    //revIndataBase=-1, there is no record in xml_documents table
1833
    //the document is a new one for local server, inert it into table
1834
    //user specified rev should be great than 0
1835
    if (revInDataBase==-1 && userSpecifyRev>0 )
1836
    {
1837
        // rev equals user specified
1838
        rev=(new Integer(userSpecifyRev)).toString();
1839
        // action should be INSERT
1840
        action = "INSERT";
1841
    }
1842
    //rev is greater the last revsion number and revInDataBase isn't -1
1843
    // it is a updated  file
1844
    else if (userSpecifyRev>revInDataBase && revInDataBase>0)
1845
    {
1846
       // rev equals user specified
1847
       rev=(new Integer(userSpecifyRev)).toString();
1848
       // action should be update
1849
       action = "UPDATE";
1850
    }
1851
    // local server has newer version, then notify the remote server
1852
    else if ( userSpecifyRev < revInDataBase && revInDataBase > 0)
1853
    {
1854
      throw new Exception("Local server: "+MetaCatUtil.getOption("server")+
1855
                " has newer revision of doc: "+docid+"."+revInDataBase
1856
                 +". Please notify it.");
1857
    }
1858
    //other situation
1859
    else
1860
    {
1861
        
1862
        throw new Exception("The docid"+docid+"'s revision number couldn't be "
1863
                    +userSpecifyRev);
1864
    }
1865
    // Variable to store homeserver code
1866
    int serverCode=-2;
1867
    
1868
     // If server is not int the xml replication talbe, insert it into
1869
    // xml_replication table
1870
    //serverList.addToServerListIfItIsNot(homeServer);
1871
    insertServerIntoReplicationTable(homeServer);
1872
    // Get server code again
1873
    serverCode = getServerCode(homeServer);
1874
    
1875
    
1876
    MetaCatUtil.debugMessage("Document "+docid+"."+rev+" "+action+ " into local"
1877
                               +" metacat with servercode: "+ serverCode, 10);
1878
                        
1879
  
1880
    // insert into xml_nodes and xml_index table
1881
    try 
1882
    { 
1883
      
1884
      XMLReader parser = initializeParser(conn, action, docid, rev,
1885
                                          user, groups, pub, serverCode, dtd,
1886
                                          ruleBase, needValidation);
1887
      conn.setAutoCommit(false);
1888
      parser.parse(new InputSource(xml));
1889
      conn.commit();
1890
      conn.setAutoCommit(true);
1891
    } 
1892
    catch (Exception e) 
1893
    {
1894
      conn.rollback();
1895
      conn.setAutoCommit(true);
1896
      throw e;
1897
    }
1898
    
1899
    // run write into access db base on relation table and access rule
1900
    try
1901
    {       
1902
      runRelationAndAccessHandler(accnum, user, groups, serverCode);
1903
    }
1904
    catch (Exception ee)
1905
    {
1906
      MetacatReplication.replErrorLog("Failed to " + 
1907
                                       "create access " + 
1908
                                       "rule for package: " + accnum +
1909
                                       " because " +ee.getMessage());
1910
      MetaCatUtil.debugMessage("Failed to  " + 
1911
                                       "create access " + 
1912
                                       "rule for package: "+ accnum +
1913
                                       " because " +ee.getMessage(), 30);
1914
    }
1915
    //Force replication to other server
1916
    ForceReplicationHandler forceReplication = new ForceReplicationHandler
1917
                                  (accnum, action, true, notifyServer);
1918
    
1919

    
1920
    return(accnum);
1921
  }
1922
  
1923
  /* Running write record to xml_relation and xml_access*/
1924
  private static void runRelationAndAccessHandler(String accnumber, 
1925
                                                  String userName, 
1926
                                                  String[]group, int servercode) 
1927
                                                   throws Exception
1928
  {
1929
    DBConnection dbconn = null;
1930
    int serialNumber = -1;
1931
    PreparedStatement pstmt =null;
1932
    String documenttype = getDocTypeFromDBForCurrentDocument(accnumber);
1933
    try
1934
    {
1935
      String packagedoctype = MetaCatUtil.getOption("packagedoctype");
1936
      Vector packagedoctypes = new Vector();
1937
      packagedoctypes = MetaCatUtil.getOptionList(packagedoctype);
1938
      String docIdWithoutRev = MetaCatUtil.getDocIdFromString(accnumber);
1939
      if (documenttype != null && packagedoctypes.contains(documenttype) )
1940
      {
1941
        dbconn=DBConnectionPool.
1942
           getDBConnection("DocumentImpl.runRelationAndAccessHandeler");
1943
        serialNumber=dbconn.getCheckOutSerialNumber();
1944
        dbconn.setAutoCommit(false);
1945
        // from the relations get the access file id for that package
1946
        String aclid = RelationHandler.getAccessFileID(docIdWithoutRev);
1947
        // if there are access file, write ACL for that package
1948
        if ( aclid != null ) 
1949
        {
1950
          runAccessControlList(dbconn, aclid, userName, group, servercode);
1951
        }
1952
        dbconn.commit();
1953
        dbconn.setAutoCommit(true);
1954
      }
1955
        // if it is an access file
1956
      else if ( documenttype != null && MetaCatUtil.getOptionList(
1957
                 MetaCatUtil.getOption("accessdoctype")).contains(documenttype))
1958
      {
1959
        dbconn=DBConnectionPool.
1960
           getDBConnection("DocumentImpl.runRelationAndAccessHandeler");
1961
        serialNumber=dbconn.getCheckOutSerialNumber();
1962
        dbconn.setAutoCommit(false);
1963
        // write ACL for the package
1964
        runAccessControlList(dbconn, docIdWithoutRev, 
1965
                             userName, group, servercode);
1966
        dbconn.commit();
1967
        dbconn.setAutoCommit(true);
1968
        
1969
      }
1970
      
1971
    } 
1972
    catch (Exception e) 
1973
    {
1974
      if( dbconn != null)
1975
      {
1976
        dbconn.rollback();
1977
        dbconn.setAutoCommit(true);
1978
      }
1979
      MetaCatUtil.debugMessage("Error in DocumentImple.runRelationAndAccessHandler " +
1980
                                e.getMessage(), 30);
1981
      throw e;
1982
    }
1983
    finally
1984
    {
1985
      if (dbconn != null)
1986
      {
1987
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1988
      }
1989
    }//
1990
  }
1991
  
1992
  // It runs in xmlIndex thread. It writes ACL for a package.
1993
  private static void runAccessControlList (DBConnection conn, String aclid, 
1994
                                    String users, String[]group, int servercode)
1995
                                                throws Exception
1996
  {
1997
    // read the access file from xml_nodes
1998
    // parse the access file and store the access info into xml_access
1999
    AccessControlList aclobj =
2000
    new AccessControlList(conn, aclid, users, group, servercode);
2001
   
2002
  }
2003
  
2004
  /* Method get document type from db*/
2005
  private static String getDocTypeFromDBForCurrentDocument(String accnumber)
2006
                                                  throws SQLException
2007
  {
2008
    String docoumentType = null;
2009
    String docid = null;
2010
    PreparedStatement pstate = null;
2011
    ResultSet rs = null;
2012
    String sql = "SELECT doctype FROM xml_documents where docid = ?";
2013
    DBConnection dbConnection = null;
2014
    int serialNumber = -1;
2015
    try
2016
    {
2017
      //get rid of revision number
2018
      docid = MetaCatUtil.getDocIdFromString(accnumber);
2019
      dbConnection=DBConnectionPool.
2020
           getDBConnection("DocumentImpl.getDocTypeFromDBForCurrentDoc");
2021
      serialNumber=dbConnection.getCheckOutSerialNumber();
2022
      pstate = dbConnection.prepareStatement(sql);
2023
      //bind variable
2024
      pstate.setString(1, docid);
2025
      //excute query
2026
      pstate.execute();
2027
      //handle resultset
2028
      rs = pstate.getResultSet();
2029
      if (rs.next())
2030
      {
2031
        docoumentType = rs.getString(1);
2032
      }
2033
      rs.close();
2034
      pstate.close();
2035
    }//try
2036
    catch (SQLException e)
2037
    {
2038
      MetaCatUtil.debugMessage("error in DocumentImpl."+
2039
                      "getDocTypeFromDBForCurrentDocument "+e.getMessage(), 30);
2040
      throw e;
2041
    }//catch
2042
    finally
2043
    {
2044
      pstate.close();
2045
      DBConnectionPool.returnDBConnection(dbConnection, serialNumber);
2046
    }//
2047
    MetaCatUtil.debugMessage("The current doctype from db is: "+
2048
                              docoumentType, 35);
2049
    return docoumentType;
2050
  }
2051
  /**
2052
   * Delete an XML file from the database (actually, just make it a revision
2053
   * in the xml_revisions table)
2054
   *
2055
   * @param docid the ID of the document to be deleted from the database
2056
   */
2057
  public static void delete(String accnum,
2058
                                 String user, String[] groups )
2059
                throws Exception 
2060
  {
2061
    // OLD
2062
    //DocumentIdentifier id = new DocumentIdentifier(accnum);
2063
    //String docid = id.getIdentifier();
2064
    //String rev = id.getRev();
2065
    
2066
    // OLD
2067
    // Determine if the docid,rev are OK for DELETE
2068
    //AccessionNumber ac = new AccessionNumber(conn);
2069
    //docid = ac.generate(docid, rev, "DELETE");
2070
    DBConnection conn = null;
2071
    int serialNumber = -1;
2072
    PreparedStatement pstmt =null;
2073
    try
2074
    {
2075
      //check out DBConnection
2076
      conn=DBConnectionPool.
2077
                    getDBConnection("DocumentImpl.delete");
2078
      serialNumber=conn.getCheckOutSerialNumber();
2079

    
2080
      // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
2081
      AccessionNumber ac = new AccessionNumber(accnum, "DELETE");
2082
      String docid = ac.getDocid();
2083
      String rev = ac.getRev();
2084
    
2085
      MetaCatUtil.debugMessage("Start deleting doc "+docid+ "...", 20);
2086
    // check for 'write' permission for 'user' to delete this document
2087
      if ( !hasWritePermission(user, groups, docid) ) {
2088
        throw new Exception("User " + user + 
2089
              " does not have permission to delete XML Document #" + accnum);
2090
      }
2091

    
2092
      conn.setAutoCommit(false);
2093
      // Copy the record to the xml_revisions table
2094
      DocumentImpl.archiveDocRevision(conn, docid, user );
2095

    
2096
      // Now delete it from the xml_index table
2097
      pstmt = conn.prepareStatement("DELETE FROM xml_index WHERE docid = ?");
2098
      pstmt.setString(1,docid);
2099
      pstmt.execute();
2100
      pstmt.close();
2101
      conn.increaseUsageCount(1);
2102
      
2103
      //stmt.execute("DELETE FROM xml_access WHERE docid = '" + docid + "'");
2104
      // Now delete it from xml_access table
2105
      pstmt = conn.
2106
              prepareStatement("DELETE FROM xml_access WHERE accessfileid = ?");
2107
      pstmt.setString(1, docid);
2108
      pstmt.execute();
2109
      pstmt.close();
2110
      conn.increaseUsageCount(1);
2111
      
2112
      // Delete it from relation table
2113
      pstmt = conn.
2114
               prepareStatement("DELETE FROM xml_relation WHERE docid = ?");
2115
      //increase usage count
2116
      conn.increaseUsageCount(1);
2117
      pstmt.setString(1, docid);
2118
      pstmt.execute();
2119
      pstmt.close();
2120
      
2121
      // Delete it from xml_accesssubtree table
2122
      pstmt = conn.
2123
               prepareStatement("DELETE FROM xml_accesssubtree WHERE docid = ?");
2124
      //increase usage count
2125
      conn.increaseUsageCount(1);
2126
      pstmt.setString(1, docid);
2127
      pstmt.execute();
2128
      pstmt.close();
2129
      
2130
      // Delete it from xml_doucments table
2131
      pstmt =conn.prepareStatement("DELETE FROM xml_documents WHERE docid = ?");
2132
      pstmt.setString(1, docid);
2133
      pstmt.execute();
2134
      pstmt.close();
2135
      //Usaga count increase 1
2136
      conn.increaseUsageCount(1);
2137
      
2138
      conn.commit();
2139
      conn.setAutoCommit(true);
2140
    }//try
2141
    catch (Exception e)
2142
    {
2143
      MetaCatUtil.debugMessage("error in DocumentImpl.delete: " + 
2144
                                e.getMessage(), 30);
2145
      throw e;
2146
    }
2147
    finally
2148
    {
2149
      
2150
      try
2151
      {
2152
        // close preparedStatement
2153
        pstmt.close();
2154
      }//try
2155
      finally
2156
      {
2157
        //check in DBonnection
2158
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2159
      }//finally
2160
    }//finally
2161
    //IF this is a package document:
2162
    //delete all of the relations that this document created.
2163
    //if the deleted document is a package document its relations should 
2164
    //no longer be active if it has been deleted from the system.
2165
    
2166
  }
2167

    
2168
  /** 
2169
    * Check for "WRITE" permission on @docid for @user and/or @groups 
2170
    * from DB connection 
2171
    */
2172
  private static boolean hasWritePermission (String user,
2173
                                  String[] groups, String docid ) 
2174
                  throws SQLException, Exception
2175
  {
2176
    // Check for WRITE permission on @docid for @user and/or @groups
2177
    PermissionController controller = new PermissionController(docid);
2178
    return controller.hasPermission(user,groups,
2179
                                    AccessControlInterface.WRITESTRING);
2180
  }
2181

    
2182
  /** 
2183
    * Check for "READ" permission base on docid, user and group
2184
    *@docid, the document
2185
    *@user, user name
2186
    *@group, user's group
2187
    * 
2188
    */
2189
  public static boolean hasReadPermission (String user,
2190
                                  String[] groups, String docId ) 
2191
                  throws SQLException, Exception
2192
  {
2193
    // Check for READ permission on @docid for @user and/or @groups
2194
    PermissionController controller = 
2195
                        new PermissionController(docId);
2196
    return controller.hasPermission(user,groups,
2197
                                            AccessControlInterface.READSTRING);
2198
  }  
2199

    
2200
  
2201
   /**
2202
   * Set up the parser handlers for writing the document to the database
2203
   */
2204
  private static XMLReader initializeParser(DBConnection dbconn, String action,
2205
                                            String docid, String rev, 
2206
                                            String user, 
2207
                                            String[] groups, String pub, 
2208
                                            int serverCode, Reader dtd,
2209
                                            String ruleBase, 
2210
                                            boolean needValidation) 
2211
                                            throws Exception 
2212
  {
2213
    XMLReader parser = null;
2214
    try 
2215
    {
2216
      // handler
2217
      ContentHandler chandler;
2218
      EntityResolver eresolver;
2219
      DTDHandler dtdhandler;  
2220
      // Get an instance of the parser
2221
      String parserName = MetaCatUtil.getOption("saxparser");
2222
      parser = XMLReaderFactory.createXMLReader(parserName);
2223
      if (ruleBase != null && ruleBase.equals(EML2))
2224
      {
2225
        MetaCatUtil.debugMessage("eml 2 parser", 20);
2226
        chandler = new EmlSAXHandler(dbconn, action, 
2227
                                    docid, rev, user, groups, pub, serverCode);
2228
        parser.setContentHandler((ContentHandler)chandler);
2229
        parser.setErrorHandler((ErrorHandler)chandler);
2230
        parser.setProperty(DECLARATIONHANDLERPROPERTY, chandler);
2231
        parser.setProperty(LEXICALPROPERTY, chandler);
2232
        // turn on schema validation feature
2233
        parser.setFeature(VALIDATIONFEATURE, true);
2234
        parser.setFeature(NAMESPACEFEATURE, true);
2235
        //parser.setFeature(NAMESPACEPREFIXESFEATURE, true);
2236
        parser.setFeature(SCHEMAVALIDATIONFEATURE, true);
2237
        // From DB to find the register external schema location
2238
        String externalSchemaLocation = null;
2239
        SchemaLocationResolver resolver = new SchemaLocationResolver();
2240
        externalSchemaLocation = resolver.getNameSpaceAndLocationString();
2241
        // Set external schemalocation.
2242
        if (externalSchemaLocation != null && 
2243
            !(externalSchemaLocation.trim()).equals(""))
2244
        {
2245
            parser.setProperty(EXTERNALSCHEMALOCATIONPROPERTY,
2246
                             externalSchemaLocation);
2247
        }
2248
      }
2249
      else
2250
      {
2251
        //create a DBSAXHandler object which has the revision specification
2252
        chandler = new DBSAXHandler(dbconn, action, 
2253
                                    docid, rev, user, groups, pub, serverCode);
2254
        parser.setContentHandler((ContentHandler)chandler);
2255
        parser.setErrorHandler((ErrorHandler)chandler);
2256
        parser.setProperty(DECLARATIONHANDLERPROPERTY, chandler);
2257
        parser.setProperty(LEXICALPROPERTY, chandler);
2258
      
2259
        if (ruleBase != null && ruleBase.equals(SCHEMA) && needValidation)
2260
        {
2261
          MetaCatUtil.debugMessage("General schema parser", 20);
2262
          // turn on schema validation feature
2263
          parser.setFeature(VALIDATIONFEATURE, true);
2264
          parser.setFeature(NAMESPACEFEATURE, true);
2265
          //parser.setFeature(NAMESPACEPREFIXESFEATURE, true);
2266
          parser.setFeature(SCHEMAVALIDATIONFEATURE, true);
2267
          // From DB to find the register external schema location
2268
          String externalSchemaLocation = null;
2269
          SchemaLocationResolver resolver = new SchemaLocationResolver();
2270
          externalSchemaLocation = resolver.getNameSpaceAndLocationString();
2271
          // Set external schemalocation.
2272
          if (externalSchemaLocation != null && 
2273
            !(externalSchemaLocation.trim()).equals(""))
2274
          {
2275
            parser.setProperty(EXTERNALSCHEMALOCATIONPROPERTY,
2276
                             externalSchemaLocation);
2277
          }
2278
     
2279
        }
2280
        else if (ruleBase != null && ruleBase.equals(DTD) && needValidation)
2281
        {
2282
          MetaCatUtil.debugMessage("dtd parser", 20);
2283
          // turn on dtd validaton feature
2284
          parser.setFeature(VALIDATIONFEATURE, true);
2285
          eresolver= new DBEntityResolver(dbconn, (DBSAXHandler)chandler, dtd);
2286
          dtdhandler = new DBDTDHandler(dbconn);
2287
          parser.setEntityResolver((EntityResolver)eresolver);
2288
          parser.setDTDHandler((DTDHandler)dtdhandler);
2289
        }
2290
        else
2291
        {
2292
          MetaCatUtil.debugMessage("other parser", 20);
2293
          // non validation
2294
          parser.setFeature(VALIDATIONFEATURE, false);
2295
          eresolver= new DBEntityResolver(dbconn, (DBSAXHandler)chandler, dtd);
2296
          dtdhandler = new DBDTDHandler(dbconn);
2297
          parser.setEntityResolver((EntityResolver)eresolver);
2298
          parser.setDTDHandler((DTDHandler)dtdhandler);
2299
        }
2300
      }//else
2301
    } 
2302
    catch (Exception e) 
2303
    {
2304
      throw e;
2305
    }
2306
    return parser;
2307
  }
2308

    
2309
  
2310
  /**
2311
   * Set up the parser handlers for writing the document to the database
2312
   */
2313
  /*private static XMLReader initializeParser(DBConnection dbconn, String action,
2314
                               String docid, String rev, boolean validate, 
2315
                                   String user, String[] groups, String pub, 
2316
                                   int serverCode, Reader dtd) 
2317
                           throws Exception 
2318
  {
2319
    XMLReader parser = null;
2320
    //DBConnection conn = null;
2321
    //int serialNumber = -1;
2322
    //
2323
    // Set up the SAX document handlers for parsing
2324
    //
2325
    try {
2326
       //check out DBConnection
2327
     
2328
      //create a DBSAXHandler object which has the revision specification
2329
      ContentHandler chandler = new DBSAXHandler(dbconn, action, 
2330
                                    docid, rev, user, groups, pub, serverCode);
2331
      EntityResolver eresolver= new DBEntityResolver(dbconn,
2332
                                                 (DBSAXHandler)chandler, dtd);
2333
      DTDHandler dtdhandler   = new DBDTDHandler(dbconn);
2334

    
2335
      // Get an instance of the parser
2336
      String parserName = MetaCatUtil.getOption("saxparser");
2337
      parser = XMLReaderFactory.createXMLReader(parserName);
2338

    
2339
      // Turn on validation
2340
      parser.setFeature("http://xml.org/sax/features/validation", validate);
2341
      // Turn off Including all external parameter entities
2342
      // (the external DTD subset also)
2343
      // Doesn't work well, probably the feature name is not correct
2344
      // parser.setFeature(
2345
      //  "http://xml.org/sax/features/external-parameter-entities", false);
2346
      
2347
      // Set Handlers in the parser
2348
      parser.setProperty("http://xml.org/sax/properties/declaration-handler",
2349
                         chandler);
2350
      parser.setProperty("http://xml.org/sax/properties/lexical-handler",
2351
                         chandler);
2352
      parser.setContentHandler((ContentHandler)chandler);
2353
      parser.setEntityResolver((EntityResolver)eresolver);
2354
      parser.setDTDHandler((DTDHandler)dtdhandler);
2355
      parser.setErrorHandler((ErrorHandler)chandler);
2356

    
2357
    } catch (Exception e) {
2358
      throw e;
2359
    }
2360
    //finally
2361
    //{
2362
      //DBConnectionPool.returnDBConnection(conn, serialNumber);
2363
    //}
2364

    
2365
    return parser;
2366
  }*/
2367

    
2368
  /**
2369
   * Save a document entry in the xml_revisions table 
2370
   * Connection use as a paramter is in order to rollback feature
2371
   */
2372
  private static void archiveDocRevision(DBConnection dbconn, String docid, 
2373
                                                    String user) 
2374
 {
2375
    String sysdate = dbAdapter.getDateTimeFunction();
2376
    //DBConnection conn = null;
2377
    //int serialNumber = -1;
2378
    PreparedStatement pstmt = null;
2379
    
2380
    // create a record in xml_revisions table 
2381
    // for that document as selected from xml_documents
2382
   
2383
   try
2384
   {
2385
     //check out DBConnection
2386
     /*conn=DBConnectionPool.
2387
                    getDBConnection("DocumentImpl.archiveDocRevision");
2388
     serialNumber=conn.getCheckOutSerialNumber();*/
2389
     pstmt = dbconn.prepareStatement(
2390
      "INSERT INTO xml_revisions " +
2391
        "(docid, rootnodeid, docname, doctype, " +
2392
        "user_owner, user_updated, date_created, date_updated, " +
2393
        "server_location, rev, public_access, catalog_id) " +
2394
      "SELECT ?, rootnodeid, docname, doctype, " + 
2395
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
2396
        "server_location, rev, public_access, catalog_id " +
2397
      "FROM xml_documents " +
2398
      "WHERE docid = ?");
2399
      // Increase dbconnection usage count
2400
      dbconn.increaseUsageCount(1);
2401
      // Bind the values to the query and execute it
2402
      pstmt.setString(1, docid);
2403
      pstmt.setString(2, user);
2404
      pstmt.setString(3, docid);
2405
      pstmt.execute();
2406
      pstmt.close();
2407
   }//try
2408
   catch (SQLException e)
2409
   {
2410
     MetaCatUtil.debugMessage("Error in DocumentImpl.archiveDocRevision : "+
2411
                                e.getMessage(), 30);
2412
   }//catch
2413
   finally
2414
   {
2415
     try
2416
     {
2417
       pstmt.close();
2418
     }//try
2419
     catch (SQLException ee)
2420
     {
2421
       MetaCatUtil.debugMessage("Error in DocumnetImpl.archiveDocRevision: "+
2422
                                  ee.getMessage(), 50);
2423
     }//catch
2424
     //finally
2425
     //{
2426
       
2427
       //check in DBConnection
2428
       //DBConnectionPool.returnDBConnection(conn, serialNumber);
2429
     //}//finally
2430
   }//finnally
2431
                                  
2432

    
2433
  }//achiveDocRevision
2434
  
2435
  /** Save a document entry in the xml_revisions table */
2436
  private static void archiveDocRevision(String docid, String user) 
2437
 {
2438
    String sysdate = dbAdapter.getDateTimeFunction();
2439
    DBConnection conn = null;
2440
    int serialNumber = -1;
2441
    PreparedStatement pstmt = null;
2442
    
2443
    // create a record in xml_revisions table 
2444
    // for that document as selected from xml_documents
2445
   
2446
   try
2447
   {
2448
     //check out DBConnection
2449
     conn=DBConnectionPool.
2450
                    getDBConnection("DocumentImpl.archiveDocRevision");
2451
     serialNumber=conn.getCheckOutSerialNumber();
2452
     pstmt = conn.prepareStatement(
2453
      "INSERT INTO xml_revisions " +
2454
        "(docid, rootnodeid, docname, doctype, " +
2455
        "user_owner, user_updated, date_created, date_updated, " +
2456
        "server_location, rev, public_access, catalog_id) " +
2457
      "SELECT ?, rootnodeid, docname, doctype, " + 
2458
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
2459
        "server_location, rev, public_access, catalog_id " +
2460
      "FROM xml_documents " +
2461
      "WHERE docid = ?");
2462
      // Bind the values to the query and execute it
2463
      pstmt.setString(1, docid);
2464
      pstmt.setString(2, user);
2465
      pstmt.setString(3, docid);
2466
      pstmt.execute();
2467
      pstmt.close();
2468
   }//try
2469
   catch (SQLException e)
2470
   {
2471
     MetaCatUtil.debugMessage("Error in DocumentImpl.archiveDocRevision : "+
2472
                                e.getMessage(), 30);
2473
   }//catch
2474
   finally
2475
   {
2476
     try
2477
     {
2478
       pstmt.close();
2479
     }//try
2480
     catch (SQLException ee)
2481
     {
2482
       MetaCatUtil.debugMessage("Error in DocumnetImpl.archiveDocRevision: "+
2483
                                  ee.getMessage(), 50);
2484
     }//catch
2485
     finally
2486
     {
2487
       //check in DBConnection
2488
       DBConnectionPool.returnDBConnection(conn, serialNumber);
2489
     }//finally
2490
   }//finnally
2491
                                  
2492

    
2493
  }//achiveDocRevision
2494
  
2495
  /**
2496
    * delete a entry in xml_table for given docid
2497
    * @param docId, the id of the document need to be delete
2498
    */
2499
  private static void deleteXMLDocuments(String docId) 
2500
                                         throws SQLException 
2501
  {
2502
    DBConnection conn = null;
2503
    int serialNumber = -1;
2504
    PreparedStatement pStmt = null;
2505
    try
2506
    {
2507
      //check out DBConnection
2508
      conn=DBConnectionPool.
2509
                    getDBConnection("DocumentImpl.deleteXMLDocuments");
2510
      serialNumber=conn.getCheckOutSerialNumber();
2511
      //delete a record 
2512
      pStmt = 
2513
             conn.prepareStatement("DELETE FROM xml_documents WHERE docid = '" 
2514
                                              + docId + "'");
2515
    pStmt.execute();
2516
    }//try
2517
    finally
2518
    {
2519
      try
2520
      {
2521
        pStmt.close();
2522
      }//try
2523
      catch (SQLException e)
2524
      {
2525
        MetaCatUtil.debugMessage("error in DocumentImpl.deleteXMLDocuments: "+
2526
                                  e.getMessage(), 50);
2527
      }//catch
2528
      finally
2529
      {
2530
        //return back DBconnection
2531
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2532
      }//finally
2533
    }//finally
2534
      
2535

    
2536
  }//deleteXMLDocuments
2537
  
2538
  /**
2539
    * Get last revision number from database for a docid
2540
    * If couldn't find an entry,  -1 will return
2541
    * The return value is integer because we want compare it to there new one
2542
    * @param docid <sitecode>.<uniqueid> part of Accession Number
2543
    */
2544
  public static int getLatestRevisionNumber(String docId)
2545
                                      throws SQLException
2546
  {
2547
    int rev = 1;
2548
    PreparedStatement pStmt = null;
2549
    DBConnection dbConn = null;
2550
    int serialNumber = -1;
2551
    // get rid of rev
2552
    docId = MetaCatUtil.getDocIdFromString(docId);
2553
    try
2554
    {
2555
      //check out DBConnection
2556
      dbConn=DBConnectionPool.
2557
                    getDBConnection("DocumentImpl.getLatestRevisionNumber");
2558
      serialNumber=dbConn.getCheckOutSerialNumber();
2559
     
2560
      pStmt = dbConn.prepareStatement
2561
              ("SELECT rev FROM xml_documents WHERE docid='" + docId + "'");
2562
      pStmt.execute();
2563

    
2564
      ResultSet rs = pStmt.getResultSet();
2565
      boolean hasRow = rs.next();
2566
      if (hasRow)
2567
      {
2568
        rev = rs.getInt(1);
2569
        pStmt.close();
2570
      }
2571
      else
2572
      {
2573
        rev=-1;
2574
        pStmt.close();
2575
      }
2576
    }//try
2577
    finally
2578
    {
2579
      try
2580
      {
2581
        pStmt.close();
2582
      }
2583
      catch (Exception ee)
2584
      {
2585
        MetaCatUtil.debugMessage("Error in DocumentImpl."+
2586
                        "getLatestRevisionNumber: "+ee.getMessage(), 50);
2587
      }
2588
      finally
2589
      {
2590
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2591
      }
2592
    }//finally  
2593
      
2594
    return rev;
2595
  }//getLatestRevisionNumber
2596
  
2597
  /**
2598
   * Get server location form database for a accNum
2599
   * 
2600
   * @param accum <sitecode>.<uniqueid>.<rev>
2601
   */
2602
  private static int getServerLocationNumber(String accNum)
2603
                                            throws SQLException
2604
  {
2605
    //get rid of revNum part
2606
    String docId=MetaCatUtil.getDocIdFromString(accNum);
2607
    PreparedStatement pStmt = null;
2608
    int serverLocation = 1;
2609
    DBConnection conn = null;
2610
    int serialNumber = -1;
2611
    
2612
    try
2613
    {
2614
      //check out DBConnection
2615
      conn=DBConnectionPool.
2616
                    getDBConnection("DocumentImpl.getServerLocationNumber");
2617
      serialNumber=conn.getCheckOutSerialNumber();
2618
     
2619
      pStmt = conn.prepareStatement
2620
      ("SELECT server_location FROM xml_documents WHERE docid='" + docId + "'");
2621
      pStmt.execute();
2622

    
2623
      ResultSet rs = pStmt.getResultSet();
2624
      boolean hasRow = rs.next();
2625
      //if there is entry in xml_documents, get the serverlocation
2626
      if (hasRow)
2627
      {
2628
        serverLocation = rs.getInt(1);
2629
        pStmt.close();
2630
      }
2631
      else
2632
      {
2633
        //if htere is no entry in xml_documents, we consider it is new document
2634
        //the server location is local host and value is 1
2635
        serverLocation=1;
2636
        pStmt.close();
2637
      }
2638
    }//try
2639
    finally
2640
    {
2641
      try
2642
      {
2643
        pStmt.close();
2644
      }//try
2645
      catch (Exception ee)
2646
      {
2647
        MetaCatUtil.debugMessage("Error in DocumentImpl.getServerLocationNu(): "
2648
                                    +ee.getMessage(), 50);
2649
      }//catch
2650
      finally
2651
      {
2652
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2653
      }//finally
2654
    }//finally
2655
      
2656
    return serverLocation;
2657
  }
2658
  
2659
  /**
2660
   * Given a server name, return its servercode in xml_replication table.
2661
   * If no server is found, -1 will return
2662
   * @param serverName, 
2663
   */
2664
  private static int getServerCode(String serverName) 
2665
  {
2666
    PreparedStatement pStmt=null;
2667
    int serverLocation=-2;
2668
    DBConnection dbConn = null;
2669
    int serialNumber = -1;
2670
    //MetaCatUtil util = new MetaCatUtil();
2671
    
2672
    
2673
    //we should consider about local host too
2674
    if (serverName.equals(MetaCatUtil.getLocalReplicationServerName()))
2675
    { 
2676
      serverLocation=1;
2677
      return serverLocation;
2678
    }
2679
    
2680
   
2681
    try
2682
    {
2683
      //check xml_replication table
2684
      //dbConn=util.openDBConnection();
2685
      //check out DBConnection
2686
      dbConn=DBConnectionPool.getDBConnection("DocumentImpl.getServerCode");
2687
      serialNumber=dbConn.getCheckOutSerialNumber();
2688
      pStmt = dbConn.prepareStatement
2689
      ("SELECT serverid FROM xml_replication WHERE server='" + serverName +"'");
2690
      pStmt.execute();
2691

    
2692
      ResultSet rs = pStmt.getResultSet();
2693
      boolean hasRow = rs.next();
2694
      //if there is entry in xml_replication, get the serverid
2695
      if (hasRow)
2696
      {
2697
        serverLocation = rs.getInt(1);
2698
        pStmt.close();
2699
      }
2700
      else
2701
      {
2702
        // if htere is no entry in xml_replication, -1 will return
2703
        serverLocation=-1;
2704
        pStmt.close();
2705
      }
2706
    }
2707
    catch (Exception e)
2708
    {
2709
      MetaCatUtil.debugMessage("Error in DocumentImpl.getServerCode(): "
2710
                                    +e.getMessage(), 30);
2711
    }
2712
    finally
2713
    {
2714
      try
2715
      {
2716
        pStmt.close();
2717
      }
2718
      catch (Exception ee)
2719
      {
2720
        MetaCatUtil.debugMessage("Error in DocumentImpl.getServerCode(): "
2721
                                    +ee.getMessage(), 50);
2722
      }
2723
      finally
2724
      {
2725
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2726
      }
2727
    }
2728
                 
2729
      
2730
    return serverLocation;
2731
  }
2732
  
2733
  /**
2734
   * Insert a server into xml_replcation table
2735
   * @param server, the name of server 
2736
   */
2737
  private static synchronized void 
2738
                                insertServerIntoReplicationTable(String server)
2739
  {
2740
    PreparedStatement pStmt=null;
2741
    DBConnection dbConn = null;
2742
    int serialNumber = -1;
2743
    
2744
    // Initial value for the server
2745
    int replicate = 0;
2746
    int dataReplicate = 0;
2747
    int hub = 0;
2748
   
2749
    try
2750
    {
2751
       // Get DBConnection
2752
       dbConn=DBConnectionPool.
2753
                getDBConnection("DocumentImpl.insertServIntoReplicationTable");
2754
       serialNumber=dbConn.getCheckOutSerialNumber();
2755
      
2756
      // Compare the server to dabase
2757
      pStmt = dbConn.prepareStatement
2758
      ("SELECT serverid FROM xml_replication WHERE server='" + server +"'");
2759
      pStmt.execute();
2760
      ResultSet rs = pStmt.getResultSet();
2761
      boolean hasRow = rs.next();
2762
      // Close preparedstatement and result set
2763
      pStmt.close();
2764
      rs.close();
2765
      
2766
      // If the server is not in the table, and server is not local host,
2767
      // insert it
2768
      if ( !hasRow 
2769
         && !server.equals(MetaCatUtil.getLocalReplicationServerName()))
2770
      {
2771
        // Set auto commit false
2772
        dbConn.setAutoCommit(false);
2773
        /*pStmt = dbConn.prepareStatement("INSERT INTO xml_replication " +
2774
                      "(server, last_checked, replicate, datareplicate, hub) " +
2775
                       "VALUES ('" + server + "', to_date(" +
2776
                       "'01/01/00', 'MM/DD/YY'), '" +
2777
                       replicate +"', '"+dataReplicate+"','"+ hub + "')");*/
2778
        pStmt = dbConn.prepareStatement("INSERT INTO xml_replication " +
2779
                      "(server, last_checked, replicate, datareplicate, hub) " +
2780
                       "VALUES ('" + server + "', " + 
2781
                       dbAdapter.toDate("01/01/80", "MM/DD/YY") + ", '" +
2782
                       replicate +"', '"+dataReplicate+"','"+ hub + "')");
2783
        
2784
                              
2785
        pStmt.execute();
2786
        dbConn.commit();
2787
        // Increase usage number
2788
        dbConn.increaseUsageCount(1);
2789
        pStmt.close();
2790
        
2791
      }
2792
    }//try
2793
    catch (Exception e)
2794
    {
2795
      MetaCatUtil.debugMessage("Error in DocumentImpl.insertServerIntoRepli(): "
2796
                                    +e.getMessage(), 30);
2797
    }//catch
2798
    finally
2799
    {
2800
     
2801
      try
2802
      {
2803
        // Set auto commit true
2804
        dbConn.setAutoCommit(true);
2805
        pStmt.close();
2806
        
2807
      }//try
2808
      catch (Exception ee)
2809
      {
2810
        MetaCatUtil.debugMessage("Error in DocumentImpl.insetServerIntoRepl(): "
2811
                                    +ee.getMessage(), 50);
2812
      }//catch
2813
      finally
2814
      {
2815
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2816
      }
2817
    
2818
    }//finally
2819

    
2820
  }
2821
  
2822
  
2823
  /**
2824
   * the main routine used to test the DBWriter utility.
2825
   * <p>
2826
   * Usage: java DocumentImpl <-f filename -a action -d docid>
2827
   *
2828
   * @param filename the filename to be loaded into the database
2829
   * @param action the action to perform (READ, INSERT, UPDATE, DELETE)
2830
   * @param docid the id of the document to process
2831
   */
2832
  static public void main(String[] args) {
2833
    DBConnection dbconn = null;
2834
    int serialNumber = -1;
2835
    try {
2836
      String filename    = null;
2837
      String dtdfilename = null;
2838
      String action      = null;
2839
      String docid       = null;
2840
      boolean showRuntime = false;
2841
      boolean useOldReadAlgorithm = false;
2842

    
2843
      // Parse the command line arguments
2844
      for ( int i=0 ; i < args.length; ++i ) {
2845
        if ( args[i].equals( "-f" ) ) {
2846
          filename =  args[++i];
2847
        } else if ( args[i].equals( "-r" ) ) {
2848
          dtdfilename =  args[++i];
2849
        } else if ( args[i].equals( "-a" ) ) {
2850
          action =  args[++i];
2851
        } else if ( args[i].equals( "-d" ) ) {
2852
          docid =  args[++i];
2853
        } else if ( args[i].equals( "-t" ) ) {
2854
          showRuntime = true;
2855
        } else if ( args[i].equals( "-old" ) ) {
2856
          useOldReadAlgorithm = true;
2857
        } else {
2858
          System.err.println
2859
            ( "   args[" +i+ "] '" +args[i]+ "' ignored." );
2860
        }
2861
      }
2862
      
2863
      // Check if the required arguments are provided
2864
      boolean argsAreValid = false;
2865
      if (action != null) {
2866
        if (action.equals("INSERT")) {
2867
          if (filename != null) {
2868
            argsAreValid = true;
2869
          } 
2870
        } else if (action.equals("UPDATE")) {
2871
          if ((filename != null) && (docid != null)) {
2872
            argsAreValid = true;
2873
          } 
2874
        } else if (action.equals("DELETE")) {
2875
          if (docid != null) {
2876
            argsAreValid = true;
2877
          } 
2878
        } else if (action.equals("READ")) {
2879
          if (docid != null) {
2880
            argsAreValid = true;
2881
          } 
2882
        } 
2883
      } 
2884

    
2885
      // Print usage message if the arguments are not valid
2886
      if (!argsAreValid) {
2887
        System.err.println("Wrong number of arguments!!!");
2888
        System.err.println(
2889
          "USAGE: java DocumentImpl [-t] <-a INSERT> [-d docid] <-f filename> "+
2890
          "[-r dtdfilename]");
2891
        System.err.println(
2892
          "   OR: java DocumentImpl [-t] <-a UPDATE -d docid -f filename> " +
2893
          "[-r dtdfilename]");
2894
        System.err.println(
2895
          "   OR: java DocumentImpl [-t] <-a DELETE -d docid>");
2896
        System.err.println(
2897
          "   OR: java DocumentImpl [-t] [-old] <-a READ -d docid>");
2898
        return;
2899
      }
2900
      
2901
      // Time the request if asked for
2902
      double startTime = System.currentTimeMillis();
2903
      
2904
      // Open a connection to the database
2905
      MetaCatUtil util = new MetaCatUtil();
2906
     
2907
      dbconn=DBConnectionPool.getDBConnection("DocumentImpl.main");
2908
      serialNumber=dbconn.getCheckOutSerialNumber();
2909

    
2910
      double connTime = System.currentTimeMillis();
2911
      // Execute the action requested (READ, INSERT, UPDATE, DELETE)
2912
      if (action.equals("READ")) {
2913
          DocumentImpl xmldoc = new DocumentImpl(docid );
2914
          if (useOldReadAlgorithm) {
2915
            System.out.println(xmldoc.readUsingSlowAlgorithm());
2916
          } else {
2917
            xmldoc.toXml(new PrintWriter(System.out), null, null, true);
2918
          }
2919
      } else if (action.equals("DELETE")) {
2920
        DocumentImpl.delete(docid, null, null);
2921
        System.out.println("Document deleted: " + docid);
2922
      } else {
2923
        /*String newdocid = DocumentImpl.write(dbconn, filename, null,
2924
                                             dtdfilename, action, docid,
2925
                                             null, null);
2926
        if ((docid != null) && (!docid.equals(newdocid))) {
2927
          if (action.equals("INSERT")) {
2928
            System.out.println("New document ID generated!!! ");
2929
          } else if (action.equals("UPDATE")) {
2930
            System.out.println("ERROR: Couldn't update document!!! ");
2931
          }
2932
        } else if ((docid == null) && (action.equals("UPDATE"))) {
2933
          System.out.println("ERROR: Couldn't update document!!! ");
2934
        }
2935
        System.out.println("Document processing finished for: " + filename
2936
              + " (" + newdocid + ")");*/
2937
      }
2938

    
2939
      double stopTime = System.currentTimeMillis();
2940
      double dbOpenTime = (connTime - startTime)/1000;
2941
      double insertTime = (stopTime - connTime)/1000;
2942
      double executionTime = (stopTime - startTime)/1000;
2943
      if (showRuntime) {
2944
        System.out.println("\n\nTotal Execution time was: " + 
2945
                           executionTime + " seconds.");
2946
        System.out.println("Time to open DB connection was: " + dbOpenTime + 
2947
                           " seconds.");
2948
        System.out.println("Time to insert document was: " + insertTime +
2949
                           " seconds.");
2950
      }
2951
      dbconn.close();
2952
    } catch (McdbException me) {
2953
      me.toXml(new PrintWriter(System.err));
2954
    } catch (AccessionNumberException ane) {
2955
      System.out.println(ane.getMessage());
2956
    } catch (Exception e) {
2957
      System.err.println("EXCEPTION HANDLING REQUIRED");
2958
      System.err.println(e.getMessage());
2959
      e.printStackTrace(System.err);
2960
    }
2961
    finally
2962
    {
2963
      // Return db connection
2964
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
2965
    }
2966
  }
2967
}
(31-31/57)