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-26 15:18:25 -0700 (Sat, 26 Apr 2003) $'
11
 * '$Revision: 1618 $'
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_accesssubtree table
2081
      pstmt = conn.
2082
               prepareStatement("DELETE FROM xml_accesssubtree WHERE docid = ?");
2083
      //increase usage count
2084
      conn.increaseUsageCount(1);
2085
      pstmt.setString(1, docid);
2086
      pstmt.execute();
2087
      pstmt.close();
2088
      
2089
      // Delete it from xml_doucments table
2090
      pstmt =conn.prepareStatement("DELETE FROM xml_documents WHERE docid = ?");
2091
      pstmt.setString(1, docid);
2092
      pstmt.execute();
2093
      pstmt.close();
2094
      //Usaga count increase 1
2095
      conn.increaseUsageCount(1);
2096
      
2097
      conn.commit();
2098
      conn.setAutoCommit(true);
2099
    }//try
2100
    finally
2101
    {
2102
      
2103
      try
2104
      {
2105
        // close preparedStatement
2106
        pstmt.close();
2107
      }//try
2108
      finally
2109
      {
2110
        //check in DBonnection
2111
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2112
      }//finally
2113
    }//finally
2114
    //IF this is a package document:
2115
    //delete all of the relations that this document created.
2116
    //if the deleted document is a package document its relations should 
2117
    //no longer be active if it has been deleted from the system.
2118
    
2119
  }
2120

    
2121
  /** 
2122
    * Check for "WRITE" permission on @docid for @user and/or @groups 
2123
    * from DB connection 
2124
    */
2125
  private static boolean hasWritePermission (String user,
2126
                                  String[] groups, String docid ) 
2127
                  throws SQLException, Exception
2128
  {
2129
    // Check for WRITE permission on @docid for @user and/or @groups
2130
    PermissionController controller = new PermissionController(docid);
2131
    return controller.hasPermission(user,groups,
2132
                                    AccessControlInterface.WRITESTRING);
2133
  }
2134

    
2135
  /** 
2136
    * Check for "READ" permission base on docid, user and group
2137
    *@docid, the document
2138
    *@user, user name
2139
    *@group, user's group
2140
    * 
2141
    */
2142
  public static boolean hasReadPermission (String user,
2143
                                  String[] groups, String docId ) 
2144
                  throws SQLException, Exception
2145
  {
2146
    // Check for READ permission on @docid for @user and/or @groups
2147
    PermissionController controller = 
2148
                        new PermissionController(docId);
2149
    return controller.hasPermission(user,groups,
2150
                                            AccessControlInterface.READSTRING);
2151
  }  
2152

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

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

    
2288
      // Get an instance of the parser
2289
      String parserName = MetaCatUtil.getOption("saxparser");
2290
      parser = XMLReaderFactory.createXMLReader(parserName);
2291

    
2292
      // Turn on validation
2293
      parser.setFeature("http://xml.org/sax/features/validation", validate);
2294
      // Turn off Including all external parameter entities
2295
      // (the external DTD subset also)
2296
      // Doesn't work well, probably the feature name is not correct
2297
      // parser.setFeature(
2298
      //  "http://xml.org/sax/features/external-parameter-entities", false);
2299
      
2300
      // Set Handlers in the parser
2301
      parser.setProperty("http://xml.org/sax/properties/declaration-handler",
2302
                         chandler);
2303
      parser.setProperty("http://xml.org/sax/properties/lexical-handler",
2304
                         chandler);
2305
      parser.setContentHandler((ContentHandler)chandler);
2306
      parser.setEntityResolver((EntityResolver)eresolver);
2307
      parser.setDTDHandler((DTDHandler)dtdhandler);
2308
      parser.setErrorHandler((ErrorHandler)chandler);
2309

    
2310
    } catch (Exception e) {
2311
      throw e;
2312
    }
2313
    //finally
2314
    //{
2315
      //DBConnectionPool.returnDBConnection(conn, serialNumber);
2316
    //}
2317

    
2318
    return parser;
2319
  }*/
2320

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

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

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

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

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

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

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

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

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

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

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

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