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: 2004-03-15 14:08:39 -0800 (Mon, 15 Mar 2004) $'
11
 * '$Revision: 2045 $'
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
  public static final String DOCNAME = "docname";
98
  public static final String PUBLICID = "publicid";
99
  public static final String SYSTEMID = "systemid";
100
  static final int ALL = 1;
101
  static final int WRITE = 2;
102
  static final int READ = 4;
103
  private static final AbstractDatabase dbAdapter = MetaCatUtil.dbAdapter;
104

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
848
  /**
849
   * Print a text representation of the XML document to a Writer
850
   *
851
   * @param pw the Writer to which we print the document
852
   */
853
  public void toXml(Writer pw, String user, String[] groups, boolean withInLineData) 
854
                                                          throws McdbException
855
  {
856
    // flag for process  eml2
857
    boolean proccessEml2 = false;
858
    boolean storedDTD = false;//flag to inidate publicid or system 
859
                              // id stored in db or not
860
    boolean firstElement = true;
861
    String dbDocName = null;
862
    String dbPublicID = null;
863
    String dbSystemID = null;
864
    
865
    if (doctype != null && doctype.equals(EMLNAMESPACE))
866
    {
867
      proccessEml2 = true;
868
    }
869
    // flag for process inline data
870
    boolean prcocessInlineData = false;
871
    
872
    TreeSet nodeRecordLists = null;
873
    PrintWriter out = null;
874
    if (pw instanceof PrintWriter) {
875
      out = (PrintWriter)pw;
876
    } else {
877
      out = new PrintWriter(pw);
878
    }
879

    
880
    MetaCatUtil util = new MetaCatUtil();
881
    
882
    // Here add code to handle subtree access control
883
    PermissionController control = new PermissionController(docid);
884
    Hashtable unaccessableSubTree =control.hasUnaccessableSubTree(user, groups, 
885
                                             AccessControlInterface.READSTRING);
886
    
887
    if (!unaccessableSubTree.isEmpty())
888
    {
889
     
890
      nodeRecordLists = getPartNodeRecordList(rootnodeid, unaccessableSubTree);
891
      
892
    }
893
    else 
894
    {
895
      nodeRecordLists = getNodeRecordList(rootnodeid);
896
    }
897

    
898
    Stack openElements = new Stack();
899
    boolean atRootElement = true;
900
    boolean previousNodeWasElement = false;
901

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

    
950
      // Handle the DOCUMENT node
951
      if (currentNode.nodetype.equals("DOCUMENT")) {
952
        out.print("<?xml version=\"1.0\"?>");
953
       
954

    
955
      // Handle the ELEMENT nodes
956
      } else if (currentNode.nodetype.equals("ELEMENT")) {
957
        if (atRootElement) {
958
          atRootElement = false;
959
        } else {
960
          if (previousNodeWasElement) {
961
            out.print(">");
962
          }
963
        }
964
        
965
        // if publicid or system is not stored into db send it out by default
966
        if ( !storedDTD & firstElement )
967
        {
968
           if (docname != null && validateType != null && validateType.equals(DTD)) 
969
           {
970
              if ((doctype != null) && (system_id != null)) 
971
              {
972
            
973
                  out.print("<!DOCTYPE " + docname + " PUBLIC \"" + doctype + 
974
                       "\" \"" + system_id + "\">");
975
               } 
976
               else 
977
               {
978
            
979
                  out.print("<!DOCTYPE " + docname + ">");
980
               }
981
           }
982
        }
983
        firstElement = false;
984
        openElements.push(currentNode);
985
        util.debugMessage("\n PUSHED: " + currentNode.nodename, 50);
986
        previousNodeWasElement = true;
987
        if ( currentNode.nodeprefix != null ) {
988
          out.print("<" + currentNode.nodeprefix + ":" + currentNode.nodename);
989
        } else {
990
          out.print("<" + currentNode.nodename);
991
        }
992
        
993
        // if currentNode is inline and handle eml2, set flag proccess in
994
        if (currentNode.nodename != null && 
995
            currentNode.nodename.equals(EmlSAXHandler.INLINE) && proccessEml2)
996
        {
997
          prcocessInlineData = true;
998
        }
999

    
1000
      // Handle the ATTRIBUTE nodes
1001
      } else if (currentNode.nodetype.equals("ATTRIBUTE")) {
1002
        if ( currentNode.nodeprefix != null ) {
1003
          out.print(" " + currentNode.nodeprefix + ":" + currentNode.nodename +
1004
                    "=\"" + currentNode.nodedata + "\"");
1005
        } else {
1006
          out.print(" " + currentNode.nodename + "=\"" +
1007
                    currentNode.nodedata + "\"");
1008
        }
1009

    
1010
      // Handle the NAMESPACE nodes
1011
      } else if (currentNode.nodetype.equals("NAMESPACE")) {
1012
        out.print(" xmlns:" + currentNode.nodename + "=\""
1013
                 + currentNode.nodedata + "\"");
1014

    
1015
      // Handle the TEXT nodes
1016
      } else if (currentNode.nodetype.equals("TEXT")) {
1017
        if (previousNodeWasElement) {
1018
          out.print(">");
1019
        }
1020
        if (!prcocessInlineData || !withInLineData)
1021
        {
1022
          // if it is not inline data just out put data or it is line data
1023
          // but user don't want it, just put local id in inlinedata
1024
          out.print(currentNode.nodedata);
1025
        }
1026
        else
1027
        {
1028
          // if it is inline data and user want to see it, pull out from 
1029
          // file system and output it
1030
          // for inline data, the data base only store the file name, so we
1031
          // can combine the file name and inline data file path, to get it
1032
          String fileName = currentNode.nodedata;
1033
          Reader reader = 
1034
                          EmlSAXHandler.readInlineDataFromFileSystem(fileName);
1035
          char [] characterArray = new char [4*1024];
1036
          try
1037
          {
1038
            int length = reader.read(characterArray);
1039
            while ( length != -1)
1040
            {
1041
              out.print(new String(characterArray, 0, length));
1042
              out.flush();
1043
              length = reader.read(characterArray);
1044
            }
1045
            reader.close();
1046
          }
1047
          catch (IOException e)
1048
          {
1049
            throw new McdbException(e.getMessage());
1050
          }
1051
        }
1052
        
1053
        // reset proccess inline data false
1054
        prcocessInlineData =false;
1055
        previousNodeWasElement = false;
1056

    
1057
      // Handle the COMMENT nodes
1058
      } else if (currentNode.nodetype.equals("COMMENT")) {
1059
        if (previousNodeWasElement) {
1060
          out.print(">");
1061
        }
1062
        out.print("<!--" + currentNode.nodedata + "-->");
1063
        previousNodeWasElement = false;
1064

    
1065
      // Handle the PI nodes
1066
      } else if (currentNode.nodetype.equals("PI")) {
1067
        if (previousNodeWasElement) {
1068
          out.print(">");
1069
        }
1070
        out.print("<?" + currentNode.nodename + " " +
1071
                        currentNode.nodedata + "?>");
1072
        previousNodeWasElement = false;
1073
     // Handle the DTD nodes (docname, publicid, systemid)  
1074
     } else if (currentNode.nodetype.equals(DTD)) {
1075
         storedDTD = true;
1076
         if (currentNode.getNodeName().equals(DOCNAME))
1077
         {
1078
           dbDocName = currentNode.getNodeData();
1079
         }
1080
         if (currentNode.getNodeName().equals(PUBLICID))
1081
         {
1082
           dbPublicID = currentNode.getNodeData();
1083
         }
1084
         if (currentNode.getNodeName().equals(SYSTEMID))
1085
         {
1086
           dbSystemID = currentNode.getNodeData();
1087
           // send out <!doctype .../>
1088
           if (dbDocName != null ) 
1089
           {
1090
              if ((dbPublicID!= null) && (dbSystemID != null)) 
1091
              {
1092
            
1093
                 out.print("<!DOCTYPE " + dbDocName+" PUBLIC \""+dbPublicID + 
1094
                       "\" \"" + dbSystemID + "\">");
1095
              } 
1096
              else 
1097
              {
1098
            
1099
                out.print("<!DOCTYPE " + dbDocName + ">");
1100
              }
1101
           }
1102
           
1103
           //reset these variable
1104
           dbDocName = null;
1105
           dbPublicID = null;
1106
           dbSystemID = null;
1107
         }
1108
       
1109
      // Handle any other node type (do nothing)
1110
      } else {
1111
        // Any other types of nodes are not handled.
1112
        // Probably should throw an exception here to indicate this
1113
      }
1114
      out.flush();
1115
    }
1116
    
1117
    // Print the final end tag for the root element
1118
    while(!openElements.empty())
1119
    {
1120
      NodeRecord currentElement = (NodeRecord)openElements.pop();
1121
      util.debugMessage("\n POPPED: " + currentElement.nodename, 50);
1122
      if ( currentElement.nodeprefix != null ) {
1123
        out.print("</" + currentElement.nodeprefix + ":" + 
1124
                  currentElement.nodename + ">" );
1125
      } else {
1126
        out.print("</" + currentElement.nodename + ">" );
1127
      }
1128
    }
1129
    out.flush();
1130
  }
1131
  
1132

    
1133
  
1134
  private boolean isRevisionOnly(DocumentIdentifier docid) throws Exception
1135
  {
1136
    //System.out.println("inRevisionOnly");
1137
    DBConnection dbconn = null;
1138
    int serialNumber = -1;
1139
    PreparedStatement pstmt =null;
1140
    String rev = docid.getRev();
1141
    String newid = docid.getIdentifier();
1142
    try
1143
    {
1144
      dbconn=DBConnectionPool.
1145
                    getDBConnection("DocumentImpl.isRevisionOnly");
1146
      serialNumber=dbconn.getCheckOutSerialNumber();
1147
      pstmt = dbconn.prepareStatement("select rev from xml_documents " +
1148
                                  "where docid like '" + newid + "'");
1149
      pstmt.execute();
1150
      ResultSet rs = pstmt.getResultSet();
1151
      boolean tablehasrows = rs.next();
1152
      if(rev.equals("newest") || rev.equals("all"))
1153
      {
1154
        return false;
1155
      }
1156
    
1157
      if(tablehasrows)
1158
      {
1159
        int r = rs.getInt(1);
1160
        pstmt.close();
1161
        if(new Integer(rev).intValue() == r)
1162
        { //the current revision in in xml_documents
1163
          //System.out.println("returning false");
1164
          return false;
1165
        }
1166
        else if(new Integer(rev).intValue() < r)
1167
        { //the current revision is in xml_revisions.
1168
          //System.out.println("returning true");
1169
          return true;
1170
        }
1171
        else if(new Integer(rev).intValue() > r)
1172
        { //error, rev cannot be greater than r
1173
          throw new Exception("requested revision cannot be greater than " +
1174
                            "the latest revision number.");
1175
        }
1176
      }
1177
      // Get miss docid and rev, throw to McdDocNotFoundException
1178
      String missDocId = MetaCatUtil.getDocIdFromString(docid.toString());
1179
      String missRevision = 
1180
                  MetaCatUtil.getRevisionStringFromString(docid.toString());
1181
      throw new McdbDocNotFoundException("the requested docid '" + 
1182
                docid.toString() + "' does not exist", missDocId, missRevision);
1183
    }//try
1184
    finally
1185
    {
1186
      pstmt.close();
1187
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1188
    }//finally
1189
  }
1190

    
1191
  private void getDocumentInfo(String docid) throws McdbException, 
1192
                                        AccessionNumberException, Exception
1193
  {
1194
    getDocumentInfo(new DocumentIdentifier(docid));
1195
  }
1196
  
1197
  /**
1198
   * Look up the document type information from the database
1199
   *
1200
   * @param docid the id of the document to look up
1201
   */
1202
  private void getDocumentInfo(DocumentIdentifier docid) throws McdbException
1203
                                                          , Exception
1204
  {
1205
    DBConnection dbconn = null;
1206
    int serialNumber = -1;
1207
    PreparedStatement pstmt = null;
1208
    String table = "xml_documents";
1209
        
1210
    try
1211
    {
1212
      if(isRevisionOnly(docid))
1213
      { //pull the document from xml_revisions instead of from xml_documents;
1214
        table = "xml_revisions";
1215
      }
1216
    }
1217
    // catch a McdbDocNotFoundException throw it
1218
    catch (McdbDocNotFoundException notFound)
1219
    {
1220
      throw notFound;
1221
    }
1222
    catch(Exception e)
1223
    {
1224
      
1225
      MetaCatUtil.debugMessage("error in DocumentImpl.getDocumentInfo: " + 
1226
                          e.getMessage(), 30);
1227
      throw e;
1228
    }
1229
    
1230

    
1231
    
1232
    try 
1233
    {
1234
      dbconn=DBConnectionPool.getDBConnection("DocumentImpl.getDocumentInfo");
1235
      serialNumber=dbconn.getCheckOutSerialNumber();
1236
      StringBuffer sql = new StringBuffer();
1237
// DOCTITLE attr cleared from the db
1238
//      sql.append("SELECT docname, doctype, rootnodeid, doctitle, ");
1239
      sql.append("SELECT docname, doctype, rootnodeid, ");
1240
      sql.append("date_created, date_updated, user_owner, user_updated, ");
1241
      sql.append("server_location, public_access, rev");
1242
      sql.append(" FROM ").append(table);
1243
      sql.append(" WHERE docid LIKE '").append(docid.getIdentifier());
1244
      sql.append("' and rev like '").append(docid.getRev()).append("'");
1245
      //System.out.println(sql.toString());
1246
      pstmt =
1247
        dbconn.prepareStatement(sql.toString());
1248
      // Bind the values to the query
1249
      //pstmt.setString(1, docid.getIdentifier());
1250
      //pstmt.setString(2, docid.getRev());
1251

    
1252
      pstmt.execute();
1253
      ResultSet rs = pstmt.getResultSet();
1254
      boolean tableHasRows = rs.next();
1255
      if (tableHasRows) {
1256
        this.docname        = rs.getString(1);
1257
        this.doctype        = rs.getString(2);
1258
        this.rootnodeid     = rs.getLong(3);
1259
// DOCTITLE attr cleared from the db
1260
//        this.doctitle       = rs.getString(4);
1261
        this.createdate     = rs.getString(4);
1262
        this.updatedate     = rs.getString(5);
1263
        this.userowner      = rs.getString(6);
1264
        this.userupdated    = rs.getString(7);
1265
        this.serverlocation = rs.getInt(8);
1266
        this.publicaccess   = rs.getString(9);
1267
        this.rev            = rs.getInt(10);
1268
      } 
1269
      pstmt.close();
1270
      
1271
      //get doc  home server name
1272
      
1273
      pstmt = dbconn.prepareStatement("select server " +
1274
                        "from xml_replication where serverid = ?");
1275
      //because connection use twise here, so we need to increase one
1276
      dbconn.increaseUsageCount(1);
1277
      pstmt.setInt(1, serverlocation);
1278
      pstmt.execute();
1279
      rs = pstmt.getResultSet();
1280
      tableHasRows = rs.next();
1281
      if (tableHasRows)
1282
      {
1283
        
1284
          String server = rs.getString(1);
1285
          //get homeserver name
1286
          if(!server.equals("localhost"))
1287
          {
1288
            this.docHomeServer=server;
1289
          }
1290
          else
1291
          {
1292
            this.docHomeServer=MetaCatUtil.getLocalReplicationServerName();
1293
          }
1294
          MetaCatUtil.debugMessage("server: "+docHomeServer, 50);
1295
        
1296
      }
1297
      pstmt.close();
1298
      if (this.doctype != null) {
1299
        pstmt =
1300
          dbconn.prepareStatement("SELECT system_id, entry_type " +
1301
                                  "FROM xml_catalog " +
1302
                                 "WHERE public_id = ?");
1303
        //should increase usage count again
1304
        dbconn.increaseUsageCount(1);
1305
        // Bind the values to the query
1306
        pstmt.setString(1, doctype);
1307
  
1308
        pstmt.execute();
1309
        rs = pstmt.getResultSet();
1310
        tableHasRows = rs.next();
1311
        if (tableHasRows) {
1312
          this.system_id  = rs.getString(1);
1313
          this.validateType = rs.getString(2);
1314
          
1315
        } 
1316
        pstmt.close();
1317
      }
1318
    } catch (SQLException e) {
1319
      System.out.println("error in DocumentImpl.getDocumentInfo: " + 
1320
                          e.getMessage());
1321
      e.printStackTrace(System.out);
1322
      throw new McdbException("Error accessing database connection in " +
1323
                              "DocumentImpl.getDocumentInfo: ", e);
1324
    }
1325
    finally
1326
    {
1327
      try
1328
      {
1329
        pstmt.close();
1330
      }
1331
      catch (SQLException ee)
1332
      {
1333
        MetaCatUtil.debugMessage("error in DocumentImple.getDocumentInfo: "
1334
                                    +ee.getMessage(), 30);
1335
      }//catch
1336
      finally
1337
      {
1338
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1339
      }
1340
    }
1341

    
1342
    if (this.docname == null) {
1343
      throw new McdbDocNotFoundException("Document not found: " + docid,
1344
                                 docid.getIdentifier(), docid.getRev());
1345
    }
1346
  }
1347
  
1348
  /**
1349
   * Look up the node data from the database, but some node would be shown
1350
   * because of access control
1351
   * @param rootnodeid the id of the root node of the node tree to look up
1352
   * @param accessControl  the hashtable has control info
1353
   */
1354
  private TreeSet getPartNodeRecordList(long rootnodeid, 
1355
                                        Hashtable accessControl) 
1356
                                        throws McdbException
1357
  {
1358
    PreparedStatement pstmt = null;
1359
    DBConnection dbconn = null;
1360
    int serialNumber = -1;
1361
    TreeSet nodeRecordList = new TreeSet(new NodeComparator());
1362
    long nodeid = 0;
1363
    long parentnodeid = 0;
1364
    long nodeindex = 0;
1365
    String nodetype = null;
1366
    String nodename = null;
1367
    String nodeprefix = null;
1368
    String nodedata = null;
1369
    String quotechar = dbAdapter.getStringDelimiter();
1370
    String sql = "SELECT nodeid,parentnodeid,nodeindex, " +
1371
                 "nodetype,nodename,nodeprefix,nodedata " +               
1372
                  "FROM xml_nodes WHERE rootnodeid = ?";
1373
                  
1374
    // go through the access control for some nodes
1375
     Enumeration en = accessControl.elements();
1376
     while (en.hasMoreElements())
1377
     {
1378
         SubTree tree = (SubTree)en.nextElement();
1379
         long startId = tree.getStartNodeId();
1380
         long endId  = tree.getEndNodeId();
1381
         sql = sql +" AND(nodeid < " + startId + " OR nodeid > " +endId +")";
1382
         
1383
     }
1384
     MetaCatUtil.debugMessage("The final query to select part node tree: " +
1385
                              sql, 25);
1386

    
1387
    try 
1388
    {
1389
      dbconn=DBConnectionPool.
1390
                    getDBConnection("DocumentImpl.getPartNodeRecordList");
1391
      serialNumber=dbconn.getCheckOutSerialNumber();
1392
      pstmt = dbconn.prepareStatement(sql);
1393

    
1394
      // Bind the values to the query
1395
      pstmt.setLong(1, rootnodeid);
1396
      pstmt.execute();
1397
      ResultSet rs = pstmt.getResultSet();
1398
      boolean tableHasRows = rs.next();
1399
      while (tableHasRows) 
1400
      {
1401
        nodeid = rs.getLong(1);
1402
        parentnodeid = rs.getLong(2);
1403
        nodeindex = rs.getLong(3);
1404
        nodetype = rs.getString(4);
1405
        nodename = rs.getString(5);
1406
        nodeprefix = rs.getString(6);
1407
        nodedata = rs.getString(7);
1408
        nodedata = MetaCatUtil.normalize(nodedata);
1409
        // add the data to the node record list hashtable
1410
        NodeRecord currentRecord = new NodeRecord(nodeid,parentnodeid,nodeindex,
1411
                                      nodetype, nodename, nodeprefix, nodedata);
1412
        nodeRecordList.add(currentRecord);
1413

    
1414
        // Advance to the next node
1415
        tableHasRows = rs.next();
1416
      } 
1417
      pstmt.close();
1418

    
1419
    } 
1420
    catch (SQLException e) 
1421
    {
1422
      throw new McdbException("Error in DocumentImpl.getPartNodeRecordList " +
1423
                              e.getMessage());
1424
    }
1425
    finally
1426
    {
1427
      try
1428
      {
1429
        pstmt.close();
1430
      }
1431
      catch (SQLException ee)
1432
      {
1433
        MetaCatUtil.debugMessage("error in DocumentImpl.getPartNodeRecordList: "
1434
                                    +ee.getMessage(), 30);
1435
      }
1436
      finally
1437
      {
1438
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1439
      }
1440
    }
1441
      
1442

    
1443
    if (!nodeRecordList.isEmpty()) 
1444
    {
1445
     
1446
      return nodeRecordList;
1447
    } 
1448
    else 
1449
    {
1450
      
1451
      throw new McdbException("Error getting node data: " + docid);
1452
    }
1453
  }
1454
  
1455
  /**
1456
   * Look up the node data from the database
1457
   *
1458
   * @param rootnodeid the id of the root node of the node tree to look up
1459
   */
1460
  private TreeSet getNodeRecordList(long rootnodeid) throws McdbException
1461
  {
1462
    PreparedStatement pstmt = null;
1463
    DBConnection dbconn = null;
1464
    int serialNumber = -1;
1465
    TreeSet nodeRecordList = new TreeSet(new NodeComparator());
1466
    long nodeid = 0;
1467
    long parentnodeid = 0;
1468
    long nodeindex = 0;
1469
    String nodetype = null;
1470
    String nodename = null;
1471
    String nodeprefix = null;
1472
    String nodedata = null;
1473
    String quotechar = dbAdapter.getStringDelimiter();
1474

    
1475
    try {
1476
      dbconn=DBConnectionPool.
1477
                    getDBConnection("DocumentImpl.getNodeRecordList");
1478
      serialNumber=dbconn.getCheckOutSerialNumber();
1479
      pstmt =
1480
      dbconn.prepareStatement("SELECT nodeid,parentnodeid,nodeindex, " +
1481
           "nodetype,nodename,nodeprefix,nodedata " +               
1482
           "FROM xml_nodes WHERE rootnodeid = ?");
1483

    
1484
      // Bind the values to the query
1485
      pstmt.setLong(1, rootnodeid);
1486

    
1487
      pstmt.execute();
1488
      ResultSet rs = pstmt.getResultSet();
1489
      boolean tableHasRows = rs.next();
1490
      while (tableHasRows) {
1491
        nodeid = rs.getLong(1);
1492
        parentnodeid = rs.getLong(2);
1493
        nodeindex = rs.getLong(3);
1494
        nodetype = rs.getString(4);
1495
        nodename = rs.getString(5);
1496
        nodeprefix = rs.getString(6);
1497
        nodedata = rs.getString(7);
1498
        nodedata = MetaCatUtil.normalize(nodedata);
1499
        // add the data to the node record list hashtable
1500
        NodeRecord currentRecord = new NodeRecord(nodeid,parentnodeid,nodeindex,
1501
                                      nodetype, nodename, nodeprefix, nodedata);
1502
        nodeRecordList.add(currentRecord);
1503

    
1504
        // Advance to the next node
1505
        tableHasRows = rs.next();
1506
      } 
1507
      pstmt.close();
1508

    
1509
    } catch (SQLException e) {
1510
      throw new McdbException("Error in DocumentImpl.getNodeRecordList " +
1511
                              e.getMessage());
1512
    }
1513
    finally
1514
    {
1515
      try
1516
      {
1517
        pstmt.close();
1518
      }
1519
      catch (SQLException ee)
1520
      {
1521
        MetaCatUtil.debugMessage("error in DocumentImpl.getNodeRecordList: "
1522
                                    +ee.getMessage(), 30);
1523
      }
1524
      finally
1525
      {
1526
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1527
      }
1528
    }
1529
  
1530
    return nodeRecordList;
1531
   
1532
  }
1533
  
1534
// NOT USED ANY MORE
1535
//  /** creates SQL code and inserts new document into DB connection 
1536
//   default serverCode of 1*/
1537
//  private void writeDocumentToDB(String action, String user)
1538
//               throws SQLException, Exception
1539
//  {
1540
//    writeDocumentToDB(action, user, null, 1);
1541
//  }
1542

    
1543
 /** creates SQL code and inserts new document into DB connection */
1544
  private void writeDocumentToDB(String action, String user, String pub, 
1545
                                 String catalogid, int serverCode) 
1546
               throws SQLException, Exception {
1547
    String sysdate = dbAdapter.getDateTimeFunction();
1548

    
1549
    try {
1550
      PreparedStatement pstmt = null;
1551

    
1552
      if (action.equals("INSERT")) {
1553
        //AccessionNumber ac = new AccessionNumber();
1554
        //this.docid = ac.generate(docid, "INSERT");
1555
        
1556
        pstmt = connection.prepareStatement(
1557
                "INSERT INTO xml_documents " +
1558
                "(docid, rootnodeid, docname, doctype, " + 
1559
                "user_owner, user_updated, date_created, date_updated, " + 
1560
                "public_access, catalog_id, server_location, rev) " +
1561
                "VALUES (?, ?, ?, ?, ?, ?, " + sysdate + ", " + sysdate + 
1562
                ", ?, ?, ?, ?)");
1563
        // Increase dbconnection usage count
1564
        connection.increaseUsageCount(1);
1565
        
1566
        //note that the server_location is set to 1. 
1567
        //this means that "localhost" in the xml_replication table must
1568
        //always be the first entry!!!!!
1569
        
1570
        // Bind the values to the query
1571
        pstmt.setString(1, this.docid);
1572
        pstmt.setLong(2, rootnodeid);
1573
        pstmt.setString(3, docname);
1574
        pstmt.setString(4, doctype);
1575
        pstmt.setString(5, user);
1576
        pstmt.setString(6, user);
1577
        //public access is usefulless, so set it to null
1578
        pstmt.setString(7, null);
1579
        /*if ( pub == null ) {
1580
          pstmt.setString(7, null);
1581
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
1582
          pstmt.setInt(7, 1);
1583
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
1584
          pstmt.setInt(7, 0);
1585
        }*/
1586
        pstmt.setString(8, catalogid);
1587
        pstmt.setInt(9, serverCode);
1588
        pstmt.setInt(10, Integer.parseInt(updatedVersion)); 
1589
      } else if (action.equals("UPDATE")) {
1590

    
1591
        // Save the old document publicaccessentry in a backup table
1592
        DocumentImpl.archiveDocRevision(connection, docid, user );
1593
        MetaCatUtil.debugMessage("after archiveDoc", 40);
1594
        DocumentImpl thisdoc = new DocumentImpl(docid, false);
1595
        int thisrev = thisdoc.getRev();
1596
        MetaCatUtil.debugMessage("this revsion is: "+thisrev, 40);
1597
        //if the updated vesion is not greater than current one,
1598
        //throw it into a exception
1599
        if (Integer.parseInt(updatedVersion)<=thisrev)
1600
        {
1601
          throw new Exception("Next revision number couldn't be less"
1602
                               +" than or equal "+ thisrev);
1603
        }
1604
        else
1605
        {
1606
          //set the user specified revision 
1607
          thisrev=Integer.parseInt(updatedVersion);
1608
        }
1609
        MetaCatUtil.debugMessage("final revsion is: "+thisrev, 40);
1610
        MetaCatUtil.debugMessage("before delete", 40);
1611
        // Delete index for the old version of docid
1612
        // The new index is inserting on the next calls to DBSAXNode
1613
        pstmt = connection.prepareStatement(
1614
                "DELETE FROM xml_index WHERE docid='" + this.docid + "'");
1615
        MetaCatUtil.debugMessage("after delete", 40);
1616
        // Increase dbconnection usage count
1617
        connection.increaseUsageCount(1);
1618
        
1619
        pstmt.execute();
1620
        pstmt.close();
1621

    
1622
        // Update the new document to reflect the new node tree
1623
        pstmt = connection.prepareStatement(
1624
            "UPDATE xml_documents " +
1625
            "SET rootnodeid = ?, docname = ?, doctype = ?, " +
1626
            "user_updated = ?, date_updated = " + sysdate + ", " +
1627
            "server_location = ?, rev = ?, public_access = ?, catalog_id = ? " +
1628
            "WHERE docid = ?");
1629
        // Increase dbconnection usage count
1630
        connection.increaseUsageCount(1);
1631
        // Bind the values to the query
1632
        pstmt.setLong(1, rootnodeid);
1633
        pstmt.setString(2, docname);
1634
        pstmt.setString(3, doctype);
1635
        pstmt.setString(4, user);
1636
        pstmt.setInt(5, serverCode);
1637
        pstmt.setInt(6, thisrev);
1638
        pstmt.setString(7, null);
1639
        /*if ( pub == null ) {
1640
          pstmt.setString(7, null);
1641
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
1642
          pstmt .setInt(7, 1);
1643
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
1644
          pstmt.setInt(7, 0);
1645
        }*/
1646
        pstmt.setString(8, catalogid);
1647
        pstmt.setString(9, this.docid);
1648

    
1649
      } else {
1650
        System.err.println("Action not supported: " + action);
1651
      }
1652

    
1653
      // Do the insertion
1654
      pstmt.execute();
1655
      
1656
      pstmt.close();
1657

    
1658
    } catch (SQLException sqle) {
1659
      throw sqle;
1660
    } catch (Exception e) {
1661
      throw e;
1662
    }
1663
  }
1664

    
1665
  /**
1666
   * Write an XML file to the database, given a filename
1667
   *
1668
   * @param conn the JDBC connection to the database
1669
   * @param filename the filename to be loaded into the database
1670
   * @param pub flag for public "read" access on document
1671
   * @param dtdfilename the dtd to be uploaded on server's file system
1672
   * @param action the action to be performed (INSERT OR UPDATE)
1673
   * @param docid the docid to use for the INSERT OR UPDATE
1674
   * @param user the user that owns the document
1675
   * @param groups the groups to which user belongs
1676
   */
1677
  /*public static String write(DBConnection conn,String filename,
1678
                             String pub, String dtdfilename,
1679
                             String action, String docid, String user,
1680
                             String[] groups )
1681
                throws Exception {
1682
                  
1683
    Reader dtd = null;
1684
    if ( dtdfilename != null ) {
1685
      dtd = new FileReader(new File(dtdfilename).toString());
1686
    }
1687
    return write ( conn, new FileReader(new File(filename).toString()),
1688
                   pub, dtd, action, docid, user, groups, false);
1689
  }*/
1690

    
1691
  public static String write(DBConnection conn,Reader xml,String pub,Reader dtd,
1692
                             String action, String docid, String user,
1693
                             String[] groups, String ruleBase, 
1694
                             boolean needValidation)
1695
                throws Exception {
1696
    //this method will be called in handleUpdateOrInsert method 
1697
    //in MetacatServlet class and now is wrapper into documentImple
1698
    // get server location for this doc
1699
    int serverLocation=getServerLocationNumber(docid);
1700
    return write(conn,xml,pub,dtd,action,docid,user,groups,serverLocation,false,
1701
                 ruleBase, needValidation);
1702
  }
1703

    
1704
 
1705
  
1706
  /**
1707
   * Write an XML file to the database, given a Reader
1708
   *
1709
   * @param conn the JDBC connection to the database
1710
   * @param xml the xml stream to be loaded into the database
1711
   * @param pub flag for public "read" access on xml document
1712
   * @param dtd the dtd to be uploaded on server's file system
1713
   * @param action the action to be performed (INSERT or UPDATE)
1714
   * @param accnum the docid + rev# to use on INSERT or UPDATE
1715
   * @param user the user that owns the document
1716
   * @param groups the groups to which user belongs
1717
   * @param serverCode the serverid from xml_replication on which this document
1718
   *        resides.
1719
   * @param override flag to stop insert replication checking.
1720
   *        if override = true then a document not belonging to the local server
1721
   *        will not be checked upon update for a file lock.
1722
   *        if override = false then a document not from this server, upon 
1723
   *        update will be locked and version checked.
1724
   */
1725

    
1726
  public static String write(DBConnection conn, Reader xml,String pub,
1727
                         Reader dtd, String action, String accnum, String user,
1728
                         String[] groups, int serverCode, boolean override,
1729
                         String ruleBase, boolean needValidation)
1730
                throws Exception
1731
  {
1732
    // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1733
    //MetaCatUtil util = new MetaCatUtil();
1734
    MetaCatUtil.debugMessage("conn usage count before writting: "
1735
                                      +conn.getUsageCount(), 50);
1736
    AccessionNumber ac = new AccessionNumber(accnum, action);
1737
    String docid = ac.getDocid();
1738
    String rev = ac.getRev();
1739
    MetaCatUtil.debugMessage("action: " + action + " servercode: " + 
1740
                             serverCode + " override: " + override, 10);
1741
                     
1742
    if((serverCode != 1 && action.equals("UPDATE")) && !override)
1743
    { //if this document being written is not a resident of this server then
1744
      //we need to try to get a lock from it's resident server.  If the
1745
      //resident server will not give a lock then we send the user a message
1746
      //saying that he/she needs to download a new copy of the file and
1747
      //merge the differences manually.
1748
      int istreamInt; 
1749
      char istreamChar;
1750
     
1751
      // check for 'write' permission for 'user' to update this document
1752
      if ( !hasWritePermission(user, groups, accnum) ) {
1753
        throw new Exception("User " + user + 
1754
              " does not have permission to update XML Document #" + accnum);
1755
      }        
1756
  
1757
      DocumentIdentifier id = new DocumentIdentifier(accnum);
1758
      String updaterev = id.getRev();
1759
      String server=MetacatReplication.getServerNameForServerCode(serverCode);
1760
      MetacatReplication.replLog("attempting to lock " + accnum);
1761
      URL u = new URL("https://" + server + "?server="+
1762
        MetaCatUtil.getLocalReplicationServerName()+"&action=getlock&updaterev=" 
1763
           +updaterev + "&docid=" + docid);
1764
      //System.out.println("sending message: " + u.toString());
1765
      String serverResStr = MetacatReplication.getURLContent(u);
1766
      String openingtag =serverResStr.substring(0, serverResStr.indexOf(">")+1);
1767
      if(openingtag.equals("<lockgranted>"))
1768
      {//the lock was granted go ahead with the insert
1769
        XMLReader parser = null;
1770
        try 
1771
        {
1772
          //System.out.println("In lockgranted");
1773
          MetacatReplication.replLog("lock granted for " + accnum + " from " +
1774
                                      server);
1775
          /*XMLReader parser = initializeParser(conn, action, docid, updaterev,
1776
                               validate, user, groups, pub, serverCode, dtd);*/
1777
          parser = initializeParser(conn, action, docid, updaterev,
1778
                                        user, groups, pub, serverCode, 
1779
                                        dtd,ruleBase, needValidation); 
1780
          conn.setAutoCommit(false);
1781
          parser.parse(new InputSource(xml)); 
1782
          conn.commit();
1783
          conn.setAutoCommit(true);
1784
        } 
1785
        catch (Exception e) 
1786
        {
1787
          conn.rollback();
1788
          conn.setAutoCommit(true);
1789
          //if it is a eml2 document, we need delete online data
1790
          if ( parser != null)
1791
          {
1792
            ContentHandler handler = parser.getContentHandler();
1793
            if (handler instanceof EmlSAXHandler)
1794
            {
1795
              EmlSAXHandler eml = (EmlSAXHandler) handler;
1796
              eml.deleteInlineFiles();
1797
            }
1798
          }
1799
          throw e;
1800
        }
1801
        // run write into access db base one relation table and access object 
1802
        runRelationAndAccessHandler(accnum, user, groups, serverCode);
1803
        
1804
        // Force replication the docid
1805
        ForceReplicationHandler frh = new ForceReplicationHandler
1806
                                                          (accnum, true, null);
1807
        return(accnum);
1808
   
1809
      }
1810

    
1811
      else if(openingtag.equals("<filelocked>"))
1812
      {//the file is currently locked by another user
1813
       //notify our user to wait a few minutes, check out a new copy and try
1814
       //again.
1815
        //System.out.println("file locked");
1816
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1817
                                   server + " reason: file already locked");
1818
        throw new Exception("The file specified is already locked by another " +
1819
                            "user.  Please wait 30 seconds, checkout the " +
1820
                            "newer document, merge your changes and try " +
1821
                            "again.");
1822
      }
1823
      else if(openingtag.equals("<outdatedfile>"))
1824
      {//our file is outdated.  notify our user to check out a new copy of the
1825
       //file and merge his version with the new version.
1826
        //System.out.println("outdated file");
1827
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1828
                                    server + " reason: local file outdated");
1829
        throw new Exception("The file you are trying to update is an outdated" +
1830
                            " version.  Please checkout the newest document, " +
1831
                            "merge your changes and try again.");
1832
      }
1833
    }
1834
    
1835
    if ( action.equals("UPDATE") ) {
1836
      // check for 'write' permission for 'user' to update this document
1837

    
1838
      if ( !hasWritePermission(user, groups, accnum) ) {
1839
        throw new Exception("User " + user + 
1840
              " does not have permission to update XML Document #" + accnum);
1841
      }          
1842
    }
1843
    XMLReader parser = null;
1844
    try 
1845
    { 
1846
      
1847
      parser = initializeParser(conn, action, docid, rev, 
1848
                                          user, groups, pub, serverCode, 
1849
                                          dtd, ruleBase, needValidation);
1850
   
1851
      conn.setAutoCommit(false);
1852
      parser.parse(new InputSource(xml));
1853
      conn.commit();
1854
      conn.setAutoCommit(true);
1855
    } 
1856
    catch (Exception e) 
1857
    {
1858
      conn.rollback();
1859
      conn.setAutoCommit(true);
1860
       //if it is a eml2 document, we need delete online data
1861
       if ( parser != null)
1862
       {
1863
          ContentHandler handler = parser.getContentHandler();
1864
          if (handler instanceof EmlSAXHandler)
1865
          {
1866
            EmlSAXHandler eml = (EmlSAXHandler) handler;
1867
            eml.deleteInlineFiles();
1868
          }
1869
       }
1870
      throw e;
1871
    }
1872
    
1873
    // run access db base on relation table and access object       
1874
    runRelationAndAccessHandler(accnum, user, groups, serverCode);
1875
    
1876
    // Force replicate out the new document to each server in our server list.
1877
    // Start the thread to replicate this new document out to the other servers
1878
    // true mean it is xml document
1879
    // null is because no metacat notify the force replication.
1880
    ForceReplicationHandler frh = new ForceReplicationHandler
1881
                                                  (accnum, action, true, null);
1882
      
1883
   
1884
    MetaCatUtil.debugMessage("Conn Usage count after writting: "
1885
                                                      +conn.getUsageCount(),50); 
1886
    return(accnum);
1887
  }
1888

    
1889
  /**
1890
   * Write an XML file to the database during replication
1891
   *
1892
   * @param conn the JDBC connection to the database
1893
   * @param xml the xml stream to be loaded into the database
1894
   * @param pub flag for public "read" access on xml document
1895
   * @param dtd the dtd to be uploaded on server's file system
1896
   * @param action the action to be performed (INSERT or UPDATE)
1897
   * @param accnum the docid + rev# to use on INSERT or UPDATE
1898
   * @param user the user that owns the document
1899
   * @param groups the groups to which user belongs
1900
   * @param homeServer the name of server which the document origanlly create
1901
   * @param validate, if the xml document is valid or not
1902
   * @param notifyServer, the server which notify local server the force 
1903
   *                       replication command
1904
   */
1905

    
1906
  public static String writeReplication(DBConnection conn, Reader xml, 
1907
                                        String pub, Reader dtd, String action, 
1908
                                        String accnum, String user,
1909
                                        String[] groups,String homeServer, 
1910
                                        String notifyServer,
1911
                                        String ruleBase, boolean needValidation)
1912
                                        throws Exception
1913
  {
1914
    MetaCatUtil.debugMessage("user in replication"+ user, 30);
1915
    // Docid without revision
1916
    String docid=MetaCatUtil.getDocIdFromAccessionNumber(accnum);
1917
    // Revision specified by user (int)
1918
    int userSpecifyRev=MetaCatUtil.getRevisionFromAccessionNumber(accnum);
1919
    MetaCatUtil.debugMessage("The user specifyRev: " + userSpecifyRev, 30);
1920
    // Revision for this docid in current database
1921
    int revInDataBase=getLatestRevisionNumber(docid);
1922
    MetaCatUtil.debugMessage("The rev in data base: "+revInDataBase, 30);
1923
    // String to store the revision
1924
    String rev = null;
1925
   
1926
    
1927
    //revIndataBase=-1, there is no record in xml_documents table
1928
    //the document is a new one for local server, inert it into table
1929
    //user specified rev should be great than 0
1930
    if (revInDataBase==-1 && userSpecifyRev>=0 )
1931
    {
1932
        // rev equals user specified
1933
        rev=(new Integer(userSpecifyRev)).toString();
1934
        // action should be INSERT
1935
        action = "INSERT";
1936
    }
1937
    //rev is greater the last revsion number and revInDataBase isn't -1
1938
    // it is a updated  file
1939
    else if (userSpecifyRev>revInDataBase && revInDataBase>=0)
1940
    {
1941
       // rev equals user specified
1942
       rev=(new Integer(userSpecifyRev)).toString();
1943
       // action should be update
1944
       action = "UPDATE";
1945
    }
1946
    // local server has newer version, then notify the remote server
1947
    else if ( userSpecifyRev < revInDataBase && revInDataBase > 0)
1948
    {
1949
      throw new Exception("Local server: "+MetaCatUtil.getOption("server")+
1950
                " has newer revision of doc: "+docid+"."+revInDataBase
1951
                 +". Please notify it.");
1952
    }
1953
    //other situation
1954
    else
1955
    {
1956
        
1957
        throw new Exception("The docid"+docid+"'s revision number couldn't be "
1958
                    +userSpecifyRev);
1959
    }
1960
    // Variable to store homeserver code
1961
    int serverCode=-2;
1962
    
1963
     // If server is not int the xml replication talbe, insert it into
1964
    // xml_replication table
1965
    //serverList.addToServerListIfItIsNot(homeServer);
1966
    insertServerIntoReplicationTable(homeServer);
1967
    // Get server code again
1968
    serverCode = getServerCode(homeServer);
1969
    
1970
    
1971
    MetaCatUtil.debugMessage("Document "+docid+"."+rev+" "+action+ " into local"
1972
                               +" metacat with servercode: "+ serverCode, 10);
1973
                        
1974
  
1975
    // insert into xml_nodes and xml_index table
1976
    XMLReader parser = null;
1977
    try 
1978
    { 
1979
      
1980
      parser = initializeParser(conn, action, docid, rev,
1981
                                          user, groups, pub, serverCode, dtd,
1982
                                          ruleBase, needValidation);
1983
      conn.setAutoCommit(false);
1984
      parser.parse(new InputSource(xml));
1985
      conn.commit();
1986
      conn.setAutoCommit(true);
1987
    } 
1988
    catch (Exception e) 
1989
    {
1990
      conn.rollback();
1991
      conn.setAutoCommit(true);
1992
      if ( parser != null)
1993
      {
1994
          ContentHandler handler = parser.getContentHandler();
1995
          if (handler instanceof EmlSAXHandler)
1996
          {
1997
            EmlSAXHandler eml = (EmlSAXHandler) handler;
1998
            eml.deleteInlineFiles();
1999
          }
2000
       }
2001
      throw e;
2002
    }
2003
    
2004
    // run write into access db base on relation table and access rule
2005
    try
2006
    {       
2007
      runRelationAndAccessHandler(accnum, user, groups, serverCode);
2008
    }
2009
    catch (Exception ee)
2010
    {
2011
      MetacatReplication.replErrorLog("Failed to " + 
2012
                                       "create access " + 
2013
                                       "rule for package: " + accnum +
2014
                                       " because " +ee.getMessage());
2015
      MetaCatUtil.debugMessage("Failed to  " + 
2016
                                       "create access " + 
2017
                                       "rule for package: "+ accnum +
2018
                                       " because " +ee.getMessage(), 30);
2019
    }
2020
    //Force replication to other server
2021
    ForceReplicationHandler forceReplication = new ForceReplicationHandler
2022
                                  (accnum, action, true, notifyServer);
2023
    
2024

    
2025
    return(accnum);
2026
  }
2027
  
2028
  /* Running write record to xml_relation and xml_access*/
2029
  private static void runRelationAndAccessHandler(String accnumber, 
2030
                                                  String userName, 
2031
                                                  String[]group, int servercode) 
2032
                                                   throws Exception
2033
  {
2034
    DBConnection dbconn = null;
2035
    int serialNumber = -1;
2036
    PreparedStatement pstmt =null;
2037
    String documenttype = getDocTypeFromDBForCurrentDocument(accnumber);
2038
    try
2039
    {
2040
      String packagedoctype = MetaCatUtil.getOption("packagedoctype");
2041
      Vector packagedoctypes = new Vector();
2042
      packagedoctypes = MetaCatUtil.getOptionList(packagedoctype);
2043
      String docIdWithoutRev = MetaCatUtil.getDocIdFromString(accnumber);
2044
      if (documenttype != null && packagedoctypes.contains(documenttype) )
2045
      {
2046
        dbconn=DBConnectionPool.
2047
           getDBConnection("DocumentImpl.runRelationAndAccessHandeler");
2048
        serialNumber=dbconn.getCheckOutSerialNumber();
2049
        dbconn.setAutoCommit(false);
2050
        // from the relations get the access file id for that package
2051
        String aclid = RelationHandler.getAccessFileID(docIdWithoutRev);
2052
        // if there are access file, write ACL for that package
2053
        if ( aclid != null ) 
2054
        {
2055
          runAccessControlList(dbconn, aclid, userName, group, servercode);
2056
        }
2057
        dbconn.commit();
2058
        dbconn.setAutoCommit(true);
2059
      }
2060
        // if it is an access file
2061
      else if ( documenttype != null && MetaCatUtil.getOptionList(
2062
                 MetaCatUtil.getOption("accessdoctype")).contains(documenttype))
2063
      {
2064
        dbconn=DBConnectionPool.
2065
           getDBConnection("DocumentImpl.runRelationAndAccessHandeler");
2066
        serialNumber=dbconn.getCheckOutSerialNumber();
2067
        dbconn.setAutoCommit(false);
2068
        // write ACL for the package
2069
        runAccessControlList(dbconn, docIdWithoutRev, 
2070
                             userName, group, servercode);
2071
        dbconn.commit();
2072
        dbconn.setAutoCommit(true);
2073
        
2074
      }
2075
      
2076
    } 
2077
    catch (Exception e) 
2078
    {
2079
      if( dbconn != null)
2080
      {
2081
        dbconn.rollback();
2082
        dbconn.setAutoCommit(true);
2083
      }
2084
      MetaCatUtil.debugMessage("Error in DocumentImple.runRelationAndAccessHandler " +
2085
                                e.getMessage(), 30);
2086
      throw e;
2087
    }
2088
    finally
2089
    {
2090
      if (dbconn != null)
2091
      {
2092
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
2093
      }
2094
    }//
2095
  }
2096
  
2097
  // It runs in xmlIndex thread. It writes ACL for a package.
2098
  private static void runAccessControlList (DBConnection conn, String aclid, 
2099
                                    String users, String[]group, int servercode)
2100
                                                throws Exception
2101
  {
2102
    // read the access file from xml_nodes
2103
    // parse the access file and store the access info into xml_access
2104
    AccessControlList aclobj =
2105
    new AccessControlList(conn, aclid, users, group, servercode);
2106
   
2107
  }
2108
  
2109
  /* Method get document type from db*/
2110
  private static String getDocTypeFromDBForCurrentDocument(String accnumber)
2111
                                                  throws SQLException
2112
  {
2113
    String docoumentType = null;
2114
    String docid = null;
2115
    PreparedStatement pstate = null;
2116
    ResultSet rs = null;
2117
    String sql = "SELECT doctype FROM xml_documents where docid = ?";
2118
    DBConnection dbConnection = null;
2119
    int serialNumber = -1;
2120
    try
2121
    {
2122
      //get rid of revision number
2123
      docid = MetaCatUtil.getDocIdFromString(accnumber);
2124
      dbConnection=DBConnectionPool.
2125
           getDBConnection("DocumentImpl.getDocTypeFromDBForCurrentDoc");
2126
      serialNumber=dbConnection.getCheckOutSerialNumber();
2127
      pstate = dbConnection.prepareStatement(sql);
2128
      //bind variable
2129
      pstate.setString(1, docid);
2130
      //excute query
2131
      pstate.execute();
2132
      //handle resultset
2133
      rs = pstate.getResultSet();
2134
      if (rs.next())
2135
      {
2136
        docoumentType = rs.getString(1);
2137
      }
2138
      rs.close();
2139
      pstate.close();
2140
    }//try
2141
    catch (SQLException e)
2142
    {
2143
      MetaCatUtil.debugMessage("error in DocumentImpl."+
2144
                      "getDocTypeFromDBForCurrentDocument "+e.getMessage(), 30);
2145
      throw e;
2146
    }//catch
2147
    finally
2148
    {
2149
      pstate.close();
2150
      DBConnectionPool.returnDBConnection(dbConnection, serialNumber);
2151
    }//
2152
    MetaCatUtil.debugMessage("The current doctype from db is: "+
2153
                              docoumentType, 35);
2154
    return docoumentType;
2155
  }
2156
  /**
2157
   * Delete an XML file from the database (actually, just make it a revision
2158
   * in the xml_revisions table)
2159
   *
2160
   * @param docid the ID of the document to be deleted from the database
2161
   */
2162
  public static void delete(String accnum,
2163
                                 String user, String[] groups )
2164
                throws Exception 
2165
  {
2166
    // OLD
2167
    //DocumentIdentifier id = new DocumentIdentifier(accnum);
2168
    //String docid = id.getIdentifier();
2169
    //String rev = id.getRev();
2170
    
2171
    // OLD
2172
    // Determine if the docid,rev are OK for DELETE
2173
    //AccessionNumber ac = new AccessionNumber(conn);
2174
    //docid = ac.generate(docid, rev, "DELETE");
2175
    DBConnection conn = null;
2176
    int serialNumber = -1;
2177
    PreparedStatement pstmt =null;
2178
    try
2179
    {
2180
      //check out DBConnection
2181
      conn=DBConnectionPool.
2182
                    getDBConnection("DocumentImpl.delete");
2183
      serialNumber=conn.getCheckOutSerialNumber();
2184

    
2185
      // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
2186
      AccessionNumber ac = new AccessionNumber(accnum, "DELETE");
2187
      String docid = ac.getDocid();
2188
      String rev = ac.getRev();
2189
    
2190
      MetaCatUtil.debugMessage("Start deleting doc "+docid+ "...", 20);
2191
    // check for 'write' permission for 'user' to delete this document
2192
      if ( !hasWritePermission(user, groups, accnum) ) {
2193
        throw new Exception("User " + user + 
2194
              " does not have permission to delete XML Document #" + accnum);
2195
      }
2196

    
2197
      conn.setAutoCommit(false);
2198
      // Copy the record to the xml_revisions table
2199
      DocumentImpl.archiveDocRevision(conn, docid, user );
2200

    
2201
      // Now delete it from the xml_index table
2202
      pstmt = conn.prepareStatement("DELETE FROM xml_index WHERE docid = ?");
2203
      pstmt.setString(1,docid);
2204
      pstmt.execute();
2205
      pstmt.close();
2206
      conn.increaseUsageCount(1);
2207
      
2208
      //stmt.execute("DELETE FROM xml_access WHERE docid = '" + docid + "'");
2209
      // Now delete it from xml_access table
2210
      pstmt = conn.
2211
              prepareStatement("DELETE FROM xml_access WHERE accessfileid = ?");
2212
      pstmt.setString(1, docid);
2213
      pstmt.execute();
2214
      pstmt.close();
2215
      conn.increaseUsageCount(1);
2216
      
2217
      // Delete it from relation table
2218
      pstmt = conn.
2219
               prepareStatement("DELETE FROM xml_relation WHERE docid = ?");
2220
      //increase usage count
2221
      conn.increaseUsageCount(1);
2222
      pstmt.setString(1, docid);
2223
      pstmt.execute();
2224
      pstmt.close();
2225
      
2226
      // Delete it from xml_accesssubtree table
2227
      pstmt = conn.
2228
               prepareStatement("DELETE FROM xml_accesssubtree WHERE docid = ?");
2229
      //increase usage count
2230
      conn.increaseUsageCount(1);
2231
      pstmt.setString(1, docid);
2232
      pstmt.execute();
2233
      pstmt.close();
2234
      
2235
      // Delete it from xml_doucments table
2236
      pstmt =conn.prepareStatement("DELETE FROM xml_documents WHERE docid = ?");
2237
      pstmt.setString(1, docid);
2238
      pstmt.execute();
2239
      pstmt.close();
2240
      //Usaga count increase 1
2241
      conn.increaseUsageCount(1);
2242
      
2243
      conn.commit();
2244
      conn.setAutoCommit(true);
2245
    }//try
2246
    catch (Exception e)
2247
    {
2248
      MetaCatUtil.debugMessage("error in DocumentImpl.delete: " + 
2249
                                e.getMessage(), 30);
2250
      throw e;
2251
    }
2252
    finally
2253
    {
2254
      
2255
      try
2256
      {
2257
        // close preparedStatement
2258
        pstmt.close();
2259
      }//try
2260
      finally
2261
      {
2262
        //check in DBonnection
2263
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2264
      }//finally
2265
    }//finally
2266
    //IF this is a package document:
2267
    //delete all of the relations that this document created.
2268
    //if the deleted document is a package document its relations should 
2269
    //no longer be active if it has been deleted from the system.
2270
    
2271
  }
2272

    
2273
  /** 
2274
    * Check for "WRITE" permission on @docid for @user and/or @groups 
2275
    * from DB connection 
2276
    */
2277
  private static boolean hasWritePermission (String user,
2278
                                  String[] groups, String docid ) 
2279
                  throws SQLException, Exception
2280
  {
2281
    // Check for WRITE permission on @docid for @user and/or @groups
2282
    PermissionController controller = new PermissionController(docid);
2283
    return controller.hasPermission(user,groups,
2284
                                    AccessControlInterface.WRITESTRING);
2285
  }
2286

    
2287
  /** 
2288
    * Check for "READ" permission base on docid, user and group
2289
    *@docid, the document
2290
    *@user, user name
2291
    *@group, user's group
2292
    * 
2293
    */
2294
  public static boolean hasReadPermission (String user,
2295
                                  String[] groups, String docId ) 
2296
                  throws SQLException, Exception
2297
  {
2298
    // Check for READ permission on @docid for @user and/or @groups
2299
    PermissionController controller = 
2300
                        new PermissionController(docId);
2301
    return controller.hasPermission(user,groups,
2302
                                            AccessControlInterface.READSTRING);
2303
  }  
2304

    
2305
  
2306
   /**
2307
   * Set up the parser handlers for writing the document to the database
2308
   */
2309
  private static XMLReader initializeParser(DBConnection dbconn, String action,
2310
                                            String docid, String rev, 
2311
                                            String user, 
2312
                                            String[] groups, String pub, 
2313
                                            int serverCode, Reader dtd,
2314
                                            String ruleBase, 
2315
                                            boolean needValidation) 
2316
                                            throws Exception 
2317
  {
2318
    XMLReader parser = null;
2319
    try 
2320
    {
2321
      // handler
2322
      ContentHandler chandler;
2323
      EntityResolver eresolver;
2324
      DTDHandler dtdhandler;  
2325
      // Get an instance of the parser
2326
      String parserName = MetaCatUtil.getOption("saxparser");
2327
      parser = XMLReaderFactory.createXMLReader(parserName);
2328
      if (ruleBase != null && ruleBase.equals(EML2))
2329
      {
2330
        MetaCatUtil.debugMessage("eml 2 parser", 20);
2331
        chandler = new EmlSAXHandler(dbconn, action, 
2332
                                    docid, rev, user, groups, pub, serverCode);
2333
        parser.setContentHandler((ContentHandler)chandler);
2334
        parser.setErrorHandler((ErrorHandler)chandler);
2335
        parser.setProperty(DECLARATIONHANDLERPROPERTY, chandler);
2336
        parser.setProperty(LEXICALPROPERTY, chandler);
2337
        // turn on schema validation feature
2338
        parser.setFeature(VALIDATIONFEATURE, true);
2339
        parser.setFeature(NAMESPACEFEATURE, true);
2340
        //parser.setFeature(NAMESPACEPREFIXESFEATURE, true);
2341
        parser.setFeature(SCHEMAVALIDATIONFEATURE, true);
2342
        // From DB to find the register external schema location
2343
        String externalSchemaLocation = null;
2344
        SchemaLocationResolver resolver = new SchemaLocationResolver();
2345
        externalSchemaLocation = resolver.getNameSpaceAndLocationString();
2346
        // Set external schemalocation.
2347
        if (externalSchemaLocation != null && 
2348
            !(externalSchemaLocation.trim()).equals(""))
2349
        {
2350
            parser.setProperty(EXTERNALSCHEMALOCATIONPROPERTY,
2351
                             externalSchemaLocation);
2352
        }
2353
      }
2354
      else
2355
      {
2356
        //create a DBSAXHandler object which has the revision specification
2357
        chandler = new DBSAXHandler(dbconn, action, 
2358
                                    docid, rev, user, groups, pub, serverCode);
2359
        parser.setContentHandler((ContentHandler)chandler);
2360
        parser.setErrorHandler((ErrorHandler)chandler);
2361
        parser.setProperty(DECLARATIONHANDLERPROPERTY, chandler);
2362
        parser.setProperty(LEXICALPROPERTY, chandler);
2363
      
2364
        if (ruleBase != null && ruleBase.equals(SCHEMA) && needValidation)
2365
        {
2366
          MetaCatUtil.debugMessage("General schema parser", 20);
2367
          // turn on schema validation feature
2368
          parser.setFeature(VALIDATIONFEATURE, true);
2369
          parser.setFeature(NAMESPACEFEATURE, true);
2370
          //parser.setFeature(NAMESPACEPREFIXESFEATURE, true);
2371
          parser.setFeature(SCHEMAVALIDATIONFEATURE, true);
2372
          // From DB to find the register external schema location
2373
          String externalSchemaLocation = null;
2374
          SchemaLocationResolver resolver = new SchemaLocationResolver();
2375
          externalSchemaLocation = resolver.getNameSpaceAndLocationString();
2376
          // Set external schemalocation.
2377
          if (externalSchemaLocation != null && 
2378
            !(externalSchemaLocation.trim()).equals(""))
2379
          {
2380
            parser.setProperty(EXTERNALSCHEMALOCATIONPROPERTY,
2381
                             externalSchemaLocation);
2382
          }
2383
     
2384
        }
2385
        else if (ruleBase != null && ruleBase.equals(DTD) && needValidation)
2386
        {
2387
          MetaCatUtil.debugMessage("dtd parser", 20);
2388
          // turn on dtd validaton feature
2389
          parser.setFeature(VALIDATIONFEATURE, true);
2390
          eresolver= new DBEntityResolver(dbconn, (DBSAXHandler)chandler, dtd);
2391
          dtdhandler = new DBDTDHandler(dbconn);
2392
          parser.setEntityResolver((EntityResolver)eresolver);
2393
          parser.setDTDHandler((DTDHandler)dtdhandler);
2394
        }
2395
        else
2396
        {
2397
          MetaCatUtil.debugMessage("other parser", 20);
2398
          // non validation
2399
          parser.setFeature(VALIDATIONFEATURE, false);
2400
          eresolver= new DBEntityResolver(dbconn, (DBSAXHandler)chandler, dtd);
2401
          dtdhandler = new DBDTDHandler(dbconn);
2402
          parser.setEntityResolver((EntityResolver)eresolver);
2403
          parser.setDTDHandler((DTDHandler)dtdhandler);
2404
        }
2405
      }//else
2406
    } 
2407
    catch (Exception e) 
2408
    {
2409
      throw e;
2410
    }
2411
    return parser;
2412
  }
2413

    
2414
  
2415
  /**
2416
   * Set up the parser handlers for writing the document to the database
2417
   */
2418
  /*private static XMLReader initializeParser(DBConnection dbconn, String action,
2419
                               String docid, String rev, boolean validate, 
2420
                                   String user, String[] groups, String pub, 
2421
                                   int serverCode, Reader dtd) 
2422
                           throws Exception 
2423
  {
2424
    XMLReader parser = null;
2425
    //DBConnection conn = null;
2426
    //int serialNumber = -1;
2427
    //
2428
    // Set up the SAX document handlers for parsing
2429
    //
2430
    try {
2431
       //check out DBConnection
2432
     
2433
      //create a DBSAXHandler object which has the revision specification
2434
      ContentHandler chandler = new DBSAXHandler(dbconn, action, 
2435
                                    docid, rev, user, groups, pub, serverCode);
2436
      EntityResolver eresolver= new DBEntityResolver(dbconn,
2437
                                                 (DBSAXHandler)chandler, dtd);
2438
      DTDHandler dtdhandler   = new DBDTDHandler(dbconn);
2439

    
2440
      // Get an instance of the parser
2441
      String parserName = MetaCatUtil.getOption("saxparser");
2442
      parser = XMLReaderFactory.createXMLReader(parserName);
2443

    
2444
      // Turn on validation
2445
      parser.setFeature("http://xml.org/sax/features/validation", validate);
2446
      // Turn off Including all external parameter entities
2447
      // (the external DTD subset also)
2448
      // Doesn't work well, probably the feature name is not correct
2449
      // parser.setFeature(
2450
      //  "http://xml.org/sax/features/external-parameter-entities", false);
2451
      
2452
      // Set Handlers in the parser
2453
      parser.setProperty("http://xml.org/sax/properties/declaration-handler",
2454
                         chandler);
2455
      parser.setProperty("http://xml.org/sax/properties/lexical-handler",
2456
                         chandler);
2457
      parser.setContentHandler((ContentHandler)chandler);
2458
      parser.setEntityResolver((EntityResolver)eresolver);
2459
      parser.setDTDHandler((DTDHandler)dtdhandler);
2460
      parser.setErrorHandler((ErrorHandler)chandler);
2461

    
2462
    } catch (Exception e) {
2463
      throw e;
2464
    }
2465
    //finally
2466
    //{
2467
      //DBConnectionPool.returnDBConnection(conn, serialNumber);
2468
    //}
2469

    
2470
    return parser;
2471
  }*/
2472

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

    
2538
  }//achiveDocRevision
2539
  
2540
  /** Save a document entry in the xml_revisions table */
2541
  private static void archiveDocRevision(String docid, String user) 
2542
 {
2543
    String sysdate = dbAdapter.getDateTimeFunction();
2544
    DBConnection conn = null;
2545
    int serialNumber = -1;
2546
    PreparedStatement pstmt = null;
2547
    
2548
    // create a record in xml_revisions table 
2549
    // for that document as selected from xml_documents
2550
   
2551
   try
2552
   {
2553
     //check out DBConnection
2554
     conn=DBConnectionPool.
2555
                    getDBConnection("DocumentImpl.archiveDocRevision");
2556
     serialNumber=conn.getCheckOutSerialNumber();
2557
     pstmt = conn.prepareStatement(
2558
      "INSERT INTO xml_revisions " +
2559
        "(docid, rootnodeid, docname, doctype, " +
2560
        "user_owner, user_updated, date_created, date_updated, " +
2561
        "server_location, rev, public_access, catalog_id) " +
2562
      "SELECT ?, rootnodeid, docname, doctype, " + 
2563
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
2564
        "server_location, rev, public_access, catalog_id " +
2565
      "FROM xml_documents " +
2566
      "WHERE docid = ?");
2567
      // Bind the values to the query and execute it
2568
      pstmt.setString(1, docid);
2569
      pstmt.setString(2, user);
2570
      pstmt.setString(3, docid);
2571
      pstmt.execute();
2572
      pstmt.close();
2573
   }//try
2574
   catch (SQLException e)
2575
   {
2576
     MetaCatUtil.debugMessage("Error in DocumentImpl.archiveDocRevision : "+
2577
                                e.getMessage(), 30);
2578
   }//catch
2579
   finally
2580
   {
2581
     try
2582
     {
2583
       pstmt.close();
2584
     }//try
2585
     catch (SQLException ee)
2586
     {
2587
       MetaCatUtil.debugMessage("Error in DocumnetImpl.archiveDocRevision: "+
2588
                                  ee.getMessage(), 50);
2589
     }//catch
2590
     finally
2591
     {
2592
       //check in DBConnection
2593
       DBConnectionPool.returnDBConnection(conn, serialNumber);
2594
     }//finally
2595
   }//finnally
2596
                                  
2597

    
2598
  }//achiveDocRevision
2599
  
2600
  /**
2601
    * delete a entry in xml_table for given docid
2602
    * @param docId, the id of the document need to be delete
2603
    */
2604
  private static void deleteXMLDocuments(String docId) 
2605
                                         throws SQLException 
2606
  {
2607
    DBConnection conn = null;
2608
    int serialNumber = -1;
2609
    PreparedStatement pStmt = null;
2610
    try
2611
    {
2612
      //check out DBConnection
2613
      conn=DBConnectionPool.
2614
                    getDBConnection("DocumentImpl.deleteXMLDocuments");
2615
      serialNumber=conn.getCheckOutSerialNumber();
2616
      //delete a record 
2617
      pStmt = 
2618
             conn.prepareStatement("DELETE FROM xml_documents WHERE docid = '" 
2619
                                              + docId + "'");
2620
    pStmt.execute();
2621
    }//try
2622
    finally
2623
    {
2624
      try
2625
      {
2626
        pStmt.close();
2627
      }//try
2628
      catch (SQLException e)
2629
      {
2630
        MetaCatUtil.debugMessage("error in DocumentImpl.deleteXMLDocuments: "+
2631
                                  e.getMessage(), 50);
2632
      }//catch
2633
      finally
2634
      {
2635
        //return back DBconnection
2636
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2637
      }//finally
2638
    }//finally
2639
      
2640

    
2641
  }//deleteXMLDocuments
2642
  
2643
  /**
2644
    * Get last revision number from database for a docid
2645
    * If couldn't find an entry,  -1 will return
2646
    * The return value is integer because we want compare it to there new one
2647
    * @param docid <sitecode>.<uniqueid> part of Accession Number
2648
    */
2649
  public static int getLatestRevisionNumber(String docId)
2650
                                      throws SQLException
2651
  {
2652
    int rev = 1;
2653
    PreparedStatement pStmt = null;
2654
    DBConnection dbConn = null;
2655
    int serialNumber = -1;
2656
    // get rid of rev
2657
    docId = MetaCatUtil.getDocIdFromString(docId);
2658
    try
2659
    {
2660
      //check out DBConnection
2661
      dbConn=DBConnectionPool.
2662
                    getDBConnection("DocumentImpl.getLatestRevisionNumber");
2663
      serialNumber=dbConn.getCheckOutSerialNumber();
2664
     
2665
      pStmt = dbConn.prepareStatement
2666
              ("SELECT rev FROM xml_documents WHERE docid='" + docId + "'");
2667
      pStmt.execute();
2668

    
2669
      ResultSet rs = pStmt.getResultSet();
2670
      boolean hasRow = rs.next();
2671
      if (hasRow)
2672
      {
2673
        rev = rs.getInt(1);
2674
        pStmt.close();
2675
      }
2676
      else
2677
      {
2678
        rev=-1;
2679
        pStmt.close();
2680
      }
2681
    }//try
2682
    finally
2683
    {
2684
      try
2685
      {
2686
        pStmt.close();
2687
      }
2688
      catch (Exception ee)
2689
      {
2690
        MetaCatUtil.debugMessage("Error in DocumentImpl."+
2691
                        "getLatestRevisionNumber: "+ee.getMessage(), 50);
2692
      }
2693
      finally
2694
      {
2695
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2696
      }
2697
    }//finally  
2698
      
2699
    return rev;
2700
  }//getLatestRevisionNumber
2701
  
2702
  /**
2703
   * Get server location form database for a accNum
2704
   * 
2705
   * @param accum <sitecode>.<uniqueid>.<rev>
2706
   */
2707
  private static int getServerLocationNumber(String accNum)
2708
                                            throws SQLException
2709
  {
2710
    //get rid of revNum part
2711
    String docId=MetaCatUtil.getDocIdFromString(accNum);
2712
    PreparedStatement pStmt = null;
2713
    int serverLocation = 1;
2714
    DBConnection conn = null;
2715
    int serialNumber = -1;
2716
    
2717
    try
2718
    {
2719
      //check out DBConnection
2720
      conn=DBConnectionPool.
2721
                    getDBConnection("DocumentImpl.getServerLocationNumber");
2722
      serialNumber=conn.getCheckOutSerialNumber();
2723
     
2724
      pStmt = conn.prepareStatement
2725
      ("SELECT server_location FROM xml_documents WHERE docid='" + docId + "'");
2726
      pStmt.execute();
2727

    
2728
      ResultSet rs = pStmt.getResultSet();
2729
      boolean hasRow = rs.next();
2730
      //if there is entry in xml_documents, get the serverlocation
2731
      if (hasRow)
2732
      {
2733
        serverLocation = rs.getInt(1);
2734
        pStmt.close();
2735
      }
2736
      else
2737
      {
2738
        //if htere is no entry in xml_documents, we consider it is new document
2739
        //the server location is local host and value is 1
2740
        serverLocation=1;
2741
        pStmt.close();
2742
      }
2743
    }//try
2744
    finally
2745
    {
2746
      try
2747
      {
2748
        pStmt.close();
2749
      }//try
2750
      catch (Exception ee)
2751
      {
2752
        MetaCatUtil.debugMessage("Error in DocumentImpl.getServerLocationNu(): "
2753
                                    +ee.getMessage(), 50);
2754
      }//catch
2755
      finally
2756
      {
2757
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2758
      }//finally
2759
    }//finally
2760
      
2761
    return serverLocation;
2762
  }
2763
  
2764
  /**
2765
   * Given a server name, return its servercode in xml_replication table.
2766
   * If no server is found, -1 will return
2767
   * @param serverName, 
2768
   */
2769
  private static int getServerCode(String serverName) 
2770
  {
2771
    PreparedStatement pStmt=null;
2772
    int serverLocation=-2;
2773
    DBConnection dbConn = null;
2774
    int serialNumber = -1;
2775
    //MetaCatUtil util = new MetaCatUtil();
2776
    
2777
    
2778
    //we should consider about local host too
2779
    if (serverName.equals(MetaCatUtil.getLocalReplicationServerName()))
2780
    { 
2781
      serverLocation=1;
2782
      return serverLocation;
2783
    }
2784
    
2785
   
2786
    try
2787
    {
2788
      //check xml_replication table
2789
      //dbConn=util.openDBConnection();
2790
      //check out DBConnection
2791
      dbConn=DBConnectionPool.getDBConnection("DocumentImpl.getServerCode");
2792
      serialNumber=dbConn.getCheckOutSerialNumber();
2793
      pStmt = dbConn.prepareStatement
2794
      ("SELECT serverid FROM xml_replication WHERE server='" + serverName +"'");
2795
      pStmt.execute();
2796

    
2797
      ResultSet rs = pStmt.getResultSet();
2798
      boolean hasRow = rs.next();
2799
      //if there is entry in xml_replication, get the serverid
2800
      if (hasRow)
2801
      {
2802
        serverLocation = rs.getInt(1);
2803
        pStmt.close();
2804
      }
2805
      else
2806
      {
2807
        // if htere is no entry in xml_replication, -1 will return
2808
        serverLocation=-1;
2809
        pStmt.close();
2810
      }
2811
    }
2812
    catch (Exception e)
2813
    {
2814
      MetaCatUtil.debugMessage("Error in DocumentImpl.getServerCode(): "
2815
                                    +e.getMessage(), 30);
2816
    }
2817
    finally
2818
    {
2819
      try
2820
      {
2821
        pStmt.close();
2822
      }
2823
      catch (Exception ee)
2824
      {
2825
        MetaCatUtil.debugMessage("Error in DocumentImpl.getServerCode(): "
2826
                                    +ee.getMessage(), 50);
2827
      }
2828
      finally
2829
      {
2830
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2831
      }
2832
    }
2833
                 
2834
      
2835
    return serverLocation;
2836
  }
2837
  
2838
  /**
2839
   * Insert a server into xml_replcation table
2840
   * @param server, the name of server 
2841
   */
2842
  private static synchronized void 
2843
                                insertServerIntoReplicationTable(String server)
2844
  {
2845
    PreparedStatement pStmt=null;
2846
    DBConnection dbConn = null;
2847
    int serialNumber = -1;
2848
    
2849
    // Initial value for the server
2850
    int replicate = 0;
2851
    int dataReplicate = 0;
2852
    int hub = 0;
2853
   
2854
    try
2855
    {
2856
       // Get DBConnection
2857
       dbConn=DBConnectionPool.
2858
                getDBConnection("DocumentImpl.insertServIntoReplicationTable");
2859
       serialNumber=dbConn.getCheckOutSerialNumber();
2860
      
2861
      // Compare the server to dabase
2862
      pStmt = dbConn.prepareStatement
2863
      ("SELECT serverid FROM xml_replication WHERE server='" + server +"'");
2864
      pStmt.execute();
2865
      ResultSet rs = pStmt.getResultSet();
2866
      boolean hasRow = rs.next();
2867
      // Close preparedstatement and result set
2868
      pStmt.close();
2869
      rs.close();
2870
      
2871
      // If the server is not in the table, and server is not local host,
2872
      // insert it
2873
      if ( !hasRow 
2874
         && !server.equals(MetaCatUtil.getLocalReplicationServerName()))
2875
      {
2876
        // Set auto commit false
2877
        dbConn.setAutoCommit(false);
2878
        /*pStmt = dbConn.prepareStatement("INSERT INTO xml_replication " +
2879
                      "(server, last_checked, replicate, datareplicate, hub) " +
2880
                       "VALUES ('" + server + "', to_date(" +
2881
                       "'01/01/00', 'MM/DD/YY'), '" +
2882
                       replicate +"', '"+dataReplicate+"','"+ hub + "')");*/
2883
        pStmt = dbConn.prepareStatement("INSERT INTO xml_replication " +
2884
                      "(server, last_checked, replicate, datareplicate, hub) " +
2885
                       "VALUES ('" + server + "', " + 
2886
                       dbAdapter.toDate("01/01/1980", "MM/DD/YYYY") + ", '" +
2887
                       replicate +"', '"+dataReplicate+"','"+ hub + "')");
2888
        
2889
                              
2890
        pStmt.execute();
2891
        dbConn.commit();
2892
        // Increase usage number
2893
        dbConn.increaseUsageCount(1);
2894
        pStmt.close();
2895
        
2896
      }
2897
    }//try
2898
    catch (Exception e)
2899
    {
2900
      MetaCatUtil.debugMessage("Error in DocumentImpl.insertServerIntoRepli(): "
2901
                                    +e.getMessage(), 30);
2902
    }//catch
2903
    finally
2904
    {
2905
     
2906
      try
2907
      {
2908
        // Set auto commit true
2909
        dbConn.setAutoCommit(true);
2910
        pStmt.close();
2911
        
2912
      }//try
2913
      catch (Exception ee)
2914
      {
2915
        MetaCatUtil.debugMessage("Error in DocumentImpl.insetServerIntoRepl(): "
2916
                                    +ee.getMessage(), 50);
2917
      }//catch
2918
      finally
2919
      {
2920
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2921
      }
2922
    
2923
    }//finally
2924

    
2925
  }
2926
  
2927
  
2928
  /**
2929
   * the main routine used to test the DBWriter utility.
2930
   * <p>
2931
   * Usage: java DocumentImpl <-f filename -a action -d docid>
2932
   *
2933
   * @param filename the filename to be loaded into the database
2934
   * @param action the action to perform (READ, INSERT, UPDATE, DELETE)
2935
   * @param docid the id of the document to process
2936
   */
2937
  static public void main(String[] args) {
2938
    DBConnection dbconn = null;
2939
    int serialNumber = -1;
2940
    try {
2941
      String filename    = null;
2942
      String dtdfilename = null;
2943
      String action      = null;
2944
      String docid       = null;
2945
      boolean showRuntime = false;
2946
      boolean useOldReadAlgorithm = false;
2947

    
2948
      // Parse the command line arguments
2949
      for ( int i=0 ; i < args.length; ++i ) {
2950
        if ( args[i].equals( "-f" ) ) {
2951
          filename =  args[++i];
2952
        } else if ( args[i].equals( "-r" ) ) {
2953
          dtdfilename =  args[++i];
2954
        } else if ( args[i].equals( "-a" ) ) {
2955
          action =  args[++i];
2956
        } else if ( args[i].equals( "-d" ) ) {
2957
          docid =  args[++i];
2958
        } else if ( args[i].equals( "-t" ) ) {
2959
          showRuntime = true;
2960
        } else if ( args[i].equals( "-old" ) ) {
2961
          useOldReadAlgorithm = true;
2962
        } else {
2963
          System.err.println
2964
            ( "   args[" +i+ "] '" +args[i]+ "' ignored." );
2965
        }
2966
      }
2967
      
2968
      // Check if the required arguments are provided
2969
      boolean argsAreValid = false;
2970
      if (action != null) {
2971
        if (action.equals("INSERT")) {
2972
          if (filename != null) {
2973
            argsAreValid = true;
2974
          } 
2975
        } else if (action.equals("UPDATE")) {
2976
          if ((filename != null) && (docid != null)) {
2977
            argsAreValid = true;
2978
          } 
2979
        } else if (action.equals("DELETE")) {
2980
          if (docid != null) {
2981
            argsAreValid = true;
2982
          } 
2983
        } else if (action.equals("READ")) {
2984
          if (docid != null) {
2985
            argsAreValid = true;
2986
          } 
2987
        } 
2988
      } 
2989

    
2990
      // Print usage message if the arguments are not valid
2991
      if (!argsAreValid) {
2992
        System.err.println("Wrong number of arguments!!!");
2993
        System.err.println(
2994
          "USAGE: java DocumentImpl [-t] <-a INSERT> [-d docid] <-f filename> "+
2995
          "[-r dtdfilename]");
2996
        System.err.println(
2997
          "   OR: java DocumentImpl [-t] <-a UPDATE -d docid -f filename> " +
2998
          "[-r dtdfilename]");
2999
        System.err.println(
3000
          "   OR: java DocumentImpl [-t] <-a DELETE -d docid>");
3001
        System.err.println(
3002
          "   OR: java DocumentImpl [-t] [-old] <-a READ -d docid>");
3003
        return;
3004
      }
3005
      
3006
      // Time the request if asked for
3007
      double startTime = System.currentTimeMillis();
3008
      
3009
      // Open a connection to the database
3010
      MetaCatUtil util = new MetaCatUtil();
3011
     
3012
      dbconn=DBConnectionPool.getDBConnection("DocumentImpl.main");
3013
      serialNumber=dbconn.getCheckOutSerialNumber();
3014

    
3015
      double connTime = System.currentTimeMillis();
3016
      // Execute the action requested (READ, INSERT, UPDATE, DELETE)
3017
      if (action.equals("READ")) {
3018
          DocumentImpl xmldoc = new DocumentImpl(docid );
3019
          if (useOldReadAlgorithm) {
3020
            System.out.println(xmldoc.readUsingSlowAlgorithm());
3021
          } else {
3022
            xmldoc.toXml(new PrintWriter(System.out), null, null, true);
3023
          }
3024
      } else if (action.equals("DELETE")) {
3025
        DocumentImpl.delete(docid, null, null);
3026
        System.out.println("Document deleted: " + docid);
3027
      } else {
3028
        /*String newdocid = DocumentImpl.write(dbconn, filename, null,
3029
                                             dtdfilename, action, docid,
3030
                                             null, null);
3031
        if ((docid != null) && (!docid.equals(newdocid))) {
3032
          if (action.equals("INSERT")) {
3033
            System.out.println("New document ID generated!!! ");
3034
          } else if (action.equals("UPDATE")) {
3035
            System.out.println("ERROR: Couldn't update document!!! ");
3036
          }
3037
        } else if ((docid == null) && (action.equals("UPDATE"))) {
3038
          System.out.println("ERROR: Couldn't update document!!! ");
3039
        }
3040
        System.out.println("Document processing finished for: " + filename
3041
              + " (" + newdocid + ")");*/
3042
      }
3043

    
3044
      double stopTime = System.currentTimeMillis();
3045
      double dbOpenTime = (connTime - startTime)/1000;
3046
      double insertTime = (stopTime - connTime)/1000;
3047
      double executionTime = (stopTime - startTime)/1000;
3048
      if (showRuntime) {
3049
        System.out.println("\n\nTotal Execution time was: " + 
3050
                           executionTime + " seconds.");
3051
        System.out.println("Time to open DB connection was: " + dbOpenTime + 
3052
                           " seconds.");
3053
        System.out.println("Time to insert document was: " + insertTime +
3054
                           " seconds.");
3055
      }
3056
      dbconn.close();
3057
    } catch (McdbException me) {
3058
      me.toXml(new PrintWriter(System.err));
3059
    } catch (AccessionNumberException ane) {
3060
      System.out.println(ane.getMessage());
3061
    } catch (Exception e) {
3062
      System.err.println("EXCEPTION HANDLING REQUIRED");
3063
      System.err.println(e.getMessage());
3064
      e.printStackTrace(System.err);
3065
    }
3066
    finally
3067
    {
3068
      // Return db connection
3069
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
3070
    }
3071
  }
3072
}
(31-31/58)