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-06 14:25:56 -0800 (Thu, 06 Mar 2003) $'
11
 * '$Revision: 1460 $'
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)
731
  {
732
    StringWriter docwriter = new StringWriter();
733
    try 
734
    {
735
      this.toXml(docwriter, user, groups);
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
    try 
754
    {
755
      this.toXml(docwriter, userName, groupNames);
756
    } 
757
    catch (McdbException mcdbe) 
758
    {
759
      return null;
760
    }
761
    String document = docwriter.toString();
762
    return document;
763
  }
764

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1312
    try 
1313
    {
1314
      dbconn=DBConnectionPool.
1315
                    getDBConnection("DocumentImpl.getPartNodeRecordList");
1316
      serialNumber=dbconn.getCheckOutSerialNumber();
1317
      pstmt = dbconn.prepareStatement(sql);
1318

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

    
1339
        // Advance to the next node
1340
        tableHasRows = rs.next();
1341
      } 
1342
      pstmt.close();
1343

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

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

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

    
1409
      // Bind the values to the query
1410
      pstmt.setLong(1, rootnodeid);
1411

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

    
1429
        // Advance to the next node
1430
        tableHasRows = rs.next();
1431
      } 
1432
      pstmt.close();
1433

    
1434
    } catch (SQLException e) {
1435
      throw new McdbException("Error in DocumentImpl.getNodeRecordList " +
1436
                              e.getMessage());
1437
    }
1438
    finally
1439
    {
1440
      try
1441
      {
1442
        pstmt.close();
1443
      }
1444
      catch (SQLException ee)
1445
      {
1446
        MetaCatUtil.debugMessage("error in DocumentImpl.getNodeRecordList: "
1447
                                    +ee.getMessage(), 30);
1448
      }
1449
      finally
1450
      {
1451
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1452
      }
1453
    }
1454
      
1455

    
1456
    if (!nodeRecordList.isEmpty()) {
1457
      return nodeRecordList;
1458
    } else {
1459
      throw new McdbException("Error getting node data: " + docid);
1460
    }
1461
  }
1462
  
1463
// NOT USED ANY MORE
1464
//  /** creates SQL code and inserts new document into DB connection 
1465
//   default serverCode of 1*/
1466
//  private void writeDocumentToDB(String action, String user)
1467
//               throws SQLException, Exception
1468
//  {
1469
//    writeDocumentToDB(action, user, null, 1);
1470
//  }
1471

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

    
1478
    try {
1479
      PreparedStatement pstmt = null;
1480

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1898
    return(accnum);
1899
  }
1900

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

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

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

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

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

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

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

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

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

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

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

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

    
2201
    return parser;
2202
  }*/
2203

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

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

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

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

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

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

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

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

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

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

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

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