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: jones $'
10
 *     '$Date: 2004-03-30 13:35:19 -0800 (Tue, 30 Mar 2004) $'
11
 * '$Revision: 2076 $'
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.io.BufferedInputStream;
31
import java.io.BufferedOutputStream;
32
import java.io.File;
33
import java.io.FileOutputStream;
34
import java.io.IOException;
35
import java.io.InputStream;
36
import java.io.PrintWriter;
37
import java.io.Reader;
38
import java.io.StringWriter;
39
import java.io.Writer;
40
import java.net.URL;
41
import java.sql.PreparedStatement;
42
import java.sql.ResultSet;
43
import java.sql.SQLException;
44
import java.util.Enumeration;
45
import java.util.Hashtable;
46
import java.util.Iterator;
47
import java.util.Stack;
48
import java.util.TreeSet;
49
import java.util.Vector;
50

    
51
import edu.ucsb.nceas.dbadapter.AbstractDatabase;
52

    
53
import org.xml.sax.ContentHandler;
54
import org.xml.sax.DTDHandler;
55
import org.xml.sax.EntityResolver;
56
import org.xml.sax.ErrorHandler;
57
import org.xml.sax.InputSource;
58
import org.xml.sax.XMLReader;
59
import org.xml.sax.helpers.XMLReaderFactory;
60

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
894
    Stack openElements = new Stack();
895
    boolean atRootElement = true;
896
    boolean previousNodeWasElement = false;
897

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

    
946
      // Handle the DOCUMENT node
947
      if (currentNode.nodetype.equals("DOCUMENT")) {
948
        out.print("<?xml version=\"1.0\"?>");
949
       
950

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

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

    
1006
      // Handle the NAMESPACE nodes
1007
      } else if (currentNode.nodetype.equals("NAMESPACE")) {
1008
        out.print(" xmlns:" + currentNode.nodename + "=\""
1009
                 + currentNode.nodedata + "\"");
1010

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

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

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

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

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

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

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

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

    
1383
    try 
1384
    {
1385
      dbconn=DBConnectionPool.
1386
                    getDBConnection("DocumentImpl.getPartNodeRecordList");
1387
      serialNumber=dbconn.getCheckOutSerialNumber();
1388
      pstmt = dbconn.prepareStatement(sql);
1389

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

    
1410
        // Advance to the next node
1411
        tableHasRows = rs.next();
1412
      } 
1413
      pstmt.close();
1414

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

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

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

    
1480
      // Bind the values to the query
1481
      pstmt.setLong(1, rootnodeid);
1482

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

    
1500
        // Advance to the next node
1501
        tableHasRows = rs.next();
1502
      } 
1503
      pstmt.close();
1504

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

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

    
1545
    try {
1546
      PreparedStatement pstmt = null;
1547

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

    
1587
        // Save the old document publicaccessentry in a backup table
1588
        DocumentImpl.archiveDocRevision(connection, docid, user );
1589
        MetaCatUtil.debugMessage("after archiveDoc", 40);
1590
        DocumentImpl thisdoc = new DocumentImpl(docid, false);
1591
        int thisrev = thisdoc.getRev();
1592
        MetaCatUtil.debugMessage("this revsion is: "+thisrev, 40);
1593
        //if the updated vesion is not greater than current one,
1594
        //throw it into a exception
1595
        if (Integer.parseInt(updatedVersion)<=thisrev)
1596
        {
1597
          throw new Exception("Next revision number couldn't be less"
1598
                               +" than or equal "+ thisrev);
1599
        }
1600
        else
1601
        {
1602
          //set the user specified revision 
1603
          thisrev=Integer.parseInt(updatedVersion);
1604
        }
1605
        MetaCatUtil.debugMessage("final revsion is: "+thisrev, 40);
1606
        boolean useXMLIndex = 
1607
            (new Boolean(MetaCatUtil.getOption("usexmlindex"))).booleanValue();
1608
        if (useXMLIndex) {
1609
            MetaCatUtil.debugMessage("before delete", 40);
1610
            // Delete index for the old version of docid
1611
            // The new index is inserting on the next calls to DBSAXNode
1612
            pstmt = connection.prepareStatement(
1613
                    "DELETE FROM xml_index WHERE docid='" + this.docid + "'");
1614
            MetaCatUtil.debugMessage("after delete", 40);
1615
            // Increase dbconnection usage count
1616
            connection.increaseUsageCount(1);
1617
            
1618
            pstmt.execute();
1619
            pstmt.close();    
1620
        }
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 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
      boolean useXMLIndex = 
2203
          (new Boolean(MetaCatUtil.getOption("usexmlindex"))).booleanValue();
2204
      if (useXMLIndex) {
2205
          pstmt = conn.prepareStatement("DELETE FROM xml_index WHERE docid = ?");
2206
          pstmt.setString(1,docid);
2207
          pstmt.execute();
2208
          pstmt.close();
2209
          conn.increaseUsageCount(1);
2210
      }
2211
      
2212
      //stmt.execute("DELETE FROM xml_access WHERE docid = '" + docid + "'");
2213
      // Now delete it from xml_access table
2214
      pstmt = conn.
2215
              prepareStatement("DELETE FROM xml_access WHERE accessfileid = ?");
2216
      pstmt.setString(1, docid);
2217
      pstmt.execute();
2218
      pstmt.close();
2219
      conn.increaseUsageCount(1);
2220
      
2221
      // Delete it from relation table
2222
      pstmt = conn.
2223
               prepareStatement("DELETE FROM xml_relation WHERE docid = ?");
2224
      //increase usage count
2225
      conn.increaseUsageCount(1);
2226
      pstmt.setString(1, docid);
2227
      pstmt.execute();
2228
      pstmt.close();
2229
      
2230
      // Delete it from xml_accesssubtree table
2231
      pstmt = conn.
2232
               prepareStatement("DELETE FROM xml_accesssubtree WHERE docid = ?");
2233
      //increase usage count
2234
      conn.increaseUsageCount(1);
2235
      pstmt.setString(1, docid);
2236
      pstmt.execute();
2237
      pstmt.close();
2238
      
2239
      // Delete it from xml_doucments table
2240
      pstmt =conn.prepareStatement("DELETE FROM xml_documents WHERE docid = ?");
2241
      pstmt.setString(1, docid);
2242
      pstmt.execute();
2243
      pstmt.close();
2244
      //Usaga count increase 1
2245
      conn.increaseUsageCount(1);
2246
      
2247
      conn.commit();
2248
      conn.setAutoCommit(true);
2249
    }//try
2250
    catch (Exception e)
2251
    {
2252
      MetaCatUtil.debugMessage("error in DocumentImpl.delete: " + 
2253
                                e.getMessage(), 30);
2254
      throw e;
2255
    }
2256
    finally
2257
    {
2258
      
2259
      try
2260
      {
2261
        // close preparedStatement
2262
        pstmt.close();
2263
      }//try
2264
      finally
2265
      {
2266
        //check in DBonnection
2267
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2268
      }//finally
2269
    }//finally
2270
    //IF this is a package document:
2271
    //delete all of the relations that this document created.
2272
    //if the deleted document is a package document its relations should 
2273
    //no longer be active if it has been deleted from the system.
2274
    
2275
  }
2276

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

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

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

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

    
2444
      // Get an instance of the parser
2445
      String parserName = MetaCatUtil.getOption("saxparser");
2446
      parser = XMLReaderFactory.createXMLReader(parserName);
2447

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

    
2466
    } catch (Exception e) {
2467
      throw e;
2468
    }
2469
    //finally
2470
    //{
2471
      //DBConnectionPool.returnDBConnection(conn, serialNumber);
2472
    //}
2473

    
2474
    return parser;
2475
  }*/
2476

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

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

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

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

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

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

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

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

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

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

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

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