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-04-07 10:28:12 -0700 (Mon, 07 Apr 2003) $'
11
 * '$Revision: 1515 $'
12
 *
13
 * This program is free software; you can redistribute it and/or modify
14
 * it under the terms of the GNU General Public License as published by
15
 * the Free Software Foundation; either version 2 of the License, or
16
 * (at your option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU General Public License
24
 * along with this program; if not, write to the Free Software
25
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
 */
27

    
28
package edu.ucsb.nceas.metacat;
29

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

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

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

    
61
import java.net.URL;
62

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
999
      // Handle any other node type (do nothing)
1000
      } else {
1001
        // Any other types of nodes are not handled.
1002
        // Probably should throw an exception here to indicate this
1003
      }
1004
      out.flush();
1005
    }
1006
    
1007
    // Print the final end tag for the root element
1008
    while(!openElements.empty())
1009
    {
1010
      NodeRecord currentElement = (NodeRecord)openElements.pop();
1011
      util.debugMessage("\n POPPED: " + currentElement.nodename, 50);
1012
      if ( currentElement.nodeprefix != null ) {
1013
        out.print("</" + currentElement.nodeprefix + ":" + 
1014
                  currentElement.nodename + ">" );
1015
      } else {
1016
        out.print("</" + currentElement.nodename + ">" );
1017
      }
1018
    }
1019
    out.flush();
1020
  }
1021
  
1022

    
1023
  
1024
  private boolean isRevisionOnly(DocumentIdentifier docid) throws Exception
1025
  {
1026
    //System.out.println("inRevisionOnly");
1027
    DBConnection dbconn = null;
1028
    int serialNumber = -1;
1029
    PreparedStatement pstmt =null;
1030
    String rev = docid.getRev();
1031
    String newid = docid.getIdentifier();
1032
    try
1033
    {
1034
      dbconn=DBConnectionPool.
1035
                    getDBConnection("DocumentImpl.isRevisionOnly");
1036
      serialNumber=dbconn.getCheckOutSerialNumber();
1037
      pstmt = dbconn.prepareStatement("select rev from xml_documents " +
1038
                                  "where docid like '" + newid + "'");
1039
      pstmt.execute();
1040
      ResultSet rs = pstmt.getResultSet();
1041
      boolean tablehasrows = rs.next();
1042
      if(rev.equals("newest") || rev.equals("all"))
1043
      {
1044
        return false;
1045
      }
1046
    
1047
      if(tablehasrows)
1048
      {
1049
        int r = rs.getInt(1);
1050
        pstmt.close();
1051
        if(new Integer(rev).intValue() == r)
1052
        { //the current revision in in xml_documents
1053
          //System.out.println("returning false");
1054
          return false;
1055
        }
1056
        else if(new Integer(rev).intValue() < r)
1057
        { //the current revision is in xml_revisions.
1058
          //System.out.println("returning true");
1059
          return true;
1060
        }
1061
        else if(new Integer(rev).intValue() > r)
1062
        { //error, rev cannot be greater than r
1063
          throw new Exception("requested revision cannot be greater than " +
1064
                            "the latest revision number.");
1065
        }
1066
      }
1067
      // Get miss docid and rev, throw to McdDocNotFoundException
1068
      String missDocId = MetaCatUtil.getDocIdFromString(docid.toString());
1069
      String missRevision = 
1070
                  MetaCatUtil.getRevisionStringFromString(docid.toString());
1071
      throw new McdbDocNotFoundException("the requested docid '" + 
1072
                docid.toString() + "' does not exist", missDocId, missRevision);
1073
    }//try
1074
    finally
1075
    {
1076
      pstmt.close();
1077
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1078
    }//finally
1079
  }
1080

    
1081
  private void getDocumentInfo(String docid) throws McdbException, 
1082
                                        AccessionNumberException, Exception
1083
  {
1084
    getDocumentInfo(new DocumentIdentifier(docid));
1085
  }
1086
  
1087
  /**
1088
   * Look up the document type information from the database
1089
   *
1090
   * @param docid the id of the document to look up
1091
   */
1092
  private void getDocumentInfo(DocumentIdentifier docid) throws McdbException
1093
                                                          , Exception
1094
  {
1095
    DBConnection dbconn = null;
1096
    int serialNumber = -1;
1097
    PreparedStatement pstmt = null;
1098
    String table = "xml_documents";
1099
        
1100
    try
1101
    {
1102
      if(isRevisionOnly(docid))
1103
      { //pull the document from xml_revisions instead of from xml_documents;
1104
        table = "xml_revisions";
1105
      }
1106
    }
1107
    // catch a McdbDocNotFoundException throw it
1108
    catch (McdbDocNotFoundException notFound)
1109
    {
1110
      throw notFound;
1111
    }
1112
    catch(Exception e)
1113
    {
1114
      
1115
      MetaCatUtil.debugMessage("error in DocumentImpl.getDocumentInfo: " + 
1116
                          e.getMessage(), 30);
1117
      throw e;
1118
    }
1119
    
1120

    
1121
    
1122
    try 
1123
    {
1124
      dbconn=DBConnectionPool.getDBConnection("DocumentImpl.getDocumentInfo");
1125
      serialNumber=dbconn.getCheckOutSerialNumber();
1126
      StringBuffer sql = new StringBuffer();
1127
// DOCTITLE attr cleared from the db
1128
//      sql.append("SELECT docname, doctype, rootnodeid, doctitle, ");
1129
      sql.append("SELECT docname, doctype, rootnodeid, ");
1130
      sql.append("date_created, date_updated, user_owner, user_updated, ");
1131
      sql.append("server_location, public_access, rev");
1132
      sql.append(" FROM ").append(table);
1133
      sql.append(" WHERE docid LIKE '").append(docid.getIdentifier());
1134
      sql.append("' and rev like '").append(docid.getRev()).append("'");
1135
      //System.out.println(sql.toString());
1136
      pstmt =
1137
        dbconn.prepareStatement(sql.toString());
1138
      // Bind the values to the query
1139
      //pstmt.setString(1, docid.getIdentifier());
1140
      //pstmt.setString(2, docid.getRev());
1141

    
1142
      pstmt.execute();
1143
      ResultSet rs = pstmt.getResultSet();
1144
      boolean tableHasRows = rs.next();
1145
      if (tableHasRows) {
1146
        this.docname        = rs.getString(1);
1147
        this.doctype        = rs.getString(2);
1148
        this.rootnodeid     = rs.getLong(3);
1149
// DOCTITLE attr cleared from the db
1150
//        this.doctitle       = rs.getString(4);
1151
        this.createdate     = rs.getString(4);
1152
        this.updatedate     = rs.getString(5);
1153
        this.userowner      = rs.getString(6);
1154
        this.userupdated    = rs.getString(7);
1155
        this.serverlocation = rs.getInt(8);
1156
        this.publicaccess   = rs.getString(9);
1157
        this.rev            = rs.getInt(10);
1158
      } 
1159
      pstmt.close();
1160
      
1161
      //get doc  home server name
1162
      
1163
      pstmt = dbconn.prepareStatement("select server " +
1164
                        "from xml_replication where serverid = ?");
1165
      //because connection use twise here, so we need to increase one
1166
      dbconn.increaseUsageCount(1);
1167
      pstmt.setInt(1, serverlocation);
1168
      pstmt.execute();
1169
      rs = pstmt.getResultSet();
1170
      tableHasRows = rs.next();
1171
      if (tableHasRows)
1172
      {
1173
        
1174
          String server = rs.getString(1);
1175
          //get homeserver name
1176
          if(!server.equals("localhost"))
1177
          {
1178
            this.docHomeServer=server;
1179
          }
1180
          else
1181
          {
1182
            this.docHomeServer=MetaCatUtil.getLocalReplicationServerName();
1183
          }
1184
          MetaCatUtil.debugMessage("server: "+docHomeServer, 50);
1185
        
1186
      }
1187
      pstmt.close();
1188
      if (this.doctype != null) {
1189
        pstmt =
1190
          dbconn.prepareStatement("SELECT system_id, entry_type " +
1191
                                  "FROM xml_catalog " +
1192
                                 "WHERE public_id = ?");
1193
        //should increase usage count again
1194
        dbconn.increaseUsageCount(1);
1195
        // Bind the values to the query
1196
        pstmt.setString(1, doctype);
1197
  
1198
        pstmt.execute();
1199
        rs = pstmt.getResultSet();
1200
        tableHasRows = rs.next();
1201
        if (tableHasRows) {
1202
          this.system_id  = rs.getString(1);
1203
          this.validateType = rs.getString(2);
1204
          
1205
        } 
1206
        pstmt.close();
1207
      }
1208
    } catch (SQLException e) {
1209
      System.out.println("error in DocumentImpl.getDocumentInfo: " + 
1210
                          e.getMessage());
1211
      e.printStackTrace(System.out);
1212
      throw new McdbException("Error accessing database connection in " +
1213
                              "DocumentImpl.getDocumentInfo: ", e);
1214
    }
1215
    finally
1216
    {
1217
      try
1218
      {
1219
        pstmt.close();
1220
      }
1221
      catch (SQLException ee)
1222
      {
1223
        MetaCatUtil.debugMessage("error in DocumentImple.getDocumentInfo: "
1224
                                    +ee.getMessage(), 30);
1225
      }//catch
1226
      finally
1227
      {
1228
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1229
      }
1230
    }
1231

    
1232
    if (this.docname == null) {
1233
      throw new McdbDocNotFoundException("Document not found: " + docid,
1234
                                 docid.getIdentifier(), docid.getRev());
1235
    }
1236
  }
1237
  
1238
  /**
1239
   * Look up the node data from the database, but some node would be shown
1240
   * because of access control
1241
   * @param rootnodeid the id of the root node of the node tree to look up
1242
   * @param accessControl  the hashtable has control info
1243
   */
1244
  private TreeSet getPartNodeRecordList(long rootnodeid, 
1245
                                        Hashtable accessControl) 
1246
                                        throws McdbException
1247
  {
1248
    PreparedStatement pstmt = null;
1249
    DBConnection dbconn = null;
1250
    int serialNumber = -1;
1251
    TreeSet nodeRecordList = new TreeSet(new NodeComparator());
1252
    long nodeid = 0;
1253
    long parentnodeid = 0;
1254
    long nodeindex = 0;
1255
    String nodetype = null;
1256
    String nodename = null;
1257
    String nodeprefix = null;
1258
    String nodedata = null;
1259
    String quotechar = dbAdapter.getStringDelimiter();
1260
    String sql = "SELECT nodeid,parentnodeid,nodeindex, " +
1261
                 "nodetype,nodename,nodeprefix,nodedata " +               
1262
                  "FROM xml_nodes WHERE rootnodeid = ?";
1263
                  
1264
    // go through the access control for some nodes
1265
     Enumeration en = accessControl.elements();
1266
     while (en.hasMoreElements())
1267
     {
1268
         SubTree tree = (SubTree)en.nextElement();
1269
         long startId = tree.getStartNodeId();
1270
         long endId  = tree.getEndNodeId();
1271
         sql = sql +" AND(nodeid < " + startId + " OR nodeid > " +endId +")";
1272
         
1273
     }
1274
     MetaCatUtil.debugMessage("The final query to select part node tree: " +
1275
                              sql, 25);
1276

    
1277
    try 
1278
    {
1279
      dbconn=DBConnectionPool.
1280
                    getDBConnection("DocumentImpl.getPartNodeRecordList");
1281
      serialNumber=dbconn.getCheckOutSerialNumber();
1282
      pstmt = dbconn.prepareStatement(sql);
1283

    
1284
      // Bind the values to the query
1285
      pstmt.setLong(1, rootnodeid);
1286
      pstmt.execute();
1287
      ResultSet rs = pstmt.getResultSet();
1288
      boolean tableHasRows = rs.next();
1289
      while (tableHasRows) 
1290
      {
1291
        nodeid = rs.getLong(1);
1292
        parentnodeid = rs.getLong(2);
1293
        nodeindex = rs.getLong(3);
1294
        nodetype = rs.getString(4);
1295
        nodename = rs.getString(5);
1296
        nodeprefix = rs.getString(6);
1297
        nodedata = rs.getString(7);
1298
        nodedata = MetaCatUtil.normalize(nodedata);
1299
        // add the data to the node record list hashtable
1300
        NodeRecord currentRecord = new NodeRecord(nodeid,parentnodeid,nodeindex,
1301
                                      nodetype, nodename, nodeprefix, nodedata);
1302
        nodeRecordList.add(currentRecord);
1303

    
1304
        // Advance to the next node
1305
        tableHasRows = rs.next();
1306
      } 
1307
      pstmt.close();
1308

    
1309
    } 
1310
    catch (SQLException e) 
1311
    {
1312
      throw new McdbException("Error in DocumentImpl.getPartNodeRecordList " +
1313
                              e.getMessage());
1314
    }
1315
    finally
1316
    {
1317
      try
1318
      {
1319
        pstmt.close();
1320
      }
1321
      catch (SQLException ee)
1322
      {
1323
        MetaCatUtil.debugMessage("error in DocumentImpl.getPartNodeRecordList: "
1324
                                    +ee.getMessage(), 30);
1325
      }
1326
      finally
1327
      {
1328
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1329
      }
1330
    }
1331
      
1332

    
1333
    if (!nodeRecordList.isEmpty()) 
1334
    {
1335
     
1336
      return nodeRecordList;
1337
    } 
1338
    else 
1339
    {
1340
      
1341
      throw new McdbException("Error getting node data: " + docid);
1342
    }
1343
  }
1344
  
1345
  /**
1346
   * Look up the node data from the database
1347
   *
1348
   * @param rootnodeid the id of the root node of the node tree to look up
1349
   */
1350
  private TreeSet getNodeRecordList(long rootnodeid) throws McdbException
1351
  {
1352
    PreparedStatement pstmt = null;
1353
    DBConnection dbconn = null;
1354
    int serialNumber = -1;
1355
    TreeSet nodeRecordList = new TreeSet(new NodeComparator());
1356
    long nodeid = 0;
1357
    long parentnodeid = 0;
1358
    long nodeindex = 0;
1359
    String nodetype = null;
1360
    String nodename = null;
1361
    String nodeprefix = null;
1362
    String nodedata = null;
1363
    String quotechar = dbAdapter.getStringDelimiter();
1364

    
1365
    try {
1366
      dbconn=DBConnectionPool.
1367
                    getDBConnection("DocumentImpl.getNodeRecordList");
1368
      serialNumber=dbconn.getCheckOutSerialNumber();
1369
      pstmt =
1370
      dbconn.prepareStatement("SELECT nodeid,parentnodeid,nodeindex, " +
1371
           "nodetype,nodename,nodeprefix,nodedata " +               
1372
           "FROM xml_nodes WHERE rootnodeid = ?");
1373

    
1374
      // Bind the values to the query
1375
      pstmt.setLong(1, rootnodeid);
1376

    
1377
      pstmt.execute();
1378
      ResultSet rs = pstmt.getResultSet();
1379
      boolean tableHasRows = rs.next();
1380
      while (tableHasRows) {
1381
        nodeid = rs.getLong(1);
1382
        parentnodeid = rs.getLong(2);
1383
        nodeindex = rs.getLong(3);
1384
        nodetype = rs.getString(4);
1385
        nodename = rs.getString(5);
1386
        nodeprefix = rs.getString(6);
1387
        nodedata = rs.getString(7);
1388
        nodedata = MetaCatUtil.normalize(nodedata);
1389
        // add the data to the node record list hashtable
1390
        NodeRecord currentRecord = new NodeRecord(nodeid,parentnodeid,nodeindex,
1391
                                      nodetype, nodename, nodeprefix, nodedata);
1392
        nodeRecordList.add(currentRecord);
1393

    
1394
        // Advance to the next node
1395
        tableHasRows = rs.next();
1396
      } 
1397
      pstmt.close();
1398

    
1399
    } catch (SQLException e) {
1400
      throw new McdbException("Error in DocumentImpl.getNodeRecordList " +
1401
                              e.getMessage());
1402
    }
1403
    finally
1404
    {
1405
      try
1406
      {
1407
        pstmt.close();
1408
      }
1409
      catch (SQLException ee)
1410
      {
1411
        MetaCatUtil.debugMessage("error in DocumentImpl.getNodeRecordList: "
1412
                                    +ee.getMessage(), 30);
1413
      }
1414
      finally
1415
      {
1416
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1417
      }
1418
    }
1419
  
1420
    return nodeRecordList;
1421
   
1422
  }
1423
  
1424
// NOT USED ANY MORE
1425
//  /** creates SQL code and inserts new document into DB connection 
1426
//   default serverCode of 1*/
1427
//  private void writeDocumentToDB(String action, String user)
1428
//               throws SQLException, Exception
1429
//  {
1430
//    writeDocumentToDB(action, user, null, 1);
1431
//  }
1432

    
1433
 /** creates SQL code and inserts new document into DB connection */
1434
  private void writeDocumentToDB(String action, String user, String pub, 
1435
                                 String catalogid, int serverCode) 
1436
               throws SQLException, Exception {
1437
    String sysdate = dbAdapter.getDateTimeFunction();
1438

    
1439
    try {
1440
      PreparedStatement pstmt = null;
1441

    
1442
      if (action.equals("INSERT")) {
1443
        //AccessionNumber ac = new AccessionNumber();
1444
        //this.docid = ac.generate(docid, "INSERT");
1445
        
1446
        pstmt = connection.prepareStatement(
1447
                "INSERT INTO xml_documents " +
1448
                "(docid, rootnodeid, docname, doctype, " + 
1449
                "user_owner, user_updated, date_created, date_updated, " + 
1450
                "public_access, catalog_id, server_location, rev) " +
1451
                "VALUES (?, ?, ?, ?, ?, ?, " + sysdate + ", " + sysdate + 
1452
                ", ?, ?, ?, ?)");
1453
        // Increase dbconnection usage count
1454
        connection.increaseUsageCount(1);
1455
        
1456
        //note that the server_location is set to 1. 
1457
        //this means that "localhost" in the xml_replication table must
1458
        //always be the first entry!!!!!
1459
        
1460
        // Bind the values to the query
1461
        pstmt.setString(1, this.docid);
1462
        pstmt.setLong(2, rootnodeid);
1463
        pstmt.setString(3, docname);
1464
        pstmt.setString(4, doctype);
1465
        pstmt.setString(5, user);
1466
        pstmt.setString(6, user);
1467
        //public access is usefulless, so set it to null
1468
        pstmt.setString(7, null);
1469
        /*if ( pub == null ) {
1470
          pstmt.setString(7, null);
1471
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
1472
          pstmt.setInt(7, 1);
1473
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
1474
          pstmt.setInt(7, 0);
1475
        }*/
1476
        pstmt.setString(8, catalogid);
1477
        pstmt.setInt(9, serverCode);
1478
        pstmt.setInt(10, Integer.parseInt(updatedVersion)); 
1479
      } else if (action.equals("UPDATE")) {
1480

    
1481
        // Save the old document publicaccessentry in a backup table
1482
        DocumentImpl.archiveDocRevision(connection, docid, user );
1483
        DocumentImpl thisdoc = new DocumentImpl(docid, false);
1484
        int thisrev = thisdoc.getRev();
1485
        
1486
        //if the updated vesion is not greater than current one,
1487
        //throw it into a exception
1488
        if (Integer.parseInt(updatedVersion)<=thisrev)
1489
        {
1490
          throw new Exception("Next revision number couldn't be less"
1491
                               +" than or equal "+ thisrev);
1492
        }
1493
        else
1494
        {
1495
          //set the user specified revision 
1496
          thisrev=Integer.parseInt(updatedVersion);
1497
        }
1498
        
1499
        // Delete index for the old version of docid
1500
        // The new index is inserting on the next calls to DBSAXNode
1501
        pstmt = connection.prepareStatement(
1502
                "DELETE FROM xml_index WHERE docid='" + this.docid + "'");
1503
        // Increase dbconnection usage count
1504
        connection.increaseUsageCount(1);
1505
        
1506
        pstmt.execute();
1507
        pstmt.close();
1508

    
1509
        // Update the new document to reflect the new node tree
1510
        pstmt = connection.prepareStatement(
1511
            "UPDATE xml_documents " +
1512
            "SET rootnodeid = ?, docname = ?, doctype = ?, " +
1513
            "user_updated = ?, date_updated = " + sysdate + ", " +
1514
            "server_location = ?, rev = ?, public_access = ?, catalog_id = ? " +
1515
            "WHERE docid = ?");
1516
        // Increase dbconnection usage count
1517
        connection.increaseUsageCount(1);
1518
        // Bind the values to the query
1519
        pstmt.setLong(1, rootnodeid);
1520
        pstmt.setString(2, docname);
1521
        pstmt.setString(3, doctype);
1522
        pstmt.setString(4, user);
1523
        pstmt.setInt(5, serverCode);
1524
        pstmt.setInt(6, thisrev);
1525
        pstmt.setString(7, null);
1526
        /*if ( pub == null ) {
1527
          pstmt.setString(7, null);
1528
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
1529
          pstmt .setInt(7, 1);
1530
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
1531
          pstmt.setInt(7, 0);
1532
        }*/
1533
        pstmt.setString(8, catalogid);
1534
        pstmt.setString(9, this.docid);
1535

    
1536
      } else {
1537
        System.err.println("Action not supported: " + action);
1538
      }
1539

    
1540
      // Do the insertion
1541
      pstmt.execute();
1542
      
1543
      pstmt.close();
1544

    
1545
    } catch (SQLException sqle) {
1546
      throw sqle;
1547
    } catch (Exception e) {
1548
      throw e;
1549
    }
1550
  }
1551

    
1552
  /**
1553
   * Write an XML file to the database, given a filename
1554
   *
1555
   * @param conn the JDBC connection to the database
1556
   * @param filename the filename to be loaded into the database
1557
   * @param pub flag for public "read" access on document
1558
   * @param dtdfilename the dtd to be uploaded on server's file system
1559
   * @param action the action to be performed (INSERT OR UPDATE)
1560
   * @param docid the docid to use for the INSERT OR UPDATE
1561
   * @param user the user that owns the document
1562
   * @param groups the groups to which user belongs
1563
   */
1564
  /*public static String write(DBConnection conn,String filename,
1565
                             String pub, String dtdfilename,
1566
                             String action, String docid, String user,
1567
                             String[] groups )
1568
                throws Exception {
1569
                  
1570
    Reader dtd = null;
1571
    if ( dtdfilename != null ) {
1572
      dtd = new FileReader(new File(dtdfilename).toString());
1573
    }
1574
    return write ( conn, new FileReader(new File(filename).toString()),
1575
                   pub, dtd, action, docid, user, groups, false);
1576
  }*/
1577

    
1578
  public static String write(DBConnection conn,Reader xml,String pub,Reader dtd,
1579
                             String action, String docid, String user,
1580
                             String[] groups, String ruleBase, 
1581
                             boolean needValidation)
1582
                throws Exception {
1583
    //this method will be called in handleUpdateOrInsert method 
1584
    //in MetacatServlet class and now is wrapper into documentImple
1585
    // get server location for this doc
1586
    int serverLocation=getServerLocationNumber(docid);
1587
    return write(conn,xml,pub,dtd,action,docid,user,groups,serverLocation,false,
1588
                 ruleBase, needValidation);
1589
  }
1590

    
1591
 
1592
  
1593
  /**
1594
   * Write an XML file to the database, given a Reader
1595
   *
1596
   * @param conn the JDBC connection to the database
1597
   * @param xml the xml stream to be loaded into the database
1598
   * @param pub flag for public "read" access on xml document
1599
   * @param dtd the dtd to be uploaded on server's file system
1600
   * @param action the action to be performed (INSERT or UPDATE)
1601
   * @param accnum the docid + rev# to use on INSERT or UPDATE
1602
   * @param user the user that owns the document
1603
   * @param groups the groups to which user belongs
1604
   * @param serverCode the serverid from xml_replication on which this document
1605
   *        resides.
1606
   * @param override flag to stop insert replication checking.
1607
   *        if override = true then a document not belonging to the local server
1608
   *        will not be checked upon update for a file lock.
1609
   *        if override = false then a document not from this server, upon 
1610
   *        update will be locked and version checked.
1611
   */
1612

    
1613
  public static String write(DBConnection conn, Reader xml,String pub,
1614
                         Reader dtd, String action, String accnum, String user,
1615
                         String[] groups, int serverCode, boolean override,
1616
                         String ruleBase, boolean needValidation)
1617
                throws Exception
1618
  {
1619
    // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1620
    //MetaCatUtil util = new MetaCatUtil();
1621
    MetaCatUtil.debugMessage("conn usage count before writting: "
1622
                                      +conn.getUsageCount(), 50);
1623
    AccessionNumber ac = new AccessionNumber(accnum, action);
1624
    String docid = ac.getDocid();
1625
    String rev = ac.getRev();
1626
    MetaCatUtil.debugMessage("action: " + action + " servercode: " + 
1627
                             serverCode + " override: " + override, 10);
1628
                     
1629
    if((serverCode != 1 && action.equals("UPDATE")) && !override)
1630
    { //if this document being written is not a resident of this server then
1631
      //we need to try to get a lock from it's resident server.  If the
1632
      //resident server will not give a lock then we send the user a message
1633
      //saying that he/she needs to download a new copy of the file and
1634
      //merge the differences manually.
1635
      int istreamInt; 
1636
      char istreamChar;
1637
     
1638
      // check for 'write' permission for 'user' to update this document
1639
      if ( !hasWritePermission(user, groups, docid) ) {
1640
        throw new Exception("User " + user + 
1641
              " does not have permission to update XML Document #" + accnum);
1642
      }        
1643
  
1644
      DocumentIdentifier id = new DocumentIdentifier(accnum);
1645
      String updaterev = id.getRev();
1646
      String server=MetacatReplication.getServerNameForServerCode(serverCode);
1647
      MetacatReplication.replLog("attempting to lock " + accnum);
1648
      URL u = new URL("https://" + server + "?server="+
1649
        MetaCatUtil.getLocalReplicationServerName()+"&action=getlock&updaterev=" 
1650
           +updaterev + "&docid=" + docid);
1651
      //System.out.println("sending message: " + u.toString());
1652
      String serverResStr = MetacatReplication.getURLContent(u);
1653
      String openingtag =serverResStr.substring(0, serverResStr.indexOf(">")+1);
1654
      if(openingtag.equals("<lockgranted>"))
1655
      {//the lock was granted go ahead with the insert
1656
        try 
1657
        {
1658
          //System.out.println("In lockgranted");
1659
          MetacatReplication.replLog("lock granted for " + accnum + " from " +
1660
                                      server);
1661
          /*XMLReader parser = initializeParser(conn, action, docid, updaterev,
1662
                               validate, user, groups, pub, serverCode, dtd);*/
1663
          XMLReader parser = initializeParser(conn, action, docid, updaterev,
1664
                                        user, groups, pub, serverCode, 
1665
                                        dtd,ruleBase, needValidation); 
1666
          conn.setAutoCommit(false);
1667
          parser.parse(new InputSource(xml)); 
1668
          conn.commit();
1669
          conn.setAutoCommit(true);
1670
        } 
1671
        catch (Exception e) 
1672
        {
1673
          conn.rollback();
1674
          conn.setAutoCommit(true);
1675
          throw e;
1676
        }
1677
                
1678
        
1679
        
1680
        // Force replication the docid
1681
        ForceReplicationHandler frh = new ForceReplicationHandler
1682
                                                          (accnum, true, null);
1683
        return(accnum);
1684
   
1685
      }
1686

    
1687
      else if(openingtag.equals("<filelocked>"))
1688
      {//the file is currently locked by another user
1689
       //notify our user to wait a few minutes, check out a new copy and try
1690
       //again.
1691
        //System.out.println("file locked");
1692
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1693
                                   server + " reason: file already locked");
1694
        throw new Exception("The file specified is already locked by another " +
1695
                            "user.  Please wait 30 seconds, checkout the " +
1696
                            "newer document, merge your changes and try " +
1697
                            "again.");
1698
      }
1699
      else if(openingtag.equals("<outdatedfile>"))
1700
      {//our file is outdated.  notify our user to check out a new copy of the
1701
       //file and merge his version with the new version.
1702
        //System.out.println("outdated file");
1703
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1704
                                    server + " reason: local file outdated");
1705
        throw new Exception("The file you are trying to update is an outdated" +
1706
                            " version.  Please checkout the newest document, " +
1707
                            "merge your changes and try again.");
1708
      }
1709
    }
1710
    
1711
    if ( action.equals("UPDATE") ) {
1712
      // check for 'write' permission for 'user' to update this document
1713

    
1714
      if ( !hasWritePermission(user, groups, docid) ) {
1715
        throw new Exception("User " + user + 
1716
              " does not have permission to update XML Document #" + accnum);
1717
      }          
1718
    }
1719

    
1720
    try 
1721
    { 
1722
      
1723
      XMLReader parser = initializeParser(conn, action, docid, rev, 
1724
                                          user, groups, pub, serverCode, 
1725
                                          dtd, ruleBase, needValidation);
1726
   
1727
      conn.setAutoCommit(false);
1728
      parser.parse(new InputSource(xml));
1729
      conn.commit();
1730
      conn.setAutoCommit(true);
1731
    } 
1732
    catch (Exception e) 
1733
    {
1734
      conn.rollback();
1735
      conn.setAutoCommit(true);
1736
      throw e;
1737
    }
1738
    
1739
    // Force replicate out the new document to each server in our server list.
1740
    // Start the thread to replicate this new document out to the other servers
1741
    // true mean it is xml document
1742
    // null is because no metacat notify the force replication.
1743
    ForceReplicationHandler frh = new ForceReplicationHandler
1744
                                                  (accnum, action, true, null);
1745
      
1746
   
1747
    MetaCatUtil.debugMessage("Conn Usage count after writting: "
1748
                                                      +conn.getUsageCount(),50); 
1749
    return(accnum);
1750
  }
1751

    
1752
  /**
1753
   * Write an XML file to the database during replication
1754
   *
1755
   * @param conn the JDBC connection to the database
1756
   * @param xml the xml stream to be loaded into the database
1757
   * @param pub flag for public "read" access on xml document
1758
   * @param dtd the dtd to be uploaded on server's file system
1759
   * @param action the action to be performed (INSERT or UPDATE)
1760
   * @param accnum the docid + rev# to use on INSERT or UPDATE
1761
   * @param user the user that owns the document
1762
   * @param groups the groups to which user belongs
1763
   * @param homeServer the name of server which the document origanlly create
1764
   * @param validate, if the xml document is valid or not
1765
   * @param notifyServer, the server which notify local server the force 
1766
   *                       replication command
1767
   */
1768

    
1769
  public static String writeReplication(DBConnection conn, Reader xml, 
1770
                                        String pub, Reader dtd, String action, 
1771
                                        String accnum, String user,
1772
                                        String[] groups,String homeServer, 
1773
                                        String notifyServer,
1774
                                        String ruleBase, boolean needValidation)
1775
                                        throws Exception
1776
  {
1777
    // Docid without revision
1778
    String docid=MetaCatUtil.getDocIdFromString(accnum);
1779
    // Revision specified by user (int)
1780
    int userSpecifyRev=MetaCatUtil.getVersionFromString(accnum);
1781
    // Revision for this docid in current database
1782
    int revInDataBase=getLatestRevisionNumber(docid);
1783
    // String to store the revision
1784
    String rev = null;
1785
   
1786
    
1787
    //revIndataBase=-1, there is no record in xml_documents table
1788
    //the document is a new one for local server, inert it into table
1789
    //user specified rev should be great than 0
1790
    if (revInDataBase==-1 && userSpecifyRev>0 )
1791
    {
1792
        // rev equals user specified
1793
        rev=(new Integer(userSpecifyRev)).toString();
1794
        // action should be INSERT
1795
        action = "INSERT";
1796
    }
1797
    //rev is greater the last revsion number and revInDataBase isn't -1
1798
    // it is a updated  file
1799
    else if (userSpecifyRev>revInDataBase && revInDataBase>0)
1800
    {
1801
       // rev equals user specified
1802
       rev=(new Integer(userSpecifyRev)).toString();
1803
       // action should be update
1804
       action = "UPDATE";
1805
    }
1806
    // local server has newer version, then notify the remote server
1807
    else if ( userSpecifyRev < revInDataBase && revInDataBase > 0)
1808
    {
1809
      throw new Exception("Local server: "+MetaCatUtil.getOption("server")+
1810
                " has newer revision of doc: "+docid+"."+revInDataBase
1811
                 +". Please notify it.");
1812
    }
1813
    //other situation
1814
    else
1815
    {
1816
        
1817
        throw new Exception("The docid"+docid+"'s revision number couldn't be "
1818
                    +userSpecifyRev);
1819
    }
1820
    // Variable to store homeserver code
1821
    int serverCode=-2;
1822
    
1823
     // If server is not int the xml replication talbe, insert it into
1824
    // xml_replication table
1825
    //serverList.addToServerListIfItIsNot(homeServer);
1826
    insertServerIntoReplicationTable(homeServer);
1827
    // Get server code again
1828
    serverCode = getServerCode(homeServer);
1829
    
1830
    
1831
    MetaCatUtil.debugMessage("Document "+docid+"."+rev+" "+action+ " into local"
1832
                               +" metacat with servercode: "+ serverCode, 10);
1833
                        
1834
  
1835
    // insert into xml_nodes and xml_index table
1836
    try 
1837
    { 
1838
      
1839
      XMLReader parser = initializeParser(conn, action, docid, rev,
1840
                                          user, groups, pub, serverCode, dtd,
1841
                                          ruleBase, needValidation);
1842
      conn.setAutoCommit(false);
1843
      parser.parse(new InputSource(xml));
1844
      conn.commit();
1845
      conn.setAutoCommit(true);
1846
    } 
1847
    catch (Exception e) 
1848
    {
1849
      conn.rollback();
1850
      conn.setAutoCommit(true);
1851
      throw e;
1852
    }
1853
    
1854
    //Force replication to other server
1855
    ForceReplicationHandler forceReplication = new ForceReplicationHandler
1856
                                  (accnum, action, true, notifyServer);
1857
    
1858

    
1859
    return(accnum);
1860
  }
1861

    
1862
  
1863
  /**
1864
   * Delete an XML file from the database (actually, just make it a revision
1865
   * in the xml_revisions table)
1866
   *
1867
   * @param docid the ID of the document to be deleted from the database
1868
   */
1869
  public static void delete(String accnum,
1870
                                 String user, String[] groups )
1871
                throws Exception 
1872
  {
1873
    // OLD
1874
    //DocumentIdentifier id = new DocumentIdentifier(accnum);
1875
    //String docid = id.getIdentifier();
1876
    //String rev = id.getRev();
1877
    
1878
    // OLD
1879
    // Determine if the docid,rev are OK for DELETE
1880
    //AccessionNumber ac = new AccessionNumber(conn);
1881
    //docid = ac.generate(docid, rev, "DELETE");
1882
    DBConnection conn = null;
1883
    int serialNumber = -1;
1884
    PreparedStatement pstmt =null;
1885
    try
1886
    {
1887
      //check out DBConnection
1888
      conn=DBConnectionPool.
1889
                    getDBConnection("DocumentImpl.delete");
1890
      serialNumber=conn.getCheckOutSerialNumber();
1891

    
1892
      // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1893
      AccessionNumber ac = new AccessionNumber(accnum, "DELETE");
1894
      String docid = ac.getDocid();
1895
      String rev = ac.getRev();
1896
    
1897

    
1898
    // check for 'write' permission for 'user' to delete this document
1899
      if ( !hasWritePermission(user, groups, docid) ) {
1900
        throw new Exception("User " + user + 
1901
              " does not have permission to delete XML Document #" + accnum);
1902
      }
1903

    
1904
      conn.setAutoCommit(false);
1905
      // Copy the record to the xml_revisions table
1906
      DocumentImpl.archiveDocRevision(conn, docid, user );
1907

    
1908
      // Now delete it from the xml_index table
1909
      pstmt = conn.prepareStatement("DELETE FROM xml_index WHERE docid = ?");
1910
      pstmt.setString(1,docid);
1911
      pstmt.execute();
1912
      pstmt.close();
1913
      conn.increaseUsageCount(1);
1914
      
1915
      //stmt.execute("DELETE FROM xml_access WHERE docid = '" + docid + "'");
1916
      // Now delete it from xml_access table
1917
      pstmt = conn.
1918
              prepareStatement("DELETE FROM xml_access WHERE accessfileid = ?");
1919
      pstmt.setString(1, docid);
1920
      pstmt.execute();
1921
      pstmt.close();
1922
      conn.increaseUsageCount(1);
1923
      
1924
      // Delete it from relation table
1925
      pstmt = conn.
1926
               prepareStatement("DELETE FROM xml_relation WHERE docid = ?");
1927
      //increase usage count
1928
      conn.increaseUsageCount(1);
1929
      pstmt.setString(1, docid);
1930
      pstmt.execute();
1931
      pstmt.close();
1932
      
1933
      // Delete it from xml_doucments table
1934
      pstmt =conn.prepareStatement("DELETE FROM xml_documents WHERE docid = ?");
1935
      pstmt.setString(1, docid);
1936
      pstmt.execute();
1937
      pstmt.close();
1938
      //Usaga count increase 1
1939
      conn.increaseUsageCount(1);
1940
      
1941
      conn.commit();
1942
      conn.setAutoCommit(true);
1943
    }//try
1944
    finally
1945
    {
1946
      
1947
      try
1948
      {
1949
        // close preparedStatement
1950
        pstmt.close();
1951
      }//try
1952
      finally
1953
      {
1954
        //check in DBonnection
1955
        DBConnectionPool.returnDBConnection(conn, serialNumber);
1956
      }//finally
1957
    }//finally
1958
    //IF this is a package document:
1959
    //delete all of the relations that this document created.
1960
    //if the deleted document is a package document its relations should 
1961
    //no longer be active if it has been deleted from the system.
1962
    
1963
  }
1964

    
1965
  /** 
1966
    * Check for "WRITE" permission on @docid for @user and/or @groups 
1967
    * from DB connection 
1968
    */
1969
  private static boolean hasWritePermission (String user,
1970
                                  String[] groups, String docid ) 
1971
                  throws SQLException, Exception
1972
  {
1973
    // Check for WRITE permission on @docid for @user and/or @groups
1974
    PermissionController controller = new PermissionController(docid);
1975
    return controller.hasPermission(user,groups,
1976
                                    AccessControlInterface.WRITESTRING);
1977
  }
1978

    
1979
  /** 
1980
    * Check for "READ" permission base on docid, user and group
1981
    *@docid, the document
1982
    *@user, user name
1983
    *@group, user's group
1984
    * 
1985
    */
1986
  public static boolean hasReadPermission (String user,
1987
                                  String[] groups, String docId ) 
1988
                  throws SQLException, Exception
1989
  {
1990
    // Check for READ permission on @docid for @user and/or @groups
1991
    PermissionController controller = 
1992
                        new PermissionController(docId);
1993
    return controller.hasPermission(user,groups,
1994
                                            AccessControlInterface.READSTRING);
1995
  }  
1996

    
1997
  
1998
   /**
1999
   * Set up the parser handlers for writing the document to the database
2000
   */
2001
  private static XMLReader initializeParser(DBConnection dbconn, String action,
2002
                                            String docid, String rev, 
2003
                                            String user, 
2004
                                            String[] groups, String pub, 
2005
                                            int serverCode, Reader dtd,
2006
                                            String ruleBase, 
2007
                                            boolean needValidation) 
2008
                                            throws Exception 
2009
  {
2010
    XMLReader parser = null;
2011
    try 
2012
    {
2013
      // handler
2014
      ContentHandler chandler;
2015
      EntityResolver eresolver;
2016
      DTDHandler dtdhandler;  
2017
      // Get an instance of the parser
2018
      String parserName = MetaCatUtil.getOption("saxparser");
2019
      parser = XMLReaderFactory.createXMLReader(parserName);
2020
      if (ruleBase != null && ruleBase.equals(EML2))
2021
      {
2022
        MetaCatUtil.debugMessage("eml 2 parser", 20);
2023
        chandler = new EmlSAXHandler(dbconn, action, 
2024
                                    docid, rev, user, groups, pub, serverCode);
2025
        parser.setContentHandler((ContentHandler)chandler);
2026
        parser.setErrorHandler((ErrorHandler)chandler);
2027
        parser.setProperty(DECLARATIONHANDLERPROPERTY, chandler);
2028
        parser.setProperty(LEXICALPROPERTY, chandler);
2029
        // turn on schema validation feature
2030
        parser.setFeature(VALIDATIONFEATURE, true);
2031
        parser.setFeature(NAMESPACEFEATURE, true);
2032
        //parser.setFeature(NAMESPACEPREFIXESFEATURE, true);
2033
        parser.setFeature(SCHEMAVALIDATIONFEATURE, true);
2034
        // From DB to find the register external schema location
2035
        String externalSchemaLocation = null;
2036
        SchemaLocationResolver resolver = new SchemaLocationResolver();
2037
        externalSchemaLocation = resolver.getNameSpaceAndLocationString();
2038
        // Set external schemalocation.
2039
        if (externalSchemaLocation != null && 
2040
            !(externalSchemaLocation.trim()).equals(""))
2041
        {
2042
            parser.setProperty(EXTERNALSCHEMALOCATIONPROPERTY,
2043
                             externalSchemaLocation);
2044
        }
2045
      }
2046
      else
2047
      {
2048
        //create a DBSAXHandler object which has the revision specification
2049
        chandler = new DBSAXHandler(dbconn, action, 
2050
                                    docid, rev, user, groups, pub, serverCode);
2051
        parser.setContentHandler((ContentHandler)chandler);
2052
        parser.setErrorHandler((ErrorHandler)chandler);
2053
        parser.setProperty(DECLARATIONHANDLERPROPERTY, chandler);
2054
        parser.setProperty(LEXICALPROPERTY, chandler);
2055
      
2056
        if (ruleBase != null && ruleBase.equals(SCHEMA) && needValidation)
2057
        {
2058
          MetaCatUtil.debugMessage("General schema parser", 20);
2059
          // turn on schema validation feature
2060
          parser.setFeature(VALIDATIONFEATURE, true);
2061
          parser.setFeature(NAMESPACEFEATURE, true);
2062
          //parser.setFeature(NAMESPACEPREFIXESFEATURE, true);
2063
          parser.setFeature(SCHEMAVALIDATIONFEATURE, true);
2064
          // From DB to find the register external schema location
2065
          String externalSchemaLocation = null;
2066
          SchemaLocationResolver resolver = new SchemaLocationResolver();
2067
          externalSchemaLocation = resolver.getNameSpaceAndLocationString();
2068
          // Set external schemalocation.
2069
          if (externalSchemaLocation != null && 
2070
            !(externalSchemaLocation.trim()).equals(""))
2071
          {
2072
            parser.setProperty(EXTERNALSCHEMALOCATIONPROPERTY,
2073
                             externalSchemaLocation);
2074
          }
2075
     
2076
        }
2077
        else if (ruleBase != null && ruleBase.equals(DTD) && needValidation)
2078
        {
2079
          MetaCatUtil.debugMessage("dtd parser", 20);
2080
          // turn on dtd validaton feature
2081
          parser.setFeature(VALIDATIONFEATURE, true);
2082
          eresolver= new DBEntityResolver(dbconn, (DBSAXHandler)chandler, dtd);
2083
          dtdhandler = new DBDTDHandler(dbconn);
2084
          parser.setEntityResolver((EntityResolver)eresolver);
2085
          parser.setDTDHandler((DTDHandler)dtdhandler);
2086
        }
2087
        else
2088
        {
2089
          MetaCatUtil.debugMessage("other parser", 20);
2090
          // non validation
2091
          parser.setFeature(VALIDATIONFEATURE, false);
2092
          eresolver= new DBEntityResolver(dbconn, (DBSAXHandler)chandler, dtd);
2093
          dtdhandler = new DBDTDHandler(dbconn);
2094
          parser.setEntityResolver((EntityResolver)eresolver);
2095
          parser.setDTDHandler((DTDHandler)dtdhandler);
2096
        }
2097
      }//else
2098
    } 
2099
    catch (Exception e) 
2100
    {
2101
      throw e;
2102
    }
2103
    return parser;
2104
  }
2105

    
2106
  
2107
  /**
2108
   * Set up the parser handlers for writing the document to the database
2109
   */
2110
  /*private static XMLReader initializeParser(DBConnection dbconn, String action,
2111
                               String docid, String rev, boolean validate, 
2112
                                   String user, String[] groups, String pub, 
2113
                                   int serverCode, Reader dtd) 
2114
                           throws Exception 
2115
  {
2116
    XMLReader parser = null;
2117
    //DBConnection conn = null;
2118
    //int serialNumber = -1;
2119
    //
2120
    // Set up the SAX document handlers for parsing
2121
    //
2122
    try {
2123
       //check out DBConnection
2124
     
2125
      //create a DBSAXHandler object which has the revision specification
2126
      ContentHandler chandler = new DBSAXHandler(dbconn, action, 
2127
                                    docid, rev, user, groups, pub, serverCode);
2128
      EntityResolver eresolver= new DBEntityResolver(dbconn,
2129
                                                 (DBSAXHandler)chandler, dtd);
2130
      DTDHandler dtdhandler   = new DBDTDHandler(dbconn);
2131

    
2132
      // Get an instance of the parser
2133
      String parserName = MetaCatUtil.getOption("saxparser");
2134
      parser = XMLReaderFactory.createXMLReader(parserName);
2135

    
2136
      // Turn on validation
2137
      parser.setFeature("http://xml.org/sax/features/validation", validate);
2138
      // Turn off Including all external parameter entities
2139
      // (the external DTD subset also)
2140
      // Doesn't work well, probably the feature name is not correct
2141
      // parser.setFeature(
2142
      //  "http://xml.org/sax/features/external-parameter-entities", false);
2143
      
2144
      // Set Handlers in the parser
2145
      parser.setProperty("http://xml.org/sax/properties/declaration-handler",
2146
                         chandler);
2147
      parser.setProperty("http://xml.org/sax/properties/lexical-handler",
2148
                         chandler);
2149
      parser.setContentHandler((ContentHandler)chandler);
2150
      parser.setEntityResolver((EntityResolver)eresolver);
2151
      parser.setDTDHandler((DTDHandler)dtdhandler);
2152
      parser.setErrorHandler((ErrorHandler)chandler);
2153

    
2154
    } catch (Exception e) {
2155
      throw e;
2156
    }
2157
    //finally
2158
    //{
2159
      //DBConnectionPool.returnDBConnection(conn, serialNumber);
2160
    //}
2161

    
2162
    return parser;
2163
  }*/
2164

    
2165
  /**
2166
   * Save a document entry in the xml_revisions table 
2167
   * Connection use as a paramter is in order to rollback feature
2168
   */
2169
  private static void archiveDocRevision(DBConnection dbconn, String docid, 
2170
                                                    String user) 
2171
 {
2172
    String sysdate = dbAdapter.getDateTimeFunction();
2173
    //DBConnection conn = null;
2174
    //int serialNumber = -1;
2175
    PreparedStatement pstmt = null;
2176
    
2177
    // create a record in xml_revisions table 
2178
    // for that document as selected from xml_documents
2179
   
2180
   try
2181
   {
2182
     //check out DBConnection
2183
     /*conn=DBConnectionPool.
2184
                    getDBConnection("DocumentImpl.archiveDocRevision");
2185
     serialNumber=conn.getCheckOutSerialNumber();*/
2186
     pstmt = dbconn.prepareStatement(
2187
      "INSERT INTO xml_revisions " +
2188
        "(docid, rootnodeid, docname, doctype, " +
2189
        "user_owner, user_updated, date_created, date_updated, " +
2190
        "server_location, rev, public_access, catalog_id) " +
2191
      "SELECT ?, rootnodeid, docname, doctype, " + 
2192
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
2193
        "server_location, rev, public_access, catalog_id " +
2194
      "FROM xml_documents " +
2195
      "WHERE docid = ?");
2196
      // Increase dbconnection usage count
2197
      dbconn.increaseUsageCount(1);
2198
      // Bind the values to the query and execute it
2199
      pstmt.setString(1, docid);
2200
      pstmt.setString(2, user);
2201
      pstmt.setString(3, docid);
2202
      pstmt.execute();
2203
      pstmt.close();
2204
   }//try
2205
   catch (SQLException e)
2206
   {
2207
     MetaCatUtil.debugMessage("Error in DocumentImpl.archiveDocRevision : "+
2208
                                e.getMessage(), 30);
2209
   }//catch
2210
   finally
2211
   {
2212
     try
2213
     {
2214
       pstmt.close();
2215
     }//try
2216
     catch (SQLException ee)
2217
     {
2218
       MetaCatUtil.debugMessage("Error in DocumnetImpl.archiveDocRevision: "+
2219
                                  ee.getMessage(), 50);
2220
     }//catch
2221
     //finally
2222
     //{
2223
       
2224
       //check in DBConnection
2225
       //DBConnectionPool.returnDBConnection(conn, serialNumber);
2226
     //}//finally
2227
   }//finnally
2228
                                  
2229

    
2230
  }//achiveDocRevision
2231
  
2232
  /** Save a document entry in the xml_revisions table */
2233
  private static void archiveDocRevision(String docid, String user) 
2234
 {
2235
    String sysdate = dbAdapter.getDateTimeFunction();
2236
    DBConnection conn = null;
2237
    int serialNumber = -1;
2238
    PreparedStatement pstmt = null;
2239
    
2240
    // create a record in xml_revisions table 
2241
    // for that document as selected from xml_documents
2242
   
2243
   try
2244
   {
2245
     //check out DBConnection
2246
     conn=DBConnectionPool.
2247
                    getDBConnection("DocumentImpl.archiveDocRevision");
2248
     serialNumber=conn.getCheckOutSerialNumber();
2249
     pstmt = conn.prepareStatement(
2250
      "INSERT INTO xml_revisions " +
2251
        "(docid, rootnodeid, docname, doctype, " +
2252
        "user_owner, user_updated, date_created, date_updated, " +
2253
        "server_location, rev, public_access, catalog_id) " +
2254
      "SELECT ?, rootnodeid, docname, doctype, " + 
2255
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
2256
        "server_location, rev, public_access, catalog_id " +
2257
      "FROM xml_documents " +
2258
      "WHERE docid = ?");
2259
      // Bind the values to the query and execute it
2260
      pstmt.setString(1, docid);
2261
      pstmt.setString(2, user);
2262
      pstmt.setString(3, docid);
2263
      pstmt.execute();
2264
      pstmt.close();
2265
   }//try
2266
   catch (SQLException e)
2267
   {
2268
     MetaCatUtil.debugMessage("Error in DocumentImpl.archiveDocRevision : "+
2269
                                e.getMessage(), 30);
2270
   }//catch
2271
   finally
2272
   {
2273
     try
2274
     {
2275
       pstmt.close();
2276
     }//try
2277
     catch (SQLException ee)
2278
     {
2279
       MetaCatUtil.debugMessage("Error in DocumnetImpl.archiveDocRevision: "+
2280
                                  ee.getMessage(), 50);
2281
     }//catch
2282
     finally
2283
     {
2284
       //check in DBConnection
2285
       DBConnectionPool.returnDBConnection(conn, serialNumber);
2286
     }//finally
2287
   }//finnally
2288
                                  
2289

    
2290
  }//achiveDocRevision
2291
  
2292
  /**
2293
    * delete a entry in xml_table for given docid
2294
    * @param docId, the id of the document need to be delete
2295
    */
2296
  private static void deleteXMLDocuments(String docId) 
2297
                                         throws SQLException 
2298
  {
2299
    DBConnection conn = null;
2300
    int serialNumber = -1;
2301
    PreparedStatement pStmt = null;
2302
    try
2303
    {
2304
      //check out DBConnection
2305
      conn=DBConnectionPool.
2306
                    getDBConnection("DocumentImpl.deleteXMLDocuments");
2307
      serialNumber=conn.getCheckOutSerialNumber();
2308
      //delete a record 
2309
      pStmt = 
2310
             conn.prepareStatement("DELETE FROM xml_documents WHERE docid = '" 
2311
                                              + docId + "'");
2312
    pStmt.execute();
2313
    }//try
2314
    finally
2315
    {
2316
      try
2317
      {
2318
        pStmt.close();
2319
      }//try
2320
      catch (SQLException e)
2321
      {
2322
        MetaCatUtil.debugMessage("error in DocumentImpl.deleteXMLDocuments: "+
2323
                                  e.getMessage(), 50);
2324
      }//catch
2325
      finally
2326
      {
2327
        //return back DBconnection
2328
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2329
      }//finally
2330
    }//finally
2331
      
2332

    
2333
  }//deleteXMLDocuments
2334
  
2335
  /**
2336
    * Get last revision number from database for a docid
2337
    * If couldn't find an entry,  -1 will return
2338
    * The return value is integer because we want compare it to there new one
2339
    * @param docid <sitecode>.<uniqueid> part of Accession Number
2340
    */
2341
  private static int getLatestRevisionNumber(String docId)
2342
                                      throws SQLException
2343
  {
2344
    int rev = 1;
2345
    PreparedStatement pStmt = null;
2346
    DBConnection dbConn = null;
2347
    int serialNumber = -1;
2348
    
2349
    try
2350
    {
2351
      //check out DBConnection
2352
      dbConn=DBConnectionPool.
2353
                    getDBConnection("DocumentImpl.getLatestRevisionNumber");
2354
      serialNumber=dbConn.getCheckOutSerialNumber();
2355
     
2356
      pStmt = dbConn.prepareStatement
2357
              ("SELECT rev FROM xml_documents WHERE docid='" + docId + "'");
2358
      pStmt.execute();
2359

    
2360
      ResultSet rs = pStmt.getResultSet();
2361
      boolean hasRow = rs.next();
2362
      if (hasRow)
2363
      {
2364
        rev = rs.getInt(1);
2365
        pStmt.close();
2366
      }
2367
      else
2368
      {
2369
        rev=-1;
2370
        pStmt.close();
2371
      }
2372
    }//try
2373
    finally
2374
    {
2375
      try
2376
      {
2377
        pStmt.close();
2378
      }
2379
      catch (Exception ee)
2380
      {
2381
        MetaCatUtil.debugMessage("Error in DocumentImpl."+
2382
                        "getLatestRevisionNumber: "+ee.getMessage(), 50);
2383
      }
2384
      finally
2385
      {
2386
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2387
      }
2388
    }//finally  
2389
      
2390
    return rev;
2391
  }//getLatestRevisionNumber
2392
  
2393
  /**
2394
   * Get server location form database for a accNum
2395
   * 
2396
   * @param accum <sitecode>.<uniqueid>.<rev>
2397
   */
2398
  private static int getServerLocationNumber(String accNum)
2399
                                            throws SQLException
2400
  {
2401
    //get rid of revNum part
2402
    String docId=MetaCatUtil.getDocIdFromString(accNum);
2403
    PreparedStatement pStmt = null;
2404
    int serverLocation = 1;
2405
    DBConnection conn = null;
2406
    int serialNumber = -1;
2407
    
2408
    try
2409
    {
2410
      //check out DBConnection
2411
      conn=DBConnectionPool.
2412
                    getDBConnection("DocumentImpl.getServerLocationNumber");
2413
      serialNumber=conn.getCheckOutSerialNumber();
2414
     
2415
      pStmt = conn.prepareStatement
2416
      ("SELECT server_location FROM xml_documents WHERE docid='" + docId + "'");
2417
      pStmt.execute();
2418

    
2419
      ResultSet rs = pStmt.getResultSet();
2420
      boolean hasRow = rs.next();
2421
      //if there is entry in xml_documents, get the serverlocation
2422
      if (hasRow)
2423
      {
2424
        serverLocation = rs.getInt(1);
2425
        pStmt.close();
2426
      }
2427
      else
2428
      {
2429
        //if htere is no entry in xml_documents, we consider it is new document
2430
        //the server location is local host and value is 1
2431
        serverLocation=1;
2432
        pStmt.close();
2433
      }
2434
    }//try
2435
    finally
2436
    {
2437
      try
2438
      {
2439
        pStmt.close();
2440
      }//try
2441
      catch (Exception ee)
2442
      {
2443
        MetaCatUtil.debugMessage("Error in DocumentImpl.getServerLocationNu(): "
2444
                                    +ee.getMessage(), 50);
2445
      }//catch
2446
      finally
2447
      {
2448
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2449
      }//finally
2450
    }//finally
2451
      
2452
    return serverLocation;
2453
  }
2454
  
2455
  /**
2456
   * Given a server name, return its servercode in xml_replication table.
2457
   * If no server is found, -1 will return
2458
   * @param serverName, 
2459
   */
2460
  private static int getServerCode(String serverName) 
2461
  {
2462
    PreparedStatement pStmt=null;
2463
    int serverLocation=-2;
2464
    DBConnection dbConn = null;
2465
    int serialNumber = -1;
2466
    //MetaCatUtil util = new MetaCatUtil();
2467
    
2468
    
2469
    //we should consider about local host too
2470
    if (serverName.equals(MetaCatUtil.getLocalReplicationServerName()))
2471
    { 
2472
      serverLocation=1;
2473
      return serverLocation;
2474
    }
2475
    
2476
   
2477
    try
2478
    {
2479
      //check xml_replication table
2480
      //dbConn=util.openDBConnection();
2481
      //check out DBConnection
2482
      dbConn=DBConnectionPool.getDBConnection("DocumentImpl.getServerCode");
2483
      serialNumber=dbConn.getCheckOutSerialNumber();
2484
      pStmt = dbConn.prepareStatement
2485
      ("SELECT serverid FROM xml_replication WHERE server='" + serverName +"'");
2486
      pStmt.execute();
2487

    
2488
      ResultSet rs = pStmt.getResultSet();
2489
      boolean hasRow = rs.next();
2490
      //if there is entry in xml_replication, get the serverid
2491
      if (hasRow)
2492
      {
2493
        serverLocation = rs.getInt(1);
2494
        pStmt.close();
2495
      }
2496
      else
2497
      {
2498
        // if htere is no entry in xml_replication, -1 will return
2499
        serverLocation=-1;
2500
        pStmt.close();
2501
      }
2502
    }
2503
    catch (Exception e)
2504
    {
2505
      MetaCatUtil.debugMessage("Error in DocumentImpl.getServerCode(): "
2506
                                    +e.getMessage(), 30);
2507
    }
2508
    finally
2509
    {
2510
      try
2511
      {
2512
        pStmt.close();
2513
      }
2514
      catch (Exception ee)
2515
      {
2516
        MetaCatUtil.debugMessage("Error in DocumentImpl.getServerCode(): "
2517
                                    +ee.getMessage(), 50);
2518
      }
2519
      finally
2520
      {
2521
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2522
      }
2523
    }
2524
                 
2525
      
2526
    return serverLocation;
2527
  }
2528
  
2529
  /**
2530
   * Insert a server into xml_replcation table
2531
   * @param server, the name of server 
2532
   */
2533
  private static synchronized void 
2534
                                insertServerIntoReplicationTable(String server)
2535
  {
2536
    PreparedStatement pStmt=null;
2537
    DBConnection dbConn = null;
2538
    int serialNumber = -1;
2539
    
2540
    // Initial value for the server
2541
    int replicate = 0;
2542
    int dataReplicate = 0;
2543
    int hub = 0;
2544
   
2545
    try
2546
    {
2547
       // Get DBConnection
2548
       dbConn=DBConnectionPool.
2549
                getDBConnection("DocumentImpl.insertServIntoReplicationTable");
2550
       serialNumber=dbConn.getCheckOutSerialNumber();
2551
      
2552
      // Compare the server to dabase
2553
      pStmt = dbConn.prepareStatement
2554
      ("SELECT serverid FROM xml_replication WHERE server='" + server +"'");
2555
      pStmt.execute();
2556
      ResultSet rs = pStmt.getResultSet();
2557
      boolean hasRow = rs.next();
2558
      // Close preparedstatement and result set
2559
      pStmt.close();
2560
      rs.close();
2561
      
2562
      // If the server is not in the table, and server is not local host,
2563
      // insert it
2564
      if ( !hasRow 
2565
         && !server.equals(MetaCatUtil.getLocalReplicationServerName()))
2566
      {
2567
        // Set auto commit false
2568
        dbConn.setAutoCommit(false);
2569
        pStmt = dbConn.prepareStatement("INSERT INTO xml_replication " +
2570
                      "(server, last_checked, replicate, datareplicate, hub) " +
2571
                       "VALUES ('" + server + "', to_date(" +
2572
                       "'01/01/00', 'MM/DD/YY'), '" +
2573
                       replicate +"', '"+dataReplicate+"','"+ hub + "')");
2574
        pStmt.execute();
2575
        dbConn.commit();
2576
        // Increase usage number
2577
        dbConn.increaseUsageCount(1);
2578
        pStmt.close();
2579
        
2580
      }
2581
    }//try
2582
    catch (Exception e)
2583
    {
2584
      MetaCatUtil.debugMessage("Error in DocumentImpl.insertServerIntoRepli(): "
2585
                                    +e.getMessage(), 30);
2586
    }//catch
2587
    finally
2588
    {
2589
     
2590
      try
2591
      {
2592
        // Set auto commit true
2593
        dbConn.setAutoCommit(true);
2594
        pStmt.close();
2595
        
2596
      }//try
2597
      catch (Exception ee)
2598
      {
2599
        MetaCatUtil.debugMessage("Error in DocumentImpl.insetServerIntoRepl(): "
2600
                                    +ee.getMessage(), 50);
2601
      }//catch
2602
      finally
2603
      {
2604
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2605
      }
2606
    
2607
    }//finally
2608

    
2609
  }
2610
  
2611
  
2612
  /**
2613
   * the main routine used to test the DBWriter utility.
2614
   * <p>
2615
   * Usage: java DocumentImpl <-f filename -a action -d docid>
2616
   *
2617
   * @param filename the filename to be loaded into the database
2618
   * @param action the action to perform (READ, INSERT, UPDATE, DELETE)
2619
   * @param docid the id of the document to process
2620
   */
2621
  static public void main(String[] args) {
2622
    DBConnection dbconn = null;
2623
    int serialNumber = -1;
2624
    try {
2625
      String filename    = null;
2626
      String dtdfilename = null;
2627
      String action      = null;
2628
      String docid       = null;
2629
      boolean showRuntime = false;
2630
      boolean useOldReadAlgorithm = false;
2631

    
2632
      // Parse the command line arguments
2633
      for ( int i=0 ; i < args.length; ++i ) {
2634
        if ( args[i].equals( "-f" ) ) {
2635
          filename =  args[++i];
2636
        } else if ( args[i].equals( "-r" ) ) {
2637
          dtdfilename =  args[++i];
2638
        } else if ( args[i].equals( "-a" ) ) {
2639
          action =  args[++i];
2640
        } else if ( args[i].equals( "-d" ) ) {
2641
          docid =  args[++i];
2642
        } else if ( args[i].equals( "-t" ) ) {
2643
          showRuntime = true;
2644
        } else if ( args[i].equals( "-old" ) ) {
2645
          useOldReadAlgorithm = true;
2646
        } else {
2647
          System.err.println
2648
            ( "   args[" +i+ "] '" +args[i]+ "' ignored." );
2649
        }
2650
      }
2651
      
2652
      // Check if the required arguments are provided
2653
      boolean argsAreValid = false;
2654
      if (action != null) {
2655
        if (action.equals("INSERT")) {
2656
          if (filename != null) {
2657
            argsAreValid = true;
2658
          } 
2659
        } else if (action.equals("UPDATE")) {
2660
          if ((filename != null) && (docid != null)) {
2661
            argsAreValid = true;
2662
          } 
2663
        } else if (action.equals("DELETE")) {
2664
          if (docid != null) {
2665
            argsAreValid = true;
2666
          } 
2667
        } else if (action.equals("READ")) {
2668
          if (docid != null) {
2669
            argsAreValid = true;
2670
          } 
2671
        } 
2672
      } 
2673

    
2674
      // Print usage message if the arguments are not valid
2675
      if (!argsAreValid) {
2676
        System.err.println("Wrong number of arguments!!!");
2677
        System.err.println(
2678
          "USAGE: java DocumentImpl [-t] <-a INSERT> [-d docid] <-f filename> "+
2679
          "[-r dtdfilename]");
2680
        System.err.println(
2681
          "   OR: java DocumentImpl [-t] <-a UPDATE -d docid -f filename> " +
2682
          "[-r dtdfilename]");
2683
        System.err.println(
2684
          "   OR: java DocumentImpl [-t] <-a DELETE -d docid>");
2685
        System.err.println(
2686
          "   OR: java DocumentImpl [-t] [-old] <-a READ -d docid>");
2687
        return;
2688
      }
2689
      
2690
      // Time the request if asked for
2691
      double startTime = System.currentTimeMillis();
2692
      
2693
      // Open a connection to the database
2694
      MetaCatUtil util = new MetaCatUtil();
2695
     
2696
      dbconn=DBConnectionPool.getDBConnection("DocumentImpl.main");
2697
      serialNumber=dbconn.getCheckOutSerialNumber();
2698

    
2699
      double connTime = System.currentTimeMillis();
2700
      // Execute the action requested (READ, INSERT, UPDATE, DELETE)
2701
      if (action.equals("READ")) {
2702
          DocumentImpl xmldoc = new DocumentImpl(docid );
2703
          if (useOldReadAlgorithm) {
2704
            System.out.println(xmldoc.readUsingSlowAlgorithm());
2705
          } else {
2706
            xmldoc.toXml(new PrintWriter(System.out), null, null, true);
2707
          }
2708
      } else if (action.equals("DELETE")) {
2709
        DocumentImpl.delete(docid, null, null);
2710
        System.out.println("Document deleted: " + docid);
2711
      } else {
2712
        /*String newdocid = DocumentImpl.write(dbconn, filename, null,
2713
                                             dtdfilename, action, docid,
2714
                                             null, null);
2715
        if ((docid != null) && (!docid.equals(newdocid))) {
2716
          if (action.equals("INSERT")) {
2717
            System.out.println("New document ID generated!!! ");
2718
          } else if (action.equals("UPDATE")) {
2719
            System.out.println("ERROR: Couldn't update document!!! ");
2720
          }
2721
        } else if ((docid == null) && (action.equals("UPDATE"))) {
2722
          System.out.println("ERROR: Couldn't update document!!! ");
2723
        }
2724
        System.out.println("Document processing finished for: " + filename
2725
              + " (" + newdocid + ")");*/
2726
      }
2727

    
2728
      double stopTime = System.currentTimeMillis();
2729
      double dbOpenTime = (connTime - startTime)/1000;
2730
      double insertTime = (stopTime - connTime)/1000;
2731
      double executionTime = (stopTime - startTime)/1000;
2732
      if (showRuntime) {
2733
        System.out.println("\n\nTotal Execution time was: " + 
2734
                           executionTime + " seconds.");
2735
        System.out.println("Time to open DB connection was: " + dbOpenTime + 
2736
                           " seconds.");
2737
        System.out.println("Time to insert document was: " + insertTime +
2738
                           " seconds.");
2739
      }
2740
      dbconn.close();
2741
    } catch (McdbException me) {
2742
      me.toXml(new PrintWriter(System.err));
2743
    } catch (AccessionNumberException ane) {
2744
      System.out.println(ane.getMessage());
2745
    } catch (Exception e) {
2746
      System.err.println("EXCEPTION HANDLING REQUIRED");
2747
      System.err.println(e.getMessage());
2748
      e.printStackTrace(System.err);
2749
    }
2750
    finally
2751
    {
2752
      // Return db connection
2753
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
2754
    }
2755
  }
2756
}
(30-30/56)