Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that represents an XML document
4
 *  Copyright: 2000 Regents of the University of California and the
5
 *             National Center for Ecological Analysis and Synthesis
6
 *    Authors: Matt Jones
7
 *    Release: @release@
8
 *
9
 *   '$Author: tao $'
10
 *     '$Date: 2003-04-19 19:08:23 -0700 (Sat, 19 Apr 2003) $'
11
 * '$Revision: 1591 $'
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
   public static final String EMLNAMESPACE =
94
                                         MetaCatUtil.getOption("eml2namespace"); 
95
                                         // "eml://ecoinformatics.org/eml-2.0.0";
96
  
97
  
98
  static final int ALL = 1;
99
  static final int WRITE = 2;
100
  static final int READ = 4;
101
  private static final AbstractDatabase dbAdapter = MetaCatUtil.dbAdapter;
102

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1440
    try {
1441
      PreparedStatement pstmt = null;
1442

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1879
    return(accnum);
1880
  }
1881
  
1882
  /* Running write record to xml_relation and xml_access*/
1883
  private static void runRelationAndAccessHandler(String accnumber, 
1884
                                                  String userName, 
1885
                                                  String[]group, int servercode) 
1886
                                                   throws Exception
1887
  {
1888
    DBConnection dbconn = null;
1889
    int serialNumber = -1;
1890
    PreparedStatement pstmt =null;
1891
    String documenttype = getDocTypeFromDBForCurrentDocument(accnumber);
1892
    try
1893
    {
1894
      String packagedoctype = MetaCatUtil.getOption("packagedoctype");
1895
      Vector packagedoctypes = new Vector();
1896
      packagedoctypes = MetaCatUtil.getOptionList(packagedoctype);
1897
      String docIdWithoutRev = MetaCatUtil.getDocIdFromString(accnumber);
1898
      if (documenttype != null && packagedoctypes.contains(documenttype) )
1899
      {
1900
        dbconn=DBConnectionPool.
1901
           getDBConnection("DocumentImpl.runRelationAndAccessHandeler");
1902
        serialNumber=dbconn.getCheckOutSerialNumber();
1903
        dbconn.setAutoCommit(false);
1904
        // from the relations get the access file id for that package
1905
        String aclid = RelationHandler.getAccessFileID(docIdWithoutRev);
1906
        // if there are access file, write ACL for that package
1907
        if ( aclid != null ) 
1908
        {
1909
          runAccessControlList(dbconn, aclid, userName, group, servercode);
1910
        }
1911
        dbconn.commit();
1912
        dbconn.setAutoCommit(true);
1913
      }
1914
        // if it is an access file
1915
      else if ( documenttype != null && MetaCatUtil.getOptionList(
1916
                 MetaCatUtil.getOption("accessdoctype")).contains(documenttype))
1917
      {
1918
        dbconn=DBConnectionPool.
1919
           getDBConnection("DocumentImpl.runRelationAndAccessHandeler");
1920
        serialNumber=dbconn.getCheckOutSerialNumber();
1921
        dbconn.setAutoCommit(false);
1922
        // write ACL for the package
1923
        runAccessControlList(dbconn, docIdWithoutRev, 
1924
                             userName, group, servercode);
1925
        dbconn.commit();
1926
        dbconn.setAutoCommit(true);
1927
        
1928
      }
1929
      
1930
    } 
1931
    catch (Exception e) 
1932
    {
1933
      if( dbconn != null)
1934
      {
1935
        dbconn.rollback();
1936
        dbconn.setAutoCommit(true);
1937
      }
1938
      MetaCatUtil.debugMessage("Error in DocumentImple.runRelationAndAccessHandler " +
1939
                                e.getMessage(), 30);
1940
      throw e;
1941
    }
1942
    finally
1943
    {
1944
      if (dbconn != null)
1945
      {
1946
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1947
      }
1948
    }//
1949
  }
1950
  
1951
  // It runs in xmlIndex thread. It writes ACL for a package.
1952
  private static void runAccessControlList (DBConnection conn, String aclid, 
1953
                                    String users, String[]group, int servercode)
1954
                                                throws Exception
1955
  {
1956
    // read the access file from xml_nodes
1957
    // parse the access file and store the access info into xml_access
1958
    AccessControlList aclobj =
1959
    new AccessControlList(conn, aclid, users, group, servercode);
1960
   
1961
  }
1962
  
1963
  /* Method get document type from db*/
1964
  private static String getDocTypeFromDBForCurrentDocument(String accnumber)
1965
                                                  throws SQLException
1966
  {
1967
    String docoumentType = null;
1968
    String docid = null;
1969
    PreparedStatement pstate = null;
1970
    ResultSet rs = null;
1971
    String sql = "SELECT doctype FROM xml_documents where docid = ?";
1972
    DBConnection dbConnection = null;
1973
    int serialNumber = -1;
1974
    try
1975
    {
1976
      //get rid of revision number
1977
      docid = MetaCatUtil.getDocIdFromString(accnumber);
1978
      dbConnection=DBConnectionPool.
1979
           getDBConnection("DocumentImpl.getDocTypeFromDBForCurrentDoc");
1980
      serialNumber=dbConnection.getCheckOutSerialNumber();
1981
      pstate = dbConnection.prepareStatement(sql);
1982
      //bind variable
1983
      pstate.setString(1, docid);
1984
      //excute query
1985
      pstate.execute();
1986
      //handle resultset
1987
      rs = pstate.getResultSet();
1988
      if (rs.next())
1989
      {
1990
        docoumentType = rs.getString(1);
1991
      }
1992
      rs.close();
1993
      pstate.close();
1994
    }//try
1995
    catch (SQLException e)
1996
    {
1997
      MetaCatUtil.debugMessage("error in DocumentImpl."+
1998
                      "getDocTypeFromDBForCurrentDocument "+e.getMessage(), 30);
1999
      throw e;
2000
    }//catch
2001
    finally
2002
    {
2003
      pstate.close();
2004
      DBConnectionPool.returnDBConnection(dbConnection, serialNumber);
2005
    }//
2006
    MetaCatUtil.debugMessage("The current doctype from db is: "+
2007
                              docoumentType, 35);
2008
    return docoumentType;
2009
  }
2010
  /**
2011
   * Delete an XML file from the database (actually, just make it a revision
2012
   * in the xml_revisions table)
2013
   *
2014
   * @param docid the ID of the document to be deleted from the database
2015
   */
2016
  public static void delete(String accnum,
2017
                                 String user, String[] groups )
2018
                throws Exception 
2019
  {
2020
    // OLD
2021
    //DocumentIdentifier id = new DocumentIdentifier(accnum);
2022
    //String docid = id.getIdentifier();
2023
    //String rev = id.getRev();
2024
    
2025
    // OLD
2026
    // Determine if the docid,rev are OK for DELETE
2027
    //AccessionNumber ac = new AccessionNumber(conn);
2028
    //docid = ac.generate(docid, rev, "DELETE");
2029
    DBConnection conn = null;
2030
    int serialNumber = -1;
2031
    PreparedStatement pstmt =null;
2032
    try
2033
    {
2034
      //check out DBConnection
2035
      conn=DBConnectionPool.
2036
                    getDBConnection("DocumentImpl.delete");
2037
      serialNumber=conn.getCheckOutSerialNumber();
2038

    
2039
      // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
2040
      AccessionNumber ac = new AccessionNumber(accnum, "DELETE");
2041
      String docid = ac.getDocid();
2042
      String rev = ac.getRev();
2043
    
2044

    
2045
    // check for 'write' permission for 'user' to delete this document
2046
      if ( !hasWritePermission(user, groups, docid) ) {
2047
        throw new Exception("User " + user + 
2048
              " does not have permission to delete XML Document #" + accnum);
2049
      }
2050

    
2051
      conn.setAutoCommit(false);
2052
      // Copy the record to the xml_revisions table
2053
      DocumentImpl.archiveDocRevision(conn, docid, user );
2054

    
2055
      // Now delete it from the xml_index table
2056
      pstmt = conn.prepareStatement("DELETE FROM xml_index WHERE docid = ?");
2057
      pstmt.setString(1,docid);
2058
      pstmt.execute();
2059
      pstmt.close();
2060
      conn.increaseUsageCount(1);
2061
      
2062
      //stmt.execute("DELETE FROM xml_access WHERE docid = '" + docid + "'");
2063
      // Now delete it from xml_access table
2064
      pstmt = conn.
2065
              prepareStatement("DELETE FROM xml_access WHERE accessfileid = ?");
2066
      pstmt.setString(1, docid);
2067
      pstmt.execute();
2068
      pstmt.close();
2069
      conn.increaseUsageCount(1);
2070
      
2071
      // Delete it from relation table
2072
      pstmt = conn.
2073
               prepareStatement("DELETE FROM xml_relation WHERE docid = ?");
2074
      //increase usage count
2075
      conn.increaseUsageCount(1);
2076
      pstmt.setString(1, docid);
2077
      pstmt.execute();
2078
      pstmt.close();
2079
      
2080
      // Delete it from xml_doucments table
2081
      pstmt =conn.prepareStatement("DELETE FROM xml_documents WHERE docid = ?");
2082
      pstmt.setString(1, docid);
2083
      pstmt.execute();
2084
      pstmt.close();
2085
      //Usaga count increase 1
2086
      conn.increaseUsageCount(1);
2087
      
2088
      conn.commit();
2089
      conn.setAutoCommit(true);
2090
    }//try
2091
    finally
2092
    {
2093
      
2094
      try
2095
      {
2096
        // close preparedStatement
2097
        pstmt.close();
2098
      }//try
2099
      finally
2100
      {
2101
        //check in DBonnection
2102
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2103
      }//finally
2104
    }//finally
2105
    //IF this is a package document:
2106
    //delete all of the relations that this document created.
2107
    //if the deleted document is a package document its relations should 
2108
    //no longer be active if it has been deleted from the system.
2109
    
2110
  }
2111

    
2112
  /** 
2113
    * Check for "WRITE" permission on @docid for @user and/or @groups 
2114
    * from DB connection 
2115
    */
2116
  private static boolean hasWritePermission (String user,
2117
                                  String[] groups, String docid ) 
2118
                  throws SQLException, Exception
2119
  {
2120
    // Check for WRITE permission on @docid for @user and/or @groups
2121
    PermissionController controller = new PermissionController(docid);
2122
    return controller.hasPermission(user,groups,
2123
                                    AccessControlInterface.WRITESTRING);
2124
  }
2125

    
2126
  /** 
2127
    * Check for "READ" permission base on docid, user and group
2128
    *@docid, the document
2129
    *@user, user name
2130
    *@group, user's group
2131
    * 
2132
    */
2133
  public static boolean hasReadPermission (String user,
2134
                                  String[] groups, String docId ) 
2135
                  throws SQLException, Exception
2136
  {
2137
    // Check for READ permission on @docid for @user and/or @groups
2138
    PermissionController controller = 
2139
                        new PermissionController(docId);
2140
    return controller.hasPermission(user,groups,
2141
                                            AccessControlInterface.READSTRING);
2142
  }  
2143

    
2144
  
2145
   /**
2146
   * Set up the parser handlers for writing the document to the database
2147
   */
2148
  private static XMLReader initializeParser(DBConnection dbconn, String action,
2149
                                            String docid, String rev, 
2150
                                            String user, 
2151
                                            String[] groups, String pub, 
2152
                                            int serverCode, Reader dtd,
2153
                                            String ruleBase, 
2154
                                            boolean needValidation) 
2155
                                            throws Exception 
2156
  {
2157
    XMLReader parser = null;
2158
    try 
2159
    {
2160
      // handler
2161
      ContentHandler chandler;
2162
      EntityResolver eresolver;
2163
      DTDHandler dtdhandler;  
2164
      // Get an instance of the parser
2165
      String parserName = MetaCatUtil.getOption("saxparser");
2166
      parser = XMLReaderFactory.createXMLReader(parserName);
2167
      if (ruleBase != null && ruleBase.equals(EML2))
2168
      {
2169
        MetaCatUtil.debugMessage("eml 2 parser", 20);
2170
        chandler = new EmlSAXHandler(dbconn, action, 
2171
                                    docid, rev, user, groups, pub, serverCode);
2172
        parser.setContentHandler((ContentHandler)chandler);
2173
        parser.setErrorHandler((ErrorHandler)chandler);
2174
        parser.setProperty(DECLARATIONHANDLERPROPERTY, chandler);
2175
        parser.setProperty(LEXICALPROPERTY, chandler);
2176
        // turn on schema validation feature
2177
        parser.setFeature(VALIDATIONFEATURE, true);
2178
        parser.setFeature(NAMESPACEFEATURE, true);
2179
        //parser.setFeature(NAMESPACEPREFIXESFEATURE, true);
2180
        parser.setFeature(SCHEMAVALIDATIONFEATURE, true);
2181
        // From DB to find the register external schema location
2182
        String externalSchemaLocation = null;
2183
        SchemaLocationResolver resolver = new SchemaLocationResolver();
2184
        externalSchemaLocation = resolver.getNameSpaceAndLocationString();
2185
        // Set external schemalocation.
2186
        if (externalSchemaLocation != null && 
2187
            !(externalSchemaLocation.trim()).equals(""))
2188
        {
2189
            parser.setProperty(EXTERNALSCHEMALOCATIONPROPERTY,
2190
                             externalSchemaLocation);
2191
        }
2192
      }
2193
      else
2194
      {
2195
        //create a DBSAXHandler object which has the revision specification
2196
        chandler = new DBSAXHandler(dbconn, action, 
2197
                                    docid, rev, user, groups, pub, serverCode);
2198
        parser.setContentHandler((ContentHandler)chandler);
2199
        parser.setErrorHandler((ErrorHandler)chandler);
2200
        parser.setProperty(DECLARATIONHANDLERPROPERTY, chandler);
2201
        parser.setProperty(LEXICALPROPERTY, chandler);
2202
      
2203
        if (ruleBase != null && ruleBase.equals(SCHEMA) && needValidation)
2204
        {
2205
          MetaCatUtil.debugMessage("General schema parser", 20);
2206
          // turn on schema validation feature
2207
          parser.setFeature(VALIDATIONFEATURE, true);
2208
          parser.setFeature(NAMESPACEFEATURE, true);
2209
          //parser.setFeature(NAMESPACEPREFIXESFEATURE, true);
2210
          parser.setFeature(SCHEMAVALIDATIONFEATURE, true);
2211
          // From DB to find the register external schema location
2212
          String externalSchemaLocation = null;
2213
          SchemaLocationResolver resolver = new SchemaLocationResolver();
2214
          externalSchemaLocation = resolver.getNameSpaceAndLocationString();
2215
          // Set external schemalocation.
2216
          if (externalSchemaLocation != null && 
2217
            !(externalSchemaLocation.trim()).equals(""))
2218
          {
2219
            parser.setProperty(EXTERNALSCHEMALOCATIONPROPERTY,
2220
                             externalSchemaLocation);
2221
          }
2222
     
2223
        }
2224
        else if (ruleBase != null && ruleBase.equals(DTD) && needValidation)
2225
        {
2226
          MetaCatUtil.debugMessage("dtd parser", 20);
2227
          // turn on dtd validaton feature
2228
          parser.setFeature(VALIDATIONFEATURE, true);
2229
          eresolver= new DBEntityResolver(dbconn, (DBSAXHandler)chandler, dtd);
2230
          dtdhandler = new DBDTDHandler(dbconn);
2231
          parser.setEntityResolver((EntityResolver)eresolver);
2232
          parser.setDTDHandler((DTDHandler)dtdhandler);
2233
        }
2234
        else
2235
        {
2236
          MetaCatUtil.debugMessage("other parser", 20);
2237
          // non validation
2238
          parser.setFeature(VALIDATIONFEATURE, false);
2239
          eresolver= new DBEntityResolver(dbconn, (DBSAXHandler)chandler, dtd);
2240
          dtdhandler = new DBDTDHandler(dbconn);
2241
          parser.setEntityResolver((EntityResolver)eresolver);
2242
          parser.setDTDHandler((DTDHandler)dtdhandler);
2243
        }
2244
      }//else
2245
    } 
2246
    catch (Exception e) 
2247
    {
2248
      throw e;
2249
    }
2250
    return parser;
2251
  }
2252

    
2253
  
2254
  /**
2255
   * Set up the parser handlers for writing the document to the database
2256
   */
2257
  /*private static XMLReader initializeParser(DBConnection dbconn, String action,
2258
                               String docid, String rev, boolean validate, 
2259
                                   String user, String[] groups, String pub, 
2260
                                   int serverCode, Reader dtd) 
2261
                           throws Exception 
2262
  {
2263
    XMLReader parser = null;
2264
    //DBConnection conn = null;
2265
    //int serialNumber = -1;
2266
    //
2267
    // Set up the SAX document handlers for parsing
2268
    //
2269
    try {
2270
       //check out DBConnection
2271
     
2272
      //create a DBSAXHandler object which has the revision specification
2273
      ContentHandler chandler = new DBSAXHandler(dbconn, action, 
2274
                                    docid, rev, user, groups, pub, serverCode);
2275
      EntityResolver eresolver= new DBEntityResolver(dbconn,
2276
                                                 (DBSAXHandler)chandler, dtd);
2277
      DTDHandler dtdhandler   = new DBDTDHandler(dbconn);
2278

    
2279
      // Get an instance of the parser
2280
      String parserName = MetaCatUtil.getOption("saxparser");
2281
      parser = XMLReaderFactory.createXMLReader(parserName);
2282

    
2283
      // Turn on validation
2284
      parser.setFeature("http://xml.org/sax/features/validation", validate);
2285
      // Turn off Including all external parameter entities
2286
      // (the external DTD subset also)
2287
      // Doesn't work well, probably the feature name is not correct
2288
      // parser.setFeature(
2289
      //  "http://xml.org/sax/features/external-parameter-entities", false);
2290
      
2291
      // Set Handlers in the parser
2292
      parser.setProperty("http://xml.org/sax/properties/declaration-handler",
2293
                         chandler);
2294
      parser.setProperty("http://xml.org/sax/properties/lexical-handler",
2295
                         chandler);
2296
      parser.setContentHandler((ContentHandler)chandler);
2297
      parser.setEntityResolver((EntityResolver)eresolver);
2298
      parser.setDTDHandler((DTDHandler)dtdhandler);
2299
      parser.setErrorHandler((ErrorHandler)chandler);
2300

    
2301
    } catch (Exception e) {
2302
      throw e;
2303
    }
2304
    //finally
2305
    //{
2306
      //DBConnectionPool.returnDBConnection(conn, serialNumber);
2307
    //}
2308

    
2309
    return parser;
2310
  }*/
2311

    
2312
  /**
2313
   * Save a document entry in the xml_revisions table 
2314
   * Connection use as a paramter is in order to rollback feature
2315
   */
2316
  private static void archiveDocRevision(DBConnection dbconn, String docid, 
2317
                                                    String user) 
2318
 {
2319
    String sysdate = dbAdapter.getDateTimeFunction();
2320
    //DBConnection conn = null;
2321
    //int serialNumber = -1;
2322
    PreparedStatement pstmt = null;
2323
    
2324
    // create a record in xml_revisions table 
2325
    // for that document as selected from xml_documents
2326
   
2327
   try
2328
   {
2329
     //check out DBConnection
2330
     /*conn=DBConnectionPool.
2331
                    getDBConnection("DocumentImpl.archiveDocRevision");
2332
     serialNumber=conn.getCheckOutSerialNumber();*/
2333
     pstmt = dbconn.prepareStatement(
2334
      "INSERT INTO xml_revisions " +
2335
        "(docid, rootnodeid, docname, doctype, " +
2336
        "user_owner, user_updated, date_created, date_updated, " +
2337
        "server_location, rev, public_access, catalog_id) " +
2338
      "SELECT ?, rootnodeid, docname, doctype, " + 
2339
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
2340
        "server_location, rev, public_access, catalog_id " +
2341
      "FROM xml_documents " +
2342
      "WHERE docid = ?");
2343
      // Increase dbconnection usage count
2344
      dbconn.increaseUsageCount(1);
2345
      // Bind the values to the query and execute it
2346
      pstmt.setString(1, docid);
2347
      pstmt.setString(2, user);
2348
      pstmt.setString(3, docid);
2349
      pstmt.execute();
2350
      pstmt.close();
2351
   }//try
2352
   catch (SQLException e)
2353
   {
2354
     MetaCatUtil.debugMessage("Error in DocumentImpl.archiveDocRevision : "+
2355
                                e.getMessage(), 30);
2356
   }//catch
2357
   finally
2358
   {
2359
     try
2360
     {
2361
       pstmt.close();
2362
     }//try
2363
     catch (SQLException ee)
2364
     {
2365
       MetaCatUtil.debugMessage("Error in DocumnetImpl.archiveDocRevision: "+
2366
                                  ee.getMessage(), 50);
2367
     }//catch
2368
     //finally
2369
     //{
2370
       
2371
       //check in DBConnection
2372
       //DBConnectionPool.returnDBConnection(conn, serialNumber);
2373
     //}//finally
2374
   }//finnally
2375
                                  
2376

    
2377
  }//achiveDocRevision
2378
  
2379
  /** Save a document entry in the xml_revisions table */
2380
  private static void archiveDocRevision(String docid, String user) 
2381
 {
2382
    String sysdate = dbAdapter.getDateTimeFunction();
2383
    DBConnection conn = null;
2384
    int serialNumber = -1;
2385
    PreparedStatement pstmt = null;
2386
    
2387
    // create a record in xml_revisions table 
2388
    // for that document as selected from xml_documents
2389
   
2390
   try
2391
   {
2392
     //check out DBConnection
2393
     conn=DBConnectionPool.
2394
                    getDBConnection("DocumentImpl.archiveDocRevision");
2395
     serialNumber=conn.getCheckOutSerialNumber();
2396
     pstmt = conn.prepareStatement(
2397
      "INSERT INTO xml_revisions " +
2398
        "(docid, rootnodeid, docname, doctype, " +
2399
        "user_owner, user_updated, date_created, date_updated, " +
2400
        "server_location, rev, public_access, catalog_id) " +
2401
      "SELECT ?, rootnodeid, docname, doctype, " + 
2402
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
2403
        "server_location, rev, public_access, catalog_id " +
2404
      "FROM xml_documents " +
2405
      "WHERE docid = ?");
2406
      // Bind the values to the query and execute it
2407
      pstmt.setString(1, docid);
2408
      pstmt.setString(2, user);
2409
      pstmt.setString(3, docid);
2410
      pstmt.execute();
2411
      pstmt.close();
2412
   }//try
2413
   catch (SQLException e)
2414
   {
2415
     MetaCatUtil.debugMessage("Error in DocumentImpl.archiveDocRevision : "+
2416
                                e.getMessage(), 30);
2417
   }//catch
2418
   finally
2419
   {
2420
     try
2421
     {
2422
       pstmt.close();
2423
     }//try
2424
     catch (SQLException ee)
2425
     {
2426
       MetaCatUtil.debugMessage("Error in DocumnetImpl.archiveDocRevision: "+
2427
                                  ee.getMessage(), 50);
2428
     }//catch
2429
     finally
2430
     {
2431
       //check in DBConnection
2432
       DBConnectionPool.returnDBConnection(conn, serialNumber);
2433
     }//finally
2434
   }//finnally
2435
                                  
2436

    
2437
  }//achiveDocRevision
2438
  
2439
  /**
2440
    * delete a entry in xml_table for given docid
2441
    * @param docId, the id of the document need to be delete
2442
    */
2443
  private static void deleteXMLDocuments(String docId) 
2444
                                         throws SQLException 
2445
  {
2446
    DBConnection conn = null;
2447
    int serialNumber = -1;
2448
    PreparedStatement pStmt = null;
2449
    try
2450
    {
2451
      //check out DBConnection
2452
      conn=DBConnectionPool.
2453
                    getDBConnection("DocumentImpl.deleteXMLDocuments");
2454
      serialNumber=conn.getCheckOutSerialNumber();
2455
      //delete a record 
2456
      pStmt = 
2457
             conn.prepareStatement("DELETE FROM xml_documents WHERE docid = '" 
2458
                                              + docId + "'");
2459
    pStmt.execute();
2460
    }//try
2461
    finally
2462
    {
2463
      try
2464
      {
2465
        pStmt.close();
2466
      }//try
2467
      catch (SQLException e)
2468
      {
2469
        MetaCatUtil.debugMessage("error in DocumentImpl.deleteXMLDocuments: "+
2470
                                  e.getMessage(), 50);
2471
      }//catch
2472
      finally
2473
      {
2474
        //return back DBconnection
2475
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2476
      }//finally
2477
    }//finally
2478
      
2479

    
2480
  }//deleteXMLDocuments
2481
  
2482
  /**
2483
    * Get last revision number from database for a docid
2484
    * If couldn't find an entry,  -1 will return
2485
    * The return value is integer because we want compare it to there new one
2486
    * @param docid <sitecode>.<uniqueid> part of Accession Number
2487
    */
2488
  public static int getLatestRevisionNumber(String docId)
2489
                                      throws SQLException
2490
  {
2491
    int rev = 1;
2492
    PreparedStatement pStmt = null;
2493
    DBConnection dbConn = null;
2494
    int serialNumber = -1;
2495
    // get rid of rev
2496
    docId = MetaCatUtil.getDocIdFromString(docId);
2497
    try
2498
    {
2499
      //check out DBConnection
2500
      dbConn=DBConnectionPool.
2501
                    getDBConnection("DocumentImpl.getLatestRevisionNumber");
2502
      serialNumber=dbConn.getCheckOutSerialNumber();
2503
     
2504
      pStmt = dbConn.prepareStatement
2505
              ("SELECT rev FROM xml_documents WHERE docid='" + docId + "'");
2506
      pStmt.execute();
2507

    
2508
      ResultSet rs = pStmt.getResultSet();
2509
      boolean hasRow = rs.next();
2510
      if (hasRow)
2511
      {
2512
        rev = rs.getInt(1);
2513
        pStmt.close();
2514
      }
2515
      else
2516
      {
2517
        rev=-1;
2518
        pStmt.close();
2519
      }
2520
    }//try
2521
    finally
2522
    {
2523
      try
2524
      {
2525
        pStmt.close();
2526
      }
2527
      catch (Exception ee)
2528
      {
2529
        MetaCatUtil.debugMessage("Error in DocumentImpl."+
2530
                        "getLatestRevisionNumber: "+ee.getMessage(), 50);
2531
      }
2532
      finally
2533
      {
2534
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2535
      }
2536
    }//finally  
2537
      
2538
    return rev;
2539
  }//getLatestRevisionNumber
2540
  
2541
  /**
2542
   * Get server location form database for a accNum
2543
   * 
2544
   * @param accum <sitecode>.<uniqueid>.<rev>
2545
   */
2546
  private static int getServerLocationNumber(String accNum)
2547
                                            throws SQLException
2548
  {
2549
    //get rid of revNum part
2550
    String docId=MetaCatUtil.getDocIdFromString(accNum);
2551
    PreparedStatement pStmt = null;
2552
    int serverLocation = 1;
2553
    DBConnection conn = null;
2554
    int serialNumber = -1;
2555
    
2556
    try
2557
    {
2558
      //check out DBConnection
2559
      conn=DBConnectionPool.
2560
                    getDBConnection("DocumentImpl.getServerLocationNumber");
2561
      serialNumber=conn.getCheckOutSerialNumber();
2562
     
2563
      pStmt = conn.prepareStatement
2564
      ("SELECT server_location FROM xml_documents WHERE docid='" + docId + "'");
2565
      pStmt.execute();
2566

    
2567
      ResultSet rs = pStmt.getResultSet();
2568
      boolean hasRow = rs.next();
2569
      //if there is entry in xml_documents, get the serverlocation
2570
      if (hasRow)
2571
      {
2572
        serverLocation = rs.getInt(1);
2573
        pStmt.close();
2574
      }
2575
      else
2576
      {
2577
        //if htere is no entry in xml_documents, we consider it is new document
2578
        //the server location is local host and value is 1
2579
        serverLocation=1;
2580
        pStmt.close();
2581
      }
2582
    }//try
2583
    finally
2584
    {
2585
      try
2586
      {
2587
        pStmt.close();
2588
      }//try
2589
      catch (Exception ee)
2590
      {
2591
        MetaCatUtil.debugMessage("Error in DocumentImpl.getServerLocationNu(): "
2592
                                    +ee.getMessage(), 50);
2593
      }//catch
2594
      finally
2595
      {
2596
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2597
      }//finally
2598
    }//finally
2599
      
2600
    return serverLocation;
2601
  }
2602
  
2603
  /**
2604
   * Given a server name, return its servercode in xml_replication table.
2605
   * If no server is found, -1 will return
2606
   * @param serverName, 
2607
   */
2608
  private static int getServerCode(String serverName) 
2609
  {
2610
    PreparedStatement pStmt=null;
2611
    int serverLocation=-2;
2612
    DBConnection dbConn = null;
2613
    int serialNumber = -1;
2614
    //MetaCatUtil util = new MetaCatUtil();
2615
    
2616
    
2617
    //we should consider about local host too
2618
    if (serverName.equals(MetaCatUtil.getLocalReplicationServerName()))
2619
    { 
2620
      serverLocation=1;
2621
      return serverLocation;
2622
    }
2623
    
2624
   
2625
    try
2626
    {
2627
      //check xml_replication table
2628
      //dbConn=util.openDBConnection();
2629
      //check out DBConnection
2630
      dbConn=DBConnectionPool.getDBConnection("DocumentImpl.getServerCode");
2631
      serialNumber=dbConn.getCheckOutSerialNumber();
2632
      pStmt = dbConn.prepareStatement
2633
      ("SELECT serverid FROM xml_replication WHERE server='" + serverName +"'");
2634
      pStmt.execute();
2635

    
2636
      ResultSet rs = pStmt.getResultSet();
2637
      boolean hasRow = rs.next();
2638
      //if there is entry in xml_replication, get the serverid
2639
      if (hasRow)
2640
      {
2641
        serverLocation = rs.getInt(1);
2642
        pStmt.close();
2643
      }
2644
      else
2645
      {
2646
        // if htere is no entry in xml_replication, -1 will return
2647
        serverLocation=-1;
2648
        pStmt.close();
2649
      }
2650
    }
2651
    catch (Exception e)
2652
    {
2653
      MetaCatUtil.debugMessage("Error in DocumentImpl.getServerCode(): "
2654
                                    +e.getMessage(), 30);
2655
    }
2656
    finally
2657
    {
2658
      try
2659
      {
2660
        pStmt.close();
2661
      }
2662
      catch (Exception ee)
2663
      {
2664
        MetaCatUtil.debugMessage("Error in DocumentImpl.getServerCode(): "
2665
                                    +ee.getMessage(), 50);
2666
      }
2667
      finally
2668
      {
2669
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2670
      }
2671
    }
2672
                 
2673
      
2674
    return serverLocation;
2675
  }
2676
  
2677
  /**
2678
   * Insert a server into xml_replcation table
2679
   * @param server, the name of server 
2680
   */
2681
  private static synchronized void 
2682
                                insertServerIntoReplicationTable(String server)
2683
  {
2684
    PreparedStatement pStmt=null;
2685
    DBConnection dbConn = null;
2686
    int serialNumber = -1;
2687
    
2688
    // Initial value for the server
2689
    int replicate = 0;
2690
    int dataReplicate = 0;
2691
    int hub = 0;
2692
   
2693
    try
2694
    {
2695
       // Get DBConnection
2696
       dbConn=DBConnectionPool.
2697
                getDBConnection("DocumentImpl.insertServIntoReplicationTable");
2698
       serialNumber=dbConn.getCheckOutSerialNumber();
2699
      
2700
      // Compare the server to dabase
2701
      pStmt = dbConn.prepareStatement
2702
      ("SELECT serverid FROM xml_replication WHERE server='" + server +"'");
2703
      pStmt.execute();
2704
      ResultSet rs = pStmt.getResultSet();
2705
      boolean hasRow = rs.next();
2706
      // Close preparedstatement and result set
2707
      pStmt.close();
2708
      rs.close();
2709
      
2710
      // If the server is not in the table, and server is not local host,
2711
      // insert it
2712
      if ( !hasRow 
2713
         && !server.equals(MetaCatUtil.getLocalReplicationServerName()))
2714
      {
2715
        // Set auto commit false
2716
        dbConn.setAutoCommit(false);
2717
        pStmt = dbConn.prepareStatement("INSERT INTO xml_replication " +
2718
                      "(server, last_checked, replicate, datareplicate, hub) " +
2719
                       "VALUES ('" + server + "', to_date(" +
2720
                       "'01/01/00', 'MM/DD/YY'), '" +
2721
                       replicate +"', '"+dataReplicate+"','"+ hub + "')");
2722
        pStmt.execute();
2723
        dbConn.commit();
2724
        // Increase usage number
2725
        dbConn.increaseUsageCount(1);
2726
        pStmt.close();
2727
        
2728
      }
2729
    }//try
2730
    catch (Exception e)
2731
    {
2732
      MetaCatUtil.debugMessage("Error in DocumentImpl.insertServerIntoRepli(): "
2733
                                    +e.getMessage(), 30);
2734
    }//catch
2735
    finally
2736
    {
2737
     
2738
      try
2739
      {
2740
        // Set auto commit true
2741
        dbConn.setAutoCommit(true);
2742
        pStmt.close();
2743
        
2744
      }//try
2745
      catch (Exception ee)
2746
      {
2747
        MetaCatUtil.debugMessage("Error in DocumentImpl.insetServerIntoRepl(): "
2748
                                    +ee.getMessage(), 50);
2749
      }//catch
2750
      finally
2751
      {
2752
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2753
      }
2754
    
2755
    }//finally
2756

    
2757
  }
2758
  
2759
  
2760
  /**
2761
   * the main routine used to test the DBWriter utility.
2762
   * <p>
2763
   * Usage: java DocumentImpl <-f filename -a action -d docid>
2764
   *
2765
   * @param filename the filename to be loaded into the database
2766
   * @param action the action to perform (READ, INSERT, UPDATE, DELETE)
2767
   * @param docid the id of the document to process
2768
   */
2769
  static public void main(String[] args) {
2770
    DBConnection dbconn = null;
2771
    int serialNumber = -1;
2772
    try {
2773
      String filename    = null;
2774
      String dtdfilename = null;
2775
      String action      = null;
2776
      String docid       = null;
2777
      boolean showRuntime = false;
2778
      boolean useOldReadAlgorithm = false;
2779

    
2780
      // Parse the command line arguments
2781
      for ( int i=0 ; i < args.length; ++i ) {
2782
        if ( args[i].equals( "-f" ) ) {
2783
          filename =  args[++i];
2784
        } else if ( args[i].equals( "-r" ) ) {
2785
          dtdfilename =  args[++i];
2786
        } else if ( args[i].equals( "-a" ) ) {
2787
          action =  args[++i];
2788
        } else if ( args[i].equals( "-d" ) ) {
2789
          docid =  args[++i];
2790
        } else if ( args[i].equals( "-t" ) ) {
2791
          showRuntime = true;
2792
        } else if ( args[i].equals( "-old" ) ) {
2793
          useOldReadAlgorithm = true;
2794
        } else {
2795
          System.err.println
2796
            ( "   args[" +i+ "] '" +args[i]+ "' ignored." );
2797
        }
2798
      }
2799
      
2800
      // Check if the required arguments are provided
2801
      boolean argsAreValid = false;
2802
      if (action != null) {
2803
        if (action.equals("INSERT")) {
2804
          if (filename != null) {
2805
            argsAreValid = true;
2806
          } 
2807
        } else if (action.equals("UPDATE")) {
2808
          if ((filename != null) && (docid != null)) {
2809
            argsAreValid = true;
2810
          } 
2811
        } else if (action.equals("DELETE")) {
2812
          if (docid != null) {
2813
            argsAreValid = true;
2814
          } 
2815
        } else if (action.equals("READ")) {
2816
          if (docid != null) {
2817
            argsAreValid = true;
2818
          } 
2819
        } 
2820
      } 
2821

    
2822
      // Print usage message if the arguments are not valid
2823
      if (!argsAreValid) {
2824
        System.err.println("Wrong number of arguments!!!");
2825
        System.err.println(
2826
          "USAGE: java DocumentImpl [-t] <-a INSERT> [-d docid] <-f filename> "+
2827
          "[-r dtdfilename]");
2828
        System.err.println(
2829
          "   OR: java DocumentImpl [-t] <-a UPDATE -d docid -f filename> " +
2830
          "[-r dtdfilename]");
2831
        System.err.println(
2832
          "   OR: java DocumentImpl [-t] <-a DELETE -d docid>");
2833
        System.err.println(
2834
          "   OR: java DocumentImpl [-t] [-old] <-a READ -d docid>");
2835
        return;
2836
      }
2837
      
2838
      // Time the request if asked for
2839
      double startTime = System.currentTimeMillis();
2840
      
2841
      // Open a connection to the database
2842
      MetaCatUtil util = new MetaCatUtil();
2843
     
2844
      dbconn=DBConnectionPool.getDBConnection("DocumentImpl.main");
2845
      serialNumber=dbconn.getCheckOutSerialNumber();
2846

    
2847
      double connTime = System.currentTimeMillis();
2848
      // Execute the action requested (READ, INSERT, UPDATE, DELETE)
2849
      if (action.equals("READ")) {
2850
          DocumentImpl xmldoc = new DocumentImpl(docid );
2851
          if (useOldReadAlgorithm) {
2852
            System.out.println(xmldoc.readUsingSlowAlgorithm());
2853
          } else {
2854
            xmldoc.toXml(new PrintWriter(System.out), null, null, true);
2855
          }
2856
      } else if (action.equals("DELETE")) {
2857
        DocumentImpl.delete(docid, null, null);
2858
        System.out.println("Document deleted: " + docid);
2859
      } else {
2860
        /*String newdocid = DocumentImpl.write(dbconn, filename, null,
2861
                                             dtdfilename, action, docid,
2862
                                             null, null);
2863
        if ((docid != null) && (!docid.equals(newdocid))) {
2864
          if (action.equals("INSERT")) {
2865
            System.out.println("New document ID generated!!! ");
2866
          } else if (action.equals("UPDATE")) {
2867
            System.out.println("ERROR: Couldn't update document!!! ");
2868
          }
2869
        } else if ((docid == null) && (action.equals("UPDATE"))) {
2870
          System.out.println("ERROR: Couldn't update document!!! ");
2871
        }
2872
        System.out.println("Document processing finished for: " + filename
2873
              + " (" + newdocid + ")");*/
2874
      }
2875

    
2876
      double stopTime = System.currentTimeMillis();
2877
      double dbOpenTime = (connTime - startTime)/1000;
2878
      double insertTime = (stopTime - connTime)/1000;
2879
      double executionTime = (stopTime - startTime)/1000;
2880
      if (showRuntime) {
2881
        System.out.println("\n\nTotal Execution time was: " + 
2882
                           executionTime + " seconds.");
2883
        System.out.println("Time to open DB connection was: " + dbOpenTime + 
2884
                           " seconds.");
2885
        System.out.println("Time to insert document was: " + insertTime +
2886
                           " seconds.");
2887
      }
2888
      dbconn.close();
2889
    } catch (McdbException me) {
2890
      me.toXml(new PrintWriter(System.err));
2891
    } catch (AccessionNumberException ane) {
2892
      System.out.println(ane.getMessage());
2893
    } catch (Exception e) {
2894
      System.err.println("EXCEPTION HANDLING REQUIRED");
2895
      System.err.println(e.getMessage());
2896
      e.printStackTrace(System.err);
2897
    }
2898
    finally
2899
    {
2900
      // Return db connection
2901
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
2902
    }
2903
  }
2904
}
(31-31/57)