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 17:24:56 -0700 (Sat, 26 Apr 2003) $'
11
 * '$Revision: 1621 $'
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
      MetaCatUtil.debugMessage("Start deleting doc "+docid+ "...", 20);
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
    catch (Exception e)
2101
    {
2102
      MetaCatUtil.debugMessage("error in DocumentImpl.delete: " + 
2103
                                e.getMessage(), 30);
2104
      throw e;
2105
    }
2106
    finally
2107
    {
2108
      
2109
      try
2110
      {
2111
        // close preparedStatement
2112
        pstmt.close();
2113
      }//try
2114
      finally
2115
      {
2116
        //check in DBonnection
2117
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2118
      }//finally
2119
    }//finally
2120
    //IF this is a package document:
2121
    //delete all of the relations that this document created.
2122
    //if the deleted document is a package document its relations should 
2123
    //no longer be active if it has been deleted from the system.
2124
    
2125
  }
2126

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

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

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

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

    
2294
      // Get an instance of the parser
2295
      String parserName = MetaCatUtil.getOption("saxparser");
2296
      parser = XMLReaderFactory.createXMLReader(parserName);
2297

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

    
2316
    } catch (Exception e) {
2317
      throw e;
2318
    }
2319
    //finally
2320
    //{
2321
      //DBConnectionPool.returnDBConnection(conn, serialNumber);
2322
    //}
2323

    
2324
    return parser;
2325
  }*/
2326

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

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

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

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

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

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

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

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

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

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

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

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