Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that represents an XML document
4
 *  Copyright: 2000 Regents of the University of California and the
5
 *             National Center for Ecological Analysis and Synthesis
6
 *    Authors: Matt Jones
7
 *    Release: @release@
8
 *
9
 *   '$Author: tao $'
10
 *     '$Date: 2003-03-18 14:10:28 -0800 (Tue, 18 Mar 2003) $'
11
 * '$Revision: 1480 $'
12
 *
13
 * This program is free software; you can redistribute it and/or modify
14
 * it under the terms of the GNU General Public License as published by
15
 * the Free Software Foundation; either version 2 of the License, or
16
 * (at your option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU General Public License
24
 * along with this program; if not, write to the Free Software
25
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
 */
27

    
28
package edu.ucsb.nceas.metacat;
29

    
30
import java.sql.*;
31
import java.io.File;
32
import java.io.FileReader;
33
import java.io.IOException;
34
import java.io.PrintWriter;
35
import java.io.Reader;
36
import java.io.StringWriter;
37
import java.io.Writer;
38
import java.io.InputStreamReader;
39
import java.io.*;
40
import java.text.SimpleDateFormat;
41

    
42
import java.util.Date;
43
import java.util.Hashtable;
44
import java.util.Iterator;
45
import java.util.Stack;
46
import java.util.TreeSet;
47
import java.util.Vector;
48
import java.util.Enumeration;
49

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

    
61
import java.net.URL;
62

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

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

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

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

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

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

    
521
    BufferedInputStream bis = null;
522
    bis = new BufferedInputStream(input);
523
    byte[] buf = new byte[4 * 1024]; // 4K buffer
524
    int b = bis.read(buf);
525
       
526
    while (b != -1) 
527
    {
528
        outPut.write(buf, 0, b);
529
        b = bis.read(buf);
530
    }
531
    bis.close();
532
	  outPut.close();
533
	  fos.close();
534
      
535
    // Force replicate data file
536
    ForceReplicationHandler forceReplication = new ForceReplicationHandler
537
                                    (accnum, false, notificationServer);
538
  
539
 }
540
  
541

    
542
  
543
  public static boolean getDataFileLockGrant(String accnum) 
544
                                                  throws Exception
545
  { 
546
    
547
    try
548
    {
549
      
550
      int serverLocation=getServerLocationNumber(accnum);
551
    
552
      return getDataFileLockGrant(accnum,serverLocation);
553
    }
554
    catch (Exception e)
555
    {
556
     
557
      throw e;
558
    }
559
  }
560
    
561
  /**
562
   * The method will check if metacat can get data file lock grant
563
   * If server code is 1, it get.
564
   * If server code is not 1 but call replication getlock successfully,
565
   * it get
566
   * else, it didn't get
567
   * @param accnum, the ID of the document 
568
   * @param action, the action to the document
569
   * @param serverCode, the server location code
570
   */
571
  public static boolean getDataFileLockGrant(String accnum, int serverCode)
572
                                          throws Exception 
573
  {
574
    boolean flag=true;
575
    //MetaCatUtil util = new MetaCatUtil();
576
    String docid = MetaCatUtil.getDocIdFromString(accnum);
577
    int rev = MetaCatUtil.getVersionFromString(accnum);
578
    
579
    if (serverCode == 1)
580
    {
581
      flag=true;
582
      return flag;
583
    }
584
    
585
    //if((serverCode != 1 && action.equals("UPDATE")) )
586
    if (serverCode != 1)
587
    { //if this document being written is not a resident of this server then
588
      //we need to try to get a lock from it's resident server.  If the
589
      //resident server will not give a lock then we send the user a message
590
      //saying that he/she needs to download a new copy of the file and
591
      //merge the differences manually.
592
      
593
      String server=MetacatReplication.getServerNameForServerCode(serverCode);
594
      MetacatReplication.replLog("attempting to lock " + accnum);
595
      URL u = new URL("https://" + server + "?server=" +
596
        MetaCatUtil.getLocalReplicationServerName()+"&action=getlock&updaterev=" 
597
           +rev + "&docid=" + docid);
598
      //System.out.println("sending message: " + u.toString());
599
      String serverResStr = MetacatReplication.getURLContent(u);
600
      String openingtag =serverResStr.substring(0, serverResStr.indexOf(">")+1);
601
      if(openingtag.equals("<lockgranted>"))
602
      {
603
        //the lock was granted go ahead with the insert
604
        //System.out.println("In lockgranted");
605
        MetacatReplication.replLog("lock granted for " + accnum + " from " +
606
                                      server);
607
        flag=true;  
608
        return flag;
609
      }//if
610

    
611
      else if(openingtag.equals("<filelocked>"))
612
      {//the file is currently locked by another user
613
       //notify our user to wait a few minutes, check out a new copy and try
614
       //again.
615
        //System.out.println("file locked");
616
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
617
                                   server + " reason: file already locked");
618
        throw new Exception("The file specified is already locked by another " +
619
                            "user.  Please wait 30 seconds, checkout the " +
620
                            "newer document, merge your changes and try " +
621
                            "again.");
622
      }
623
      else if(openingtag.equals("<outdatedfile>"))
624
      {//our file is outdated.  notify our user to check out a new copy of the
625
       //file and merge his version with the new version.
626
        //System.out.println("outdated file");
627
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
628
                                    server + " reason: local file outdated");
629
        throw new Exception("The file you are trying to update is an outdated" +
630
                            " version.  Please checkout the newest document, " +
631
                            "merge your changes and try again.");
632
      }//else if
633
    }//if
634
    
635
   return flag;
636
   
637
  }//getDataFileLockGrant
638
  
639
  /**
640
   * get the document name
641
   */
642
  public String getDocname() {
643
    return docname;
644
  }
645

    
646
  /**
647
   * get the document type (which is the PublicID)
648
   */
649
  public String getDoctype() {
650
    return doctype;
651
  }
652

    
653
  /**
654
   * get the system identifier
655
   */
656
  public String getSystemID() {
657
    return system_id;
658
  }
659

    
660
  /**
661
   * get the root node identifier
662
   */
663
  public long getRootNodeID() {
664
    return rootnodeid;
665
  }
666
  
667
  /**
668
   * get the creation date
669
   */
670
  public String getCreateDate() {
671
    return createdate;
672
  }
673
  
674
  /**
675
   * get the update date
676
   */
677
  public String getUpdateDate() {
678
    return updatedate;
679
  }
680

    
681
  /** 
682
   * Get the document identifier (docid)
683
   */
684
  public String getDocID() {
685
    return docid;
686
  }
687
  
688
// DOCTITLE attr cleared from the db
689
//  /**
690
//   *get the document title
691
//   */
692
//  public String getDocTitle() {
693
//    return doctitle;
694
//  }
695
  
696
  public String getUserowner() {
697
    return userowner;
698
  }
699
  
700
  public String getUserupdated() {
701
    return userupdated;
702
  }
703
  
704
  public int getServerlocation() {
705
    return serverlocation;
706
  }
707
  
708
  public String getDocHomeServer() {
709
    return docHomeServer;
710
  }
711
  
712
 
713
 
714
  public String getPublicaccess() {
715
    return publicaccess;
716
  }
717
  
718
  public int getRev() {
719
    return rev;
720
  }
721
  
722
  public String getValidateType()
723
  {
724
    return validateType;
725
  }
726
  
727
  /**
728
   * Print a string representation of the XML document
729
   */
730
  public String toString(String user, String[] groups, boolean withInlinedata)
731
  {
732
    StringWriter docwriter = new StringWriter();
733
    try 
734
    {
735
      this.toXml(docwriter, user, groups, withInlinedata);
736
    } 
737
    catch (McdbException mcdbe) 
738
    {
739
      return null;
740
    }
741
    String document = docwriter.toString();
742
    return document;
743
  }
744
  
745
   /**
746
   * Print a string representation of the XML document
747
   */
748
  public String toString()
749
  {
750
    StringWriter docwriter = new StringWriter();
751
    String userName = null;
752
    String[] groupNames = null;
753
    boolean withInlineData = false;
754
    try 
755
    {
756
      this.toXml(docwriter, userName, groupNames, withInlineData);
757
    } 
758
    catch (McdbException mcdbe) 
759
    {
760
      return null;
761
    }
762
    String document = docwriter.toString();
763
    return document;
764
  }
765

    
766
  /**
767
   * Get a text representation of the XML document as a string
768
   * This older algorithm uses a recursive tree of Objects to represent the
769
   * nodes of the tree.  Each object is passed the data for the document 
770
   * and searches all of the document data to find its children nodes and
771
   * recursively build.  Thus, because each node reads the whole document,
772
   * this algorithm is extremely slow for larger documents, and the time
773
   * to completion is O(N^N) wrt the number of nodes.  See toXml() for a
774
   * better algorithm.
775
   */
776
  public String readUsingSlowAlgorithm() throws McdbException
777
  {
778
    StringBuffer doc = new StringBuffer();
779

    
780
    // First, check that we have the needed node data, and get it if not
781
    if (nodeRecordList == null) {
782
      nodeRecordList = getNodeRecordList(rootnodeid);
783
    }
784

    
785
    // Create the elements from the downloaded data in the TreeSet
786
    rootNode = new ElementNode(nodeRecordList, rootnodeid);
787

    
788
    // Append the resulting document to the StringBuffer and return it
789
    doc.append("<?xml version=\"1.0\"?>\n");
790
      
791
    if (docname != null) {
792
      if ((doctype != null) && (system_id != null)) {
793
        doc.append("<!DOCTYPE " + docname + " PUBLIC \"" + doctype + 
794
                   "\" \"" + system_id + "\">\n");
795
      } else {
796
        doc.append("<!DOCTYPE " + docname + ">\n");
797
      }
798
    }
799
    doc.append(rootNode.toString());
800
  
801
    return (doc.toString());
802
  }
803

    
804
  /**
805
   * Print a text representation of the XML document to a Writer
806
   *
807
   * @param pw the Writer to which we print the document
808
   */
809
  public void toXml(Writer pw, String user, String[] groups, boolean withInLineData) 
810
                                                          throws McdbException
811
  {
812
    // flag for process  eml2
813
    boolean proccessEml2 = false;
814
    if (doctype != null && doctype.equals(EMLNAMESPACE))
815
    {
816
      proccessEml2 = true;
817
    }
818
    // flag for process inline data
819
    boolean prcocessInlineData = false;
820
    
821
    TreeSet nodeRecordLists = null;
822
    PrintWriter out = null;
823
    if (pw instanceof PrintWriter) {
824
      out = (PrintWriter)pw;
825
    } else {
826
      out = new PrintWriter(pw);
827
    }
828

    
829
    MetaCatUtil util = new MetaCatUtil();
830
    
831
    // Here add code to handle subtree access control
832
    PermissionController control = new PermissionController(docid);
833
    Hashtable unaccessableSubTree =control.hasUnaccessableSubTree(user, groups, 
834
                                             AccessControlInterface.READSTRING);
835
    
836
    if (!unaccessableSubTree.isEmpty())
837
    {
838
     
839
      nodeRecordLists = getPartNodeRecordList(rootnodeid, unaccessableSubTree);
840
      
841
    }
842
    else 
843
    {
844
      nodeRecordLists = getNodeRecordList(rootnodeid);
845
    }
846

    
847
    Stack openElements = new Stack();
848
    boolean atRootElement = true;
849
    boolean previousNodeWasElement = false;
850

    
851
    // Step through all of the node records we were given
852
   
853
    Iterator it = nodeRecordLists.iterator();
854
   
855
    while (it.hasNext()) 
856
    {
857
      
858
      NodeRecord currentNode = (NodeRecord)it.next();
859
      util.debugMessage("[Got Node ID: " + currentNode.nodeid +
860
                          " (" + currentNode.parentnodeid +
861
                          ", " + currentNode.nodeindex + 
862
                          ", " + currentNode.nodetype + 
863
                          ", " + currentNode.nodename + 
864
                          ", " + currentNode.nodedata + ")]", 50);
865
      // Print the end tag for the previous node if needed
866
      //
867
      // This is determined by inspecting the parent nodeid for the
868
      // currentNode.  If it is the same as the nodeid of the last element
869
      // that was pushed onto the stack, then we are still in that previous
870
      // parent element, and we do nothing.  However, if it differs, then we
871
      // have returned to a level above the previous parent, so we go into
872
      // a loop and pop off nodes and print out their end tags until we get
873
      // the node on the stack to match the currentNode parentnodeid
874
      //
875
      // So, this of course means that we rely on the list of elements
876
      // having been sorted in a depth first traversal of the nodes, which
877
      // is handled by the NodeComparator class used by the TreeSet
878
      if (!atRootElement) {
879
        NodeRecord currentElement = (NodeRecord)openElements.peek();
880
        if ( currentNode.parentnodeid != currentElement.nodeid ) {
881
          while ( currentNode.parentnodeid != currentElement.nodeid ) {
882
            currentElement = (NodeRecord)openElements.pop();
883
            util.debugMessage("\n POPPED: " + currentElement.nodename, 50);
884
            if (previousNodeWasElement) {
885
              out.print(">");
886
              previousNodeWasElement = false;
887
            }  
888
            if ( currentElement.nodeprefix != null ) {
889
              out.print("</" + currentElement.nodeprefix + ":" + 
890
                        currentElement.nodename + ">" );
891
            } else {
892
              out.print("</" + currentElement.nodename + ">" );
893
            }
894
            currentElement = (NodeRecord)openElements.peek();
895
          }
896
        }
897
      }
898

    
899
      // Handle the DOCUMENT node
900
      if (currentNode.nodetype.equals("DOCUMENT")) {
901
        out.println("<?xml version=\"1.0\"?>");
902
        if (docname != null && validateType != null && validateType.equals(DTD)) 
903
        {
904
          if ((doctype != null) && (system_id != null)) 
905
          {
906
            
907
            out.println("<!DOCTYPE " + docname + " PUBLIC \"" + doctype + 
908
                       "\" \"" + system_id + "\">");
909
          } 
910
          else 
911
          {
912
            
913
            out.println("<!DOCTYPE " + docname + ">");
914
          }
915
        }
916

    
917
      // Handle the ELEMENT nodes
918
      } else if (currentNode.nodetype.equals("ELEMENT")) {
919
        if (atRootElement) {
920
          atRootElement = false;
921
        } else {
922
          if (previousNodeWasElement) {
923
            out.print(">");
924
          }
925
        }
926
        openElements.push(currentNode);
927
        util.debugMessage("\n PUSHED: " + currentNode.nodename, 50);
928
        previousNodeWasElement = true;
929
        if ( currentNode.nodeprefix != null ) {
930
          out.print("<" + currentNode.nodeprefix + ":" + currentNode.nodename);
931
        } else {
932
          out.print("<" + currentNode.nodename);
933
        }
934
        
935
        // if currentNode is inline and handle eml2, set flag proccess in
936
        if (currentNode.nodename != null && 
937
            currentNode.nodename.equals(EmlSAXHandler.INLINE) && proccessEml2)
938
        {
939
          prcocessInlineData = true;
940
        }
941

    
942
      // Handle the ATTRIBUTE nodes
943
      } else if (currentNode.nodetype.equals("ATTRIBUTE")) {
944
        if ( currentNode.nodeprefix != null ) {
945
          out.print(" " + currentNode.nodeprefix + ":" + currentNode.nodename +
946
                    "=\"" + currentNode.nodedata + "\"");
947
        } else {
948
          out.print(" " + currentNode.nodename + "=\"" +
949
                    currentNode.nodedata + "\"");
950
        }
951

    
952
      // Handle the NAMESPACE nodes
953
      } else if (currentNode.nodetype.equals("NAMESPACE")) {
954
        out.print(" xmlns:" + currentNode.nodename + "=\""
955
                 + currentNode.nodedata + "\"");
956

    
957
      // Handle the TEXT nodes
958
      } else if (currentNode.nodetype.equals("TEXT")) {
959
        if (previousNodeWasElement) {
960
          out.print(">");
961
        }
962
        if (!prcocessInlineData || !withInLineData)
963
        {
964
          // if it is not inline data just out put data or it is line data
965
          // but user don't want it, just put local id in inlinedata
966
          out.print(currentNode.nodedata);
967
        }
968
        else
969
        {
970
          // if it is inline data and user want to see it, pull out from 
971
          // file system and output it
972
          // for inline data, the data base only store the file name, so we
973
          // can combine the file name and inline data file path, to get it
974
          String fileName = currentNode.nodedata;
975
          String content = readInlineDataFromFileSystem(fileName);
976
          out.print(content);
977
        }
978
        // reset proccess inline data false
979
        prcocessInlineData =false;
980
        previousNodeWasElement = false;
981

    
982
      // Handle the COMMENT nodes
983
      } else if (currentNode.nodetype.equals("COMMENT")) {
984
        if (previousNodeWasElement) {
985
          out.print(">");
986
        }
987
        out.print("<!--" + currentNode.nodedata + "-->");
988
        previousNodeWasElement = false;
989

    
990
      // Handle the PI nodes
991
      } else if (currentNode.nodetype.equals("PI")) {
992
        if (previousNodeWasElement) {
993
          out.print(">");
994
        }
995
        out.print("<?" + currentNode.nodename + " " +
996
                        currentNode.nodedata + "?>");
997
        previousNodeWasElement = false;
998

    
999
      // Handle any other node type (do nothing)
1000
      } else {
1001
        // Any other types of nodes are not handled.
1002
        // Probably should throw an exception here to indicate this
1003
      }
1004
      out.flush();
1005
    }
1006
    
1007
    // Print the final end tag for the root element
1008
    while(!openElements.empty())
1009
    {
1010
      NodeRecord currentElement = (NodeRecord)openElements.pop();
1011
      util.debugMessage("\n POPPED: " + currentElement.nodename, 50);
1012
      if ( currentElement.nodeprefix != null ) {
1013
        out.print("</" + currentElement.nodeprefix + ":" + 
1014
                  currentElement.nodename + ">" );
1015
      } else {
1016
        out.print("</" + currentElement.nodename + ">" );
1017
      }
1018
    }
1019
    out.flush();
1020
  }
1021
  
1022
  /* In eml2, the inline data wouldn't store in db, it store in file system
1023
   * The db stores file name(without path).
1024
   */
1025
  private String readInlineDataFromFileSystem(String fileName) 
1026
                                              throws McdbException
1027
  {
1028
    String data = null;
1029
    String path = MetaCatUtil.getOption("inlinedatafilepath");
1030
    // the new file name will look like path/docid.rev.2
1031
    File inlineDataDirectory = new File(path);
1032
    File dataFile = new File(inlineDataDirectory, fileName);
1033
    try
1034
    {
1035
      FileReader fileReader = new FileReader(dataFile);
1036
      BufferedReader stringReader = new BufferedReader(fileReader);
1037
      // read first line of data
1038
      String tmp = stringReader.readLine();
1039
      // pass first line data to data varible
1040
      data = tmp;
1041
      // at the end tmp will be null
1042
      while (tmp != null)
1043
      {
1044
        // read a new line
1045
        tmp = stringReader.readLine();
1046
        // append new line to data
1047
        if (tmp != null)
1048
        {
1049
          data = data+tmp;
1050
        }
1051
      }
1052
      
1053
    }
1054
    catch (Exception e)
1055
    {
1056
      throw new McdbException(e.getMessage());
1057
    }
1058
    MetaCatUtil.debugMessage("the inline data retrieve from file: "+data, 50);
1059
    return data;
1060
  }
1061
  
1062
  private boolean isRevisionOnly(DocumentIdentifier docid) throws Exception
1063
  {
1064
    //System.out.println("inRevisionOnly");
1065
    DBConnection dbconn = null;
1066
    int serialNumber = -1;
1067
    PreparedStatement pstmt =null;
1068
    String rev = docid.getRev();
1069
    String newid = docid.getIdentifier();
1070
    try
1071
    {
1072
      dbconn=DBConnectionPool.
1073
                    getDBConnection("DocumentImpl.isRevisionOnly");
1074
      serialNumber=dbconn.getCheckOutSerialNumber();
1075
      pstmt = dbconn.prepareStatement("select rev from xml_documents " +
1076
                                  "where docid like '" + newid + "'");
1077
      pstmt.execute();
1078
      ResultSet rs = pstmt.getResultSet();
1079
      boolean tablehasrows = rs.next();
1080
      if(rev.equals("newest") || rev.equals("all"))
1081
      {
1082
        return false;
1083
      }
1084
    
1085
      if(tablehasrows)
1086
      {
1087
        int r = rs.getInt(1);
1088
        pstmt.close();
1089
        if(new Integer(rev).intValue() == r)
1090
        { //the current revision in in xml_documents
1091
          //System.out.println("returning false");
1092
          return false;
1093
        }
1094
        else if(new Integer(rev).intValue() < r)
1095
        { //the current revision is in xml_revisions.
1096
          //System.out.println("returning true");
1097
          return true;
1098
        }
1099
        else if(new Integer(rev).intValue() > r)
1100
        { //error, rev cannot be greater than r
1101
          throw new Exception("requested revision cannot be greater than " +
1102
                            "the latest revision number.");
1103
        }
1104
      }
1105
      // Get miss docid and rev, throw to McdDocNotFoundException
1106
      String missDocId = MetaCatUtil.getDocIdFromString(docid.toString());
1107
      String missRevision = 
1108
                  MetaCatUtil.getRevisionStringFromString(docid.toString());
1109
      throw new McdbDocNotFoundException("the requested docid '" + 
1110
                docid.toString() + "' does not exist", missDocId, missRevision);
1111
    }//try
1112
    finally
1113
    {
1114
      pstmt.close();
1115
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1116
    }//finally
1117
  }
1118

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

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

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

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

    
1315
    try 
1316
    {
1317
      dbconn=DBConnectionPool.
1318
                    getDBConnection("DocumentImpl.getPartNodeRecordList");
1319
      serialNumber=dbconn.getCheckOutSerialNumber();
1320
      pstmt = dbconn.prepareStatement(sql);
1321

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

    
1342
        // Advance to the next node
1343
        tableHasRows = rs.next();
1344
      } 
1345
      pstmt.close();
1346

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

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

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

    
1412
      // Bind the values to the query
1413
      pstmt.setLong(1, rootnodeid);
1414

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

    
1432
        // Advance to the next node
1433
        tableHasRows = rs.next();
1434
      } 
1435
      pstmt.close();
1436

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

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

    
1477
    try {
1478
      PreparedStatement pstmt = null;
1479

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

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

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

    
1574
      } else {
1575
        System.err.println("Action not supported: " + action);
1576
      }
1577

    
1578
      // Do the insertion
1579
      pstmt.execute();
1580
      
1581
      pstmt.close();
1582

    
1583
    } catch (SQLException sqle) {
1584
      throw sqle;
1585
    } catch (Exception e) {
1586
      throw e;
1587
    }
1588
  }
1589

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

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

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

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

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

    
1752
      if ( !hasWritePermission(user, groups, docid) ) {
1753
        throw new Exception("User " + user + 
1754
              " does not have permission to update XML Document #" + accnum);
1755
      }          
1756
    }
1757

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

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

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

    
1897
    return(accnum);
1898
  }
1899

    
1900
  
1901
  /**
1902
   * Delete an XML file from the database (actually, just make it a revision
1903
   * in the xml_revisions table)
1904
   *
1905
   * @param docid the ID of the document to be deleted from the database
1906
   */
1907
  public static void delete(String accnum,
1908
                                 String user, String[] groups )
1909
                throws Exception 
1910
  {
1911
    // OLD
1912
    //DocumentIdentifier id = new DocumentIdentifier(accnum);
1913
    //String docid = id.getIdentifier();
1914
    //String rev = id.getRev();
1915
    
1916
    // OLD
1917
    // Determine if the docid,rev are OK for DELETE
1918
    //AccessionNumber ac = new AccessionNumber(conn);
1919
    //docid = ac.generate(docid, rev, "DELETE");
1920
    DBConnection conn = null;
1921
    int serialNumber = -1;
1922
    PreparedStatement pstmt =null;
1923
    try
1924
    {
1925
      //check out DBConnection
1926
      conn=DBConnectionPool.
1927
                    getDBConnection("DocumentImpl.delete");
1928
      serialNumber=conn.getCheckOutSerialNumber();
1929

    
1930
      // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1931
      AccessionNumber ac = new AccessionNumber(accnum, "DELETE");
1932
      String docid = ac.getDocid();
1933
      String rev = ac.getRev();
1934
    
1935

    
1936
    // check for 'write' permission for 'user' to delete this document
1937
      if ( !hasWritePermission(user, groups, docid) ) {
1938
        throw new Exception("User " + user + 
1939
              " does not have permission to delete XML Document #" + accnum);
1940
      }
1941

    
1942
      conn.setAutoCommit(false);
1943
      // Copy the record to the xml_revisions table
1944
      DocumentImpl.archiveDocRevision(conn, docid, user );
1945

    
1946
      // Now delete it from the xml_index table
1947
      pstmt = conn.prepareStatement("DELETE FROM xml_index WHERE docid = ?");
1948
      pstmt.setString(1,docid);
1949
      pstmt.execute();
1950
      pstmt.close();
1951
      conn.increaseUsageCount(1);
1952
      
1953
      //stmt.execute("DELETE FROM xml_access WHERE docid = '" + docid + "'");
1954
      // Now delete it from xml_access table
1955
      pstmt = conn.
1956
              prepareStatement("DELETE FROM xml_access WHERE accessfileid = ?");
1957
      pstmt.setString(1, docid);
1958
      pstmt.execute();
1959
      pstmt.close();
1960
      conn.increaseUsageCount(1);
1961
      
1962
      // Delete it from relation table
1963
      pstmt = conn.
1964
               prepareStatement("DELETE FROM xml_relation WHERE docid = ?");
1965
      //increase usage count
1966
      conn.increaseUsageCount(1);
1967
      pstmt.setString(1, docid);
1968
      pstmt.execute();
1969
      pstmt.close();
1970
      
1971
      // Delete it from xml_doucments table
1972
      pstmt =conn.prepareStatement("DELETE FROM xml_documents WHERE docid = ?");
1973
      pstmt.setString(1, docid);
1974
      pstmt.execute();
1975
      pstmt.close();
1976
      //Usaga count increase 1
1977
      conn.increaseUsageCount(1);
1978
      
1979
      conn.commit();
1980
      conn.setAutoCommit(true);
1981
    }//try
1982
    finally
1983
    {
1984
      
1985
      try
1986
      {
1987
        // close preparedStatement
1988
        pstmt.close();
1989
      }//try
1990
      finally
1991
      {
1992
        //check in DBonnection
1993
        DBConnectionPool.returnDBConnection(conn, serialNumber);
1994
      }//finally
1995
    }//finally
1996
    //IF this is a package document:
1997
    //delete all of the relations that this document created.
1998
    //if the deleted document is a package document its relations should 
1999
    //no longer be active if it has been deleted from the system.
2000
    
2001
  }
2002

    
2003
  /** 
2004
    * Check for "WRITE" permission on @docid for @user and/or @groups 
2005
    * from DB connection 
2006
    */
2007
  private static boolean hasWritePermission (String user,
2008
                                  String[] groups, String docid ) 
2009
                  throws SQLException, Exception
2010
  {
2011
    // Check for WRITE permission on @docid for @user and/or @groups
2012
    PermissionController controller = new PermissionController(docid);
2013
    return controller.hasPermission(user,groups,
2014
                                    AccessControlInterface.WRITESTRING);
2015
  }
2016

    
2017
  /** 
2018
    * Check for "READ" permission base on docid, user and group
2019
    *@docid, the document
2020
    *@user, user name
2021
    *@group, user's group
2022
    * 
2023
    */
2024
  public static boolean hasReadPermission (String user,
2025
                                  String[] groups, String docId ) 
2026
                  throws SQLException, Exception
2027
  {
2028
    // Check for READ permission on @docid for @user and/or @groups
2029
    PermissionController controller = 
2030
                        new PermissionController(docId);
2031
    return controller.hasPermission(user,groups,
2032
                                            AccessControlInterface.READSTRING);
2033
  }  
2034

    
2035
  
2036
   /**
2037
   * Set up the parser handlers for writing the document to the database
2038
   */
2039
  private static XMLReader initializeParser(DBConnection dbconn, String action,
2040
                                            String docid, String rev, 
2041
                                            String user, 
2042
                                            String[] groups, String pub, 
2043
                                            int serverCode, Reader dtd,
2044
                                            String ruleBase, 
2045
                                            boolean needValidation) 
2046
                                            throws Exception 
2047
  {
2048
    XMLReader parser = null;
2049
    try 
2050
    {
2051
      // handler
2052
      ContentHandler chandler;
2053
      EntityResolver eresolver;
2054
      DTDHandler dtdhandler;  
2055
      // Get an instance of the parser
2056
      String parserName = MetaCatUtil.getOption("saxparser");
2057
      parser = XMLReaderFactory.createXMLReader(parserName);
2058
      if (ruleBase != null && ruleBase.equals(EML2))
2059
      {
2060
        MetaCatUtil.debugMessage("eml 2 parser", 20);
2061
        chandler = new EmlSAXHandler(dbconn, action, 
2062
                                    docid, rev, user, groups, pub, serverCode);
2063
        parser.setContentHandler((ContentHandler)chandler);
2064
        parser.setErrorHandler((ErrorHandler)chandler);
2065
        parser.setProperty(DECLARATIONHANDLERPROPERTY, chandler);
2066
        parser.setProperty(LEXICALPROPERTY, chandler);
2067
        // turn on schema validation feature
2068
        parser.setFeature(VALIDATIONFEATURE, true);
2069
        parser.setFeature(NAMESPACEFEATURE, true);
2070
        //parser.setFeature(NAMESPACEPREFIXESFEATURE, true);
2071
        parser.setFeature(SCHEMAVALIDATIONFEATURE, true);
2072
        // From DB to find the register external schema location
2073
        String externalSchemaLocation = null;
2074
        SchemaLocationResolver resolver = new SchemaLocationResolver();
2075
        externalSchemaLocation = resolver.getNameSpaceAndLocationString();
2076
        // Set external schemalocation.
2077
        if (externalSchemaLocation != null && 
2078
            !(externalSchemaLocation.trim()).equals(""))
2079
        {
2080
            parser.setProperty(EXTERNALSCHEMALOCATIONPROPERTY,
2081
                             externalSchemaLocation);
2082
        }
2083
      }
2084
      else
2085
      {
2086
        //create a DBSAXHandler object which has the revision specification
2087
        chandler = new DBSAXHandler(dbconn, action, 
2088
                                    docid, rev, user, groups, pub, serverCode);
2089
        parser.setContentHandler((ContentHandler)chandler);
2090
        parser.setErrorHandler((ErrorHandler)chandler);
2091
        parser.setProperty(DECLARATIONHANDLERPROPERTY, chandler);
2092
        parser.setProperty(LEXICALPROPERTY, chandler);
2093
      
2094
        if (ruleBase != null && ruleBase.equals(SCHEMA) && needValidation)
2095
        {
2096
          MetaCatUtil.debugMessage("General schema parser", 20);
2097
          // turn on schema validation feature
2098
          parser.setFeature(VALIDATIONFEATURE, true);
2099
          parser.setFeature(NAMESPACEFEATURE, true);
2100
          //parser.setFeature(NAMESPACEPREFIXESFEATURE, true);
2101
          parser.setFeature(SCHEMAVALIDATIONFEATURE, true);
2102
          // From DB to find the register external schema location
2103
          String externalSchemaLocation = null;
2104
          SchemaLocationResolver resolver = new SchemaLocationResolver();
2105
          externalSchemaLocation = resolver.getNameSpaceAndLocationString();
2106
          // Set external schemalocation.
2107
          if (externalSchemaLocation != null && 
2108
            !(externalSchemaLocation.trim()).equals(""))
2109
          {
2110
            parser.setProperty(EXTERNALSCHEMALOCATIONPROPERTY,
2111
                             externalSchemaLocation);
2112
          }
2113
     
2114
        }
2115
        else if (ruleBase != null && ruleBase.equals(DTD) && needValidation)
2116
        {
2117
          MetaCatUtil.debugMessage("dtd parser", 20);
2118
          // turn on dtd validaton feature
2119
          parser.setFeature(VALIDATIONFEATURE, true);
2120
          eresolver= new DBEntityResolver(dbconn, (DBSAXHandler)chandler, dtd);
2121
          dtdhandler = new DBDTDHandler(dbconn);
2122
          parser.setEntityResolver((EntityResolver)eresolver);
2123
          parser.setDTDHandler((DTDHandler)dtdhandler);
2124
        }
2125
        else
2126
        {
2127
          MetaCatUtil.debugMessage("other parser", 20);
2128
          // non validation
2129
          parser.setFeature(VALIDATIONFEATURE, false);
2130
          eresolver= new DBEntityResolver(dbconn, (DBSAXHandler)chandler, dtd);
2131
          dtdhandler = new DBDTDHandler(dbconn);
2132
          parser.setEntityResolver((EntityResolver)eresolver);
2133
          parser.setDTDHandler((DTDHandler)dtdhandler);
2134
        }
2135
      }//else
2136
    } 
2137
    catch (Exception e) 
2138
    {
2139
      throw e;
2140
    }
2141
    return parser;
2142
  }
2143

    
2144
  
2145
  /**
2146
   * Set up the parser handlers for writing the document to the database
2147
   */
2148
  /*private static XMLReader initializeParser(DBConnection dbconn, String action,
2149
                               String docid, String rev, boolean validate, 
2150
                                   String user, String[] groups, String pub, 
2151
                                   int serverCode, Reader dtd) 
2152
                           throws Exception 
2153
  {
2154
    XMLReader parser = null;
2155
    //DBConnection conn = null;
2156
    //int serialNumber = -1;
2157
    //
2158
    // Set up the SAX document handlers for parsing
2159
    //
2160
    try {
2161
       //check out DBConnection
2162
     
2163
      //create a DBSAXHandler object which has the revision specification
2164
      ContentHandler chandler = new DBSAXHandler(dbconn, action, 
2165
                                    docid, rev, user, groups, pub, serverCode);
2166
      EntityResolver eresolver= new DBEntityResolver(dbconn,
2167
                                                 (DBSAXHandler)chandler, dtd);
2168
      DTDHandler dtdhandler   = new DBDTDHandler(dbconn);
2169

    
2170
      // Get an instance of the parser
2171
      String parserName = MetaCatUtil.getOption("saxparser");
2172
      parser = XMLReaderFactory.createXMLReader(parserName);
2173

    
2174
      // Turn on validation
2175
      parser.setFeature("http://xml.org/sax/features/validation", validate);
2176
      // Turn off Including all external parameter entities
2177
      // (the external DTD subset also)
2178
      // Doesn't work well, probably the feature name is not correct
2179
      // parser.setFeature(
2180
      //  "http://xml.org/sax/features/external-parameter-entities", false);
2181
      
2182
      // Set Handlers in the parser
2183
      parser.setProperty("http://xml.org/sax/properties/declaration-handler",
2184
                         chandler);
2185
      parser.setProperty("http://xml.org/sax/properties/lexical-handler",
2186
                         chandler);
2187
      parser.setContentHandler((ContentHandler)chandler);
2188
      parser.setEntityResolver((EntityResolver)eresolver);
2189
      parser.setDTDHandler((DTDHandler)dtdhandler);
2190
      parser.setErrorHandler((ErrorHandler)chandler);
2191

    
2192
    } catch (Exception e) {
2193
      throw e;
2194
    }
2195
    //finally
2196
    //{
2197
      //DBConnectionPool.returnDBConnection(conn, serialNumber);
2198
    //}
2199

    
2200
    return parser;
2201
  }*/
2202

    
2203
  /**
2204
   * Save a document entry in the xml_revisions table 
2205
   * Connection use as a paramter is in order to rollback feature
2206
   */
2207
  private static void archiveDocRevision(DBConnection dbconn, String docid, 
2208
                                                    String user) 
2209
 {
2210
    String sysdate = dbAdapter.getDateTimeFunction();
2211
    //DBConnection conn = null;
2212
    //int serialNumber = -1;
2213
    PreparedStatement pstmt = null;
2214
    
2215
    // create a record in xml_revisions table 
2216
    // for that document as selected from xml_documents
2217
   
2218
   try
2219
   {
2220
     //check out DBConnection
2221
     /*conn=DBConnectionPool.
2222
                    getDBConnection("DocumentImpl.archiveDocRevision");
2223
     serialNumber=conn.getCheckOutSerialNumber();*/
2224
     pstmt = dbconn.prepareStatement(
2225
      "INSERT INTO xml_revisions " +
2226
        "(docid, rootnodeid, docname, doctype, " +
2227
        "user_owner, user_updated, date_created, date_updated, " +
2228
        "server_location, rev, public_access, catalog_id) " +
2229
      "SELECT ?, rootnodeid, docname, doctype, " + 
2230
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
2231
        "server_location, rev, public_access, catalog_id " +
2232
      "FROM xml_documents " +
2233
      "WHERE docid = ?");
2234
      // Increase dbconnection usage count
2235
      dbconn.increaseUsageCount(1);
2236
      // Bind the values to the query and execute it
2237
      pstmt.setString(1, docid);
2238
      pstmt.setString(2, user);
2239
      pstmt.setString(3, docid);
2240
      pstmt.execute();
2241
      pstmt.close();
2242
   }//try
2243
   catch (SQLException e)
2244
   {
2245
     MetaCatUtil.debugMessage("Error in DocumentImpl.archiveDocRevision : "+
2246
                                e.getMessage(), 30);
2247
   }//catch
2248
   finally
2249
   {
2250
     try
2251
     {
2252
       pstmt.close();
2253
     }//try
2254
     catch (SQLException ee)
2255
     {
2256
       MetaCatUtil.debugMessage("Error in DocumnetImpl.archiveDocRevision: "+
2257
                                  ee.getMessage(), 50);
2258
     }//catch
2259
     //finally
2260
     //{
2261
       
2262
       //check in DBConnection
2263
       //DBConnectionPool.returnDBConnection(conn, serialNumber);
2264
     //}//finally
2265
   }//finnally
2266
                                  
2267

    
2268
  }//achiveDocRevision
2269
  
2270
  /** Save a document entry in the xml_revisions table */
2271
  private static void archiveDocRevision(String docid, String user) 
2272
 {
2273
    String sysdate = dbAdapter.getDateTimeFunction();
2274
    DBConnection conn = null;
2275
    int serialNumber = -1;
2276
    PreparedStatement pstmt = null;
2277
    
2278
    // create a record in xml_revisions table 
2279
    // for that document as selected from xml_documents
2280
   
2281
   try
2282
   {
2283
     //check out DBConnection
2284
     conn=DBConnectionPool.
2285
                    getDBConnection("DocumentImpl.archiveDocRevision");
2286
     serialNumber=conn.getCheckOutSerialNumber();
2287
     pstmt = conn.prepareStatement(
2288
      "INSERT INTO xml_revisions " +
2289
        "(docid, rootnodeid, docname, doctype, " +
2290
        "user_owner, user_updated, date_created, date_updated, " +
2291
        "server_location, rev, public_access, catalog_id) " +
2292
      "SELECT ?, rootnodeid, docname, doctype, " + 
2293
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
2294
        "server_location, rev, public_access, catalog_id " +
2295
      "FROM xml_documents " +
2296
      "WHERE docid = ?");
2297
      // Bind the values to the query and execute it
2298
      pstmt.setString(1, docid);
2299
      pstmt.setString(2, user);
2300
      pstmt.setString(3, docid);
2301
      pstmt.execute();
2302
      pstmt.close();
2303
   }//try
2304
   catch (SQLException e)
2305
   {
2306
     MetaCatUtil.debugMessage("Error in DocumentImpl.archiveDocRevision : "+
2307
                                e.getMessage(), 30);
2308
   }//catch
2309
   finally
2310
   {
2311
     try
2312
     {
2313
       pstmt.close();
2314
     }//try
2315
     catch (SQLException ee)
2316
     {
2317
       MetaCatUtil.debugMessage("Error in DocumnetImpl.archiveDocRevision: "+
2318
                                  ee.getMessage(), 50);
2319
     }//catch
2320
     finally
2321
     {
2322
       //check in DBConnection
2323
       DBConnectionPool.returnDBConnection(conn, serialNumber);
2324
     }//finally
2325
   }//finnally
2326
                                  
2327

    
2328
  }//achiveDocRevision
2329
  
2330
  /**
2331
    * delete a entry in xml_table for given docid
2332
    * @param docId, the id of the document need to be delete
2333
    */
2334
  private static void deleteXMLDocuments(String docId) 
2335
                                         throws SQLException 
2336
  {
2337
    DBConnection conn = null;
2338
    int serialNumber = -1;
2339
    PreparedStatement pStmt = null;
2340
    try
2341
    {
2342
      //check out DBConnection
2343
      conn=DBConnectionPool.
2344
                    getDBConnection("DocumentImpl.deleteXMLDocuments");
2345
      serialNumber=conn.getCheckOutSerialNumber();
2346
      //delete a record 
2347
      pStmt = 
2348
             conn.prepareStatement("DELETE FROM xml_documents WHERE docid = '" 
2349
                                              + docId + "'");
2350
    pStmt.execute();
2351
    }//try
2352
    finally
2353
    {
2354
      try
2355
      {
2356
        pStmt.close();
2357
      }//try
2358
      catch (SQLException e)
2359
      {
2360
        MetaCatUtil.debugMessage("error in DocumentImpl.deleteXMLDocuments: "+
2361
                                  e.getMessage(), 50);
2362
      }//catch
2363
      finally
2364
      {
2365
        //return back DBconnection
2366
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2367
      }//finally
2368
    }//finally
2369
      
2370

    
2371
  }//deleteXMLDocuments
2372
  
2373
  /**
2374
    * Get last revision number from database for a docid
2375
    * If couldn't find an entry,  -1 will return
2376
    * The return value is integer because we want compare it to there new one
2377
    * @param docid <sitecode>.<uniqueid> part of Accession Number
2378
    */
2379
  private static int getLatestRevisionNumber(String docId)
2380
                                      throws SQLException
2381
  {
2382
    int rev = 1;
2383
    PreparedStatement pStmt = null;
2384
    DBConnection dbConn = null;
2385
    int serialNumber = -1;
2386
    
2387
    try
2388
    {
2389
      //check out DBConnection
2390
      dbConn=DBConnectionPool.
2391
                    getDBConnection("DocumentImpl.getLatestRevisionNumber");
2392
      serialNumber=dbConn.getCheckOutSerialNumber();
2393
     
2394
      pStmt = dbConn.prepareStatement
2395
              ("SELECT rev FROM xml_documents WHERE docid='" + docId + "'");
2396
      pStmt.execute();
2397

    
2398
      ResultSet rs = pStmt.getResultSet();
2399
      boolean hasRow = rs.next();
2400
      if (hasRow)
2401
      {
2402
        rev = rs.getInt(1);
2403
        pStmt.close();
2404
      }
2405
      else
2406
      {
2407
        rev=-1;
2408
        pStmt.close();
2409
      }
2410
    }//try
2411
    finally
2412
    {
2413
      try
2414
      {
2415
        pStmt.close();
2416
      }
2417
      catch (Exception ee)
2418
      {
2419
        MetaCatUtil.debugMessage("Error in DocumentImpl."+
2420
                        "getLatestRevisionNumber: "+ee.getMessage(), 50);
2421
      }
2422
      finally
2423
      {
2424
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2425
      }
2426
    }//finally  
2427
      
2428
    return rev;
2429
  }//getLatestRevisionNumber
2430
  
2431
  /**
2432
   * Get server location form database for a accNum
2433
   * 
2434
   * @param accum <sitecode>.<uniqueid>.<rev>
2435
   */
2436
  private static int getServerLocationNumber(String accNum)
2437
                                            throws SQLException
2438
  {
2439
    //get rid of revNum part
2440
    String docId=MetaCatUtil.getDocIdFromString(accNum);
2441
    PreparedStatement pStmt = null;
2442
    int serverLocation = 1;
2443
    DBConnection conn = null;
2444
    int serialNumber = -1;
2445
    
2446
    try
2447
    {
2448
      //check out DBConnection
2449
      conn=DBConnectionPool.
2450
                    getDBConnection("DocumentImpl.getServerLocationNumber");
2451
      serialNumber=conn.getCheckOutSerialNumber();
2452
     
2453
      pStmt = conn.prepareStatement
2454
      ("SELECT server_location FROM xml_documents WHERE docid='" + docId + "'");
2455
      pStmt.execute();
2456

    
2457
      ResultSet rs = pStmt.getResultSet();
2458
      boolean hasRow = rs.next();
2459
      //if there is entry in xml_documents, get the serverlocation
2460
      if (hasRow)
2461
      {
2462
        serverLocation = rs.getInt(1);
2463
        pStmt.close();
2464
      }
2465
      else
2466
      {
2467
        //if htere is no entry in xml_documents, we consider it is new document
2468
        //the server location is local host and value is 1
2469
        serverLocation=1;
2470
        pStmt.close();
2471
      }
2472
    }//try
2473
    finally
2474
    {
2475
      try
2476
      {
2477
        pStmt.close();
2478
      }//try
2479
      catch (Exception ee)
2480
      {
2481
        MetaCatUtil.debugMessage("Error in DocumentImpl.getServerLocationNu(): "
2482
                                    +ee.getMessage(), 50);
2483
      }//catch
2484
      finally
2485
      {
2486
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2487
      }//finally
2488
    }//finally
2489
      
2490
    return serverLocation;
2491
  }
2492
  
2493
  /**
2494
   * Given a server name, return its servercode in xml_replication table.
2495
   * If no server is found, -1 will return
2496
   * @param serverName, 
2497
   */
2498
  private static int getServerCode(String serverName) 
2499
  {
2500
    PreparedStatement pStmt=null;
2501
    int serverLocation=-2;
2502
    DBConnection dbConn = null;
2503
    int serialNumber = -1;
2504
    //MetaCatUtil util = new MetaCatUtil();
2505
    
2506
    
2507
    //we should consider about local host too
2508
    if (serverName.equals(MetaCatUtil.getLocalReplicationServerName()))
2509
    { 
2510
      serverLocation=1;
2511
      return serverLocation;
2512
    }
2513
    
2514
   
2515
    try
2516
    {
2517
      //check xml_replication table
2518
      //dbConn=util.openDBConnection();
2519
      //check out DBConnection
2520
      dbConn=DBConnectionPool.getDBConnection("DocumentImpl.getServerCode");
2521
      serialNumber=dbConn.getCheckOutSerialNumber();
2522
      pStmt = dbConn.prepareStatement
2523
      ("SELECT serverid FROM xml_replication WHERE server='" + serverName +"'");
2524
      pStmt.execute();
2525

    
2526
      ResultSet rs = pStmt.getResultSet();
2527
      boolean hasRow = rs.next();
2528
      //if there is entry in xml_replication, get the serverid
2529
      if (hasRow)
2530
      {
2531
        serverLocation = rs.getInt(1);
2532
        pStmt.close();
2533
      }
2534
      else
2535
      {
2536
        // if htere is no entry in xml_replication, -1 will return
2537
        serverLocation=-1;
2538
        pStmt.close();
2539
      }
2540
    }
2541
    catch (Exception e)
2542
    {
2543
      MetaCatUtil.debugMessage("Error in DocumentImpl.getServerCode(): "
2544
                                    +e.getMessage(), 30);
2545
    }
2546
    finally
2547
    {
2548
      try
2549
      {
2550
        pStmt.close();
2551
      }
2552
      catch (Exception ee)
2553
      {
2554
        MetaCatUtil.debugMessage("Error in DocumentImpl.getServerCode(): "
2555
                                    +ee.getMessage(), 50);
2556
      }
2557
      finally
2558
      {
2559
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2560
      }
2561
    }
2562
                 
2563
      
2564
    return serverLocation;
2565
  }
2566
  
2567
  /**
2568
   * Insert a server into xml_replcation table
2569
   * @param server, the name of server 
2570
   */
2571
  private static synchronized void 
2572
                                insertServerIntoReplicationTable(String server)
2573
  {
2574
    PreparedStatement pStmt=null;
2575
    DBConnection dbConn = null;
2576
    int serialNumber = -1;
2577
    
2578
    // Initial value for the server
2579
    int replicate = 0;
2580
    int dataReplicate = 0;
2581
    int hub = 0;
2582
   
2583
    try
2584
    {
2585
       // Get DBConnection
2586
       dbConn=DBConnectionPool.
2587
                getDBConnection("DocumentImpl.insertServIntoReplicationTable");
2588
       serialNumber=dbConn.getCheckOutSerialNumber();
2589
      
2590
      // Compare the server to dabase
2591
      pStmt = dbConn.prepareStatement
2592
      ("SELECT serverid FROM xml_replication WHERE server='" + server +"'");
2593
      pStmt.execute();
2594
      ResultSet rs = pStmt.getResultSet();
2595
      boolean hasRow = rs.next();
2596
      // Close preparedstatement and result set
2597
      pStmt.close();
2598
      rs.close();
2599
      
2600
      // If the server is not in the table, and server is not local host,
2601
      // insert it
2602
      if ( !hasRow 
2603
         && !server.equals(MetaCatUtil.getLocalReplicationServerName()))
2604
      {
2605
        // Set auto commit false
2606
        dbConn.setAutoCommit(false);
2607
        pStmt = dbConn.prepareStatement("INSERT INTO xml_replication " +
2608
                      "(server, last_checked, replicate, datareplicate, hub) " +
2609
                       "VALUES ('" + server + "', to_date(" +
2610
                       "'01/01/00', 'MM/DD/YY'), '" +
2611
                       replicate +"', '"+dataReplicate+"','"+ hub + "')");
2612
        pStmt.execute();
2613
        dbConn.commit();
2614
        // Increase usage number
2615
        dbConn.increaseUsageCount(1);
2616
        pStmt.close();
2617
        
2618
      }
2619
    }//try
2620
    catch (Exception e)
2621
    {
2622
      MetaCatUtil.debugMessage("Error in DocumentImpl.insertServerIntoRepli(): "
2623
                                    +e.getMessage(), 30);
2624
    }//catch
2625
    finally
2626
    {
2627
     
2628
      try
2629
      {
2630
        // Set auto commit true
2631
        dbConn.setAutoCommit(true);
2632
        pStmt.close();
2633
        
2634
      }//try
2635
      catch (Exception ee)
2636
      {
2637
        MetaCatUtil.debugMessage("Error in DocumentImpl.insetServerIntoRepl(): "
2638
                                    +ee.getMessage(), 50);
2639
      }//catch
2640
      finally
2641
      {
2642
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2643
      }
2644
    
2645
    }//finally
2646

    
2647
  }
2648
  
2649
  
2650
  /**
2651
   * the main routine used to test the DBWriter utility.
2652
   * <p>
2653
   * Usage: java DocumentImpl <-f filename -a action -d docid>
2654
   *
2655
   * @param filename the filename to be loaded into the database
2656
   * @param action the action to perform (READ, INSERT, UPDATE, DELETE)
2657
   * @param docid the id of the document to process
2658
   */
2659
  static public void main(String[] args) {
2660
    DBConnection dbconn = null;
2661
    int serialNumber = -1;
2662
    try {
2663
      String filename    = null;
2664
      String dtdfilename = null;
2665
      String action      = null;
2666
      String docid       = null;
2667
      boolean showRuntime = false;
2668
      boolean useOldReadAlgorithm = false;
2669

    
2670
      // Parse the command line arguments
2671
      for ( int i=0 ; i < args.length; ++i ) {
2672
        if ( args[i].equals( "-f" ) ) {
2673
          filename =  args[++i];
2674
        } else if ( args[i].equals( "-r" ) ) {
2675
          dtdfilename =  args[++i];
2676
        } else if ( args[i].equals( "-a" ) ) {
2677
          action =  args[++i];
2678
        } else if ( args[i].equals( "-d" ) ) {
2679
          docid =  args[++i];
2680
        } else if ( args[i].equals( "-t" ) ) {
2681
          showRuntime = true;
2682
        } else if ( args[i].equals( "-old" ) ) {
2683
          useOldReadAlgorithm = true;
2684
        } else {
2685
          System.err.println
2686
            ( "   args[" +i+ "] '" +args[i]+ "' ignored." );
2687
        }
2688
      }
2689
      
2690
      // Check if the required arguments are provided
2691
      boolean argsAreValid = false;
2692
      if (action != null) {
2693
        if (action.equals("INSERT")) {
2694
          if (filename != null) {
2695
            argsAreValid = true;
2696
          } 
2697
        } else if (action.equals("UPDATE")) {
2698
          if ((filename != null) && (docid != null)) {
2699
            argsAreValid = true;
2700
          } 
2701
        } else if (action.equals("DELETE")) {
2702
          if (docid != null) {
2703
            argsAreValid = true;
2704
          } 
2705
        } else if (action.equals("READ")) {
2706
          if (docid != null) {
2707
            argsAreValid = true;
2708
          } 
2709
        } 
2710
      } 
2711

    
2712
      // Print usage message if the arguments are not valid
2713
      if (!argsAreValid) {
2714
        System.err.println("Wrong number of arguments!!!");
2715
        System.err.println(
2716
          "USAGE: java DocumentImpl [-t] <-a INSERT> [-d docid] <-f filename> "+
2717
          "[-r dtdfilename]");
2718
        System.err.println(
2719
          "   OR: java DocumentImpl [-t] <-a UPDATE -d docid -f filename> " +
2720
          "[-r dtdfilename]");
2721
        System.err.println(
2722
          "   OR: java DocumentImpl [-t] <-a DELETE -d docid>");
2723
        System.err.println(
2724
          "   OR: java DocumentImpl [-t] [-old] <-a READ -d docid>");
2725
        return;
2726
      }
2727
      
2728
      // Time the request if asked for
2729
      double startTime = System.currentTimeMillis();
2730
      
2731
      // Open a connection to the database
2732
      MetaCatUtil util = new MetaCatUtil();
2733
     
2734
      dbconn=DBConnectionPool.getDBConnection("DocumentImpl.main");
2735
      serialNumber=dbconn.getCheckOutSerialNumber();
2736

    
2737
      double connTime = System.currentTimeMillis();
2738
      // Execute the action requested (READ, INSERT, UPDATE, DELETE)
2739
      if (action.equals("READ")) {
2740
          DocumentImpl xmldoc = new DocumentImpl(docid );
2741
          if (useOldReadAlgorithm) {
2742
            System.out.println(xmldoc.readUsingSlowAlgorithm());
2743
          } else {
2744
            xmldoc.toXml(new PrintWriter(System.out), null, null, true);
2745
          }
2746
      } else if (action.equals("DELETE")) {
2747
        DocumentImpl.delete(docid, null, null);
2748
        System.out.println("Document deleted: " + docid);
2749
      } else {
2750
        /*String newdocid = DocumentImpl.write(dbconn, filename, null,
2751
                                             dtdfilename, action, docid,
2752
                                             null, null);
2753
        if ((docid != null) && (!docid.equals(newdocid))) {
2754
          if (action.equals("INSERT")) {
2755
            System.out.println("New document ID generated!!! ");
2756
          } else if (action.equals("UPDATE")) {
2757
            System.out.println("ERROR: Couldn't update document!!! ");
2758
          }
2759
        } else if ((docid == null) && (action.equals("UPDATE"))) {
2760
          System.out.println("ERROR: Couldn't update document!!! ");
2761
        }
2762
        System.out.println("Document processing finished for: " + filename
2763
              + " (" + newdocid + ")");*/
2764
      }
2765

    
2766
      double stopTime = System.currentTimeMillis();
2767
      double dbOpenTime = (connTime - startTime)/1000;
2768
      double insertTime = (stopTime - connTime)/1000;
2769
      double executionTime = (stopTime - startTime)/1000;
2770
      if (showRuntime) {
2771
        System.out.println("\n\nTotal Execution time was: " + 
2772
                           executionTime + " seconds.");
2773
        System.out.println("Time to open DB connection was: " + dbOpenTime + 
2774
                           " seconds.");
2775
        System.out.println("Time to insert document was: " + insertTime +
2776
                           " seconds.");
2777
      }
2778
      dbconn.close();
2779
    } catch (McdbException me) {
2780
      me.toXml(new PrintWriter(System.err));
2781
    } catch (AccessionNumberException ane) {
2782
      System.out.println(ane.getMessage());
2783
    } catch (Exception e) {
2784
      System.err.println("EXCEPTION HANDLING REQUIRED");
2785
      System.err.println(e.getMessage());
2786
      e.printStackTrace(System.err);
2787
    }
2788
    finally
2789
    {
2790
      // Return db connection
2791
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
2792
    }
2793
  }
2794
}
(29-29/54)