Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that represents an XML document
4
 *  Copyright: 2000 Regents of the University of California and the
5
 *             National Center for Ecological Analysis and Synthesis
6
 *    Authors: Matt Jones
7
 *    Release: @release@
8
 *
9
 *   '$Author: tao $'
10
 *     '$Date: 2003-07-30 09:04:09 -0700 (Wed, 30 Jul 2003) $'
11
 * '$Revision: 1766 $'
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
        try 
1716
        {
1717
          //System.out.println("In lockgranted");
1718
          MetacatReplication.replLog("lock granted for " + accnum + " from " +
1719
                                      server);
1720
          /*XMLReader parser = initializeParser(conn, action, docid, updaterev,
1721
                               validate, user, groups, pub, serverCode, dtd);*/
1722
          XMLReader parser = initializeParser(conn, action, docid, updaterev,
1723
                                        user, groups, pub, serverCode, 
1724
                                        dtd,ruleBase, needValidation); 
1725
          conn.setAutoCommit(false);
1726
          parser.parse(new InputSource(xml)); 
1727
          conn.commit();
1728
          conn.setAutoCommit(true);
1729
        } 
1730
        catch (Exception e) 
1731
        {
1732
          conn.rollback();
1733
          conn.setAutoCommit(true);
1734
          throw e;
1735
        }
1736
        // run write into access db base one relation table and access object 
1737
        runRelationAndAccessHandler(accnum, user, groups, serverCode);
1738
        
1739
        // Force replication the docid
1740
        ForceReplicationHandler frh = new ForceReplicationHandler
1741
                                                          (accnum, true, null);
1742
        return(accnum);
1743
   
1744
      }
1745

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

    
1773
      if ( !hasWritePermission(user, groups, docid) ) {
1774
        throw new Exception("User " + user + 
1775
              " does not have permission to update XML Document #" + accnum);
1776
      }          
1777
    }
1778

    
1779
    try 
1780
    { 
1781
      
1782
      XMLReader parser = initializeParser(conn, action, docid, rev, 
1783
                                          user, groups, pub, serverCode, 
1784
                                          dtd, ruleBase, needValidation);
1785
   
1786
      conn.setAutoCommit(false);
1787
      parser.parse(new InputSource(xml));
1788
      conn.commit();
1789
      conn.setAutoCommit(true);
1790
    } 
1791
    catch (Exception e) 
1792
    {
1793
      conn.rollback();
1794
      conn.setAutoCommit(true);
1795
      throw e;
1796
    }
1797
    
1798
    // run access db base on relation table and access object       
1799
    runRelationAndAccessHandler(accnum, user, groups, serverCode);
1800
    
1801
    // Force replicate out the new document to each server in our server list.
1802
    // Start the thread to replicate this new document out to the other servers
1803
    // true mean it is xml document
1804
    // null is because no metacat notify the force replication.
1805
    ForceReplicationHandler frh = new ForceReplicationHandler
1806
                                                  (accnum, action, true, null);
1807
      
1808
   
1809
    MetaCatUtil.debugMessage("Conn Usage count after writting: "
1810
                                                      +conn.getUsageCount(),50); 
1811
    return(accnum);
1812
  }
1813

    
1814
  /**
1815
   * Write an XML file to the database during replication
1816
   *
1817
   * @param conn the JDBC connection to the database
1818
   * @param xml the xml stream to be loaded into the database
1819
   * @param pub flag for public "read" access on xml document
1820
   * @param dtd the dtd to be uploaded on server's file system
1821
   * @param action the action to be performed (INSERT or UPDATE)
1822
   * @param accnum the docid + rev# to use on INSERT or UPDATE
1823
   * @param user the user that owns the document
1824
   * @param groups the groups to which user belongs
1825
   * @param homeServer the name of server which the document origanlly create
1826
   * @param validate, if the xml document is valid or not
1827
   * @param notifyServer, the server which notify local server the force 
1828
   *                       replication command
1829
   */
1830

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

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

    
2097
      // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
2098
      AccessionNumber ac = new AccessionNumber(accnum, "DELETE");
2099
      String docid = ac.getDocid();
2100
      String rev = ac.getRev();
2101
    
2102
      MetaCatUtil.debugMessage("Start deleting doc "+docid+ "...", 20);
2103
    // check for 'write' permission for 'user' to delete this document
2104
      if ( !hasWritePermission(user, groups, docid) ) {
2105
        throw new Exception("User " + user + 
2106
              " does not have permission to delete XML Document #" + accnum);
2107
      }
2108

    
2109
      conn.setAutoCommit(false);
2110
      // Copy the record to the xml_revisions table
2111
      DocumentImpl.archiveDocRevision(conn, docid, user );
2112

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

    
2185
  /** 
2186
    * Check for "WRITE" permission on @docid for @user and/or @groups 
2187
    * from DB connection 
2188
    */
2189
  private static boolean hasWritePermission (String user,
2190
                                  String[] groups, String docid ) 
2191
                  throws SQLException, Exception
2192
  {
2193
    // Check for WRITE permission on @docid for @user and/or @groups
2194
    PermissionController controller = new PermissionController(docid);
2195
    return controller.hasPermission(user,groups,
2196
                                    AccessControlInterface.WRITESTRING);
2197
  }
2198

    
2199
  /** 
2200
    * Check for "READ" permission base on docid, user and group
2201
    *@docid, the document
2202
    *@user, user name
2203
    *@group, user's group
2204
    * 
2205
    */
2206
  public static boolean hasReadPermission (String user,
2207
                                  String[] groups, String docId ) 
2208
                  throws SQLException, Exception
2209
  {
2210
    // Check for READ permission on @docid for @user and/or @groups
2211
    PermissionController controller = 
2212
                        new PermissionController(docId);
2213
    return controller.hasPermission(user,groups,
2214
                                            AccessControlInterface.READSTRING);
2215
  }  
2216

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

    
2326
  
2327
  /**
2328
   * Set up the parser handlers for writing the document to the database
2329
   */
2330
  /*private static XMLReader initializeParser(DBConnection dbconn, String action,
2331
                               String docid, String rev, boolean validate, 
2332
                                   String user, String[] groups, String pub, 
2333
                                   int serverCode, Reader dtd) 
2334
                           throws Exception 
2335
  {
2336
    XMLReader parser = null;
2337
    //DBConnection conn = null;
2338
    //int serialNumber = -1;
2339
    //
2340
    // Set up the SAX document handlers for parsing
2341
    //
2342
    try {
2343
       //check out DBConnection
2344
     
2345
      //create a DBSAXHandler object which has the revision specification
2346
      ContentHandler chandler = new DBSAXHandler(dbconn, action, 
2347
                                    docid, rev, user, groups, pub, serverCode);
2348
      EntityResolver eresolver= new DBEntityResolver(dbconn,
2349
                                                 (DBSAXHandler)chandler, dtd);
2350
      DTDHandler dtdhandler   = new DBDTDHandler(dbconn);
2351

    
2352
      // Get an instance of the parser
2353
      String parserName = MetaCatUtil.getOption("saxparser");
2354
      parser = XMLReaderFactory.createXMLReader(parserName);
2355

    
2356
      // Turn on validation
2357
      parser.setFeature("http://xml.org/sax/features/validation", validate);
2358
      // Turn off Including all external parameter entities
2359
      // (the external DTD subset also)
2360
      // Doesn't work well, probably the feature name is not correct
2361
      // parser.setFeature(
2362
      //  "http://xml.org/sax/features/external-parameter-entities", false);
2363
      
2364
      // Set Handlers in the parser
2365
      parser.setProperty("http://xml.org/sax/properties/declaration-handler",
2366
                         chandler);
2367
      parser.setProperty("http://xml.org/sax/properties/lexical-handler",
2368
                         chandler);
2369
      parser.setContentHandler((ContentHandler)chandler);
2370
      parser.setEntityResolver((EntityResolver)eresolver);
2371
      parser.setDTDHandler((DTDHandler)dtdhandler);
2372
      parser.setErrorHandler((ErrorHandler)chandler);
2373

    
2374
    } catch (Exception e) {
2375
      throw e;
2376
    }
2377
    //finally
2378
    //{
2379
      //DBConnectionPool.returnDBConnection(conn, serialNumber);
2380
    //}
2381

    
2382
    return parser;
2383
  }*/
2384

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

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

    
2510
  }//achiveDocRevision
2511
  
2512
  /**
2513
    * delete a entry in xml_table for given docid
2514
    * @param docId, the id of the document need to be delete
2515
    */
2516
  private static void deleteXMLDocuments(String docId) 
2517
                                         throws SQLException 
2518
  {
2519
    DBConnection conn = null;
2520
    int serialNumber = -1;
2521
    PreparedStatement pStmt = null;
2522
    try
2523
    {
2524
      //check out DBConnection
2525
      conn=DBConnectionPool.
2526
                    getDBConnection("DocumentImpl.deleteXMLDocuments");
2527
      serialNumber=conn.getCheckOutSerialNumber();
2528
      //delete a record 
2529
      pStmt = 
2530
             conn.prepareStatement("DELETE FROM xml_documents WHERE docid = '" 
2531
                                              + docId + "'");
2532
    pStmt.execute();
2533
    }//try
2534
    finally
2535
    {
2536
      try
2537
      {
2538
        pStmt.close();
2539
      }//try
2540
      catch (SQLException e)
2541
      {
2542
        MetaCatUtil.debugMessage("error in DocumentImpl.deleteXMLDocuments: "+
2543
                                  e.getMessage(), 50);
2544
      }//catch
2545
      finally
2546
      {
2547
        //return back DBconnection
2548
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2549
      }//finally
2550
    }//finally
2551
      
2552

    
2553
  }//deleteXMLDocuments
2554
  
2555
  /**
2556
    * Get last revision number from database for a docid
2557
    * If couldn't find an entry,  -1 will return
2558
    * The return value is integer because we want compare it to there new one
2559
    * @param docid <sitecode>.<uniqueid> part of Accession Number
2560
    */
2561
  public static int getLatestRevisionNumber(String docId)
2562
                                      throws SQLException
2563
  {
2564
    int rev = 1;
2565
    PreparedStatement pStmt = null;
2566
    DBConnection dbConn = null;
2567
    int serialNumber = -1;
2568
    // get rid of rev
2569
    docId = MetaCatUtil.getDocIdFromString(docId);
2570
    try
2571
    {
2572
      //check out DBConnection
2573
      dbConn=DBConnectionPool.
2574
                    getDBConnection("DocumentImpl.getLatestRevisionNumber");
2575
      serialNumber=dbConn.getCheckOutSerialNumber();
2576
     
2577
      pStmt = dbConn.prepareStatement
2578
              ("SELECT rev FROM xml_documents WHERE docid='" + docId + "'");
2579
      pStmt.execute();
2580

    
2581
      ResultSet rs = pStmt.getResultSet();
2582
      boolean hasRow = rs.next();
2583
      if (hasRow)
2584
      {
2585
        rev = rs.getInt(1);
2586
        pStmt.close();
2587
      }
2588
      else
2589
      {
2590
        rev=-1;
2591
        pStmt.close();
2592
      }
2593
    }//try
2594
    finally
2595
    {
2596
      try
2597
      {
2598
        pStmt.close();
2599
      }
2600
      catch (Exception ee)
2601
      {
2602
        MetaCatUtil.debugMessage("Error in DocumentImpl."+
2603
                        "getLatestRevisionNumber: "+ee.getMessage(), 50);
2604
      }
2605
      finally
2606
      {
2607
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2608
      }
2609
    }//finally  
2610
      
2611
    return rev;
2612
  }//getLatestRevisionNumber
2613
  
2614
  /**
2615
   * Get server location form database for a accNum
2616
   * 
2617
   * @param accum <sitecode>.<uniqueid>.<rev>
2618
   */
2619
  private static int getServerLocationNumber(String accNum)
2620
                                            throws SQLException
2621
  {
2622
    //get rid of revNum part
2623
    String docId=MetaCatUtil.getDocIdFromString(accNum);
2624
    PreparedStatement pStmt = null;
2625
    int serverLocation = 1;
2626
    DBConnection conn = null;
2627
    int serialNumber = -1;
2628
    
2629
    try
2630
    {
2631
      //check out DBConnection
2632
      conn=DBConnectionPool.
2633
                    getDBConnection("DocumentImpl.getServerLocationNumber");
2634
      serialNumber=conn.getCheckOutSerialNumber();
2635
     
2636
      pStmt = conn.prepareStatement
2637
      ("SELECT server_location FROM xml_documents WHERE docid='" + docId + "'");
2638
      pStmt.execute();
2639

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

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

    
2837
  }
2838
  
2839
  
2840
  /**
2841
   * the main routine used to test the DBWriter utility.
2842
   * <p>
2843
   * Usage: java DocumentImpl <-f filename -a action -d docid>
2844
   *
2845
   * @param filename the filename to be loaded into the database
2846
   * @param action the action to perform (READ, INSERT, UPDATE, DELETE)
2847
   * @param docid the id of the document to process
2848
   */
2849
  static public void main(String[] args) {
2850
    DBConnection dbconn = null;
2851
    int serialNumber = -1;
2852
    try {
2853
      String filename    = null;
2854
      String dtdfilename = null;
2855
      String action      = null;
2856
      String docid       = null;
2857
      boolean showRuntime = false;
2858
      boolean useOldReadAlgorithm = false;
2859

    
2860
      // Parse the command line arguments
2861
      for ( int i=0 ; i < args.length; ++i ) {
2862
        if ( args[i].equals( "-f" ) ) {
2863
          filename =  args[++i];
2864
        } else if ( args[i].equals( "-r" ) ) {
2865
          dtdfilename =  args[++i];
2866
        } else if ( args[i].equals( "-a" ) ) {
2867
          action =  args[++i];
2868
        } else if ( args[i].equals( "-d" ) ) {
2869
          docid =  args[++i];
2870
        } else if ( args[i].equals( "-t" ) ) {
2871
          showRuntime = true;
2872
        } else if ( args[i].equals( "-old" ) ) {
2873
          useOldReadAlgorithm = true;
2874
        } else {
2875
          System.err.println
2876
            ( "   args[" +i+ "] '" +args[i]+ "' ignored." );
2877
        }
2878
      }
2879
      
2880
      // Check if the required arguments are provided
2881
      boolean argsAreValid = false;
2882
      if (action != null) {
2883
        if (action.equals("INSERT")) {
2884
          if (filename != null) {
2885
            argsAreValid = true;
2886
          } 
2887
        } else if (action.equals("UPDATE")) {
2888
          if ((filename != null) && (docid != null)) {
2889
            argsAreValid = true;
2890
          } 
2891
        } else if (action.equals("DELETE")) {
2892
          if (docid != null) {
2893
            argsAreValid = true;
2894
          } 
2895
        } else if (action.equals("READ")) {
2896
          if (docid != null) {
2897
            argsAreValid = true;
2898
          } 
2899
        } 
2900
      } 
2901

    
2902
      // Print usage message if the arguments are not valid
2903
      if (!argsAreValid) {
2904
        System.err.println("Wrong number of arguments!!!");
2905
        System.err.println(
2906
          "USAGE: java DocumentImpl [-t] <-a INSERT> [-d docid] <-f filename> "+
2907
          "[-r dtdfilename]");
2908
        System.err.println(
2909
          "   OR: java DocumentImpl [-t] <-a UPDATE -d docid -f filename> " +
2910
          "[-r dtdfilename]");
2911
        System.err.println(
2912
          "   OR: java DocumentImpl [-t] <-a DELETE -d docid>");
2913
        System.err.println(
2914
          "   OR: java DocumentImpl [-t] [-old] <-a READ -d docid>");
2915
        return;
2916
      }
2917
      
2918
      // Time the request if asked for
2919
      double startTime = System.currentTimeMillis();
2920
      
2921
      // Open a connection to the database
2922
      MetaCatUtil util = new MetaCatUtil();
2923
     
2924
      dbconn=DBConnectionPool.getDBConnection("DocumentImpl.main");
2925
      serialNumber=dbconn.getCheckOutSerialNumber();
2926

    
2927
      double connTime = System.currentTimeMillis();
2928
      // Execute the action requested (READ, INSERT, UPDATE, DELETE)
2929
      if (action.equals("READ")) {
2930
          DocumentImpl xmldoc = new DocumentImpl(docid );
2931
          if (useOldReadAlgorithm) {
2932
            System.out.println(xmldoc.readUsingSlowAlgorithm());
2933
          } else {
2934
            xmldoc.toXml(new PrintWriter(System.out), null, null, true);
2935
          }
2936
      } else if (action.equals("DELETE")) {
2937
        DocumentImpl.delete(docid, null, null);
2938
        System.out.println("Document deleted: " + docid);
2939
      } else {
2940
        /*String newdocid = DocumentImpl.write(dbconn, filename, null,
2941
                                             dtdfilename, action, docid,
2942
                                             null, null);
2943
        if ((docid != null) && (!docid.equals(newdocid))) {
2944
          if (action.equals("INSERT")) {
2945
            System.out.println("New document ID generated!!! ");
2946
          } else if (action.equals("UPDATE")) {
2947
            System.out.println("ERROR: Couldn't update document!!! ");
2948
          }
2949
        } else if ((docid == null) && (action.equals("UPDATE"))) {
2950
          System.out.println("ERROR: Couldn't update document!!! ");
2951
        }
2952
        System.out.println("Document processing finished for: " + filename
2953
              + " (" + newdocid + ")");*/
2954
      }
2955

    
2956
      double stopTime = System.currentTimeMillis();
2957
      double dbOpenTime = (connTime - startTime)/1000;
2958
      double insertTime = (stopTime - connTime)/1000;
2959
      double executionTime = (stopTime - startTime)/1000;
2960
      if (showRuntime) {
2961
        System.out.println("\n\nTotal Execution time was: " + 
2962
                           executionTime + " seconds.");
2963
        System.out.println("Time to open DB connection was: " + dbOpenTime + 
2964
                           " seconds.");
2965
        System.out.println("Time to insert document was: " + insertTime +
2966
                           " seconds.");
2967
      }
2968
      dbconn.close();
2969
    } catch (McdbException me) {
2970
      me.toXml(new PrintWriter(System.err));
2971
    } catch (AccessionNumberException ane) {
2972
      System.out.println(ane.getMessage());
2973
    } catch (Exception e) {
2974
      System.err.println("EXCEPTION HANDLING REQUIRED");
2975
      System.err.println(e.getMessage());
2976
      e.printStackTrace(System.err);
2977
    }
2978
    finally
2979
    {
2980
      // Return db connection
2981
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
2982
    }
2983
  }
2984
}
(31-31/57)