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-08-10 14:26:20 -0700 (Sun, 10 Aug 2003) $'
11
 * '$Revision: 1781 $'
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
          Reader reader = 
1018
                          EmlSAXHandler.readInlineDataFromFileSystem(fileName);
1019
          char [] characterArray = new char [4*1024];
1020
          try
1021
          {
1022
            int length = reader.read(characterArray);
1023
            while ( length != -1)
1024
            {
1025
              out.print(new String(characterArray, 0, length));
1026
              out.flush();
1027
              length = reader.read(characterArray);
1028
            }
1029
            reader.close();
1030
          }
1031
          catch (IOException e)
1032
          {
1033
            throw new McdbException(e.getMessage());
1034
          }
1035
        }
1036
        
1037
        // reset proccess inline data false
1038
        prcocessInlineData =false;
1039
        previousNodeWasElement = false;
1040

    
1041
      // Handle the COMMENT nodes
1042
      } else if (currentNode.nodetype.equals("COMMENT")) {
1043
        if (previousNodeWasElement) {
1044
          out.print(">");
1045
        }
1046
        out.print("<!--" + currentNode.nodedata + "-->");
1047
        previousNodeWasElement = false;
1048

    
1049
      // Handle the PI nodes
1050
      } else if (currentNode.nodetype.equals("PI")) {
1051
        if (previousNodeWasElement) {
1052
          out.print(">");
1053
        }
1054
        out.print("<?" + currentNode.nodename + " " +
1055
                        currentNode.nodedata + "?>");
1056
        previousNodeWasElement = false;
1057

    
1058
      // Handle any other node type (do nothing)
1059
      } else {
1060
        // Any other types of nodes are not handled.
1061
        // Probably should throw an exception here to indicate this
1062
      }
1063
      out.flush();
1064
    }
1065
    
1066
    // Print the final end tag for the root element
1067
    while(!openElements.empty())
1068
    {
1069
      NodeRecord currentElement = (NodeRecord)openElements.pop();
1070
      util.debugMessage("\n POPPED: " + currentElement.nodename, 50);
1071
      if ( currentElement.nodeprefix != null ) {
1072
        out.print("</" + currentElement.nodeprefix + ":" + 
1073
                  currentElement.nodename + ">" );
1074
      } else {
1075
        out.print("</" + currentElement.nodename + ">" );
1076
      }
1077
    }
1078
    out.flush();
1079
  }
1080
  
1081

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

    
1140
  private void getDocumentInfo(String docid) throws McdbException, 
1141
                                        AccessionNumberException, Exception
1142
  {
1143
    getDocumentInfo(new DocumentIdentifier(docid));
1144
  }
1145
  
1146
  /**
1147
   * Look up the document type information from the database
1148
   *
1149
   * @param docid the id of the document to look up
1150
   */
1151
  private void getDocumentInfo(DocumentIdentifier docid) throws McdbException
1152
                                                          , Exception
1153
  {
1154
    DBConnection dbconn = null;
1155
    int serialNumber = -1;
1156
    PreparedStatement pstmt = null;
1157
    String table = "xml_documents";
1158
        
1159
    try
1160
    {
1161
      if(isRevisionOnly(docid))
1162
      { //pull the document from xml_revisions instead of from xml_documents;
1163
        table = "xml_revisions";
1164
      }
1165
    }
1166
    // catch a McdbDocNotFoundException throw it
1167
    catch (McdbDocNotFoundException notFound)
1168
    {
1169
      throw notFound;
1170
    }
1171
    catch(Exception e)
1172
    {
1173
      
1174
      MetaCatUtil.debugMessage("error in DocumentImpl.getDocumentInfo: " + 
1175
                          e.getMessage(), 30);
1176
      throw e;
1177
    }
1178
    
1179

    
1180
    
1181
    try 
1182
    {
1183
      dbconn=DBConnectionPool.getDBConnection("DocumentImpl.getDocumentInfo");
1184
      serialNumber=dbconn.getCheckOutSerialNumber();
1185
      StringBuffer sql = new StringBuffer();
1186
// DOCTITLE attr cleared from the db
1187
//      sql.append("SELECT docname, doctype, rootnodeid, doctitle, ");
1188
      sql.append("SELECT docname, doctype, rootnodeid, ");
1189
      sql.append("date_created, date_updated, user_owner, user_updated, ");
1190
      sql.append("server_location, public_access, rev");
1191
      sql.append(" FROM ").append(table);
1192
      sql.append(" WHERE docid LIKE '").append(docid.getIdentifier());
1193
      sql.append("' and rev like '").append(docid.getRev()).append("'");
1194
      //System.out.println(sql.toString());
1195
      pstmt =
1196
        dbconn.prepareStatement(sql.toString());
1197
      // Bind the values to the query
1198
      //pstmt.setString(1, docid.getIdentifier());
1199
      //pstmt.setString(2, docid.getRev());
1200

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

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

    
1336
    try 
1337
    {
1338
      dbconn=DBConnectionPool.
1339
                    getDBConnection("DocumentImpl.getPartNodeRecordList");
1340
      serialNumber=dbconn.getCheckOutSerialNumber();
1341
      pstmt = dbconn.prepareStatement(sql);
1342

    
1343
      // Bind the values to the query
1344
      pstmt.setLong(1, rootnodeid);
1345
      pstmt.execute();
1346
      ResultSet rs = pstmt.getResultSet();
1347
      boolean tableHasRows = rs.next();
1348
      while (tableHasRows) 
1349
      {
1350
        nodeid = rs.getLong(1);
1351
        parentnodeid = rs.getLong(2);
1352
        nodeindex = rs.getLong(3);
1353
        nodetype = rs.getString(4);
1354
        nodename = rs.getString(5);
1355
        nodeprefix = rs.getString(6);
1356
        nodedata = rs.getString(7);
1357
        nodedata = MetaCatUtil.normalize(nodedata);
1358
        // add the data to the node record list hashtable
1359
        NodeRecord currentRecord = new NodeRecord(nodeid,parentnodeid,nodeindex,
1360
                                      nodetype, nodename, nodeprefix, nodedata);
1361
        nodeRecordList.add(currentRecord);
1362

    
1363
        // Advance to the next node
1364
        tableHasRows = rs.next();
1365
      } 
1366
      pstmt.close();
1367

    
1368
    } 
1369
    catch (SQLException e) 
1370
    {
1371
      throw new McdbException("Error in DocumentImpl.getPartNodeRecordList " +
1372
                              e.getMessage());
1373
    }
1374
    finally
1375
    {
1376
      try
1377
      {
1378
        pstmt.close();
1379
      }
1380
      catch (SQLException ee)
1381
      {
1382
        MetaCatUtil.debugMessage("error in DocumentImpl.getPartNodeRecordList: "
1383
                                    +ee.getMessage(), 30);
1384
      }
1385
      finally
1386
      {
1387
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1388
      }
1389
    }
1390
      
1391

    
1392
    if (!nodeRecordList.isEmpty()) 
1393
    {
1394
     
1395
      return nodeRecordList;
1396
    } 
1397
    else 
1398
    {
1399
      
1400
      throw new McdbException("Error getting node data: " + docid);
1401
    }
1402
  }
1403
  
1404
  /**
1405
   * Look up the node data from the database
1406
   *
1407
   * @param rootnodeid the id of the root node of the node tree to look up
1408
   */
1409
  private TreeSet getNodeRecordList(long rootnodeid) throws McdbException
1410
  {
1411
    PreparedStatement pstmt = null;
1412
    DBConnection dbconn = null;
1413
    int serialNumber = -1;
1414
    TreeSet nodeRecordList = new TreeSet(new NodeComparator());
1415
    long nodeid = 0;
1416
    long parentnodeid = 0;
1417
    long nodeindex = 0;
1418
    String nodetype = null;
1419
    String nodename = null;
1420
    String nodeprefix = null;
1421
    String nodedata = null;
1422
    String quotechar = dbAdapter.getStringDelimiter();
1423

    
1424
    try {
1425
      dbconn=DBConnectionPool.
1426
                    getDBConnection("DocumentImpl.getNodeRecordList");
1427
      serialNumber=dbconn.getCheckOutSerialNumber();
1428
      pstmt =
1429
      dbconn.prepareStatement("SELECT nodeid,parentnodeid,nodeindex, " +
1430
           "nodetype,nodename,nodeprefix,nodedata " +               
1431
           "FROM xml_nodes WHERE rootnodeid = ?");
1432

    
1433
      // Bind the values to the query
1434
      pstmt.setLong(1, rootnodeid);
1435

    
1436
      pstmt.execute();
1437
      ResultSet rs = pstmt.getResultSet();
1438
      boolean tableHasRows = rs.next();
1439
      while (tableHasRows) {
1440
        nodeid = rs.getLong(1);
1441
        parentnodeid = rs.getLong(2);
1442
        nodeindex = rs.getLong(3);
1443
        nodetype = rs.getString(4);
1444
        nodename = rs.getString(5);
1445
        nodeprefix = rs.getString(6);
1446
        nodedata = rs.getString(7);
1447
        nodedata = MetaCatUtil.normalize(nodedata);
1448
        // add the data to the node record list hashtable
1449
        NodeRecord currentRecord = new NodeRecord(nodeid,parentnodeid,nodeindex,
1450
                                      nodetype, nodename, nodeprefix, nodedata);
1451
        nodeRecordList.add(currentRecord);
1452

    
1453
        // Advance to the next node
1454
        tableHasRows = rs.next();
1455
      } 
1456
      pstmt.close();
1457

    
1458
    } catch (SQLException e) {
1459
      throw new McdbException("Error in DocumentImpl.getNodeRecordList " +
1460
                              e.getMessage());
1461
    }
1462
    finally
1463
    {
1464
      try
1465
      {
1466
        pstmt.close();
1467
      }
1468
      catch (SQLException ee)
1469
      {
1470
        MetaCatUtil.debugMessage("error in DocumentImpl.getNodeRecordList: "
1471
                                    +ee.getMessage(), 30);
1472
      }
1473
      finally
1474
      {
1475
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1476
      }
1477
    }
1478
  
1479
    return nodeRecordList;
1480
   
1481
  }
1482
  
1483
// NOT USED ANY MORE
1484
//  /** creates SQL code and inserts new document into DB connection 
1485
//   default serverCode of 1*/
1486
//  private void writeDocumentToDB(String action, String user)
1487
//               throws SQLException, Exception
1488
//  {
1489
//    writeDocumentToDB(action, user, null, 1);
1490
//  }
1491

    
1492
 /** creates SQL code and inserts new document into DB connection */
1493
  private void writeDocumentToDB(String action, String user, String pub, 
1494
                                 String catalogid, int serverCode) 
1495
               throws SQLException, Exception {
1496
    String sysdate = dbAdapter.getDateTimeFunction();
1497

    
1498
    try {
1499
      PreparedStatement pstmt = null;
1500

    
1501
      if (action.equals("INSERT")) {
1502
        //AccessionNumber ac = new AccessionNumber();
1503
        //this.docid = ac.generate(docid, "INSERT");
1504
        
1505
        pstmt = connection.prepareStatement(
1506
                "INSERT INTO xml_documents " +
1507
                "(docid, rootnodeid, docname, doctype, " + 
1508
                "user_owner, user_updated, date_created, date_updated, " + 
1509
                "public_access, catalog_id, server_location, rev) " +
1510
                "VALUES (?, ?, ?, ?, ?, ?, " + sysdate + ", " + sysdate + 
1511
                ", ?, ?, ?, ?)");
1512
        // Increase dbconnection usage count
1513
        connection.increaseUsageCount(1);
1514
        
1515
        //note that the server_location is set to 1. 
1516
        //this means that "localhost" in the xml_replication table must
1517
        //always be the first entry!!!!!
1518
        
1519
        // Bind the values to the query
1520
        pstmt.setString(1, this.docid);
1521
        pstmt.setLong(2, rootnodeid);
1522
        pstmt.setString(3, docname);
1523
        pstmt.setString(4, doctype);
1524
        pstmt.setString(5, user);
1525
        pstmt.setString(6, user);
1526
        //public access is usefulless, so set it to null
1527
        pstmt.setString(7, null);
1528
        /*if ( pub == null ) {
1529
          pstmt.setString(7, null);
1530
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
1531
          pstmt.setInt(7, 1);
1532
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
1533
          pstmt.setInt(7, 0);
1534
        }*/
1535
        pstmt.setString(8, catalogid);
1536
        pstmt.setInt(9, serverCode);
1537
        pstmt.setInt(10, Integer.parseInt(updatedVersion)); 
1538
      } else if (action.equals("UPDATE")) {
1539

    
1540
        // Save the old document publicaccessentry in a backup table
1541
        DocumentImpl.archiveDocRevision(connection, docid, user );
1542
        DocumentImpl thisdoc = new DocumentImpl(docid, false);
1543
        int thisrev = thisdoc.getRev();
1544
        
1545
        //if the updated vesion is not greater than current one,
1546
        //throw it into a exception
1547
        if (Integer.parseInt(updatedVersion)<=thisrev)
1548
        {
1549
          throw new Exception("Next revision number couldn't be less"
1550
                               +" than or equal "+ thisrev);
1551
        }
1552
        else
1553
        {
1554
          //set the user specified revision 
1555
          thisrev=Integer.parseInt(updatedVersion);
1556
        }
1557
        
1558
        // Delete index for the old version of docid
1559
        // The new index is inserting on the next calls to DBSAXNode
1560
        pstmt = connection.prepareStatement(
1561
                "DELETE FROM xml_index WHERE docid='" + this.docid + "'");
1562
        // Increase dbconnection usage count
1563
        connection.increaseUsageCount(1);
1564
        
1565
        pstmt.execute();
1566
        pstmt.close();
1567

    
1568
        // Update the new document to reflect the new node tree
1569
        pstmt = connection.prepareStatement(
1570
            "UPDATE xml_documents " +
1571
            "SET rootnodeid = ?, docname = ?, doctype = ?, " +
1572
            "user_updated = ?, date_updated = " + sysdate + ", " +
1573
            "server_location = ?, rev = ?, public_access = ?, catalog_id = ? " +
1574
            "WHERE docid = ?");
1575
        // Increase dbconnection usage count
1576
        connection.increaseUsageCount(1);
1577
        // Bind the values to the query
1578
        pstmt.setLong(1, rootnodeid);
1579
        pstmt.setString(2, docname);
1580
        pstmt.setString(3, doctype);
1581
        pstmt.setString(4, user);
1582
        pstmt.setInt(5, serverCode);
1583
        pstmt.setInt(6, thisrev);
1584
        pstmt.setString(7, null);
1585
        /*if ( pub == null ) {
1586
          pstmt.setString(7, null);
1587
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
1588
          pstmt .setInt(7, 1);
1589
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
1590
          pstmt.setInt(7, 0);
1591
        }*/
1592
        pstmt.setString(8, catalogid);
1593
        pstmt.setString(9, this.docid);
1594

    
1595
      } else {
1596
        System.err.println("Action not supported: " + action);
1597
      }
1598

    
1599
      // Do the insertion
1600
      pstmt.execute();
1601
      
1602
      pstmt.close();
1603

    
1604
    } catch (SQLException sqle) {
1605
      throw sqle;
1606
    } catch (Exception e) {
1607
      throw e;
1608
    }
1609
  }
1610

    
1611
  /**
1612
   * Write an XML file to the database, given a filename
1613
   *
1614
   * @param conn the JDBC connection to the database
1615
   * @param filename the filename to be loaded into the database
1616
   * @param pub flag for public "read" access on document
1617
   * @param dtdfilename the dtd to be uploaded on server's file system
1618
   * @param action the action to be performed (INSERT OR UPDATE)
1619
   * @param docid the docid to use for the INSERT OR UPDATE
1620
   * @param user the user that owns the document
1621
   * @param groups the groups to which user belongs
1622
   */
1623
  /*public static String write(DBConnection conn,String filename,
1624
                             String pub, String dtdfilename,
1625
                             String action, String docid, String user,
1626
                             String[] groups )
1627
                throws Exception {
1628
                  
1629
    Reader dtd = null;
1630
    if ( dtdfilename != null ) {
1631
      dtd = new FileReader(new File(dtdfilename).toString());
1632
    }
1633
    return write ( conn, new FileReader(new File(filename).toString()),
1634
                   pub, dtd, action, docid, user, groups, false);
1635
  }*/
1636

    
1637
  public static String write(DBConnection conn,Reader xml,String pub,Reader dtd,
1638
                             String action, String docid, String user,
1639
                             String[] groups, String ruleBase, 
1640
                             boolean needValidation)
1641
                throws Exception {
1642
    //this method will be called in handleUpdateOrInsert method 
1643
    //in MetacatServlet class and now is wrapper into documentImple
1644
    // get server location for this doc
1645
    int serverLocation=getServerLocationNumber(docid);
1646
    return write(conn,xml,pub,dtd,action,docid,user,groups,serverLocation,false,
1647
                 ruleBase, needValidation);
1648
  }
1649

    
1650
 
1651
  
1652
  /**
1653
   * Write an XML file to the database, given a Reader
1654
   *
1655
   * @param conn the JDBC connection to the database
1656
   * @param xml the xml stream to be loaded into the database
1657
   * @param pub flag for public "read" access on xml document
1658
   * @param dtd the dtd to be uploaded on server's file system
1659
   * @param action the action to be performed (INSERT or UPDATE)
1660
   * @param accnum the docid + rev# to use on INSERT or UPDATE
1661
   * @param user the user that owns the document
1662
   * @param groups the groups to which user belongs
1663
   * @param serverCode the serverid from xml_replication on which this document
1664
   *        resides.
1665
   * @param override flag to stop insert replication checking.
1666
   *        if override = true then a document not belonging to the local server
1667
   *        will not be checked upon update for a file lock.
1668
   *        if override = false then a document not from this server, upon 
1669
   *        update will be locked and version checked.
1670
   */
1671

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

    
1757
      else if(openingtag.equals("<filelocked>"))
1758
      {//the file is currently locked by another user
1759
       //notify our user to wait a few minutes, check out a new copy and try
1760
       //again.
1761
        //System.out.println("file locked");
1762
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1763
                                   server + " reason: file already locked");
1764
        throw new Exception("The file specified is already locked by another " +
1765
                            "user.  Please wait 30 seconds, checkout the " +
1766
                            "newer document, merge your changes and try " +
1767
                            "again.");
1768
      }
1769
      else if(openingtag.equals("<outdatedfile>"))
1770
      {//our file is outdated.  notify our user to check out a new copy of the
1771
       //file and merge his version with the new version.
1772
        //System.out.println("outdated file");
1773
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1774
                                    server + " reason: local file outdated");
1775
        throw new Exception("The file you are trying to update is an outdated" +
1776
                            " version.  Please checkout the newest document, " +
1777
                            "merge your changes and try again.");
1778
      }
1779
    }
1780
    
1781
    if ( action.equals("UPDATE") ) {
1782
      // check for 'write' permission for 'user' to update this document
1783

    
1784
      if ( !hasWritePermission(user, groups, docid) ) {
1785
        throw new Exception("User " + user + 
1786
              " does not have permission to update XML Document #" + accnum);
1787
      }          
1788
    }
1789
    XMLReader parser = null;
1790
    try 
1791
    { 
1792
      
1793
      parser = initializeParser(conn, action, docid, rev, 
1794
                                          user, groups, pub, serverCode, 
1795
                                          dtd, ruleBase, needValidation);
1796
   
1797
      conn.setAutoCommit(false);
1798
      parser.parse(new InputSource(xml));
1799
      conn.commit();
1800
      conn.setAutoCommit(true);
1801
    } 
1802
    catch (Exception e) 
1803
    {
1804
      conn.rollback();
1805
      conn.setAutoCommit(true);
1806
       //if it is a eml2 document, we need delete online data
1807
       if ( parser != null)
1808
       {
1809
          ContentHandler handler = parser.getContentHandler();
1810
          if (handler instanceof EmlSAXHandler)
1811
          {
1812
            EmlSAXHandler eml = (EmlSAXHandler) handler;
1813
            eml.deleteInlineFiles();
1814
          }
1815
       }
1816
      throw e;
1817
    }
1818
    
1819
    // run access db base on relation table and access object       
1820
    runRelationAndAccessHandler(accnum, user, groups, serverCode);
1821
    
1822
    // Force replicate out the new document to each server in our server list.
1823
    // Start the thread to replicate this new document out to the other servers
1824
    // true mean it is xml document
1825
    // null is because no metacat notify the force replication.
1826
    ForceReplicationHandler frh = new ForceReplicationHandler
1827
                                                  (accnum, action, true, null);
1828
      
1829
   
1830
    MetaCatUtil.debugMessage("Conn Usage count after writting: "
1831
                                                      +conn.getUsageCount(),50); 
1832
    return(accnum);
1833
  }
1834

    
1835
  /**
1836
   * Write an XML file to the database during replication
1837
   *
1838
   * @param conn the JDBC connection to the database
1839
   * @param xml the xml stream to be loaded into the database
1840
   * @param pub flag for public "read" access on xml document
1841
   * @param dtd the dtd to be uploaded on server's file system
1842
   * @param action the action to be performed (INSERT or UPDATE)
1843
   * @param accnum the docid + rev# to use on INSERT or UPDATE
1844
   * @param user the user that owns the document
1845
   * @param groups the groups to which user belongs
1846
   * @param homeServer the name of server which the document origanlly create
1847
   * @param validate, if the xml document is valid or not
1848
   * @param notifyServer, the server which notify local server the force 
1849
   *                       replication command
1850
   */
1851

    
1852
  public static String writeReplication(DBConnection conn, Reader xml, 
1853
                                        String pub, Reader dtd, String action, 
1854
                                        String accnum, String user,
1855
                                        String[] groups,String homeServer, 
1856
                                        String notifyServer,
1857
                                        String ruleBase, boolean needValidation)
1858
                                        throws Exception
1859
  {
1860
    // Docid without revision
1861
    String docid=MetaCatUtil.getDocIdFromString(accnum);
1862
    // Revision specified by user (int)
1863
    int userSpecifyRev=MetaCatUtil.getVersionFromString(accnum);
1864
    // Revision for this docid in current database
1865
    int revInDataBase=getLatestRevisionNumber(docid);
1866
    // String to store the revision
1867
    String rev = null;
1868
   
1869
    
1870
    //revIndataBase=-1, there is no record in xml_documents table
1871
    //the document is a new one for local server, inert it into table
1872
    //user specified rev should be great than 0
1873
    if (revInDataBase==-1 && userSpecifyRev>0 )
1874
    {
1875
        // rev equals user specified
1876
        rev=(new Integer(userSpecifyRev)).toString();
1877
        // action should be INSERT
1878
        action = "INSERT";
1879
    }
1880
    //rev is greater the last revsion number and revInDataBase isn't -1
1881
    // it is a updated  file
1882
    else if (userSpecifyRev>revInDataBase && revInDataBase>0)
1883
    {
1884
       // rev equals user specified
1885
       rev=(new Integer(userSpecifyRev)).toString();
1886
       // action should be update
1887
       action = "UPDATE";
1888
    }
1889
    // local server has newer version, then notify the remote server
1890
    else if ( userSpecifyRev < revInDataBase && revInDataBase > 0)
1891
    {
1892
      throw new Exception("Local server: "+MetaCatUtil.getOption("server")+
1893
                " has newer revision of doc: "+docid+"."+revInDataBase
1894
                 +". Please notify it.");
1895
    }
1896
    //other situation
1897
    else
1898
    {
1899
        
1900
        throw new Exception("The docid"+docid+"'s revision number couldn't be "
1901
                    +userSpecifyRev);
1902
    }
1903
    // Variable to store homeserver code
1904
    int serverCode=-2;
1905
    
1906
     // If server is not int the xml replication talbe, insert it into
1907
    // xml_replication table
1908
    //serverList.addToServerListIfItIsNot(homeServer);
1909
    insertServerIntoReplicationTable(homeServer);
1910
    // Get server code again
1911
    serverCode = getServerCode(homeServer);
1912
    
1913
    
1914
    MetaCatUtil.debugMessage("Document "+docid+"."+rev+" "+action+ " into local"
1915
                               +" metacat with servercode: "+ serverCode, 10);
1916
                        
1917
  
1918
    // insert into xml_nodes and xml_index table
1919
    XMLReader parser = null;
1920
    try 
1921
    { 
1922
      
1923
      parser = initializeParser(conn, action, docid, rev,
1924
                                          user, groups, pub, serverCode, dtd,
1925
                                          ruleBase, needValidation);
1926
      conn.setAutoCommit(false);
1927
      parser.parse(new InputSource(xml));
1928
      conn.commit();
1929
      conn.setAutoCommit(true);
1930
    } 
1931
    catch (Exception e) 
1932
    {
1933
      conn.rollback();
1934
      conn.setAutoCommit(true);
1935
      if ( parser != null)
1936
      {
1937
          ContentHandler handler = parser.getContentHandler();
1938
          if (handler instanceof EmlSAXHandler)
1939
          {
1940
            EmlSAXHandler eml = (EmlSAXHandler) handler;
1941
            eml.deleteInlineFiles();
1942
          }
1943
       }
1944
      throw e;
1945
    }
1946
    
1947
    // run write into access db base on relation table and access rule
1948
    try
1949
    {       
1950
      runRelationAndAccessHandler(accnum, user, groups, serverCode);
1951
    }
1952
    catch (Exception ee)
1953
    {
1954
      MetacatReplication.replErrorLog("Failed to " + 
1955
                                       "create access " + 
1956
                                       "rule for package: " + accnum +
1957
                                       " because " +ee.getMessage());
1958
      MetaCatUtil.debugMessage("Failed to  " + 
1959
                                       "create access " + 
1960
                                       "rule for package: "+ accnum +
1961
                                       " because " +ee.getMessage(), 30);
1962
    }
1963
    //Force replication to other server
1964
    ForceReplicationHandler forceReplication = new ForceReplicationHandler
1965
                                  (accnum, action, true, notifyServer);
1966
    
1967

    
1968
    return(accnum);
1969
  }
1970
  
1971
  /* Running write record to xml_relation and xml_access*/
1972
  private static void runRelationAndAccessHandler(String accnumber, 
1973
                                                  String userName, 
1974
                                                  String[]group, int servercode) 
1975
                                                   throws Exception
1976
  {
1977
    DBConnection dbconn = null;
1978
    int serialNumber = -1;
1979
    PreparedStatement pstmt =null;
1980
    String documenttype = getDocTypeFromDBForCurrentDocument(accnumber);
1981
    try
1982
    {
1983
      String packagedoctype = MetaCatUtil.getOption("packagedoctype");
1984
      Vector packagedoctypes = new Vector();
1985
      packagedoctypes = MetaCatUtil.getOptionList(packagedoctype);
1986
      String docIdWithoutRev = MetaCatUtil.getDocIdFromString(accnumber);
1987
      if (documenttype != null && packagedoctypes.contains(documenttype) )
1988
      {
1989
        dbconn=DBConnectionPool.
1990
           getDBConnection("DocumentImpl.runRelationAndAccessHandeler");
1991
        serialNumber=dbconn.getCheckOutSerialNumber();
1992
        dbconn.setAutoCommit(false);
1993
        // from the relations get the access file id for that package
1994
        String aclid = RelationHandler.getAccessFileID(docIdWithoutRev);
1995
        // if there are access file, write ACL for that package
1996
        if ( aclid != null ) 
1997
        {
1998
          runAccessControlList(dbconn, aclid, userName, group, servercode);
1999
        }
2000
        dbconn.commit();
2001
        dbconn.setAutoCommit(true);
2002
      }
2003
        // if it is an access file
2004
      else if ( documenttype != null && MetaCatUtil.getOptionList(
2005
                 MetaCatUtil.getOption("accessdoctype")).contains(documenttype))
2006
      {
2007
        dbconn=DBConnectionPool.
2008
           getDBConnection("DocumentImpl.runRelationAndAccessHandeler");
2009
        serialNumber=dbconn.getCheckOutSerialNumber();
2010
        dbconn.setAutoCommit(false);
2011
        // write ACL for the package
2012
        runAccessControlList(dbconn, docIdWithoutRev, 
2013
                             userName, group, servercode);
2014
        dbconn.commit();
2015
        dbconn.setAutoCommit(true);
2016
        
2017
      }
2018
      
2019
    } 
2020
    catch (Exception e) 
2021
    {
2022
      if( dbconn != null)
2023
      {
2024
        dbconn.rollback();
2025
        dbconn.setAutoCommit(true);
2026
      }
2027
      MetaCatUtil.debugMessage("Error in DocumentImple.runRelationAndAccessHandler " +
2028
                                e.getMessage(), 30);
2029
      throw e;
2030
    }
2031
    finally
2032
    {
2033
      if (dbconn != null)
2034
      {
2035
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
2036
      }
2037
    }//
2038
  }
2039
  
2040
  // It runs in xmlIndex thread. It writes ACL for a package.
2041
  private static void runAccessControlList (DBConnection conn, String aclid, 
2042
                                    String users, String[]group, int servercode)
2043
                                                throws Exception
2044
  {
2045
    // read the access file from xml_nodes
2046
    // parse the access file and store the access info into xml_access
2047
    AccessControlList aclobj =
2048
    new AccessControlList(conn, aclid, users, group, servercode);
2049
   
2050
  }
2051
  
2052
  /* Method get document type from db*/
2053
  private static String getDocTypeFromDBForCurrentDocument(String accnumber)
2054
                                                  throws SQLException
2055
  {
2056
    String docoumentType = null;
2057
    String docid = null;
2058
    PreparedStatement pstate = null;
2059
    ResultSet rs = null;
2060
    String sql = "SELECT doctype FROM xml_documents where docid = ?";
2061
    DBConnection dbConnection = null;
2062
    int serialNumber = -1;
2063
    try
2064
    {
2065
      //get rid of revision number
2066
      docid = MetaCatUtil.getDocIdFromString(accnumber);
2067
      dbConnection=DBConnectionPool.
2068
           getDBConnection("DocumentImpl.getDocTypeFromDBForCurrentDoc");
2069
      serialNumber=dbConnection.getCheckOutSerialNumber();
2070
      pstate = dbConnection.prepareStatement(sql);
2071
      //bind variable
2072
      pstate.setString(1, docid);
2073
      //excute query
2074
      pstate.execute();
2075
      //handle resultset
2076
      rs = pstate.getResultSet();
2077
      if (rs.next())
2078
      {
2079
        docoumentType = rs.getString(1);
2080
      }
2081
      rs.close();
2082
      pstate.close();
2083
    }//try
2084
    catch (SQLException e)
2085
    {
2086
      MetaCatUtil.debugMessage("error in DocumentImpl."+
2087
                      "getDocTypeFromDBForCurrentDocument "+e.getMessage(), 30);
2088
      throw e;
2089
    }//catch
2090
    finally
2091
    {
2092
      pstate.close();
2093
      DBConnectionPool.returnDBConnection(dbConnection, serialNumber);
2094
    }//
2095
    MetaCatUtil.debugMessage("The current doctype from db is: "+
2096
                              docoumentType, 35);
2097
    return docoumentType;
2098
  }
2099
  /**
2100
   * Delete an XML file from the database (actually, just make it a revision
2101
   * in the xml_revisions table)
2102
   *
2103
   * @param docid the ID of the document to be deleted from the database
2104
   */
2105
  public static void delete(String accnum,
2106
                                 String user, String[] groups )
2107
                throws Exception 
2108
  {
2109
    // OLD
2110
    //DocumentIdentifier id = new DocumentIdentifier(accnum);
2111
    //String docid = id.getIdentifier();
2112
    //String rev = id.getRev();
2113
    
2114
    // OLD
2115
    // Determine if the docid,rev are OK for DELETE
2116
    //AccessionNumber ac = new AccessionNumber(conn);
2117
    //docid = ac.generate(docid, rev, "DELETE");
2118
    DBConnection conn = null;
2119
    int serialNumber = -1;
2120
    PreparedStatement pstmt =null;
2121
    try
2122
    {
2123
      //check out DBConnection
2124
      conn=DBConnectionPool.
2125
                    getDBConnection("DocumentImpl.delete");
2126
      serialNumber=conn.getCheckOutSerialNumber();
2127

    
2128
      // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
2129
      AccessionNumber ac = new AccessionNumber(accnum, "DELETE");
2130
      String docid = ac.getDocid();
2131
      String rev = ac.getRev();
2132
    
2133
      MetaCatUtil.debugMessage("Start deleting doc "+docid+ "...", 20);
2134
    // check for 'write' permission for 'user' to delete this document
2135
      if ( !hasWritePermission(user, groups, docid) ) {
2136
        throw new Exception("User " + user + 
2137
              " does not have permission to delete XML Document #" + accnum);
2138
      }
2139

    
2140
      conn.setAutoCommit(false);
2141
      // Copy the record to the xml_revisions table
2142
      DocumentImpl.archiveDocRevision(conn, docid, user );
2143

    
2144
      // Now delete it from the xml_index table
2145
      pstmt = conn.prepareStatement("DELETE FROM xml_index WHERE docid = ?");
2146
      pstmt.setString(1,docid);
2147
      pstmt.execute();
2148
      pstmt.close();
2149
      conn.increaseUsageCount(1);
2150
      
2151
      //stmt.execute("DELETE FROM xml_access WHERE docid = '" + docid + "'");
2152
      // Now delete it from xml_access table
2153
      pstmt = conn.
2154
              prepareStatement("DELETE FROM xml_access WHERE accessfileid = ?");
2155
      pstmt.setString(1, docid);
2156
      pstmt.execute();
2157
      pstmt.close();
2158
      conn.increaseUsageCount(1);
2159
      
2160
      // Delete it from relation table
2161
      pstmt = conn.
2162
               prepareStatement("DELETE FROM xml_relation WHERE docid = ?");
2163
      //increase usage count
2164
      conn.increaseUsageCount(1);
2165
      pstmt.setString(1, docid);
2166
      pstmt.execute();
2167
      pstmt.close();
2168
      
2169
      // Delete it from xml_accesssubtree table
2170
      pstmt = conn.
2171
               prepareStatement("DELETE FROM xml_accesssubtree WHERE docid = ?");
2172
      //increase usage count
2173
      conn.increaseUsageCount(1);
2174
      pstmt.setString(1, docid);
2175
      pstmt.execute();
2176
      pstmt.close();
2177
      
2178
      // Delete it from xml_doucments table
2179
      pstmt =conn.prepareStatement("DELETE FROM xml_documents WHERE docid = ?");
2180
      pstmt.setString(1, docid);
2181
      pstmt.execute();
2182
      pstmt.close();
2183
      //Usaga count increase 1
2184
      conn.increaseUsageCount(1);
2185
      
2186
      conn.commit();
2187
      conn.setAutoCommit(true);
2188
    }//try
2189
    catch (Exception e)
2190
    {
2191
      MetaCatUtil.debugMessage("error in DocumentImpl.delete: " + 
2192
                                e.getMessage(), 30);
2193
      throw e;
2194
    }
2195
    finally
2196
    {
2197
      
2198
      try
2199
      {
2200
        // close preparedStatement
2201
        pstmt.close();
2202
      }//try
2203
      finally
2204
      {
2205
        //check in DBonnection
2206
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2207
      }//finally
2208
    }//finally
2209
    //IF this is a package document:
2210
    //delete all of the relations that this document created.
2211
    //if the deleted document is a package document its relations should 
2212
    //no longer be active if it has been deleted from the system.
2213
    
2214
  }
2215

    
2216
  /** 
2217
    * Check for "WRITE" permission on @docid for @user and/or @groups 
2218
    * from DB connection 
2219
    */
2220
  private static boolean hasWritePermission (String user,
2221
                                  String[] groups, String docid ) 
2222
                  throws SQLException, Exception
2223
  {
2224
    // Check for WRITE permission on @docid for @user and/or @groups
2225
    PermissionController controller = new PermissionController(docid);
2226
    return controller.hasPermission(user,groups,
2227
                                    AccessControlInterface.WRITESTRING);
2228
  }
2229

    
2230
  /** 
2231
    * Check for "READ" permission base on docid, user and group
2232
    *@docid, the document
2233
    *@user, user name
2234
    *@group, user's group
2235
    * 
2236
    */
2237
  public static boolean hasReadPermission (String user,
2238
                                  String[] groups, String docId ) 
2239
                  throws SQLException, Exception
2240
  {
2241
    // Check for READ permission on @docid for @user and/or @groups
2242
    PermissionController controller = 
2243
                        new PermissionController(docId);
2244
    return controller.hasPermission(user,groups,
2245
                                            AccessControlInterface.READSTRING);
2246
  }  
2247

    
2248
  
2249
   /**
2250
   * Set up the parser handlers for writing the document to the database
2251
   */
2252
  private static XMLReader initializeParser(DBConnection dbconn, String action,
2253
                                            String docid, String rev, 
2254
                                            String user, 
2255
                                            String[] groups, String pub, 
2256
                                            int serverCode, Reader dtd,
2257
                                            String ruleBase, 
2258
                                            boolean needValidation) 
2259
                                            throws Exception 
2260
  {
2261
    XMLReader parser = null;
2262
    try 
2263
    {
2264
      // handler
2265
      ContentHandler chandler;
2266
      EntityResolver eresolver;
2267
      DTDHandler dtdhandler;  
2268
      // Get an instance of the parser
2269
      String parserName = MetaCatUtil.getOption("saxparser");
2270
      parser = XMLReaderFactory.createXMLReader(parserName);
2271
      if (ruleBase != null && ruleBase.equals(EML2))
2272
      {
2273
        MetaCatUtil.debugMessage("eml 2 parser", 20);
2274
        chandler = new EmlSAXHandler(dbconn, action, 
2275
                                    docid, rev, user, groups, pub, serverCode);
2276
        parser.setContentHandler((ContentHandler)chandler);
2277
        parser.setErrorHandler((ErrorHandler)chandler);
2278
        parser.setProperty(DECLARATIONHANDLERPROPERTY, chandler);
2279
        parser.setProperty(LEXICALPROPERTY, chandler);
2280
        // turn on schema validation feature
2281
        parser.setFeature(VALIDATIONFEATURE, true);
2282
        parser.setFeature(NAMESPACEFEATURE, true);
2283
        //parser.setFeature(NAMESPACEPREFIXESFEATURE, true);
2284
        parser.setFeature(SCHEMAVALIDATIONFEATURE, true);
2285
        // From DB to find the register external schema location
2286
        String externalSchemaLocation = null;
2287
        SchemaLocationResolver resolver = new SchemaLocationResolver();
2288
        externalSchemaLocation = resolver.getNameSpaceAndLocationString();
2289
        // Set external schemalocation.
2290
        if (externalSchemaLocation != null && 
2291
            !(externalSchemaLocation.trim()).equals(""))
2292
        {
2293
            parser.setProperty(EXTERNALSCHEMALOCATIONPROPERTY,
2294
                             externalSchemaLocation);
2295
        }
2296
      }
2297
      else
2298
      {
2299
        //create a DBSAXHandler object which has the revision specification
2300
        chandler = new DBSAXHandler(dbconn, action, 
2301
                                    docid, rev, user, groups, pub, serverCode);
2302
        parser.setContentHandler((ContentHandler)chandler);
2303
        parser.setErrorHandler((ErrorHandler)chandler);
2304
        parser.setProperty(DECLARATIONHANDLERPROPERTY, chandler);
2305
        parser.setProperty(LEXICALPROPERTY, chandler);
2306
      
2307
        if (ruleBase != null && ruleBase.equals(SCHEMA) && needValidation)
2308
        {
2309
          MetaCatUtil.debugMessage("General schema parser", 20);
2310
          // turn on schema validation feature
2311
          parser.setFeature(VALIDATIONFEATURE, true);
2312
          parser.setFeature(NAMESPACEFEATURE, true);
2313
          //parser.setFeature(NAMESPACEPREFIXESFEATURE, true);
2314
          parser.setFeature(SCHEMAVALIDATIONFEATURE, true);
2315
          // From DB to find the register external schema location
2316
          String externalSchemaLocation = null;
2317
          SchemaLocationResolver resolver = new SchemaLocationResolver();
2318
          externalSchemaLocation = resolver.getNameSpaceAndLocationString();
2319
          // Set external schemalocation.
2320
          if (externalSchemaLocation != null && 
2321
            !(externalSchemaLocation.trim()).equals(""))
2322
          {
2323
            parser.setProperty(EXTERNALSCHEMALOCATIONPROPERTY,
2324
                             externalSchemaLocation);
2325
          }
2326
     
2327
        }
2328
        else if (ruleBase != null && ruleBase.equals(DTD) && needValidation)
2329
        {
2330
          MetaCatUtil.debugMessage("dtd parser", 20);
2331
          // turn on dtd validaton feature
2332
          parser.setFeature(VALIDATIONFEATURE, true);
2333
          eresolver= new DBEntityResolver(dbconn, (DBSAXHandler)chandler, dtd);
2334
          dtdhandler = new DBDTDHandler(dbconn);
2335
          parser.setEntityResolver((EntityResolver)eresolver);
2336
          parser.setDTDHandler((DTDHandler)dtdhandler);
2337
        }
2338
        else
2339
        {
2340
          MetaCatUtil.debugMessage("other parser", 20);
2341
          // non validation
2342
          parser.setFeature(VALIDATIONFEATURE, false);
2343
          eresolver= new DBEntityResolver(dbconn, (DBSAXHandler)chandler, dtd);
2344
          dtdhandler = new DBDTDHandler(dbconn);
2345
          parser.setEntityResolver((EntityResolver)eresolver);
2346
          parser.setDTDHandler((DTDHandler)dtdhandler);
2347
        }
2348
      }//else
2349
    } 
2350
    catch (Exception e) 
2351
    {
2352
      throw e;
2353
    }
2354
    return parser;
2355
  }
2356

    
2357
  
2358
  /**
2359
   * Set up the parser handlers for writing the document to the database
2360
   */
2361
  /*private static XMLReader initializeParser(DBConnection dbconn, String action,
2362
                               String docid, String rev, boolean validate, 
2363
                                   String user, String[] groups, String pub, 
2364
                                   int serverCode, Reader dtd) 
2365
                           throws Exception 
2366
  {
2367
    XMLReader parser = null;
2368
    //DBConnection conn = null;
2369
    //int serialNumber = -1;
2370
    //
2371
    // Set up the SAX document handlers for parsing
2372
    //
2373
    try {
2374
       //check out DBConnection
2375
     
2376
      //create a DBSAXHandler object which has the revision specification
2377
      ContentHandler chandler = new DBSAXHandler(dbconn, action, 
2378
                                    docid, rev, user, groups, pub, serverCode);
2379
      EntityResolver eresolver= new DBEntityResolver(dbconn,
2380
                                                 (DBSAXHandler)chandler, dtd);
2381
      DTDHandler dtdhandler   = new DBDTDHandler(dbconn);
2382

    
2383
      // Get an instance of the parser
2384
      String parserName = MetaCatUtil.getOption("saxparser");
2385
      parser = XMLReaderFactory.createXMLReader(parserName);
2386

    
2387
      // Turn on validation
2388
      parser.setFeature("http://xml.org/sax/features/validation", validate);
2389
      // Turn off Including all external parameter entities
2390
      // (the external DTD subset also)
2391
      // Doesn't work well, probably the feature name is not correct
2392
      // parser.setFeature(
2393
      //  "http://xml.org/sax/features/external-parameter-entities", false);
2394
      
2395
      // Set Handlers in the parser
2396
      parser.setProperty("http://xml.org/sax/properties/declaration-handler",
2397
                         chandler);
2398
      parser.setProperty("http://xml.org/sax/properties/lexical-handler",
2399
                         chandler);
2400
      parser.setContentHandler((ContentHandler)chandler);
2401
      parser.setEntityResolver((EntityResolver)eresolver);
2402
      parser.setDTDHandler((DTDHandler)dtdhandler);
2403
      parser.setErrorHandler((ErrorHandler)chandler);
2404

    
2405
    } catch (Exception e) {
2406
      throw e;
2407
    }
2408
    //finally
2409
    //{
2410
      //DBConnectionPool.returnDBConnection(conn, serialNumber);
2411
    //}
2412

    
2413
    return parser;
2414
  }*/
2415

    
2416
  /**
2417
   * Save a document entry in the xml_revisions table 
2418
   * Connection use as a paramter is in order to rollback feature
2419
   */
2420
  private static void archiveDocRevision(DBConnection dbconn, String docid, 
2421
                                                    String user) 
2422
 {
2423
    String sysdate = dbAdapter.getDateTimeFunction();
2424
    //DBConnection conn = null;
2425
    //int serialNumber = -1;
2426
    PreparedStatement pstmt = null;
2427
    
2428
    // create a record in xml_revisions table 
2429
    // for that document as selected from xml_documents
2430
   
2431
   try
2432
   {
2433
     //check out DBConnection
2434
     /*conn=DBConnectionPool.
2435
                    getDBConnection("DocumentImpl.archiveDocRevision");
2436
     serialNumber=conn.getCheckOutSerialNumber();*/
2437
     pstmt = dbconn.prepareStatement(
2438
      "INSERT INTO xml_revisions " +
2439
        "(docid, rootnodeid, docname, doctype, " +
2440
        "user_owner, user_updated, date_created, date_updated, " +
2441
        "server_location, rev, public_access, catalog_id) " +
2442
      "SELECT ?, rootnodeid, docname, doctype, " + 
2443
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
2444
        "server_location, rev, public_access, catalog_id " +
2445
      "FROM xml_documents " +
2446
      "WHERE docid = ?");
2447
      // Increase dbconnection usage count
2448
      dbconn.increaseUsageCount(1);
2449
      // Bind the values to the query and execute it
2450
      pstmt.setString(1, docid);
2451
      pstmt.setString(2, user);
2452
      pstmt.setString(3, docid);
2453
      pstmt.execute();
2454
      pstmt.close();
2455
   }//try
2456
   catch (SQLException e)
2457
   {
2458
     MetaCatUtil.debugMessage("Error in DocumentImpl.archiveDocRevision : "+
2459
                                e.getMessage(), 30);
2460
   }//catch
2461
   finally
2462
   {
2463
     try
2464
     {
2465
       pstmt.close();
2466
     }//try
2467
     catch (SQLException ee)
2468
     {
2469
       MetaCatUtil.debugMessage("Error in DocumnetImpl.archiveDocRevision: "+
2470
                                  ee.getMessage(), 50);
2471
     }//catch
2472
     //finally
2473
     //{
2474
       
2475
       //check in DBConnection
2476
       //DBConnectionPool.returnDBConnection(conn, serialNumber);
2477
     //}//finally
2478
   }//finnally
2479
                                  
2480

    
2481
  }//achiveDocRevision
2482
  
2483
  /** Save a document entry in the xml_revisions table */
2484
  private static void archiveDocRevision(String docid, String user) 
2485
 {
2486
    String sysdate = dbAdapter.getDateTimeFunction();
2487
    DBConnection conn = null;
2488
    int serialNumber = -1;
2489
    PreparedStatement pstmt = null;
2490
    
2491
    // create a record in xml_revisions table 
2492
    // for that document as selected from xml_documents
2493
   
2494
   try
2495
   {
2496
     //check out DBConnection
2497
     conn=DBConnectionPool.
2498
                    getDBConnection("DocumentImpl.archiveDocRevision");
2499
     serialNumber=conn.getCheckOutSerialNumber();
2500
     pstmt = conn.prepareStatement(
2501
      "INSERT INTO xml_revisions " +
2502
        "(docid, rootnodeid, docname, doctype, " +
2503
        "user_owner, user_updated, date_created, date_updated, " +
2504
        "server_location, rev, public_access, catalog_id) " +
2505
      "SELECT ?, rootnodeid, docname, doctype, " + 
2506
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
2507
        "server_location, rev, public_access, catalog_id " +
2508
      "FROM xml_documents " +
2509
      "WHERE docid = ?");
2510
      // Bind the values to the query and execute it
2511
      pstmt.setString(1, docid);
2512
      pstmt.setString(2, user);
2513
      pstmt.setString(3, docid);
2514
      pstmt.execute();
2515
      pstmt.close();
2516
   }//try
2517
   catch (SQLException e)
2518
   {
2519
     MetaCatUtil.debugMessage("Error in DocumentImpl.archiveDocRevision : "+
2520
                                e.getMessage(), 30);
2521
   }//catch
2522
   finally
2523
   {
2524
     try
2525
     {
2526
       pstmt.close();
2527
     }//try
2528
     catch (SQLException ee)
2529
     {
2530
       MetaCatUtil.debugMessage("Error in DocumnetImpl.archiveDocRevision: "+
2531
                                  ee.getMessage(), 50);
2532
     }//catch
2533
     finally
2534
     {
2535
       //check in DBConnection
2536
       DBConnectionPool.returnDBConnection(conn, serialNumber);
2537
     }//finally
2538
   }//finnally
2539
                                  
2540

    
2541
  }//achiveDocRevision
2542
  
2543
  /**
2544
    * delete a entry in xml_table for given docid
2545
    * @param docId, the id of the document need to be delete
2546
    */
2547
  private static void deleteXMLDocuments(String docId) 
2548
                                         throws SQLException 
2549
  {
2550
    DBConnection conn = null;
2551
    int serialNumber = -1;
2552
    PreparedStatement pStmt = null;
2553
    try
2554
    {
2555
      //check out DBConnection
2556
      conn=DBConnectionPool.
2557
                    getDBConnection("DocumentImpl.deleteXMLDocuments");
2558
      serialNumber=conn.getCheckOutSerialNumber();
2559
      //delete a record 
2560
      pStmt = 
2561
             conn.prepareStatement("DELETE FROM xml_documents WHERE docid = '" 
2562
                                              + docId + "'");
2563
    pStmt.execute();
2564
    }//try
2565
    finally
2566
    {
2567
      try
2568
      {
2569
        pStmt.close();
2570
      }//try
2571
      catch (SQLException e)
2572
      {
2573
        MetaCatUtil.debugMessage("error in DocumentImpl.deleteXMLDocuments: "+
2574
                                  e.getMessage(), 50);
2575
      }//catch
2576
      finally
2577
      {
2578
        //return back DBconnection
2579
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2580
      }//finally
2581
    }//finally
2582
      
2583

    
2584
  }//deleteXMLDocuments
2585
  
2586
  /**
2587
    * Get last revision number from database for a docid
2588
    * If couldn't find an entry,  -1 will return
2589
    * The return value is integer because we want compare it to there new one
2590
    * @param docid <sitecode>.<uniqueid> part of Accession Number
2591
    */
2592
  public static int getLatestRevisionNumber(String docId)
2593
                                      throws SQLException
2594
  {
2595
    int rev = 1;
2596
    PreparedStatement pStmt = null;
2597
    DBConnection dbConn = null;
2598
    int serialNumber = -1;
2599
    // get rid of rev
2600
    docId = MetaCatUtil.getDocIdFromString(docId);
2601
    try
2602
    {
2603
      //check out DBConnection
2604
      dbConn=DBConnectionPool.
2605
                    getDBConnection("DocumentImpl.getLatestRevisionNumber");
2606
      serialNumber=dbConn.getCheckOutSerialNumber();
2607
     
2608
      pStmt = dbConn.prepareStatement
2609
              ("SELECT rev FROM xml_documents WHERE docid='" + docId + "'");
2610
      pStmt.execute();
2611

    
2612
      ResultSet rs = pStmt.getResultSet();
2613
      boolean hasRow = rs.next();
2614
      if (hasRow)
2615
      {
2616
        rev = rs.getInt(1);
2617
        pStmt.close();
2618
      }
2619
      else
2620
      {
2621
        rev=-1;
2622
        pStmt.close();
2623
      }
2624
    }//try
2625
    finally
2626
    {
2627
      try
2628
      {
2629
        pStmt.close();
2630
      }
2631
      catch (Exception ee)
2632
      {
2633
        MetaCatUtil.debugMessage("Error in DocumentImpl."+
2634
                        "getLatestRevisionNumber: "+ee.getMessage(), 50);
2635
      }
2636
      finally
2637
      {
2638
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2639
      }
2640
    }//finally  
2641
      
2642
    return rev;
2643
  }//getLatestRevisionNumber
2644
  
2645
  /**
2646
   * Get server location form database for a accNum
2647
   * 
2648
   * @param accum <sitecode>.<uniqueid>.<rev>
2649
   */
2650
  private static int getServerLocationNumber(String accNum)
2651
                                            throws SQLException
2652
  {
2653
    //get rid of revNum part
2654
    String docId=MetaCatUtil.getDocIdFromString(accNum);
2655
    PreparedStatement pStmt = null;
2656
    int serverLocation = 1;
2657
    DBConnection conn = null;
2658
    int serialNumber = -1;
2659
    
2660
    try
2661
    {
2662
      //check out DBConnection
2663
      conn=DBConnectionPool.
2664
                    getDBConnection("DocumentImpl.getServerLocationNumber");
2665
      serialNumber=conn.getCheckOutSerialNumber();
2666
     
2667
      pStmt = conn.prepareStatement
2668
      ("SELECT server_location FROM xml_documents WHERE docid='" + docId + "'");
2669
      pStmt.execute();
2670

    
2671
      ResultSet rs = pStmt.getResultSet();
2672
      boolean hasRow = rs.next();
2673
      //if there is entry in xml_documents, get the serverlocation
2674
      if (hasRow)
2675
      {
2676
        serverLocation = rs.getInt(1);
2677
        pStmt.close();
2678
      }
2679
      else
2680
      {
2681
        //if htere is no entry in xml_documents, we consider it is new document
2682
        //the server location is local host and value is 1
2683
        serverLocation=1;
2684
        pStmt.close();
2685
      }
2686
    }//try
2687
    finally
2688
    {
2689
      try
2690
      {
2691
        pStmt.close();
2692
      }//try
2693
      catch (Exception ee)
2694
      {
2695
        MetaCatUtil.debugMessage("Error in DocumentImpl.getServerLocationNu(): "
2696
                                    +ee.getMessage(), 50);
2697
      }//catch
2698
      finally
2699
      {
2700
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2701
      }//finally
2702
    }//finally
2703
      
2704
    return serverLocation;
2705
  }
2706
  
2707
  /**
2708
   * Given a server name, return its servercode in xml_replication table.
2709
   * If no server is found, -1 will return
2710
   * @param serverName, 
2711
   */
2712
  private static int getServerCode(String serverName) 
2713
  {
2714
    PreparedStatement pStmt=null;
2715
    int serverLocation=-2;
2716
    DBConnection dbConn = null;
2717
    int serialNumber = -1;
2718
    //MetaCatUtil util = new MetaCatUtil();
2719
    
2720
    
2721
    //we should consider about local host too
2722
    if (serverName.equals(MetaCatUtil.getLocalReplicationServerName()))
2723
    { 
2724
      serverLocation=1;
2725
      return serverLocation;
2726
    }
2727
    
2728
   
2729
    try
2730
    {
2731
      //check xml_replication table
2732
      //dbConn=util.openDBConnection();
2733
      //check out DBConnection
2734
      dbConn=DBConnectionPool.getDBConnection("DocumentImpl.getServerCode");
2735
      serialNumber=dbConn.getCheckOutSerialNumber();
2736
      pStmt = dbConn.prepareStatement
2737
      ("SELECT serverid FROM xml_replication WHERE server='" + serverName +"'");
2738
      pStmt.execute();
2739

    
2740
      ResultSet rs = pStmt.getResultSet();
2741
      boolean hasRow = rs.next();
2742
      //if there is entry in xml_replication, get the serverid
2743
      if (hasRow)
2744
      {
2745
        serverLocation = rs.getInt(1);
2746
        pStmt.close();
2747
      }
2748
      else
2749
      {
2750
        // if htere is no entry in xml_replication, -1 will return
2751
        serverLocation=-1;
2752
        pStmt.close();
2753
      }
2754
    }
2755
    catch (Exception e)
2756
    {
2757
      MetaCatUtil.debugMessage("Error in DocumentImpl.getServerCode(): "
2758
                                    +e.getMessage(), 30);
2759
    }
2760
    finally
2761
    {
2762
      try
2763
      {
2764
        pStmt.close();
2765
      }
2766
      catch (Exception ee)
2767
      {
2768
        MetaCatUtil.debugMessage("Error in DocumentImpl.getServerCode(): "
2769
                                    +ee.getMessage(), 50);
2770
      }
2771
      finally
2772
      {
2773
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2774
      }
2775
    }
2776
                 
2777
      
2778
    return serverLocation;
2779
  }
2780
  
2781
  /**
2782
   * Insert a server into xml_replcation table
2783
   * @param server, the name of server 
2784
   */
2785
  private static synchronized void 
2786
                                insertServerIntoReplicationTable(String server)
2787
  {
2788
    PreparedStatement pStmt=null;
2789
    DBConnection dbConn = null;
2790
    int serialNumber = -1;
2791
    
2792
    // Initial value for the server
2793
    int replicate = 0;
2794
    int dataReplicate = 0;
2795
    int hub = 0;
2796
   
2797
    try
2798
    {
2799
       // Get DBConnection
2800
       dbConn=DBConnectionPool.
2801
                getDBConnection("DocumentImpl.insertServIntoReplicationTable");
2802
       serialNumber=dbConn.getCheckOutSerialNumber();
2803
      
2804
      // Compare the server to dabase
2805
      pStmt = dbConn.prepareStatement
2806
      ("SELECT serverid FROM xml_replication WHERE server='" + server +"'");
2807
      pStmt.execute();
2808
      ResultSet rs = pStmt.getResultSet();
2809
      boolean hasRow = rs.next();
2810
      // Close preparedstatement and result set
2811
      pStmt.close();
2812
      rs.close();
2813
      
2814
      // If the server is not in the table, and server is not local host,
2815
      // insert it
2816
      if ( !hasRow 
2817
         && !server.equals(MetaCatUtil.getLocalReplicationServerName()))
2818
      {
2819
        // Set auto commit false
2820
        dbConn.setAutoCommit(false);
2821
        /*pStmt = dbConn.prepareStatement("INSERT INTO xml_replication " +
2822
                      "(server, last_checked, replicate, datareplicate, hub) " +
2823
                       "VALUES ('" + server + "', to_date(" +
2824
                       "'01/01/00', 'MM/DD/YY'), '" +
2825
                       replicate +"', '"+dataReplicate+"','"+ hub + "')");*/
2826
        pStmt = dbConn.prepareStatement("INSERT INTO xml_replication " +
2827
                      "(server, last_checked, replicate, datareplicate, hub) " +
2828
                       "VALUES ('" + server + "', " + 
2829
                       dbAdapter.toDate("01/01/1980", "MM/DD/YYYY") + ", '" +
2830
                       replicate +"', '"+dataReplicate+"','"+ hub + "')");
2831
        
2832
                              
2833
        pStmt.execute();
2834
        dbConn.commit();
2835
        // Increase usage number
2836
        dbConn.increaseUsageCount(1);
2837
        pStmt.close();
2838
        
2839
      }
2840
    }//try
2841
    catch (Exception e)
2842
    {
2843
      MetaCatUtil.debugMessage("Error in DocumentImpl.insertServerIntoRepli(): "
2844
                                    +e.getMessage(), 30);
2845
    }//catch
2846
    finally
2847
    {
2848
     
2849
      try
2850
      {
2851
        // Set auto commit true
2852
        dbConn.setAutoCommit(true);
2853
        pStmt.close();
2854
        
2855
      }//try
2856
      catch (Exception ee)
2857
      {
2858
        MetaCatUtil.debugMessage("Error in DocumentImpl.insetServerIntoRepl(): "
2859
                                    +ee.getMessage(), 50);
2860
      }//catch
2861
      finally
2862
      {
2863
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2864
      }
2865
    
2866
    }//finally
2867

    
2868
  }
2869
  
2870
  
2871
  /**
2872
   * the main routine used to test the DBWriter utility.
2873
   * <p>
2874
   * Usage: java DocumentImpl <-f filename -a action -d docid>
2875
   *
2876
   * @param filename the filename to be loaded into the database
2877
   * @param action the action to perform (READ, INSERT, UPDATE, DELETE)
2878
   * @param docid the id of the document to process
2879
   */
2880
  static public void main(String[] args) {
2881
    DBConnection dbconn = null;
2882
    int serialNumber = -1;
2883
    try {
2884
      String filename    = null;
2885
      String dtdfilename = null;
2886
      String action      = null;
2887
      String docid       = null;
2888
      boolean showRuntime = false;
2889
      boolean useOldReadAlgorithm = false;
2890

    
2891
      // Parse the command line arguments
2892
      for ( int i=0 ; i < args.length; ++i ) {
2893
        if ( args[i].equals( "-f" ) ) {
2894
          filename =  args[++i];
2895
        } else if ( args[i].equals( "-r" ) ) {
2896
          dtdfilename =  args[++i];
2897
        } else if ( args[i].equals( "-a" ) ) {
2898
          action =  args[++i];
2899
        } else if ( args[i].equals( "-d" ) ) {
2900
          docid =  args[++i];
2901
        } else if ( args[i].equals( "-t" ) ) {
2902
          showRuntime = true;
2903
        } else if ( args[i].equals( "-old" ) ) {
2904
          useOldReadAlgorithm = true;
2905
        } else {
2906
          System.err.println
2907
            ( "   args[" +i+ "] '" +args[i]+ "' ignored." );
2908
        }
2909
      }
2910
      
2911
      // Check if the required arguments are provided
2912
      boolean argsAreValid = false;
2913
      if (action != null) {
2914
        if (action.equals("INSERT")) {
2915
          if (filename != null) {
2916
            argsAreValid = true;
2917
          } 
2918
        } else if (action.equals("UPDATE")) {
2919
          if ((filename != null) && (docid != null)) {
2920
            argsAreValid = true;
2921
          } 
2922
        } else if (action.equals("DELETE")) {
2923
          if (docid != null) {
2924
            argsAreValid = true;
2925
          } 
2926
        } else if (action.equals("READ")) {
2927
          if (docid != null) {
2928
            argsAreValid = true;
2929
          } 
2930
        } 
2931
      } 
2932

    
2933
      // Print usage message if the arguments are not valid
2934
      if (!argsAreValid) {
2935
        System.err.println("Wrong number of arguments!!!");
2936
        System.err.println(
2937
          "USAGE: java DocumentImpl [-t] <-a INSERT> [-d docid] <-f filename> "+
2938
          "[-r dtdfilename]");
2939
        System.err.println(
2940
          "   OR: java DocumentImpl [-t] <-a UPDATE -d docid -f filename> " +
2941
          "[-r dtdfilename]");
2942
        System.err.println(
2943
          "   OR: java DocumentImpl [-t] <-a DELETE -d docid>");
2944
        System.err.println(
2945
          "   OR: java DocumentImpl [-t] [-old] <-a READ -d docid>");
2946
        return;
2947
      }
2948
      
2949
      // Time the request if asked for
2950
      double startTime = System.currentTimeMillis();
2951
      
2952
      // Open a connection to the database
2953
      MetaCatUtil util = new MetaCatUtil();
2954
     
2955
      dbconn=DBConnectionPool.getDBConnection("DocumentImpl.main");
2956
      serialNumber=dbconn.getCheckOutSerialNumber();
2957

    
2958
      double connTime = System.currentTimeMillis();
2959
      // Execute the action requested (READ, INSERT, UPDATE, DELETE)
2960
      if (action.equals("READ")) {
2961
          DocumentImpl xmldoc = new DocumentImpl(docid );
2962
          if (useOldReadAlgorithm) {
2963
            System.out.println(xmldoc.readUsingSlowAlgorithm());
2964
          } else {
2965
            xmldoc.toXml(new PrintWriter(System.out), null, null, true);
2966
          }
2967
      } else if (action.equals("DELETE")) {
2968
        DocumentImpl.delete(docid, null, null);
2969
        System.out.println("Document deleted: " + docid);
2970
      } else {
2971
        /*String newdocid = DocumentImpl.write(dbconn, filename, null,
2972
                                             dtdfilename, action, docid,
2973
                                             null, null);
2974
        if ((docid != null) && (!docid.equals(newdocid))) {
2975
          if (action.equals("INSERT")) {
2976
            System.out.println("New document ID generated!!! ");
2977
          } else if (action.equals("UPDATE")) {
2978
            System.out.println("ERROR: Couldn't update document!!! ");
2979
          }
2980
        } else if ((docid == null) && (action.equals("UPDATE"))) {
2981
          System.out.println("ERROR: Couldn't update document!!! ");
2982
        }
2983
        System.out.println("Document processing finished for: " + filename
2984
              + " (" + newdocid + ")");*/
2985
      }
2986

    
2987
      double stopTime = System.currentTimeMillis();
2988
      double dbOpenTime = (connTime - startTime)/1000;
2989
      double insertTime = (stopTime - connTime)/1000;
2990
      double executionTime = (stopTime - startTime)/1000;
2991
      if (showRuntime) {
2992
        System.out.println("\n\nTotal Execution time was: " + 
2993
                           executionTime + " seconds.");
2994
        System.out.println("Time to open DB connection was: " + dbOpenTime + 
2995
                           " seconds.");
2996
        System.out.println("Time to insert document was: " + insertTime +
2997
                           " seconds.");
2998
      }
2999
      dbconn.close();
3000
    } catch (McdbException me) {
3001
      me.toXml(new PrintWriter(System.err));
3002
    } catch (AccessionNumberException ane) {
3003
      System.out.println(ane.getMessage());
3004
    } catch (Exception e) {
3005
      System.err.println("EXCEPTION HANDLING REQUIRED");
3006
      System.err.println(e.getMessage());
3007
      e.printStackTrace(System.err);
3008
    }
3009
    finally
3010
    {
3011
      // Return db connection
3012
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
3013
    }
3014
  }
3015
}
(31-31/57)