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-07-23 12:04:13 -0700 (Wed, 23 Jul 2003) $'
11
 * '$Revision: 1751 $'
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
      String sqlDateString=dbAdapter.toDate(dateString, "YY-MM-DD HH24:MI:SS");
317
  
318
      StringBuffer sql = new StringBuffer();
319
      sql.append("insert into xml_documents (docid, docname, doctype, ");
320
      sql.append("user_owner, user_updated, server_location, rev,date_created");
321
      sql.append(", date_updated, public_access) values ('");
322
      sql.append(docid).append("','");
323
      sql.append(docname).append("','");
324
      sql.append(doctype).append("','");
325
      sql.append(user).append("','");
326
      sql.append(user).append("','");
327
      sql.append(serverCode).append("','");
328
      sql.append(rev).append("',");
329
      sql.append(sqlDateString).append(",");
330
      sql.append(sqlDateString).append(",");
331
      sql.append("'0')");
332
      pstmt = dbconn.prepareStatement(sql.toString());
333
      MetaCatUtil.debugMessage("2, new sql for todate:================== "+
334
                               sql.toString(), 1);
335
      pstmt.execute();
336
      pstmt.close();
337
      //dbconn.close();
338
    } 
339
    finally 
340
    {
341
      try
342
      {
343
        pstmt.close();
344
      }
345
      finally
346
      {
347
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
348
      }
349
    }    
350
  }
351
  
352
    /**
353
   * Register a document that resides on the filesystem with the database.
354
   * (ie, just an entry in xml_documents, nothing in xml_nodes).
355
   * Creates a reference to a filesystem document (used for non-xml data files)
356
   * This method will be called for register data file in xml_documents in 
357
   * Replication.
358
   * This method is revised from registerDocument.
359
   *
360
   * @param conn the JDBC Connection to which all information is written
361
   * @param docname - the name of DTD, i.e. the name immediately following 
362
   *        the DOCTYPE keyword ( should be the root element name ) or
363
   *        the root element name if no DOCTYPE declaration provided
364
   *        (Oracle's and IBM parsers are not aware if it is not the 
365
   *        root element name)
366
   * @param doctype - Public ID of the DTD, i.e. the name immediately 
367
   *                  following the PUBLIC keyword in DOCTYPE declaration or
368
   *                  the docname if no Public ID provided or
369
   *                  null if no DOCTYPE declaration provided
370
   * @param accnum the accession number to use for the INSERT OR UPDATE, which 
371
   *               includes a revision number for this revision of the document 
372
   *               (e.g., knb.1.1)
373
   * @param user the user that owns the document
374
   * @param serverCode the serverid from xml_replication on which this document
375
   *        resides.
376
   */
377
  public static void registerDocumentInReplication(
378
                     String docname, String doctype, String accnum, 
379
                     String user, int serverCode)
380
                     throws SQLException, AccessionNumberException, Exception
381
  {
382
    DBConnection dbconn = null;
383
    int serialNumber = -1;
384
    //MetaCatUtil util = new MetaCatUtil();
385
    AccessionNumber ac;
386
    PreparedStatement pstmt = null;
387
    try {
388
      //dbconn = util.openDBConnection();
389
       dbconn=DBConnectionPool.
390
                  getDBConnection("DocumentImpl.registerDocumentInReplication");
391
      serialNumber=dbconn.getCheckOutSerialNumber();
392
      String docIdWithoutRev=MetaCatUtil.getDocIdFromString(accnum);
393
      int userSpecifyRev=MetaCatUtil.getVersionFromString(accnum);
394
      int revInDataBase=getLatestRevisionNumber(docIdWithoutRev);
395
      //revIndataBase=-1, there is no record in xml_documents table
396
      //the data file is a new one, inert it into table
397
      //user specified rev should be great than 0
398
      if (revInDataBase==-1 && userSpecifyRev>0 )
399
      {
400
       
401
        ac = new AccessionNumber(accnum, "insert");
402
      }
403
      //rev is greater the last revsion number and revInDataBase isn't -1
404
      // it is a updated data file
405
      else if (userSpecifyRev>revInDataBase && revInDataBase>0)
406
      {
407
        
408
        //archive the old entry 
409
        archiveDocRevision(docIdWithoutRev, user);
410
        //delete the old entry in xml_documents
411
        deleteXMLDocuments(docIdWithoutRev);
412
        ac = new AccessionNumber(accnum, "update");
413
      }
414
      // local server has newer version, then notify the remote server
415
      else if ( userSpecifyRev < revInDataBase && revInDataBase > 0)
416
      {
417
        throw new Exception("Local server: "+MetaCatUtil.getOption("server")+
418
                 " has newer revision of doc: "+docIdWithoutRev+"."
419
                  +revInDataBase+". Please notify it.");
420
      }
421
      //other situation
422
      else
423
      {
424
        
425
        throw new Exception("Revision number couldn't be "
426
                    +userSpecifyRev);
427
      }
428
      String docid = ac.getDocid();
429
      String rev = ac.getRev();
430
      SimpleDateFormat formatter = new SimpleDateFormat ("yy-MM-dd HH:mm:ss");
431
      Date localtime = new Date();
432
      String dateString = formatter.format(localtime);
433
  
434
      /*String sqlDateString = "to_date('" + dateString + 
435
                                          "', 'YY-MM-DD HH24:MI:SS')";*/
436
      String sqlDateString=dbAdapter.toDate(dateString, "YY-MM-DD HH24:MI:SS");
437
      StringBuffer sql = new StringBuffer();
438
      sql.append("insert into xml_documents (docid, docname, doctype, ");
439
      sql.append("user_owner, user_updated, server_location, rev,date_created");
440
      sql.append(", date_updated, public_access) values ('");
441
      sql.append(docid).append("','");
442
      sql.append(docname).append("','");
443
      sql.append(doctype).append("','");
444
      sql.append(user).append("','");
445
      sql.append(user).append("','");
446
      sql.append(serverCode).append("','");
447
      sql.append(rev).append("',");
448
      sql.append(sqlDateString).append(",");
449
      sql.append(sqlDateString).append(",");
450
      sql.append("'0')");
451
      // Set auto commit fasle
452
      dbconn.setAutoCommit(false);
453
      pstmt = dbconn.prepareStatement(sql.toString());
454
      MetaCatUtil.debugMessage("3, new sql for todate:================== "+
455
                               sql.toString(), 1);
456
      pstmt.execute();
457
      // Commit the insert
458
      dbconn.commit();
459
      pstmt.close();
460
      //dbconn.close();
461
    } 
462
    finally 
463
    {
464
      // Set DBConnection auto commit true
465
      dbconn.setAutoCommit(true);
466
      pstmt.close();
467
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
468
    }    
469
  }
470
  
471
 /**
472
   * This method will register a data file entry in xml_documents and save a
473
   * data file input Stream into file system.. It is only used in replication
474
   *
475
   * @param  input, the input stream which contain the file content.
476
   * @param  , the input stream which contain the file content
477
   * @param docname - the name of DTD, for data file, it is a docid number.
478
   * @param doctype - "BIN" for data file
479
   * @param accnum the accession number to use for the INSERT OR UPDATE, which 
480
   *               includes a revision number for this revision of the document 
481
   *               (e.g., knb.1.1)
482
   * @param user the user that owns the document
483
   * @param docHomeServer, the home server of the docid
484
   * @param notificationServer, the server to notify force replication info to 
485
   *                            local metacat
486
   */
487
 public static void writeDataFileInReplication(InputStream input, 
488
                 String filePath, String docname, String doctype, String accnum, 
489
                   String user, String docHomeServer, String notificationServer)
490
                     throws SQLException, AccessionNumberException, Exception
491
 {
492
    int serverCode=-2;
493
   
494
    
495
    if (filePath==null||filePath.equals(""))
496
    {
497
      throw new 
498
            Exception("Please specify the directory where file will be store");
499
    }
500
    if (accnum==null||accnum.equals(""))
501
    {
502
      throw new Exception("Please specify the stored file name");
503
    }
504
    
505
   
506
    
507
    // If server is not int the xml replication talbe, insert it into 
508
    // xml_replication table
509
    //serverList.addToServerListIfItIsNot(docHomeServer);
510
    insertServerIntoReplicationTable(docHomeServer);
511
    
512
    // Get server code again
513
    serverCode = getServerCode(docHomeServer);
514
    
515
    
516
    //register data file into xml_documents table
517
    registerDocumentInReplication(docname, doctype, accnum, user, serverCode);
518
    //write inputstream into file system.
519
    File dataDirectory = new File(filePath);
520
    File newFile = new File(dataDirectory, accnum); 
521
       
522
    // create a buffered byte output stream
523
    // that uses a default-sized output buffer
524
    FileOutputStream fos = new FileOutputStream(newFile);
525
    BufferedOutputStream outPut = new BufferedOutputStream(fos);
526

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

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

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

    
652
  /**
653
   * get the document type (which is the PublicID)
654
   */
655
  public String getDoctype() {
656
    return doctype;
657
  }
658

    
659
  /**
660
   * get the system identifier
661
   */
662
  public String getSystemID() {
663
    return system_id;
664
  }
665

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

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

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

    
786
    // First, check that we have the needed node data, and get it if not
787
    if (nodeRecordList == null) {
788
      nodeRecordList = getNodeRecordList(rootnodeid);
789
    }
790

    
791
    // Create the elements from the downloaded data in the TreeSet
792
    rootNode = new ElementNode(nodeRecordList, rootnodeid);
793

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

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

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

    
853
    Stack openElements = new Stack();
854
    boolean atRootElement = true;
855
    boolean previousNodeWasElement = false;
856

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

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

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

    
948
      // Handle the ATTRIBUTE nodes
949
      } else if (currentNode.nodetype.equals("ATTRIBUTE")) {
950
        if ( currentNode.nodeprefix != null ) {
951
          out.print(" " + currentNode.nodeprefix + ":" + currentNode.nodename +
952
                    "=\"" + currentNode.nodedata + "\"");
953
        } else {
954
          out.print(" " + currentNode.nodename + "=\"" +
955
                    currentNode.nodedata + "\"");
956
        }
957

    
958
      // Handle the NAMESPACE nodes
959
      } else if (currentNode.nodetype.equals("NAMESPACE")) {
960
        out.print(" xmlns:" + currentNode.nodename + "=\""
961
                 + currentNode.nodedata + "\"");
962

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

    
988
      // Handle the COMMENT nodes
989
      } else if (currentNode.nodetype.equals("COMMENT")) {
990
        if (previousNodeWasElement) {
991
          out.print(">");
992
        }
993
        out.print("<!--" + currentNode.nodedata + "-->");
994
        previousNodeWasElement = false;
995

    
996
      // Handle the PI nodes
997
      } else if (currentNode.nodetype.equals("PI")) {
998
        if (previousNodeWasElement) {
999
          out.print(">");
1000
        }
1001
        out.print("<?" + currentNode.nodename + " " +
1002
                        currentNode.nodedata + "?>");
1003
        previousNodeWasElement = false;
1004

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

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

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

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

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

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

    
1283
    try 
1284
    {
1285
      dbconn=DBConnectionPool.
1286
                    getDBConnection("DocumentImpl.getPartNodeRecordList");
1287
      serialNumber=dbconn.getCheckOutSerialNumber();
1288
      pstmt = dbconn.prepareStatement(sql);
1289

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

    
1310
        // Advance to the next node
1311
        tableHasRows = rs.next();
1312
      } 
1313
      pstmt.close();
1314

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

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

    
1371
    try {
1372
      dbconn=DBConnectionPool.
1373
                    getDBConnection("DocumentImpl.getNodeRecordList");
1374
      serialNumber=dbconn.getCheckOutSerialNumber();
1375
      pstmt =
1376
      dbconn.prepareStatement("SELECT nodeid,parentnodeid,nodeindex, " +
1377
           "nodetype,nodename,nodeprefix,nodedata " +               
1378
           "FROM xml_nodes WHERE rootnodeid = ?");
1379

    
1380
      // Bind the values to the query
1381
      pstmt.setLong(1, rootnodeid);
1382

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

    
1400
        // Advance to the next node
1401
        tableHasRows = rs.next();
1402
      } 
1403
      pstmt.close();
1404

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

    
1439
 /** creates SQL code and inserts new document into DB connection */
1440
  private void writeDocumentToDB(String action, String user, String pub, 
1441
                                 String catalogid, int serverCode) 
1442
               throws SQLException, Exception {
1443
    String sysdate = dbAdapter.getDateTimeFunction();
1444

    
1445
    try {
1446
      PreparedStatement pstmt = null;
1447

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

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

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

    
1542
      } else {
1543
        System.err.println("Action not supported: " + action);
1544
      }
1545

    
1546
      // Do the insertion
1547
      pstmt.execute();
1548
      
1549
      pstmt.close();
1550

    
1551
    } catch (SQLException sqle) {
1552
      throw sqle;
1553
    } catch (Exception e) {
1554
      throw e;
1555
    }
1556
  }
1557

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

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

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

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

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

    
1720
      if ( !hasWritePermission(user, groups, docid) ) {
1721
        throw new Exception("User " + user + 
1722
              " does not have permission to update XML Document #" + accnum);
1723
      }          
1724
    }
1725

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

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

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

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

    
2044
      // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
2045
      AccessionNumber ac = new AccessionNumber(accnum, "DELETE");
2046
      String docid = ac.getDocid();
2047
      String rev = ac.getRev();
2048
    
2049
      MetaCatUtil.debugMessage("Start deleting doc "+docid+ "...", 20);
2050
    // check for 'write' permission for 'user' to delete this document
2051
      if ( !hasWritePermission(user, groups, docid) ) {
2052
        throw new Exception("User " + user + 
2053
              " does not have permission to delete XML Document #" + accnum);
2054
      }
2055

    
2056
      conn.setAutoCommit(false);
2057
      // Copy the record to the xml_revisions table
2058
      DocumentImpl.archiveDocRevision(conn, docid, user );
2059

    
2060
      // Now delete it from the xml_index table
2061
      pstmt = conn.prepareStatement("DELETE FROM xml_index WHERE docid = ?");
2062
      pstmt.setString(1,docid);
2063
      pstmt.execute();
2064
      pstmt.close();
2065
      conn.increaseUsageCount(1);
2066
      
2067
      //stmt.execute("DELETE FROM xml_access WHERE docid = '" + docid + "'");
2068
      // Now delete it from xml_access table
2069
      pstmt = conn.
2070
              prepareStatement("DELETE FROM xml_access WHERE accessfileid = ?");
2071
      pstmt.setString(1, docid);
2072
      pstmt.execute();
2073
      pstmt.close();
2074
      conn.increaseUsageCount(1);
2075
      
2076
      // Delete it from relation table
2077
      pstmt = conn.
2078
               prepareStatement("DELETE FROM xml_relation WHERE docid = ?");
2079
      //increase usage count
2080
      conn.increaseUsageCount(1);
2081
      pstmt.setString(1, docid);
2082
      pstmt.execute();
2083
      pstmt.close();
2084
      
2085
      // Delete it from xml_accesssubtree table
2086
      pstmt = conn.
2087
               prepareStatement("DELETE FROM xml_accesssubtree WHERE docid = ?");
2088
      //increase usage count
2089
      conn.increaseUsageCount(1);
2090
      pstmt.setString(1, docid);
2091
      pstmt.execute();
2092
      pstmt.close();
2093
      
2094
      // Delete it from xml_doucments table
2095
      pstmt =conn.prepareStatement("DELETE FROM xml_documents WHERE docid = ?");
2096
      pstmt.setString(1, docid);
2097
      pstmt.execute();
2098
      pstmt.close();
2099
      //Usaga count increase 1
2100
      conn.increaseUsageCount(1);
2101
      
2102
      conn.commit();
2103
      conn.setAutoCommit(true);
2104
    }//try
2105
    catch (Exception e)
2106
    {
2107
      MetaCatUtil.debugMessage("error in DocumentImpl.delete: " + 
2108
                                e.getMessage(), 30);
2109
      throw e;
2110
    }
2111
    finally
2112
    {
2113
      
2114
      try
2115
      {
2116
        // close preparedStatement
2117
        pstmt.close();
2118
      }//try
2119
      finally
2120
      {
2121
        //check in DBonnection
2122
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2123
      }//finally
2124
    }//finally
2125
    //IF this is a package document:
2126
    //delete all of the relations that this document created.
2127
    //if the deleted document is a package document its relations should 
2128
    //no longer be active if it has been deleted from the system.
2129
    
2130
  }
2131

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

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

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

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

    
2299
      // Get an instance of the parser
2300
      String parserName = MetaCatUtil.getOption("saxparser");
2301
      parser = XMLReaderFactory.createXMLReader(parserName);
2302

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

    
2321
    } catch (Exception e) {
2322
      throw e;
2323
    }
2324
    //finally
2325
    //{
2326
      //DBConnectionPool.returnDBConnection(conn, serialNumber);
2327
    //}
2328

    
2329
    return parser;
2330
  }*/
2331

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

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

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

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

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

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

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

    
2784
  }
2785
  
2786
  
2787
  /**
2788
   * the main routine used to test the DBWriter utility.
2789
   * <p>
2790
   * Usage: java DocumentImpl <-f filename -a action -d docid>
2791
   *
2792
   * @param filename the filename to be loaded into the database
2793
   * @param action the action to perform (READ, INSERT, UPDATE, DELETE)
2794
   * @param docid the id of the document to process
2795
   */
2796
  static public void main(String[] args) {
2797
    DBConnection dbconn = null;
2798
    int serialNumber = -1;
2799
    try {
2800
      String filename    = null;
2801
      String dtdfilename = null;
2802
      String action      = null;
2803
      String docid       = null;
2804
      boolean showRuntime = false;
2805
      boolean useOldReadAlgorithm = false;
2806

    
2807
      // Parse the command line arguments
2808
      for ( int i=0 ; i < args.length; ++i ) {
2809
        if ( args[i].equals( "-f" ) ) {
2810
          filename =  args[++i];
2811
        } else if ( args[i].equals( "-r" ) ) {
2812
          dtdfilename =  args[++i];
2813
        } else if ( args[i].equals( "-a" ) ) {
2814
          action =  args[++i];
2815
        } else if ( args[i].equals( "-d" ) ) {
2816
          docid =  args[++i];
2817
        } else if ( args[i].equals( "-t" ) ) {
2818
          showRuntime = true;
2819
        } else if ( args[i].equals( "-old" ) ) {
2820
          useOldReadAlgorithm = true;
2821
        } else {
2822
          System.err.println
2823
            ( "   args[" +i+ "] '" +args[i]+ "' ignored." );
2824
        }
2825
      }
2826
      
2827
      // Check if the required arguments are provided
2828
      boolean argsAreValid = false;
2829
      if (action != null) {
2830
        if (action.equals("INSERT")) {
2831
          if (filename != null) {
2832
            argsAreValid = true;
2833
          } 
2834
        } else if (action.equals("UPDATE")) {
2835
          if ((filename != null) && (docid != null)) {
2836
            argsAreValid = true;
2837
          } 
2838
        } else if (action.equals("DELETE")) {
2839
          if (docid != null) {
2840
            argsAreValid = true;
2841
          } 
2842
        } else if (action.equals("READ")) {
2843
          if (docid != null) {
2844
            argsAreValid = true;
2845
          } 
2846
        } 
2847
      } 
2848

    
2849
      // Print usage message if the arguments are not valid
2850
      if (!argsAreValid) {
2851
        System.err.println("Wrong number of arguments!!!");
2852
        System.err.println(
2853
          "USAGE: java DocumentImpl [-t] <-a INSERT> [-d docid] <-f filename> "+
2854
          "[-r dtdfilename]");
2855
        System.err.println(
2856
          "   OR: java DocumentImpl [-t] <-a UPDATE -d docid -f filename> " +
2857
          "[-r dtdfilename]");
2858
        System.err.println(
2859
          "   OR: java DocumentImpl [-t] <-a DELETE -d docid>");
2860
        System.err.println(
2861
          "   OR: java DocumentImpl [-t] [-old] <-a READ -d docid>");
2862
        return;
2863
      }
2864
      
2865
      // Time the request if asked for
2866
      double startTime = System.currentTimeMillis();
2867
      
2868
      // Open a connection to the database
2869
      MetaCatUtil util = new MetaCatUtil();
2870
     
2871
      dbconn=DBConnectionPool.getDBConnection("DocumentImpl.main");
2872
      serialNumber=dbconn.getCheckOutSerialNumber();
2873

    
2874
      double connTime = System.currentTimeMillis();
2875
      // Execute the action requested (READ, INSERT, UPDATE, DELETE)
2876
      if (action.equals("READ")) {
2877
          DocumentImpl xmldoc = new DocumentImpl(docid );
2878
          if (useOldReadAlgorithm) {
2879
            System.out.println(xmldoc.readUsingSlowAlgorithm());
2880
          } else {
2881
            xmldoc.toXml(new PrintWriter(System.out), null, null, true);
2882
          }
2883
      } else if (action.equals("DELETE")) {
2884
        DocumentImpl.delete(docid, null, null);
2885
        System.out.println("Document deleted: " + docid);
2886
      } else {
2887
        /*String newdocid = DocumentImpl.write(dbconn, filename, null,
2888
                                             dtdfilename, action, docid,
2889
                                             null, null);
2890
        if ((docid != null) && (!docid.equals(newdocid))) {
2891
          if (action.equals("INSERT")) {
2892
            System.out.println("New document ID generated!!! ");
2893
          } else if (action.equals("UPDATE")) {
2894
            System.out.println("ERROR: Couldn't update document!!! ");
2895
          }
2896
        } else if ((docid == null) && (action.equals("UPDATE"))) {
2897
          System.out.println("ERROR: Couldn't update document!!! ");
2898
        }
2899
        System.out.println("Document processing finished for: " + filename
2900
              + " (" + newdocid + ")");*/
2901
      }
2902

    
2903
      double stopTime = System.currentTimeMillis();
2904
      double dbOpenTime = (connTime - startTime)/1000;
2905
      double insertTime = (stopTime - connTime)/1000;
2906
      double executionTime = (stopTime - startTime)/1000;
2907
      if (showRuntime) {
2908
        System.out.println("\n\nTotal Execution time was: " + 
2909
                           executionTime + " seconds.");
2910
        System.out.println("Time to open DB connection was: " + dbOpenTime + 
2911
                           " seconds.");
2912
        System.out.println("Time to insert document was: " + insertTime +
2913
                           " seconds.");
2914
      }
2915
      dbconn.close();
2916
    } catch (McdbException me) {
2917
      me.toXml(new PrintWriter(System.err));
2918
    } catch (AccessionNumberException ane) {
2919
      System.out.println(ane.getMessage());
2920
    } catch (Exception e) {
2921
      System.err.println("EXCEPTION HANDLING REQUIRED");
2922
      System.err.println(e.getMessage());
2923
      e.printStackTrace(System.err);
2924
    }
2925
    finally
2926
    {
2927
      // Return db connection
2928
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
2929
    }
2930
  }
2931
}
(31-31/57)