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-18 20:29:56 -0700 (Fri, 18 Apr 2003) $'
11
 * '$Revision: 1582 $'
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 relational db and access db       
1679
        RunRelationHandlerAndAccessHandler(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 write into relational db and access db       
1741
    RunRelationHandlerAndAccessHandler(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 relational db and access db       
1859
    RunRelationHandlerAndAccessHandler(accnum, user, groups, serverCode);
1860
    //Force replication to other server
1861
    ForceReplicationHandler forceReplication = new ForceReplicationHandler
1862
                                  (accnum, action, true, notifyServer);
1863
    
1864

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

    
2028
      // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
2029
      AccessionNumber ac = new AccessionNumber(accnum, "DELETE");
2030
      String docid = ac.getDocid();
2031
      String rev = ac.getRev();
2032
    
2033

    
2034
    // check for 'write' permission for 'user' to delete this document
2035
      if ( !hasWritePermission(user, groups, docid) ) {
2036
        throw new Exception("User " + user + 
2037
              " does not have permission to delete XML Document #" + accnum);
2038
      }
2039

    
2040
      conn.setAutoCommit(false);
2041
      // Copy the record to the xml_revisions table
2042
      DocumentImpl.archiveDocRevision(conn, docid, user );
2043

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

    
2101
  /** 
2102
    * Check for "WRITE" permission on @docid for @user and/or @groups 
2103
    * from DB connection 
2104
    */
2105
  private static boolean hasWritePermission (String user,
2106
                                  String[] groups, String docid ) 
2107
                  throws SQLException, Exception
2108
  {
2109
    // Check for WRITE permission on @docid for @user and/or @groups
2110
    PermissionController controller = new PermissionController(docid);
2111
    return controller.hasPermission(user,groups,
2112
                                    AccessControlInterface.WRITESTRING);
2113
  }
2114

    
2115
  /** 
2116
    * Check for "READ" permission base on docid, user and group
2117
    *@docid, the document
2118
    *@user, user name
2119
    *@group, user's group
2120
    * 
2121
    */
2122
  public static boolean hasReadPermission (String user,
2123
                                  String[] groups, String docId ) 
2124
                  throws SQLException, Exception
2125
  {
2126
    // Check for READ permission on @docid for @user and/or @groups
2127
    PermissionController controller = 
2128
                        new PermissionController(docId);
2129
    return controller.hasPermission(user,groups,
2130
                                            AccessControlInterface.READSTRING);
2131
  }  
2132

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

    
2242
  
2243
  /**
2244
   * Set up the parser handlers for writing the document to the database
2245
   */
2246
  /*private static XMLReader initializeParser(DBConnection dbconn, String action,
2247
                               String docid, String rev, boolean validate, 
2248
                                   String user, String[] groups, String pub, 
2249
                                   int serverCode, Reader dtd) 
2250
                           throws Exception 
2251
  {
2252
    XMLReader parser = null;
2253
    //DBConnection conn = null;
2254
    //int serialNumber = -1;
2255
    //
2256
    // Set up the SAX document handlers for parsing
2257
    //
2258
    try {
2259
       //check out DBConnection
2260
     
2261
      //create a DBSAXHandler object which has the revision specification
2262
      ContentHandler chandler = new DBSAXHandler(dbconn, action, 
2263
                                    docid, rev, user, groups, pub, serverCode);
2264
      EntityResolver eresolver= new DBEntityResolver(dbconn,
2265
                                                 (DBSAXHandler)chandler, dtd);
2266
      DTDHandler dtdhandler   = new DBDTDHandler(dbconn);
2267

    
2268
      // Get an instance of the parser
2269
      String parserName = MetaCatUtil.getOption("saxparser");
2270
      parser = XMLReaderFactory.createXMLReader(parserName);
2271

    
2272
      // Turn on validation
2273
      parser.setFeature("http://xml.org/sax/features/validation", validate);
2274
      // Turn off Including all external parameter entities
2275
      // (the external DTD subset also)
2276
      // Doesn't work well, probably the feature name is not correct
2277
      // parser.setFeature(
2278
      //  "http://xml.org/sax/features/external-parameter-entities", false);
2279
      
2280
      // Set Handlers in the parser
2281
      parser.setProperty("http://xml.org/sax/properties/declaration-handler",
2282
                         chandler);
2283
      parser.setProperty("http://xml.org/sax/properties/lexical-handler",
2284
                         chandler);
2285
      parser.setContentHandler((ContentHandler)chandler);
2286
      parser.setEntityResolver((EntityResolver)eresolver);
2287
      parser.setDTDHandler((DTDHandler)dtdhandler);
2288
      parser.setErrorHandler((ErrorHandler)chandler);
2289

    
2290
    } catch (Exception e) {
2291
      throw e;
2292
    }
2293
    //finally
2294
    //{
2295
      //DBConnectionPool.returnDBConnection(conn, serialNumber);
2296
    //}
2297

    
2298
    return parser;
2299
  }*/
2300

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

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

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

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

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

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

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

    
2746
  }
2747
  
2748
  
2749
  /**
2750
   * the main routine used to test the DBWriter utility.
2751
   * <p>
2752
   * Usage: java DocumentImpl <-f filename -a action -d docid>
2753
   *
2754
   * @param filename the filename to be loaded into the database
2755
   * @param action the action to perform (READ, INSERT, UPDATE, DELETE)
2756
   * @param docid the id of the document to process
2757
   */
2758
  static public void main(String[] args) {
2759
    DBConnection dbconn = null;
2760
    int serialNumber = -1;
2761
    try {
2762
      String filename    = null;
2763
      String dtdfilename = null;
2764
      String action      = null;
2765
      String docid       = null;
2766
      boolean showRuntime = false;
2767
      boolean useOldReadAlgorithm = false;
2768

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

    
2811
      // Print usage message if the arguments are not valid
2812
      if (!argsAreValid) {
2813
        System.err.println("Wrong number of arguments!!!");
2814
        System.err.println(
2815
          "USAGE: java DocumentImpl [-t] <-a INSERT> [-d docid] <-f filename> "+
2816
          "[-r dtdfilename]");
2817
        System.err.println(
2818
          "   OR: java DocumentImpl [-t] <-a UPDATE -d docid -f filename> " +
2819
          "[-r dtdfilename]");
2820
        System.err.println(
2821
          "   OR: java DocumentImpl [-t] <-a DELETE -d docid>");
2822
        System.err.println(
2823
          "   OR: java DocumentImpl [-t] [-old] <-a READ -d docid>");
2824
        return;
2825
      }
2826
      
2827
      // Time the request if asked for
2828
      double startTime = System.currentTimeMillis();
2829
      
2830
      // Open a connection to the database
2831
      MetaCatUtil util = new MetaCatUtil();
2832
     
2833
      dbconn=DBConnectionPool.getDBConnection("DocumentImpl.main");
2834
      serialNumber=dbconn.getCheckOutSerialNumber();
2835

    
2836
      double connTime = System.currentTimeMillis();
2837
      // Execute the action requested (READ, INSERT, UPDATE, DELETE)
2838
      if (action.equals("READ")) {
2839
          DocumentImpl xmldoc = new DocumentImpl(docid );
2840
          if (useOldReadAlgorithm) {
2841
            System.out.println(xmldoc.readUsingSlowAlgorithm());
2842
          } else {
2843
            xmldoc.toXml(new PrintWriter(System.out), null, null, true);
2844
          }
2845
      } else if (action.equals("DELETE")) {
2846
        DocumentImpl.delete(docid, null, null);
2847
        System.out.println("Document deleted: " + docid);
2848
      } else {
2849
        /*String newdocid = DocumentImpl.write(dbconn, filename, null,
2850
                                             dtdfilename, action, docid,
2851
                                             null, null);
2852
        if ((docid != null) && (!docid.equals(newdocid))) {
2853
          if (action.equals("INSERT")) {
2854
            System.out.println("New document ID generated!!! ");
2855
          } else if (action.equals("UPDATE")) {
2856
            System.out.println("ERROR: Couldn't update document!!! ");
2857
          }
2858
        } else if ((docid == null) && (action.equals("UPDATE"))) {
2859
          System.out.println("ERROR: Couldn't update document!!! ");
2860
        }
2861
        System.out.println("Document processing finished for: " + filename
2862
              + " (" + newdocid + ")");*/
2863
      }
2864

    
2865
      double stopTime = System.currentTimeMillis();
2866
      double dbOpenTime = (connTime - startTime)/1000;
2867
      double insertTime = (stopTime - connTime)/1000;
2868
      double executionTime = (stopTime - startTime)/1000;
2869
      if (showRuntime) {
2870
        System.out.println("\n\nTotal Execution time was: " + 
2871
                           executionTime + " seconds.");
2872
        System.out.println("Time to open DB connection was: " + dbOpenTime + 
2873
                           " seconds.");
2874
        System.out.println("Time to insert document was: " + insertTime +
2875
                           " seconds.");
2876
      }
2877
      dbconn.close();
2878
    } catch (McdbException me) {
2879
      me.toXml(new PrintWriter(System.err));
2880
    } catch (AccessionNumberException ane) {
2881
      System.out.println(ane.getMessage());
2882
    } catch (Exception e) {
2883
      System.err.println("EXCEPTION HANDLING REQUIRED");
2884
      System.err.println(e.getMessage());
2885
      e.printStackTrace(System.err);
2886
    }
2887
    finally
2888
    {
2889
      // Return db connection
2890
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
2891
    }
2892
  }
2893
}
(31-31/57)