Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that represents an XML document
4
 *  Copyright: 2000 Regents of the University of California and the
5
 *             National Center for Ecological Analysis and Synthesis
6
 *    Authors: Matt Jones
7
 *    Release: @release@
8
 *
9
 *   '$Author: tao $'
10
 *     '$Date: 2003-03-03 12:14:59 -0800 (Mon, 03 Mar 2003) $'
11
 * '$Revision: 1441 $'
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
  
94
  
95
  static final int ALL = 1;
96
  static final int WRITE = 2;
97
  static final int READ = 4;
98
  private static final AbstractDatabase dbAdapter = MetaCatUtil.dbAdapter;
99

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
801
  /**
802
   * Print a text representation of the XML document to a Writer
803
   *
804
   * @param pw the Writer to which we print the document
805
   */
806
  public void toXml(Writer pw, String user, String[] groups) 
807
                                                          throws McdbException
808
  {
809
    TreeSet nodeRecordLists = null;
810
    PrintWriter out = null;
811
    if (pw instanceof PrintWriter) {
812
      out = (PrintWriter)pw;
813
    } else {
814
      out = new PrintWriter(pw);
815
    }
816

    
817
    MetaCatUtil util = new MetaCatUtil();
818
    
819
    // Here add code to handle subtree access control
820
    PermissionController control = new PermissionController(docid);
821
    Hashtable unaccessableSubTree =control.hasUnaccessableSubTree(user, groups, 
822
                                             AccessControlInterface.READSTRING);
823
    
824
    if (!unaccessableSubTree.isEmpty())
825
    {
826
     
827
      nodeRecordLists = getPartNodeRecordList(rootnodeid, unaccessableSubTree);
828
      
829
    }
830
    else 
831
    {
832
      nodeRecordLists = getNodeRecordList(rootnodeid);
833
    }
834

    
835
    Stack openElements = new Stack();
836
    boolean atRootElement = true;
837
    boolean previousNodeWasElement = false;
838

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

    
887
      // Handle the DOCUMENT node
888
      if (currentNode.nodetype.equals("DOCUMENT")) {
889
        out.println("<?xml version=\"1.0\"?>");
890
        if (docname != null && validateType != null && validateType.equals(DTD)) 
891
        {
892
          if ((doctype != null) && (system_id != null)) 
893
          {
894
            
895
            out.println("<!DOCTYPE " + docname + " PUBLIC \"" + doctype + 
896
                       "\" \"" + system_id + "\">");
897
          } 
898
          else 
899
          {
900
            
901
            out.println("<!DOCTYPE " + docname + ">");
902
          }
903
        }
904

    
905
      // Handle the ELEMENT nodes
906
      } else if (currentNode.nodetype.equals("ELEMENT")) {
907
        if (atRootElement) {
908
          atRootElement = false;
909
        } else {
910
          if (previousNodeWasElement) {
911
            out.print(">");
912
          }
913
        }
914
        openElements.push(currentNode);
915
        util.debugMessage("\n PUSHED: " + currentNode.nodename, 50);
916
        previousNodeWasElement = true;
917
        if ( currentNode.nodeprefix != null ) {
918
          out.print("<" + currentNode.nodeprefix + ":" + currentNode.nodename);
919
        } else {
920
          out.print("<" + currentNode.nodename);
921
        }
922

    
923
      // Handle the ATTRIBUTE nodes
924
      } else if (currentNode.nodetype.equals("ATTRIBUTE")) {
925
        if ( currentNode.nodeprefix != null ) {
926
          out.print(" " + currentNode.nodeprefix + ":" + currentNode.nodename +
927
                    "=\"" + currentNode.nodedata + "\"");
928
        } else {
929
          out.print(" " + currentNode.nodename + "=\"" +
930
                    currentNode.nodedata + "\"");
931
        }
932

    
933
      // Handle the NAMESPACE nodes
934
      } else if (currentNode.nodetype.equals("NAMESPACE")) {
935
        out.print(" xmlns:" + currentNode.nodename + "=\""
936
                 + currentNode.nodedata + "\"");
937

    
938
      // Handle the TEXT nodes
939
      } else if (currentNode.nodetype.equals("TEXT")) {
940
        if (previousNodeWasElement) {
941
          out.print(">");
942
        }
943
        out.print(currentNode.nodedata);
944
        previousNodeWasElement = false;
945

    
946
      // Handle the COMMENT nodes
947
      } else if (currentNode.nodetype.equals("COMMENT")) {
948
        if (previousNodeWasElement) {
949
          out.print(">");
950
        }
951
        out.print("<!--" + currentNode.nodedata + "-->");
952
        previousNodeWasElement = false;
953

    
954
      // Handle the PI nodes
955
      } else if (currentNode.nodetype.equals("PI")) {
956
        if (previousNodeWasElement) {
957
          out.print(">");
958
        }
959
        out.print("<?" + currentNode.nodename + " " +
960
                        currentNode.nodedata + "?>");
961
        previousNodeWasElement = false;
962

    
963
      // Handle any other node type (do nothing)
964
      } else {
965
        // Any other types of nodes are not handled.
966
        // Probably should throw an exception here to indicate this
967
      }
968
      out.flush();
969
    }
970
    
971
    // Print the final end tag for the root element
972
    while(!openElements.empty())
973
    {
974
      NodeRecord currentElement = (NodeRecord)openElements.pop();
975
      util.debugMessage("\n POPPED: " + currentElement.nodename, 50);
976
      if ( currentElement.nodeprefix != null ) {
977
        out.print("</" + currentElement.nodeprefix + ":" + 
978
                  currentElement.nodename + ">" );
979
      } else {
980
        out.print("</" + currentElement.nodename + ">" );
981
      }
982
    }
983
    out.flush();
984
  }
985
  
986
  private boolean isRevisionOnly(DocumentIdentifier docid) throws Exception
987
  {
988
    //System.out.println("inRevisionOnly");
989
    DBConnection dbconn = null;
990
    int serialNumber = -1;
991
    PreparedStatement pstmt =null;
992
    String rev = docid.getRev();
993
    String newid = docid.getIdentifier();
994
    try
995
    {
996
      dbconn=DBConnectionPool.
997
                    getDBConnection("DocumentImpl.isRevisionOnly");
998
      serialNumber=dbconn.getCheckOutSerialNumber();
999
      pstmt = dbconn.prepareStatement("select rev from xml_documents " +
1000
                                  "where docid like '" + newid + "'");
1001
      pstmt.execute();
1002
      ResultSet rs = pstmt.getResultSet();
1003
      boolean tablehasrows = rs.next();
1004
      if(rev.equals("newest") || rev.equals("all"))
1005
      {
1006
        return false;
1007
      }
1008
    
1009
      if(tablehasrows)
1010
      {
1011
        int r = rs.getInt(1);
1012
        pstmt.close();
1013
        if(new Integer(rev).intValue() == r)
1014
        { //the current revision in in xml_documents
1015
          //System.out.println("returning false");
1016
          return false;
1017
        }
1018
        else if(new Integer(rev).intValue() < r)
1019
        { //the current revision is in xml_revisions.
1020
          //System.out.println("returning true");
1021
          return true;
1022
        }
1023
        else if(new Integer(rev).intValue() > r)
1024
        { //error, rev cannot be greater than r
1025
          throw new Exception("requested revision cannot be greater than " +
1026
                            "the latest revision number.");
1027
        }
1028
      }
1029
      // Get miss docid and rev, throw to McdDocNotFoundException
1030
      String missDocId = MetaCatUtil.getDocIdFromString(docid.toString());
1031
      String missRevision = 
1032
                  MetaCatUtil.getRevisionStringFromString(docid.toString());
1033
      throw new McdbDocNotFoundException("the requested docid '" + 
1034
                docid.toString() + "' does not exist", missDocId, missRevision);
1035
    }//try
1036
    finally
1037
    {
1038
      pstmt.close();
1039
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1040
    }//finally
1041
  }
1042

    
1043
  private void getDocumentInfo(String docid) throws McdbException, 
1044
                                        AccessionNumberException, Exception
1045
  {
1046
    getDocumentInfo(new DocumentIdentifier(docid));
1047
  }
1048
  
1049
  /**
1050
   * Look up the document type information from the database
1051
   *
1052
   * @param docid the id of the document to look up
1053
   */
1054
  private void getDocumentInfo(DocumentIdentifier docid) throws McdbException
1055
                                                          , Exception
1056
  {
1057
    DBConnection dbconn = null;
1058
    int serialNumber = -1;
1059
    PreparedStatement pstmt = null;
1060
    String table = "xml_documents";
1061
        
1062
    try
1063
    {
1064
      if(isRevisionOnly(docid))
1065
      { //pull the document from xml_revisions instead of from xml_documents;
1066
        table = "xml_revisions";
1067
      }
1068
    }
1069
    // catch a McdbDocNotFoundException throw it
1070
    catch (McdbDocNotFoundException notFound)
1071
    {
1072
      throw notFound;
1073
    }
1074
    catch(Exception e)
1075
    {
1076
      
1077
      MetaCatUtil.debugMessage("error in DocumentImpl.getDocumentInfo: " + 
1078
                          e.getMessage(), 30);
1079
      throw e;
1080
    }
1081
    
1082

    
1083
    
1084
    try 
1085
    {
1086
      dbconn=DBConnectionPool.getDBConnection("DocumentImpl.getDocumentInfo");
1087
      serialNumber=dbconn.getCheckOutSerialNumber();
1088
      StringBuffer sql = new StringBuffer();
1089
// DOCTITLE attr cleared from the db
1090
//      sql.append("SELECT docname, doctype, rootnodeid, doctitle, ");
1091
      sql.append("SELECT docname, doctype, rootnodeid, ");
1092
      sql.append("date_created, date_updated, user_owner, user_updated, ");
1093
      sql.append("server_location, public_access, rev");
1094
      sql.append(" FROM ").append(table);
1095
      sql.append(" WHERE docid LIKE '").append(docid.getIdentifier());
1096
      sql.append("' and rev like '").append(docid.getRev()).append("'");
1097
      //System.out.println(sql.toString());
1098
      pstmt =
1099
        dbconn.prepareStatement(sql.toString());
1100
      // Bind the values to the query
1101
      //pstmt.setString(1, docid.getIdentifier());
1102
      //pstmt.setString(2, docid.getRev());
1103

    
1104
      pstmt.execute();
1105
      ResultSet rs = pstmt.getResultSet();
1106
      boolean tableHasRows = rs.next();
1107
      if (tableHasRows) {
1108
        this.docname        = rs.getString(1);
1109
        this.doctype        = rs.getString(2);
1110
        this.rootnodeid     = rs.getLong(3);
1111
// DOCTITLE attr cleared from the db
1112
//        this.doctitle       = rs.getString(4);
1113
        this.createdate     = rs.getString(4);
1114
        this.updatedate     = rs.getString(5);
1115
        this.userowner      = rs.getString(6);
1116
        this.userupdated    = rs.getString(7);
1117
        this.serverlocation = rs.getInt(8);
1118
        this.publicaccess   = rs.getString(9);
1119
        this.rev            = rs.getInt(10);
1120
      } 
1121
      pstmt.close();
1122
      
1123
      //get doc  home server name
1124
      
1125
      pstmt = dbconn.prepareStatement("select server " +
1126
                        "from xml_replication where serverid = ?");
1127
      //because connection use twise here, so we need to increase one
1128
      dbconn.increaseUsageCount(1);
1129
      pstmt.setInt(1, serverlocation);
1130
      pstmt.execute();
1131
      rs = pstmt.getResultSet();
1132
      tableHasRows = rs.next();
1133
      if (tableHasRows)
1134
      {
1135
        
1136
          String server = rs.getString(1);
1137
          //get homeserver name
1138
          if(!server.equals("localhost"))
1139
          {
1140
            this.docHomeServer=server;
1141
          }
1142
          else
1143
          {
1144
            this.docHomeServer=MetaCatUtil.getLocalReplicationServerName();
1145
          }
1146
          MetaCatUtil.debugMessage("server: "+docHomeServer, 50);
1147
        
1148
      }
1149
      pstmt.close();
1150
      if (this.doctype != null) {
1151
        pstmt =
1152
          dbconn.prepareStatement("SELECT system_id, entry_type " +
1153
                                  "FROM xml_catalog " +
1154
                                 "WHERE public_id = ?");
1155
        //should increase usage count again
1156
        dbconn.increaseUsageCount(1);
1157
        // Bind the values to the query
1158
        pstmt.setString(1, doctype);
1159
  
1160
        pstmt.execute();
1161
        rs = pstmt.getResultSet();
1162
        tableHasRows = rs.next();
1163
        if (tableHasRows) {
1164
          this.system_id  = rs.getString(1);
1165
          this.validateType = rs.getString(2);
1166
          
1167
        } 
1168
        pstmt.close();
1169
      }
1170
    } catch (SQLException e) {
1171
      System.out.println("error in DocumentImpl.getDocumentInfo: " + 
1172
                          e.getMessage());
1173
      e.printStackTrace(System.out);
1174
      throw new McdbException("Error accessing database connection in " +
1175
                              "DocumentImpl.getDocumentInfo: ", e);
1176
    }
1177
    finally
1178
    {
1179
      try
1180
      {
1181
        pstmt.close();
1182
      }
1183
      catch (SQLException ee)
1184
      {
1185
        MetaCatUtil.debugMessage("error in DocumentImple.getDocumentInfo: "
1186
                                    +ee.getMessage(), 30);
1187
      }//catch
1188
      finally
1189
      {
1190
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1191
      }
1192
    }
1193

    
1194
    if (this.docname == null) {
1195
      throw new McdbDocNotFoundException("Document not found: " + docid,
1196
                                 docid.getIdentifier(), docid.getRev());
1197
    }
1198
  }
1199
  
1200
  /**
1201
   * Look up the node data from the database, but some node would be shown
1202
   * because of access control
1203
   * @param rootnodeid the id of the root node of the node tree to look up
1204
   * @param accessControl  the hashtable has control info
1205
   */
1206
  private TreeSet getPartNodeRecordList(long rootnodeid, 
1207
                                        Hashtable accessControl) 
1208
                                        throws McdbException
1209
  {
1210
    PreparedStatement pstmt = null;
1211
    DBConnection dbconn = null;
1212
    int serialNumber = -1;
1213
    TreeSet nodeRecordList = new TreeSet(new NodeComparator());
1214
    long nodeid = 0;
1215
    long parentnodeid = 0;
1216
    long nodeindex = 0;
1217
    String nodetype = null;
1218
    String nodename = null;
1219
    String nodeprefix = null;
1220
    String nodedata = null;
1221
    String quotechar = dbAdapter.getStringDelimiter();
1222
    String sql = "SELECT nodeid,parentnodeid,nodeindex, " +
1223
                 "nodetype,nodename,nodeprefix,nodedata " +               
1224
                  "FROM xml_nodes WHERE rootnodeid = ?";
1225
                  
1226
    // go through the access control for some nodes
1227
     Enumeration en = accessControl.elements();
1228
     while (en.hasMoreElements())
1229
     {
1230
         SubTree tree = (SubTree)en.nextElement();
1231
         long startId = tree.getStartNodeId();
1232
         long endId  = tree.getEndNodeId();
1233
         sql = sql +" AND(nodeid < " + startId + " OR nodeid > " +endId +")";
1234
         
1235
     }
1236
     MetaCatUtil.debugMessage("The final query to select part node tree: " +
1237
                              sql, 25);
1238

    
1239
    try 
1240
    {
1241
      dbconn=DBConnectionPool.
1242
                    getDBConnection("DocumentImpl.getPartNodeRecordList");
1243
      serialNumber=dbconn.getCheckOutSerialNumber();
1244
      pstmt = dbconn.prepareStatement(sql);
1245

    
1246
      // Bind the values to the query
1247
      pstmt.setLong(1, rootnodeid);
1248
      pstmt.execute();
1249
      ResultSet rs = pstmt.getResultSet();
1250
      boolean tableHasRows = rs.next();
1251
      while (tableHasRows) 
1252
      {
1253
        nodeid = rs.getLong(1);
1254
        parentnodeid = rs.getLong(2);
1255
        nodeindex = rs.getLong(3);
1256
        nodetype = rs.getString(4);
1257
        nodename = rs.getString(5);
1258
        nodeprefix = rs.getString(6);
1259
        nodedata = rs.getString(7);
1260
        nodedata = MetaCatUtil.normalize(nodedata);
1261
        // add the data to the node record list hashtable
1262
        NodeRecord currentRecord = new NodeRecord(nodeid,parentnodeid,nodeindex,
1263
                                      nodetype, nodename, nodeprefix, nodedata);
1264
        nodeRecordList.add(currentRecord);
1265

    
1266
        // Advance to the next node
1267
        tableHasRows = rs.next();
1268
      } 
1269
      pstmt.close();
1270

    
1271
    } 
1272
    catch (SQLException e) 
1273
    {
1274
      throw new McdbException("Error in DocumentImpl.getPartNodeRecordList " +
1275
                              e.getMessage());
1276
    }
1277
    finally
1278
    {
1279
      try
1280
      {
1281
        pstmt.close();
1282
      }
1283
      catch (SQLException ee)
1284
      {
1285
        MetaCatUtil.debugMessage("error in DocumentImpl.getPartNodeRecordList: "
1286
                                    +ee.getMessage(), 30);
1287
      }
1288
      finally
1289
      {
1290
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1291
      }
1292
    }
1293
      
1294

    
1295
    if (!nodeRecordList.isEmpty()) 
1296
    {
1297
     
1298
      return nodeRecordList;
1299
    } 
1300
    else 
1301
    {
1302
      
1303
      throw new McdbException("Error getting node data: " + docid);
1304
    }
1305
  }
1306
  
1307
  /**
1308
   * Look up the node data from the database
1309
   *
1310
   * @param rootnodeid the id of the root node of the node tree to look up
1311
   */
1312
  private TreeSet getNodeRecordList(long rootnodeid) throws McdbException
1313
  {
1314
    PreparedStatement pstmt = null;
1315
    DBConnection dbconn = null;
1316
    int serialNumber = -1;
1317
    TreeSet nodeRecordList = new TreeSet(new NodeComparator());
1318
    long nodeid = 0;
1319
    long parentnodeid = 0;
1320
    long nodeindex = 0;
1321
    String nodetype = null;
1322
    String nodename = null;
1323
    String nodeprefix = null;
1324
    String nodedata = null;
1325
    String quotechar = dbAdapter.getStringDelimiter();
1326

    
1327
    try {
1328
      dbconn=DBConnectionPool.
1329
                    getDBConnection("DocumentImpl.getNodeRecordList");
1330
      serialNumber=dbconn.getCheckOutSerialNumber();
1331
      pstmt =
1332
      dbconn.prepareStatement("SELECT nodeid,parentnodeid,nodeindex, " +
1333
           "nodetype,nodename,nodeprefix,nodedata " +               
1334
           "FROM xml_nodes WHERE rootnodeid = ?");
1335

    
1336
      // Bind the values to the query
1337
      pstmt.setLong(1, rootnodeid);
1338

    
1339
      pstmt.execute();
1340
      ResultSet rs = pstmt.getResultSet();
1341
      boolean tableHasRows = rs.next();
1342
      while (tableHasRows) {
1343
        nodeid = rs.getLong(1);
1344
        parentnodeid = rs.getLong(2);
1345
        nodeindex = rs.getLong(3);
1346
        nodetype = rs.getString(4);
1347
        nodename = rs.getString(5);
1348
        nodeprefix = rs.getString(6);
1349
        nodedata = rs.getString(7);
1350
        nodedata = MetaCatUtil.normalize(nodedata);
1351
        // add the data to the node record list hashtable
1352
        NodeRecord currentRecord = new NodeRecord(nodeid,parentnodeid,nodeindex,
1353
                                      nodetype, nodename, nodeprefix, nodedata);
1354
        nodeRecordList.add(currentRecord);
1355

    
1356
        // Advance to the next node
1357
        tableHasRows = rs.next();
1358
      } 
1359
      pstmt.close();
1360

    
1361
    } catch (SQLException e) {
1362
      throw new McdbException("Error in DocumentImpl.getNodeRecordList " +
1363
                              e.getMessage());
1364
    }
1365
    finally
1366
    {
1367
      try
1368
      {
1369
        pstmt.close();
1370
      }
1371
      catch (SQLException ee)
1372
      {
1373
        MetaCatUtil.debugMessage("error in DocumentImpl.getNodeRecordList: "
1374
                                    +ee.getMessage(), 30);
1375
      }
1376
      finally
1377
      {
1378
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1379
      }
1380
    }
1381
      
1382

    
1383
    if (!nodeRecordList.isEmpty()) {
1384
      return nodeRecordList;
1385
    } else {
1386
      throw new McdbException("Error getting node data: " + docid);
1387
    }
1388
  }
1389
  
1390
// NOT USED ANY MORE
1391
//  /** creates SQL code and inserts new document into DB connection 
1392
//   default serverCode of 1*/
1393
//  private void writeDocumentToDB(String action, String user)
1394
//               throws SQLException, Exception
1395
//  {
1396
//    writeDocumentToDB(action, user, null, 1);
1397
//  }
1398

    
1399
 /** creates SQL code and inserts new document into DB connection */
1400
  private void writeDocumentToDB(String action, String user, String pub, 
1401
                                 String catalogid, int serverCode) 
1402
               throws SQLException, Exception {
1403
    String sysdate = dbAdapter.getDateTimeFunction();
1404

    
1405
    try {
1406
      PreparedStatement pstmt = null;
1407

    
1408
      if (action.equals("INSERT")) {
1409
        //AccessionNumber ac = new AccessionNumber();
1410
        //this.docid = ac.generate(docid, "INSERT");
1411
        
1412
        pstmt = connection.prepareStatement(
1413
                "INSERT INTO xml_documents " +
1414
                "(docid, rootnodeid, docname, doctype, " + 
1415
                "user_owner, user_updated, date_created, date_updated, " + 
1416
                "public_access, catalog_id, server_location, rev) " +
1417
                "VALUES (?, ?, ?, ?, ?, ?, " + sysdate + ", " + sysdate + 
1418
                ", ?, ?, ?, ?)");
1419
        // Increase dbconnection usage count
1420
        connection.increaseUsageCount(1);
1421
        
1422
        //note that the server_location is set to 1. 
1423
        //this means that "localhost" in the xml_replication table must
1424
        //always be the first entry!!!!!
1425
        
1426
        // Bind the values to the query
1427
        pstmt.setString(1, this.docid);
1428
        pstmt.setLong(2, rootnodeid);
1429
        pstmt.setString(3, docname);
1430
        pstmt.setString(4, doctype);
1431
        pstmt.setString(5, user);
1432
        pstmt.setString(6, user);
1433
        //public access is usefulless, so set it to null
1434
        pstmt.setString(7, null);
1435
        /*if ( pub == null ) {
1436
          pstmt.setString(7, null);
1437
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
1438
          pstmt.setInt(7, 1);
1439
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
1440
          pstmt.setInt(7, 0);
1441
        }*/
1442
        pstmt.setString(8, catalogid);
1443
        pstmt.setInt(9, serverCode);
1444
        pstmt.setInt(10, Integer.parseInt(updatedVersion)); 
1445
      } else if (action.equals("UPDATE")) {
1446

    
1447
        // Save the old document publicaccessentry in a backup table
1448
        DocumentImpl.archiveDocRevision(connection, docid, user );
1449
        DocumentImpl thisdoc = new DocumentImpl(docid, false);
1450
        int thisrev = thisdoc.getRev();
1451
        
1452
        //if the updated vesion is not greater than current one,
1453
        //throw it into a exception
1454
        if (Integer.parseInt(updatedVersion)<=thisrev)
1455
        {
1456
          throw new Exception("Next revision number couldn't be less"
1457
                               +" than or equal "+ thisrev);
1458
        }
1459
        else
1460
        {
1461
          //set the user specified revision 
1462
          thisrev=Integer.parseInt(updatedVersion);
1463
        }
1464
        
1465
        // Delete index for the old version of docid
1466
        // The new index is inserting on the next calls to DBSAXNode
1467
        pstmt = connection.prepareStatement(
1468
                "DELETE FROM xml_index WHERE docid='" + this.docid + "'");
1469
        // Increase dbconnection usage count
1470
        connection.increaseUsageCount(1);
1471
        
1472
        pstmt.execute();
1473
        pstmt.close();
1474

    
1475
        // Update the new document to reflect the new node tree
1476
        pstmt = connection.prepareStatement(
1477
            "UPDATE xml_documents " +
1478
            "SET rootnodeid = ?, docname = ?, doctype = ?, " +
1479
            "user_updated = ?, date_updated = " + sysdate + ", " +
1480
            "server_location = ?, rev = ?, public_access = ?, catalog_id = ? " +
1481
            "WHERE docid = ?");
1482
        // Increase dbconnection usage count
1483
        connection.increaseUsageCount(1);
1484
        // Bind the values to the query
1485
        pstmt.setLong(1, rootnodeid);
1486
        pstmt.setString(2, docname);
1487
        pstmt.setString(3, doctype);
1488
        pstmt.setString(4, user);
1489
        pstmt.setInt(5, serverCode);
1490
        pstmt.setInt(6, thisrev);
1491
        pstmt.setString(7, null);
1492
        /*if ( pub == null ) {
1493
          pstmt.setString(7, null);
1494
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
1495
          pstmt .setInt(7, 1);
1496
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
1497
          pstmt.setInt(7, 0);
1498
        }*/
1499
        pstmt.setString(8, catalogid);
1500
        pstmt.setString(9, this.docid);
1501

    
1502
      } else {
1503
        System.err.println("Action not supported: " + action);
1504
      }
1505

    
1506
      // Do the insertion
1507
      pstmt.execute();
1508
      
1509
      pstmt.close();
1510

    
1511
    } catch (SQLException sqle) {
1512
      throw sqle;
1513
    } catch (Exception e) {
1514
      throw e;
1515
    }
1516
  }
1517

    
1518
  /**
1519
   * Write an XML file to the database, given a filename
1520
   *
1521
   * @param conn the JDBC connection to the database
1522
   * @param filename the filename to be loaded into the database
1523
   * @param pub flag for public "read" access on document
1524
   * @param dtdfilename the dtd to be uploaded on server's file system
1525
   * @param action the action to be performed (INSERT OR UPDATE)
1526
   * @param docid the docid to use for the INSERT OR UPDATE
1527
   * @param user the user that owns the document
1528
   * @param groups the groups to which user belongs
1529
   */
1530
  /*public static String write(DBConnection conn,String filename,
1531
                             String pub, String dtdfilename,
1532
                             String action, String docid, String user,
1533
                             String[] groups )
1534
                throws Exception {
1535
                  
1536
    Reader dtd = null;
1537
    if ( dtdfilename != null ) {
1538
      dtd = new FileReader(new File(dtdfilename).toString());
1539
    }
1540
    return write ( conn, new FileReader(new File(filename).toString()),
1541
                   pub, dtd, action, docid, user, groups, false);
1542
  }*/
1543

    
1544
  public static String write(DBConnection conn,Reader xml,String pub,Reader dtd,
1545
                             String action, String docid, String user,
1546
                             String[] groups, String ruleBase, 
1547
                             boolean needValidation)
1548
                throws Exception {
1549
    //this method will be called in handleUpdateOrInsert method 
1550
    //in MetacatServlet class and now is wrapper into documentImple
1551
    // get server location for this doc
1552
    int serverLocation=getServerLocationNumber(docid);
1553
    return write(conn,xml,pub,dtd,action,docid,user,groups,serverLocation,false,
1554
                 ruleBase, needValidation);
1555
  }
1556

    
1557
 
1558
  
1559
  /**
1560
   * Write an XML file to the database, given a Reader
1561
   *
1562
   * @param conn the JDBC connection to the database
1563
   * @param xml the xml stream to be loaded into the database
1564
   * @param pub flag for public "read" access on xml document
1565
   * @param dtd the dtd to be uploaded on server's file system
1566
   * @param action the action to be performed (INSERT or UPDATE)
1567
   * @param accnum the docid + rev# to use on INSERT or UPDATE
1568
   * @param user the user that owns the document
1569
   * @param groups the groups to which user belongs
1570
   * @param serverCode the serverid from xml_replication on which this document
1571
   *        resides.
1572
   * @param override flag to stop insert replication checking.
1573
   *        if override = true then a document not belonging to the local server
1574
   *        will not be checked upon update for a file lock.
1575
   *        if override = false then a document not from this server, upon 
1576
   *        update will be locked and version checked.
1577
   */
1578

    
1579
  public static String write(DBConnection conn, Reader xml,String pub,
1580
                         Reader dtd, String action, String accnum, String user,
1581
                         String[] groups, int serverCode, boolean override,
1582
                         String ruleBase, boolean needValidation)
1583
                throws Exception
1584
  {
1585
    // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1586
    //MetaCatUtil util = new MetaCatUtil();
1587
    MetaCatUtil.debugMessage("conn usage count before writting: "
1588
                                      +conn.getUsageCount(), 50);
1589
    AccessionNumber ac = new AccessionNumber(accnum, action);
1590
    String docid = ac.getDocid();
1591
    String rev = ac.getRev();
1592
    MetaCatUtil.debugMessage("action: " + action + " servercode: " + 
1593
                             serverCode + " override: " + override, 10);
1594
                     
1595
    if((serverCode != 1 && action.equals("UPDATE")) && !override)
1596
    { //if this document being written is not a resident of this server then
1597
      //we need to try to get a lock from it's resident server.  If the
1598
      //resident server will not give a lock then we send the user a message
1599
      //saying that he/she needs to download a new copy of the file and
1600
      //merge the differences manually.
1601
      int istreamInt; 
1602
      char istreamChar;
1603
     
1604
      // check for 'write' permission for 'user' to update this document
1605
      if ( !hasWritePermission(user, groups, docid) ) {
1606
        throw new Exception("User " + user + 
1607
              " does not have permission to update XML Document #" + accnum);
1608
      }        
1609
  
1610
      DocumentIdentifier id = new DocumentIdentifier(accnum);
1611
      String updaterev = id.getRev();
1612
      String server=MetacatReplication.getServerNameForServerCode(serverCode);
1613
      MetacatReplication.replLog("attempting to lock " + accnum);
1614
      URL u = new URL("https://" + server + "?server="+
1615
        MetaCatUtil.getLocalReplicationServerName()+"&action=getlock&updaterev=" 
1616
           +updaterev + "&docid=" + docid);
1617
      //System.out.println("sending message: " + u.toString());
1618
      String serverResStr = MetacatReplication.getURLContent(u);
1619
      String openingtag =serverResStr.substring(0, serverResStr.indexOf(">")+1);
1620
      if(openingtag.equals("<lockgranted>"))
1621
      {//the lock was granted go ahead with the insert
1622
        try 
1623
        {
1624
          //System.out.println("In lockgranted");
1625
          MetacatReplication.replLog("lock granted for " + accnum + " from " +
1626
                                      server);
1627
          /*XMLReader parser = initializeParser(conn, action, docid, updaterev,
1628
                               validate, user, groups, pub, serverCode, dtd);*/
1629
          XMLReader parser = initializeParser(conn, action, docid, updaterev,
1630
                                        user, groups, pub, serverCode, 
1631
                                        dtd,ruleBase, needValidation); 
1632
          conn.setAutoCommit(false);
1633
          parser.parse(new InputSource(xml)); 
1634
          conn.commit();
1635
          conn.setAutoCommit(true);
1636
        } 
1637
        catch (Exception e) 
1638
        {
1639
          conn.rollback();
1640
          conn.setAutoCommit(true);
1641
          throw e;
1642
        }
1643
                
1644
        
1645
        
1646
        // Force replication the docid
1647
        ForceReplicationHandler frh = new ForceReplicationHandler
1648
                                                          (accnum, true, null);
1649
        return(accnum);
1650
   
1651
      }
1652

    
1653
      else if(openingtag.equals("<filelocked>"))
1654
      {//the file is currently locked by another user
1655
       //notify our user to wait a few minutes, check out a new copy and try
1656
       //again.
1657
        //System.out.println("file locked");
1658
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1659
                                   server + " reason: file already locked");
1660
        throw new Exception("The file specified is already locked by another " +
1661
                            "user.  Please wait 30 seconds, checkout the " +
1662
                            "newer document, merge your changes and try " +
1663
                            "again.");
1664
      }
1665
      else if(openingtag.equals("<outdatedfile>"))
1666
      {//our file is outdated.  notify our user to check out a new copy of the
1667
       //file and merge his version with the new version.
1668
        //System.out.println("outdated file");
1669
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1670
                                    server + " reason: local file outdated");
1671
        throw new Exception("The file you are trying to update is an outdated" +
1672
                            " version.  Please checkout the newest document, " +
1673
                            "merge your changes and try again.");
1674
      }
1675
    }
1676
    
1677
    if ( action.equals("UPDATE") ) {
1678
      // check for 'write' permission for 'user' to update this document
1679

    
1680
      if ( !hasWritePermission(user, groups, docid) ) {
1681
        throw new Exception("User " + user + 
1682
              " does not have permission to update XML Document #" + accnum);
1683
      }          
1684
    }
1685

    
1686
    try 
1687
    { 
1688
      
1689
      XMLReader parser = initializeParser(conn, action, docid, rev, 
1690
                                          user, groups, pub, serverCode, 
1691
                                          dtd, ruleBase, needValidation);
1692
   
1693
      conn.setAutoCommit(false);
1694
      parser.parse(new InputSource(xml));
1695
      conn.commit();
1696
      conn.setAutoCommit(true);
1697
    } 
1698
    catch (Exception e) 
1699
    {
1700
      conn.rollback();
1701
      conn.setAutoCommit(true);
1702
      throw e;
1703
    }
1704
    
1705
    // Force replicate out the new document to each server in our server list.
1706
    // Start the thread to replicate this new document out to the other servers
1707
    // true mean it is xml document
1708
    // null is because no metacat notify the force replication.
1709
    ForceReplicationHandler frh = new ForceReplicationHandler
1710
                                                  (accnum, action, true, null);
1711
      
1712
   
1713
    MetaCatUtil.debugMessage("Conn Usage count after writting: "
1714
                                                      +conn.getUsageCount(),50); 
1715
    return(accnum);
1716
  }
1717

    
1718
  /**
1719
   * Write an XML file to the database during replication
1720
   *
1721
   * @param conn the JDBC connection to the database
1722
   * @param xml the xml stream to be loaded into the database
1723
   * @param pub flag for public "read" access on xml document
1724
   * @param dtd the dtd to be uploaded on server's file system
1725
   * @param action the action to be performed (INSERT or UPDATE)
1726
   * @param accnum the docid + rev# to use on INSERT or UPDATE
1727
   * @param user the user that owns the document
1728
   * @param groups the groups to which user belongs
1729
   * @param homeServer the name of server which the document origanlly create
1730
   * @param validate, if the xml document is valid or not
1731
   * @param notifyServer, the server which notify local server the force 
1732
   *                       replication command
1733
   */
1734

    
1735
  public static String writeReplication(DBConnection conn, Reader xml, 
1736
                                        String pub, Reader dtd, String action, 
1737
                                        String accnum, String user,
1738
                                        String[] groups,String homeServer, 
1739
                                        String notifyServer,
1740
                                        String ruleBase, boolean needValidation)
1741
                                        throws Exception
1742
  {
1743
    // Docid without revision
1744
    String docid=MetaCatUtil.getDocIdFromString(accnum);
1745
    // Revision specified by user (int)
1746
    int userSpecifyRev=MetaCatUtil.getVersionFromString(accnum);
1747
    // Revision for this docid in current database
1748
    int revInDataBase=getLatestRevisionNumber(docid);
1749
    // String to store the revision
1750
    String rev = null;
1751
   
1752
    
1753
    //revIndataBase=-1, there is no record in xml_documents table
1754
    //the document is a new one for local server, inert it into table
1755
    //user specified rev should be great than 0
1756
    if (revInDataBase==-1 && userSpecifyRev>0 )
1757
    {
1758
        // rev equals user specified
1759
        rev=(new Integer(userSpecifyRev)).toString();
1760
        // action should be INSERT
1761
        action = "INSERT";
1762
    }
1763
    //rev is greater the last revsion number and revInDataBase isn't -1
1764
    // it is a updated  file
1765
    else if (userSpecifyRev>revInDataBase && revInDataBase>0)
1766
    {
1767
       // rev equals user specified
1768
       rev=(new Integer(userSpecifyRev)).toString();
1769
       // action should be update
1770
       action = "UPDATE";
1771
    }
1772
    // local server has newer version, then notify the remote server
1773
    else if ( userSpecifyRev < revInDataBase && revInDataBase > 0)
1774
    {
1775
      throw new Exception("Local server: "+MetaCatUtil.getOption("server")+
1776
                " has newer revision of doc: "+docid+"."+revInDataBase
1777
                 +". Please notify it.");
1778
    }
1779
    //other situation
1780
    else
1781
    {
1782
        
1783
        throw new Exception("The docid"+docid+"'s revision number couldn't be "
1784
                    +userSpecifyRev);
1785
    }
1786
    // Variable to store homeserver code
1787
    int serverCode=-2;
1788
    
1789
     // If server is not int the xml replication talbe, insert it into
1790
    // xml_replication table
1791
    //serverList.addToServerListIfItIsNot(homeServer);
1792
    insertServerIntoReplicationTable(homeServer);
1793
    // Get server code again
1794
    serverCode = getServerCode(homeServer);
1795
    
1796
    
1797
    MetaCatUtil.debugMessage("Document "+docid+"."+rev+" "+action+ " into local"
1798
                               +" metacat with servercode: "+ serverCode, 10);
1799
                        
1800
  
1801
    // insert into xml_nodes and xml_index table
1802
    try 
1803
    { 
1804
      
1805
      XMLReader parser = initializeParser(conn, action, docid, rev,
1806
                                          user, groups, pub, serverCode, dtd,
1807
                                          ruleBase, needValidation);
1808
      conn.setAutoCommit(false);
1809
      parser.parse(new InputSource(xml));
1810
      conn.commit();
1811
      conn.setAutoCommit(true);
1812
    } 
1813
    catch (Exception e) 
1814
    {
1815
      conn.rollback();
1816
      conn.setAutoCommit(true);
1817
      throw e;
1818
    }
1819
    
1820
    //Force replication to other server
1821
    ForceReplicationHandler forceReplication = new ForceReplicationHandler
1822
                                  (accnum, action, true, notifyServer);
1823
    
1824

    
1825
    return(accnum);
1826
  }
1827

    
1828
  
1829
  /**
1830
   * Delete an XML file from the database (actually, just make it a revision
1831
   * in the xml_revisions table)
1832
   *
1833
   * @param docid the ID of the document to be deleted from the database
1834
   */
1835
  public static void delete(String accnum,
1836
                                 String user, String[] groups )
1837
                throws Exception 
1838
  {
1839
    // OLD
1840
    //DocumentIdentifier id = new DocumentIdentifier(accnum);
1841
    //String docid = id.getIdentifier();
1842
    //String rev = id.getRev();
1843
    
1844
    // OLD
1845
    // Determine if the docid,rev are OK for DELETE
1846
    //AccessionNumber ac = new AccessionNumber(conn);
1847
    //docid = ac.generate(docid, rev, "DELETE");
1848
    DBConnection conn = null;
1849
    int serialNumber = -1;
1850
    PreparedStatement pstmt =null;
1851
    try
1852
    {
1853
      //check out DBConnection
1854
      conn=DBConnectionPool.
1855
                    getDBConnection("DocumentImpl.delete");
1856
      serialNumber=conn.getCheckOutSerialNumber();
1857

    
1858
      // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1859
      AccessionNumber ac = new AccessionNumber(accnum, "DELETE");
1860
      String docid = ac.getDocid();
1861
      String rev = ac.getRev();
1862
    
1863

    
1864
    // check for 'write' permission for 'user' to delete this document
1865
      if ( !hasWritePermission(user, groups, docid) ) {
1866
        throw new Exception("User " + user + 
1867
              " does not have permission to delete XML Document #" + accnum);
1868
      }
1869

    
1870
      conn.setAutoCommit(false);
1871
      // Copy the record to the xml_revisions table
1872
      DocumentImpl.archiveDocRevision(conn, docid, user );
1873

    
1874
      // Now delete it from the xml_index table
1875
      pstmt = conn.prepareStatement("DELETE FROM xml_index WHERE docid = ?");
1876
      pstmt.setString(1,docid);
1877
      pstmt.execute();
1878
      pstmt.close();
1879
      conn.increaseUsageCount(1);
1880
      
1881
      //stmt.execute("DELETE FROM xml_access WHERE docid = '" + docid + "'");
1882
      // Now delete it from xml_access table
1883
      pstmt = conn.
1884
              prepareStatement("DELETE FROM xml_access WHERE accessfileid = ?");
1885
      pstmt.setString(1, docid);
1886
      pstmt.execute();
1887
      pstmt.close();
1888
      conn.increaseUsageCount(1);
1889
      
1890
      // Delete it from relation table
1891
      pstmt = conn.
1892
               prepareStatement("DELETE FROM xml_relation WHERE docid = ?");
1893
      //increase usage count
1894
      conn.increaseUsageCount(1);
1895
      pstmt.setString(1, docid);
1896
      pstmt.execute();
1897
      pstmt.close();
1898
      
1899
      // Delete it from xml_doucments table
1900
      pstmt =conn.prepareStatement("DELETE FROM xml_documents WHERE docid = ?");
1901
      pstmt.setString(1, docid);
1902
      pstmt.execute();
1903
      pstmt.close();
1904
      //Usaga count increase 1
1905
      conn.increaseUsageCount(1);
1906
      
1907
      conn.commit();
1908
      conn.setAutoCommit(true);
1909
    }//try
1910
    finally
1911
    {
1912
      
1913
      try
1914
      {
1915
        // close preparedStatement
1916
        pstmt.close();
1917
      }//try
1918
      finally
1919
      {
1920
        //check in DBonnection
1921
        DBConnectionPool.returnDBConnection(conn, serialNumber);
1922
      }//finally
1923
    }//finally
1924
    //IF this is a package document:
1925
    //delete all of the relations that this document created.
1926
    //if the deleted document is a package document its relations should 
1927
    //no longer be active if it has been deleted from the system.
1928
    
1929
  }
1930

    
1931
  /** 
1932
    * Check for "WRITE" permission on @docid for @user and/or @groups 
1933
    * from DB connection 
1934
    */
1935
  private static boolean hasWritePermission (String user,
1936
                                  String[] groups, String docid ) 
1937
                  throws SQLException, Exception
1938
  {
1939
    // Check for WRITE permission on @docid for @user and/or @groups
1940
    PermissionController controller = new PermissionController(docid);
1941
    return controller.hasPermission(user,groups,
1942
                                    AccessControlInterface.WRITESTRING);
1943
  }
1944

    
1945
  /** 
1946
    * Check for "READ" permission base on docid, user and group
1947
    *@docid, the document
1948
    *@user, user name
1949
    *@group, user's group
1950
    * 
1951
    */
1952
  public static boolean hasReadPermission (String user,
1953
                                  String[] groups, String docId ) 
1954
                  throws SQLException, Exception
1955
  {
1956
    // Check for READ permission on @docid for @user and/or @groups
1957
    PermissionController controller = 
1958
                        new PermissionController(docId);
1959
    return controller.hasPermission(user,groups,
1960
                                            AccessControlInterface.READSTRING);
1961
  }  
1962

    
1963
  
1964
   /**
1965
   * Set up the parser handlers for writing the document to the database
1966
   */
1967
  private static XMLReader initializeParser(DBConnection dbconn, String action,
1968
                                            String docid, String rev, 
1969
                                            String user, 
1970
                                            String[] groups, String pub, 
1971
                                            int serverCode, Reader dtd,
1972
                                            String ruleBase, 
1973
                                            boolean needValidation) 
1974
                                            throws Exception 
1975
  {
1976
    XMLReader parser = null;
1977
    try 
1978
    {
1979
      // handler
1980
      ContentHandler chandler;
1981
      EntityResolver eresolver;
1982
      DTDHandler dtdhandler;  
1983
      // Get an instance of the parser
1984
      String parserName = MetaCatUtil.getOption("saxparser");
1985
      parser = XMLReaderFactory.createXMLReader(parserName);
1986
      if (ruleBase != null && ruleBase.equals(EML2))
1987
      {
1988
        MetaCatUtil.debugMessage("eml 2 parser", 20);
1989
        chandler = new EmlSAXHandler(dbconn, action, 
1990
                                    docid, rev, user, groups, pub, serverCode);
1991
        parser.setContentHandler((ContentHandler)chandler);
1992
        parser.setErrorHandler((ErrorHandler)chandler);
1993
        parser.setProperty(DECLARATIONHANDLERPROPERTY, chandler);
1994
        parser.setProperty(LEXICALPROPERTY, chandler);
1995
        // turn on schema validation feature
1996
        parser.setFeature(VALIDATIONFEATURE, true);
1997
        parser.setFeature(NAMESPACEFEATURE, true);
1998
        //parser.setFeature(NAMESPACEPREFIXESFEATURE, true);
1999
        parser.setFeature(SCHEMAVALIDATIONFEATURE, true);
2000
        // From DB to find the register external schema location
2001
        String externalSchemaLocation = null;
2002
        SchemaLocationResolver resolver = new SchemaLocationResolver();
2003
        externalSchemaLocation = resolver.getNameSpaceAndLocationString();
2004
        // Set external schemalocation.
2005
        if (externalSchemaLocation != null && 
2006
            !(externalSchemaLocation.trim()).equals(""))
2007
        {
2008
            parser.setProperty(EXTERNALSCHEMALOCATIONPROPERTY,
2009
                             externalSchemaLocation);
2010
        }
2011
      }
2012
      else
2013
      {
2014
        //create a DBSAXHandler object which has the revision specification
2015
        chandler = new DBSAXHandler(dbconn, action, 
2016
                                    docid, rev, user, groups, pub, serverCode);
2017
        parser.setContentHandler((ContentHandler)chandler);
2018
        parser.setErrorHandler((ErrorHandler)chandler);
2019
        parser.setProperty(DECLARATIONHANDLERPROPERTY, chandler);
2020
        parser.setProperty(LEXICALPROPERTY, chandler);
2021
      
2022
        if (ruleBase != null && ruleBase.equals(SCHEMA) && needValidation)
2023
        {
2024
          MetaCatUtil.debugMessage("General schema parser", 20);
2025
          // turn on schema validation feature
2026
          parser.setFeature(VALIDATIONFEATURE, true);
2027
          parser.setFeature(NAMESPACEFEATURE, true);
2028
          //parser.setFeature(NAMESPACEPREFIXESFEATURE, true);
2029
          parser.setFeature(SCHEMAVALIDATIONFEATURE, true);
2030
          // From DB to find the register external schema location
2031
          String externalSchemaLocation = null;
2032
          SchemaLocationResolver resolver = new SchemaLocationResolver();
2033
          externalSchemaLocation = resolver.getNameSpaceAndLocationString();
2034
          // Set external schemalocation.
2035
          if (externalSchemaLocation != null && 
2036
            !(externalSchemaLocation.trim()).equals(""))
2037
          {
2038
            parser.setProperty(EXTERNALSCHEMALOCATIONPROPERTY,
2039
                             externalSchemaLocation);
2040
          }
2041
     
2042
        }
2043
        else if (ruleBase != null && ruleBase.equals(DTD) && needValidation)
2044
        {
2045
          MetaCatUtil.debugMessage("dtd parser", 20);
2046
          // turn on dtd validaton feature
2047
          parser.setFeature(VALIDATIONFEATURE, true);
2048
          eresolver= new DBEntityResolver(dbconn, (DBSAXHandler)chandler, dtd);
2049
          dtdhandler = new DBDTDHandler(dbconn);
2050
          parser.setEntityResolver((EntityResolver)eresolver);
2051
          parser.setDTDHandler((DTDHandler)dtdhandler);
2052
        }
2053
        else
2054
        {
2055
          MetaCatUtil.debugMessage("other parser", 20);
2056
          // non validation
2057
          parser.setFeature(VALIDATIONFEATURE, false);
2058
          eresolver= new DBEntityResolver(dbconn, (DBSAXHandler)chandler, dtd);
2059
          dtdhandler = new DBDTDHandler(dbconn);
2060
          parser.setEntityResolver((EntityResolver)eresolver);
2061
          parser.setDTDHandler((DTDHandler)dtdhandler);
2062
        }
2063
      }//else
2064
    } 
2065
    catch (Exception e) 
2066
    {
2067
      throw e;
2068
    }
2069
    return parser;
2070
  }
2071

    
2072
  
2073
  /**
2074
   * Set up the parser handlers for writing the document to the database
2075
   */
2076
  /*private static XMLReader initializeParser(DBConnection dbconn, String action,
2077
                               String docid, String rev, boolean validate, 
2078
                                   String user, String[] groups, String pub, 
2079
                                   int serverCode, Reader dtd) 
2080
                           throws Exception 
2081
  {
2082
    XMLReader parser = null;
2083
    //DBConnection conn = null;
2084
    //int serialNumber = -1;
2085
    //
2086
    // Set up the SAX document handlers for parsing
2087
    //
2088
    try {
2089
       //check out DBConnection
2090
     
2091
      //create a DBSAXHandler object which has the revision specification
2092
      ContentHandler chandler = new DBSAXHandler(dbconn, action, 
2093
                                    docid, rev, user, groups, pub, serverCode);
2094
      EntityResolver eresolver= new DBEntityResolver(dbconn,
2095
                                                 (DBSAXHandler)chandler, dtd);
2096
      DTDHandler dtdhandler   = new DBDTDHandler(dbconn);
2097

    
2098
      // Get an instance of the parser
2099
      String parserName = MetaCatUtil.getOption("saxparser");
2100
      parser = XMLReaderFactory.createXMLReader(parserName);
2101

    
2102
      // Turn on validation
2103
      parser.setFeature("http://xml.org/sax/features/validation", validate);
2104
      // Turn off Including all external parameter entities
2105
      // (the external DTD subset also)
2106
      // Doesn't work well, probably the feature name is not correct
2107
      // parser.setFeature(
2108
      //  "http://xml.org/sax/features/external-parameter-entities", false);
2109
      
2110
      // Set Handlers in the parser
2111
      parser.setProperty("http://xml.org/sax/properties/declaration-handler",
2112
                         chandler);
2113
      parser.setProperty("http://xml.org/sax/properties/lexical-handler",
2114
                         chandler);
2115
      parser.setContentHandler((ContentHandler)chandler);
2116
      parser.setEntityResolver((EntityResolver)eresolver);
2117
      parser.setDTDHandler((DTDHandler)dtdhandler);
2118
      parser.setErrorHandler((ErrorHandler)chandler);
2119

    
2120
    } catch (Exception e) {
2121
      throw e;
2122
    }
2123
    //finally
2124
    //{
2125
      //DBConnectionPool.returnDBConnection(conn, serialNumber);
2126
    //}
2127

    
2128
    return parser;
2129
  }*/
2130

    
2131
  /**
2132
   * Save a document entry in the xml_revisions table 
2133
   * Connection use as a paramter is in order to rollback feature
2134
   */
2135
  private static void archiveDocRevision(DBConnection dbconn, String docid, 
2136
                                                    String user) 
2137
 {
2138
    String sysdate = dbAdapter.getDateTimeFunction();
2139
    //DBConnection conn = null;
2140
    //int serialNumber = -1;
2141
    PreparedStatement pstmt = null;
2142
    
2143
    // create a record in xml_revisions table 
2144
    // for that document as selected from xml_documents
2145
   
2146
   try
2147
   {
2148
     //check out DBConnection
2149
     /*conn=DBConnectionPool.
2150
                    getDBConnection("DocumentImpl.archiveDocRevision");
2151
     serialNumber=conn.getCheckOutSerialNumber();*/
2152
     pstmt = dbconn.prepareStatement(
2153
      "INSERT INTO xml_revisions " +
2154
        "(docid, rootnodeid, docname, doctype, " +
2155
        "user_owner, user_updated, date_created, date_updated, " +
2156
        "server_location, rev, public_access, catalog_id) " +
2157
      "SELECT ?, rootnodeid, docname, doctype, " + 
2158
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
2159
        "server_location, rev, public_access, catalog_id " +
2160
      "FROM xml_documents " +
2161
      "WHERE docid = ?");
2162
      // Increase dbconnection usage count
2163
      dbconn.increaseUsageCount(1);
2164
      // Bind the values to the query and execute it
2165
      pstmt.setString(1, docid);
2166
      pstmt.setString(2, user);
2167
      pstmt.setString(3, docid);
2168
      pstmt.execute();
2169
      pstmt.close();
2170
   }//try
2171
   catch (SQLException e)
2172
   {
2173
     MetaCatUtil.debugMessage("Error in DocumentImpl.archiveDocRevision : "+
2174
                                e.getMessage(), 30);
2175
   }//catch
2176
   finally
2177
   {
2178
     try
2179
     {
2180
       pstmt.close();
2181
     }//try
2182
     catch (SQLException ee)
2183
     {
2184
       MetaCatUtil.debugMessage("Error in DocumnetImpl.archiveDocRevision: "+
2185
                                  ee.getMessage(), 50);
2186
     }//catch
2187
     //finally
2188
     //{
2189
       
2190
       //check in DBConnection
2191
       //DBConnectionPool.returnDBConnection(conn, serialNumber);
2192
     //}//finally
2193
   }//finnally
2194
                                  
2195

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

    
2256
  }//achiveDocRevision
2257
  
2258
  /**
2259
    * delete a entry in xml_table for given docid
2260
    * @param docId, the id of the document need to be delete
2261
    */
2262
  private static void deleteXMLDocuments(String docId) 
2263
                                         throws SQLException 
2264
  {
2265
    DBConnection conn = null;
2266
    int serialNumber = -1;
2267
    PreparedStatement pStmt = null;
2268
    try
2269
    {
2270
      //check out DBConnection
2271
      conn=DBConnectionPool.
2272
                    getDBConnection("DocumentImpl.deleteXMLDocuments");
2273
      serialNumber=conn.getCheckOutSerialNumber();
2274
      //delete a record 
2275
      pStmt = 
2276
             conn.prepareStatement("DELETE FROM xml_documents WHERE docid = '" 
2277
                                              + docId + "'");
2278
    pStmt.execute();
2279
    }//try
2280
    finally
2281
    {
2282
      try
2283
      {
2284
        pStmt.close();
2285
      }//try
2286
      catch (SQLException e)
2287
      {
2288
        MetaCatUtil.debugMessage("error in DocumentImpl.deleteXMLDocuments: "+
2289
                                  e.getMessage(), 50);
2290
      }//catch
2291
      finally
2292
      {
2293
        //return back DBconnection
2294
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2295
      }//finally
2296
    }//finally
2297
      
2298

    
2299
  }//deleteXMLDocuments
2300
  
2301
  /**
2302
    * Get last revision number from database for a docid
2303
    * If couldn't find an entry,  -1 will return
2304
    * The return value is integer because we want compare it to there new one
2305
    * @param docid <sitecode>.<uniqueid> part of Accession Number
2306
    */
2307
  private static int getLatestRevisionNumber(String docId)
2308
                                      throws SQLException
2309
  {
2310
    int rev = 1;
2311
    PreparedStatement pStmt = null;
2312
    DBConnection dbConn = null;
2313
    int serialNumber = -1;
2314
    
2315
    try
2316
    {
2317
      //check out DBConnection
2318
      dbConn=DBConnectionPool.
2319
                    getDBConnection("DocumentImpl.getLatestRevisionNumber");
2320
      serialNumber=dbConn.getCheckOutSerialNumber();
2321
     
2322
      pStmt = dbConn.prepareStatement
2323
              ("SELECT rev FROM xml_documents WHERE docid='" + docId + "'");
2324
      pStmt.execute();
2325

    
2326
      ResultSet rs = pStmt.getResultSet();
2327
      boolean hasRow = rs.next();
2328
      if (hasRow)
2329
      {
2330
        rev = rs.getInt(1);
2331
        pStmt.close();
2332
      }
2333
      else
2334
      {
2335
        rev=-1;
2336
        pStmt.close();
2337
      }
2338
    }//try
2339
    finally
2340
    {
2341
      try
2342
      {
2343
        pStmt.close();
2344
      }
2345
      catch (Exception ee)
2346
      {
2347
        MetaCatUtil.debugMessage("Error in DocumentImpl."+
2348
                        "getLatestRevisionNumber: "+ee.getMessage(), 50);
2349
      }
2350
      finally
2351
      {
2352
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2353
      }
2354
    }//finally  
2355
      
2356
    return rev;
2357
  }//getLatestRevisionNumber
2358
  
2359
  /**
2360
   * Get server location form database for a accNum
2361
   * 
2362
   * @param accum <sitecode>.<uniqueid>.<rev>
2363
   */
2364
  private static int getServerLocationNumber(String accNum)
2365
                                            throws SQLException
2366
  {
2367
    //get rid of revNum part
2368
    String docId=MetaCatUtil.getDocIdFromString(accNum);
2369
    PreparedStatement pStmt = null;
2370
    int serverLocation = 1;
2371
    DBConnection conn = null;
2372
    int serialNumber = -1;
2373
    
2374
    try
2375
    {
2376
      //check out DBConnection
2377
      conn=DBConnectionPool.
2378
                    getDBConnection("DocumentImpl.getServerLocationNumber");
2379
      serialNumber=conn.getCheckOutSerialNumber();
2380
     
2381
      pStmt = conn.prepareStatement
2382
      ("SELECT server_location FROM xml_documents WHERE docid='" + docId + "'");
2383
      pStmt.execute();
2384

    
2385
      ResultSet rs = pStmt.getResultSet();
2386
      boolean hasRow = rs.next();
2387
      //if there is entry in xml_documents, get the serverlocation
2388
      if (hasRow)
2389
      {
2390
        serverLocation = rs.getInt(1);
2391
        pStmt.close();
2392
      }
2393
      else
2394
      {
2395
        //if htere is no entry in xml_documents, we consider it is new document
2396
        //the server location is local host and value is 1
2397
        serverLocation=1;
2398
        pStmt.close();
2399
      }
2400
    }//try
2401
    finally
2402
    {
2403
      try
2404
      {
2405
        pStmt.close();
2406
      }//try
2407
      catch (Exception ee)
2408
      {
2409
        MetaCatUtil.debugMessage("Error in DocumentImpl.getServerLocationNu(): "
2410
                                    +ee.getMessage(), 50);
2411
      }//catch
2412
      finally
2413
      {
2414
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2415
      }//finally
2416
    }//finally
2417
      
2418
    return serverLocation;
2419
  }
2420
  
2421
  /**
2422
   * Given a server name, return its servercode in xml_replication table.
2423
   * If no server is found, -1 will return
2424
   * @param serverName, 
2425
   */
2426
  private static int getServerCode(String serverName) 
2427
  {
2428
    PreparedStatement pStmt=null;
2429
    int serverLocation=-2;
2430
    DBConnection dbConn = null;
2431
    int serialNumber = -1;
2432
    //MetaCatUtil util = new MetaCatUtil();
2433
    
2434
    
2435
    //we should consider about local host too
2436
    if (serverName.equals(MetaCatUtil.getLocalReplicationServerName()))
2437
    { 
2438
      serverLocation=1;
2439
      return serverLocation;
2440
    }
2441
    
2442
   
2443
    try
2444
    {
2445
      //check xml_replication table
2446
      //dbConn=util.openDBConnection();
2447
      //check out DBConnection
2448
      dbConn=DBConnectionPool.getDBConnection("DocumentImpl.getServerCode");
2449
      serialNumber=dbConn.getCheckOutSerialNumber();
2450
      pStmt = dbConn.prepareStatement
2451
      ("SELECT serverid FROM xml_replication WHERE server='" + serverName +"'");
2452
      pStmt.execute();
2453

    
2454
      ResultSet rs = pStmt.getResultSet();
2455
      boolean hasRow = rs.next();
2456
      //if there is entry in xml_replication, get the serverid
2457
      if (hasRow)
2458
      {
2459
        serverLocation = rs.getInt(1);
2460
        pStmt.close();
2461
      }
2462
      else
2463
      {
2464
        // if htere is no entry in xml_replication, -1 will return
2465
        serverLocation=-1;
2466
        pStmt.close();
2467
      }
2468
    }
2469
    catch (Exception e)
2470
    {
2471
      MetaCatUtil.debugMessage("Error in DocumentImpl.getServerCode(): "
2472
                                    +e.getMessage(), 30);
2473
    }
2474
    finally
2475
    {
2476
      try
2477
      {
2478
        pStmt.close();
2479
      }
2480
      catch (Exception ee)
2481
      {
2482
        MetaCatUtil.debugMessage("Error in DocumentImpl.getServerCode(): "
2483
                                    +ee.getMessage(), 50);
2484
      }
2485
      finally
2486
      {
2487
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2488
      }
2489
    }
2490
                 
2491
      
2492
    return serverLocation;
2493
  }
2494
  
2495
  /**
2496
   * Insert a server into xml_replcation table
2497
   * @param server, the name of server 
2498
   */
2499
  private static synchronized void 
2500
                                insertServerIntoReplicationTable(String server)
2501
  {
2502
    PreparedStatement pStmt=null;
2503
    DBConnection dbConn = null;
2504
    int serialNumber = -1;
2505
    
2506
    // Initial value for the server
2507
    int replicate = 0;
2508
    int dataReplicate = 0;
2509
    int hub = 0;
2510
   
2511
    try
2512
    {
2513
       // Get DBConnection
2514
       dbConn=DBConnectionPool.
2515
                getDBConnection("DocumentImpl.insertServIntoReplicationTable");
2516
       serialNumber=dbConn.getCheckOutSerialNumber();
2517
      
2518
      // Compare the server to dabase
2519
      pStmt = dbConn.prepareStatement
2520
      ("SELECT serverid FROM xml_replication WHERE server='" + server +"'");
2521
      pStmt.execute();
2522
      ResultSet rs = pStmt.getResultSet();
2523
      boolean hasRow = rs.next();
2524
      // Close preparedstatement and result set
2525
      pStmt.close();
2526
      rs.close();
2527
      
2528
      // If the server is not in the table, and server is not local host,
2529
      // insert it
2530
      if ( !hasRow 
2531
         && !server.equals(MetaCatUtil.getLocalReplicationServerName()))
2532
      {
2533
        // Set auto commit false
2534
        dbConn.setAutoCommit(false);
2535
        pStmt = dbConn.prepareStatement("INSERT INTO xml_replication " +
2536
                      "(server, last_checked, replicate, datareplicate, hub) " +
2537
                       "VALUES ('" + server + "', to_date(" +
2538
                       "'01/01/00', 'MM/DD/YY'), '" +
2539
                       replicate +"', '"+dataReplicate+"','"+ hub + "')");
2540
        pStmt.execute();
2541
        dbConn.commit();
2542
        // Increase usage number
2543
        dbConn.increaseUsageCount(1);
2544
        pStmt.close();
2545
        
2546
      }
2547
    }//try
2548
    catch (Exception e)
2549
    {
2550
      MetaCatUtil.debugMessage("Error in DocumentImpl.insertServerIntoRepli(): "
2551
                                    +e.getMessage(), 30);
2552
    }//catch
2553
    finally
2554
    {
2555
     
2556
      try
2557
      {
2558
        // Set auto commit true
2559
        dbConn.setAutoCommit(true);
2560
        pStmt.close();
2561
        
2562
      }//try
2563
      catch (Exception ee)
2564
      {
2565
        MetaCatUtil.debugMessage("Error in DocumentImpl.insetServerIntoRepl(): "
2566
                                    +ee.getMessage(), 50);
2567
      }//catch
2568
      finally
2569
      {
2570
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2571
      }
2572
    
2573
    }//finally
2574

    
2575
  }
2576
  
2577
  
2578
  /**
2579
   * the main routine used to test the DBWriter utility.
2580
   * <p>
2581
   * Usage: java DocumentImpl <-f filename -a action -d docid>
2582
   *
2583
   * @param filename the filename to be loaded into the database
2584
   * @param action the action to perform (READ, INSERT, UPDATE, DELETE)
2585
   * @param docid the id of the document to process
2586
   */
2587
  static public void main(String[] args) {
2588
    DBConnection dbconn = null;
2589
    int serialNumber = -1;
2590
    try {
2591
      String filename    = null;
2592
      String dtdfilename = null;
2593
      String action      = null;
2594
      String docid       = null;
2595
      boolean showRuntime = false;
2596
      boolean useOldReadAlgorithm = false;
2597

    
2598
      // Parse the command line arguments
2599
      for ( int i=0 ; i < args.length; ++i ) {
2600
        if ( args[i].equals( "-f" ) ) {
2601
          filename =  args[++i];
2602
        } else if ( args[i].equals( "-r" ) ) {
2603
          dtdfilename =  args[++i];
2604
        } else if ( args[i].equals( "-a" ) ) {
2605
          action =  args[++i];
2606
        } else if ( args[i].equals( "-d" ) ) {
2607
          docid =  args[++i];
2608
        } else if ( args[i].equals( "-t" ) ) {
2609
          showRuntime = true;
2610
        } else if ( args[i].equals( "-old" ) ) {
2611
          useOldReadAlgorithm = true;
2612
        } else {
2613
          System.err.println
2614
            ( "   args[" +i+ "] '" +args[i]+ "' ignored." );
2615
        }
2616
      }
2617
      
2618
      // Check if the required arguments are provided
2619
      boolean argsAreValid = false;
2620
      if (action != null) {
2621
        if (action.equals("INSERT")) {
2622
          if (filename != null) {
2623
            argsAreValid = true;
2624
          } 
2625
        } else if (action.equals("UPDATE")) {
2626
          if ((filename != null) && (docid != null)) {
2627
            argsAreValid = true;
2628
          } 
2629
        } else if (action.equals("DELETE")) {
2630
          if (docid != null) {
2631
            argsAreValid = true;
2632
          } 
2633
        } else if (action.equals("READ")) {
2634
          if (docid != null) {
2635
            argsAreValid = true;
2636
          } 
2637
        } 
2638
      } 
2639

    
2640
      // Print usage message if the arguments are not valid
2641
      if (!argsAreValid) {
2642
        System.err.println("Wrong number of arguments!!!");
2643
        System.err.println(
2644
          "USAGE: java DocumentImpl [-t] <-a INSERT> [-d docid] <-f filename> "+
2645
          "[-r dtdfilename]");
2646
        System.err.println(
2647
          "   OR: java DocumentImpl [-t] <-a UPDATE -d docid -f filename> " +
2648
          "[-r dtdfilename]");
2649
        System.err.println(
2650
          "   OR: java DocumentImpl [-t] <-a DELETE -d docid>");
2651
        System.err.println(
2652
          "   OR: java DocumentImpl [-t] [-old] <-a READ -d docid>");
2653
        return;
2654
      }
2655
      
2656
      // Time the request if asked for
2657
      double startTime = System.currentTimeMillis();
2658
      
2659
      // Open a connection to the database
2660
      MetaCatUtil util = new MetaCatUtil();
2661
     
2662
      dbconn=DBConnectionPool.getDBConnection("DocumentImpl.main");
2663
      serialNumber=dbconn.getCheckOutSerialNumber();
2664

    
2665
      double connTime = System.currentTimeMillis();
2666
      // Execute the action requested (READ, INSERT, UPDATE, DELETE)
2667
      if (action.equals("READ")) {
2668
          DocumentImpl xmldoc = new DocumentImpl(docid );
2669
          if (useOldReadAlgorithm) {
2670
            System.out.println(xmldoc.readUsingSlowAlgorithm());
2671
          } else {
2672
            xmldoc.toXml(new PrintWriter(System.out), null, null);
2673
          }
2674
      } else if (action.equals("DELETE")) {
2675
        DocumentImpl.delete(docid, null, null);
2676
        System.out.println("Document deleted: " + docid);
2677
      } else {
2678
        /*String newdocid = DocumentImpl.write(dbconn, filename, null,
2679
                                             dtdfilename, action, docid,
2680
                                             null, null);
2681
        if ((docid != null) && (!docid.equals(newdocid))) {
2682
          if (action.equals("INSERT")) {
2683
            System.out.println("New document ID generated!!! ");
2684
          } else if (action.equals("UPDATE")) {
2685
            System.out.println("ERROR: Couldn't update document!!! ");
2686
          }
2687
        } else if ((docid == null) && (action.equals("UPDATE"))) {
2688
          System.out.println("ERROR: Couldn't update document!!! ");
2689
        }
2690
        System.out.println("Document processing finished for: " + filename
2691
              + " (" + newdocid + ")");*/
2692
      }
2693

    
2694
      double stopTime = System.currentTimeMillis();
2695
      double dbOpenTime = (connTime - startTime)/1000;
2696
      double insertTime = (stopTime - connTime)/1000;
2697
      double executionTime = (stopTime - startTime)/1000;
2698
      if (showRuntime) {
2699
        System.out.println("\n\nTotal Execution time was: " + 
2700
                           executionTime + " seconds.");
2701
        System.out.println("Time to open DB connection was: " + dbOpenTime + 
2702
                           " seconds.");
2703
        System.out.println("Time to insert document was: " + insertTime +
2704
                           " seconds.");
2705
      }
2706
      dbconn.close();
2707
    } catch (McdbException me) {
2708
      me.toXml(new PrintWriter(System.err));
2709
    } catch (AccessionNumberException ane) {
2710
      System.out.println(ane.getMessage());
2711
    } catch (Exception e) {
2712
      System.err.println("EXCEPTION HANDLING REQUIRED");
2713
      System.err.println(e.getMessage());
2714
      e.printStackTrace(System.err);
2715
    }
2716
    finally
2717
    {
2718
      // Return db connection
2719
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
2720
    }
2721
  }
2722
}
(29-29/54)