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-02-04 15:26:24 -0800 (Tue, 04 Feb 2003) $'
11
 * '$Revision: 1383 $'
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.Iterator;
44
import java.util.Stack;
45
import java.util.TreeSet;
46
import java.util.Enumeration;
47

    
48
import org.xml.sax.AttributeList;
49
import org.xml.sax.ContentHandler;
50
import org.xml.sax.DTDHandler;
51
import org.xml.sax.EntityResolver;
52
import org.xml.sax.ErrorHandler;
53
import org.xml.sax.InputSource;
54
import org.xml.sax.XMLReader;
55
import org.xml.sax.SAXException;
56
import org.xml.sax.SAXParseException;
57
import org.xml.sax.helpers.XMLReaderFactory;
58

    
59
import java.net.URL;
60

    
61
import edu.ucsb.nceas.dbadapter.AbstractDatabase;
62

    
63
/**
64
 * A class that represents an XML document. It can be created with a simple
65
 * document identifier from a database connection.  It also will write an
66
 * XML text document to a database connection using SAX.
67
 */
68
public class DocumentImpl {
69

    
70
   /* Constents */
71
   public static final String SCHEMA                 = "schema";
72
   public static final String DTD                    = "dtd";
73
   public static final String EXTERNALSCHEMALOCATIONPROPERTY = 
74
              "http://apache.org/xml/properties/schema/external-schemaLocation";
75
   public static final String EXTERNALSCHEMALOCATION = 
76
     "eml://ecoinformatics.org/eml-2.0.0 http://dev.nceas.ucsb.edu/tao/schema/eml.xsd";
77
   public static final String DECLARATIONHANDLERPROPERTY =
78
                            "http://xml.org/sax/properties/declaration-handler";
79
   public static final String LEXICALPROPERTY =
80
                             "http://xml.org/sax/properties/lexical-handler";
81
   public static final String VALIDATIONFEATURE = 
82
                             "http://xml.org/sax/features/validation";
83
   public static final String SCHEMAVALIDATIONFEATURE = 
84
                             "http://apache.org/xml/features/validation/schema";
85
   public static final String NAMESPACEFEATURE = 
86
                              "http://xml.org/sax/features/namespaces";
87
   public static final String NAMESPACEPREFIXESFEATURE = 
88
                              "http://xml.org/sax/features/namespace-prefixes";
89
  
90
  
91
  static final int ALL = 1;
92
  static final int WRITE = 2;
93
  static final int READ = 4;
94
  private static final AbstractDatabase dbAdapter = MetaCatUtil.dbAdapter;
95

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

    
155
  /**
156
   * Constructor, creates document from database connection, used 
157
   * for reading the document
158
   *
159
   * @param conn the database connection from which to read the document
160
   * @param docid the identifier of the document to be created
161
   */
162
  public DocumentImpl(String docid) throws McdbException 
163
  {
164
    this(docid, true);
165
  }
166

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

    
549
    BufferedInputStream bis = null;
550
    bis = new BufferedInputStream(input);
551
    byte[] buf = new byte[4 * 1024]; // 4K buffer
552
    int b = bis.read(buf);
553
       
554
    while (b != -1) 
555
    {
556
        outPut.write(buf, 0, b);
557
        b = bis.read(buf);
558
    }
559
    bis.close();
560
	  outPut.close();
561
	  fos.close();
562
      
563
    // Force replicate data file
564
    ForceReplicationHandler forceReplication = new ForceReplicationHandler
565
                                    (accnum, false, notificationServer);
566
  
567
 }
568
  
569

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

    
639
      else if(openingtag.equals("<filelocked>"))
640
      {//the file is currently locked by another user
641
       //notify our user to wait a few minutes, check out a new copy and try
642
       //again.
643
        //System.out.println("file locked");
644
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
645
                                   server + " reason: file already locked");
646
        throw new Exception("The file specified is already locked by another " +
647
                            "user.  Please wait 30 seconds, checkout the " +
648
                            "newer document, merge your changes and try " +
649
                            "again.");
650
      }
651
      else if(openingtag.equals("<outdatedfile>"))
652
      {//our file is outdated.  notify our user to check out a new copy of the
653
       //file and merge his version with the new version.
654
        //System.out.println("outdated file");
655
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
656
                                    server + " reason: local file outdated");
657
        throw new Exception("The file you are trying to update is an outdated" +
658
                            " version.  Please checkout the newest document, " +
659
                            "merge your changes and try again.");
660
      }//else if
661
    }//if
662
    
663
   return flag;
664
   
665
  }//getDataFileLockGrant
666
  
667
  /**
668
   * get the document name
669
   */
670
  public String getDocname() {
671
    return docname;
672
  }
673

    
674
  /**
675
   * get the document type (which is the PublicID)
676
   */
677
  public String getDoctype() {
678
    return doctype;
679
  }
680

    
681
  /**
682
   * get the system identifier
683
   */
684
  public String getSystemID() {
685
    return system_id;
686
  }
687

    
688
  /**
689
   * get the root node identifier
690
   */
691
  public long getRootNodeID() {
692
    return rootnodeid;
693
  }
694
  
695
  /**
696
   * get the creation date
697
   */
698
  public String getCreateDate() {
699
    return createdate;
700
  }
701
  
702
  /**
703
   * get the update date
704
   */
705
  public String getUpdateDate() {
706
    return updatedate;
707
  }
708

    
709
  /** 
710
   * Get the document identifier (docid)
711
   */
712
  public String getDocID() {
713
    return docid;
714
  }
715
  
716
// DOCTITLE attr cleared from the db
717
//  /**
718
//   *get the document title
719
//   */
720
//  public String getDocTitle() {
721
//    return doctitle;
722
//  }
723
  
724
  public String getUserowner() {
725
    return userowner;
726
  }
727
  
728
  public String getUserupdated() {
729
    return userupdated;
730
  }
731
  
732
  public int getServerlocation() {
733
    return serverlocation;
734
  }
735
  
736
  public String getDocHomeServer() {
737
    return docHomeServer;
738
  }
739
  
740
 
741
 
742
  public String getPublicaccess() {
743
    return publicaccess;
744
  }
745
  
746
  public int getRev() {
747
    return rev;
748
  }
749
  
750
   /**
751
   * Print a string representation of the XML document
752
   */
753
  public String toString()
754
  {
755
    StringWriter docwriter = new StringWriter();
756
    try {
757
      this.toXml(docwriter);
758
    } catch (McdbException mcdbe) {
759
      return null;
760
    }
761
    String document = docwriter.toString();
762
    return document;
763
  }
764

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

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

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

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

    
803
  /**
804
   * Print a text representation of the XML document to a Writer
805
   *
806
   * @param pw the Writer to which we print the document
807
   */
808
  public void toXml(Writer pw) throws McdbException
809
  {
810
    PrintWriter out = null;
811
    if (pw instanceof PrintWriter) {
812
      out = (PrintWriter)pw;
813
    } else {
814
      out = new PrintWriter(pw);
815
    }
816

    
817
    MetaCatUtil util = new MetaCatUtil();
818
    
819
    // First, check that we have the needed node data, and get it if not
820
    if (nodeRecordList == null) {
821
      nodeRecordList = getNodeRecordList(rootnodeid);
822
    }
823

    
824
    Stack openElements = new Stack();
825
    boolean atRootElement = true;
826
    boolean previousNodeWasElement = false;
827

    
828
    // Step through all of the node records we were given
829
    Iterator it = nodeRecordList.iterator();
830
    while (it.hasNext()) {
831
      NodeRecord currentNode = (NodeRecord)it.next();
832
      //util.debugMessage("[Got Node ID: " + currentNode.nodeid +
833
                          //" (" + currentNode.parentnodeid +
834
                          //", " + currentNode.nodeindex + 
835
                          //", " + currentNode.nodetype + 
836
                          //", " + currentNode.nodename + 
837
                          //", " + currentNode.nodedata + ")]");
838
      // Print the end tag for the previous node if needed
839
      //
840
      // This is determined by inspecting the parent nodeid for the
841
      // currentNode.  If it is the same as the nodeid of the last element
842
      // that was pushed onto the stack, then we are still in that previous
843
      // parent element, and we do nothing.  However, if it differs, then we
844
      // have returned to a level above the previous parent, so we go into
845
      // a loop and pop off nodes and print out their end tags until we get
846
      // the node on the stack to match the currentNode parentnodeid
847
      //
848
      // So, this of course means that we rely on the list of elements
849
      // having been sorted in a depth first traversal of the nodes, which
850
      // is handled by the NodeComparator class used by the TreeSet
851
      if (!atRootElement) {
852
        NodeRecord currentElement = (NodeRecord)openElements.peek();
853
        if ( currentNode.parentnodeid != currentElement.nodeid ) {
854
          while ( currentNode.parentnodeid != currentElement.nodeid ) {
855
            currentElement = (NodeRecord)openElements.pop();
856
            util.debugMessage("\n POPPED: " + currentElement.nodename);
857
            if (previousNodeWasElement) {
858
              out.print(">");
859
              previousNodeWasElement = false;
860
            }  
861
            if ( currentElement.nodeprefix != null ) {
862
              out.print("</" + currentElement.nodeprefix + ":" + 
863
                        currentElement.nodename + ">" );
864
            } else {
865
              out.print("</" + currentElement.nodename + ">" );
866
            }
867
            currentElement = (NodeRecord)openElements.peek();
868
          }
869
        }
870
      }
871

    
872
      // Handle the DOCUMENT node
873
      if (currentNode.nodetype.equals("DOCUMENT")) {
874
        out.println("<?xml version=\"1.0\"?>");
875
      
876
        if (docname != null) {
877
          if ((doctype != null) && (system_id != null)) {
878
            out.println("<!DOCTYPE " + docname + " PUBLIC \"" + doctype + 
879
                       "\" \"" + system_id + "\">");
880
          } else {
881
            out.println("<!DOCTYPE " + docname + ">");
882
          }
883
        }
884

    
885
      // Handle the ELEMENT nodes
886
      } else if (currentNode.nodetype.equals("ELEMENT")) {
887
        if (atRootElement) {
888
          atRootElement = false;
889
        } else {
890
          if (previousNodeWasElement) {
891
            out.print(">");
892
          }
893
        }
894
        openElements.push(currentNode);
895
        util.debugMessage("\n PUSHED: " + currentNode.nodename);
896
        previousNodeWasElement = true;
897
        if ( currentNode.nodeprefix != null ) {
898
          out.print("<" + currentNode.nodeprefix + ":" + currentNode.nodename);
899
        } else {
900
          out.print("<" + currentNode.nodename);
901
        }
902

    
903
      // Handle the ATTRIBUTE nodes
904
      } else if (currentNode.nodetype.equals("ATTRIBUTE")) {
905
        if ( currentNode.nodeprefix != null ) {
906
          out.print(" " + currentNode.nodeprefix + ":" + currentNode.nodename +
907
                    "=\"" + currentNode.nodedata + "\"");
908
        } else {
909
          out.print(" " + currentNode.nodename + "=\"" +
910
                    currentNode.nodedata + "\"");
911
        }
912

    
913
      // Handle the NAMESPACE nodes
914
      } else if (currentNode.nodetype.equals("NAMESPACE")) {
915
        out.print(" xmlns:" + currentNode.nodename + "=\""
916
                 + currentNode.nodedata + "\"");
917

    
918
      // Handle the TEXT nodes
919
      } else if (currentNode.nodetype.equals("TEXT")) {
920
        if (previousNodeWasElement) {
921
          out.print(">");
922
        }
923
        out.print(currentNode.nodedata);
924
        previousNodeWasElement = false;
925

    
926
      // Handle the COMMENT nodes
927
      } else if (currentNode.nodetype.equals("COMMENT")) {
928
        if (previousNodeWasElement) {
929
          out.print(">");
930
        }
931
        out.print("<!--" + currentNode.nodedata + "-->");
932
        previousNodeWasElement = false;
933

    
934
      // Handle the PI nodes
935
      } else if (currentNode.nodetype.equals("PI")) {
936
        if (previousNodeWasElement) {
937
          out.print(">");
938
        }
939
        out.print("<?" + currentNode.nodename + " " +
940
                        currentNode.nodedata + "?>");
941
        previousNodeWasElement = false;
942

    
943
      // Handle any other node type (do nothing)
944
      } else {
945
        // Any other types of nodes are not handled.
946
        // Probably should throw an exception here to indicate this
947
      }
948
      out.flush();
949
    }
950

    
951
    // Print the final end tag for the root element
952
    while(!openElements.empty())
953
    {
954
      NodeRecord currentElement = (NodeRecord)openElements.pop();
955
      util.debugMessage("\n POPPED: " + currentElement.nodename);
956
      if ( currentElement.nodeprefix != null ) {
957
        out.print("</" + currentElement.nodeprefix + ":" + 
958
                  currentElement.nodename + ">" );
959
      } else {
960
        out.print("</" + currentElement.nodename + ">" );
961
      }
962
    }
963
    out.flush();
964
  }
965
  
966
  private boolean isRevisionOnly(DocumentIdentifier docid) throws Exception
967
  {
968
    //System.out.println("inRevisionOnly");
969
    DBConnection dbconn = null;
970
    int serialNumber = -1;
971
    PreparedStatement pstmt =null;
972
    String rev = docid.getRev();
973
    String newid = docid.getIdentifier();
974
    try
975
    {
976
      dbconn=DBConnectionPool.
977
                    getDBConnection("DocumentImpl.isRevisionOnly");
978
      serialNumber=dbconn.getCheckOutSerialNumber();
979
      pstmt = dbconn.prepareStatement("select rev from xml_documents " +
980
                                  "where docid like '" + newid + "'");
981
      pstmt.execute();
982
      ResultSet rs = pstmt.getResultSet();
983
      boolean tablehasrows = rs.next();
984
      if(rev.equals("newest") || rev.equals("all"))
985
      {
986
        return false;
987
      }
988
    
989
      if(tablehasrows)
990
      {
991
        int r = rs.getInt(1);
992
        pstmt.close();
993
        if(new Integer(rev).intValue() == r)
994
        { //the current revision in in xml_documents
995
          //System.out.println("returning false");
996
          return false;
997
        }
998
        else if(new Integer(rev).intValue() < r)
999
        { //the current revision is in xml_revisions.
1000
          //System.out.println("returning true");
1001
          return true;
1002
        }
1003
        else if(new Integer(rev).intValue() > r)
1004
        { //error, rev cannot be greater than r
1005
          throw new Exception("requested revision cannot be greater than " +
1006
                            "the latest revision number.");
1007
        }
1008
      }
1009
      // Get miss docid and rev, throw to McdDocNotFoundException
1010
      String missDocId = MetaCatUtil.getDocIdFromString(docid.toString());
1011
      String missRevision = 
1012
                  MetaCatUtil.getRevisionStringFromString(docid.toString());
1013
      throw new McdbDocNotFoundException("the requested docid '" + 
1014
                docid.toString() + "' does not exist", missDocId, missRevision);
1015
    }//try
1016
    finally
1017
    {
1018
      pstmt.close();
1019
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1020
    }//finally
1021
  }
1022

    
1023
  private void getDocumentInfo(String docid) throws McdbException, 
1024
                                        AccessionNumberException, Exception
1025
  {
1026
    getDocumentInfo(new DocumentIdentifier(docid));
1027
  }
1028
  
1029
  /**
1030
   * Look up the document type information from the database
1031
   *
1032
   * @param docid the id of the document to look up
1033
   */
1034
  private void getDocumentInfo(DocumentIdentifier docid) throws McdbException
1035
                                                          , Exception
1036
  {
1037
    DBConnection dbconn = null;
1038
    int serialNumber = -1;
1039
    PreparedStatement pstmt = null;
1040
    String table = "xml_documents";
1041
        
1042
    try
1043
    {
1044
      if(isRevisionOnly(docid))
1045
      { //pull the document from xml_revisions instead of from xml_documents;
1046
        table = "xml_revisions";
1047
      }
1048
    }
1049
    // catch a McdbDocNotFoundException throw it
1050
    catch (McdbDocNotFoundException notFound)
1051
    {
1052
      throw notFound;
1053
    }
1054
    catch(Exception e)
1055
    {
1056
      
1057
      MetaCatUtil.debugMessage("error in DocumentImpl.getDocumentInfo: " + 
1058
                          e.getMessage(), 30);
1059
      throw e;
1060
    }
1061
    
1062

    
1063
    
1064
    try 
1065
    {
1066
      dbconn=DBConnectionPool.getDBConnection("DocumentImpl.getDocumentInfo");
1067
      serialNumber=dbconn.getCheckOutSerialNumber();
1068
      StringBuffer sql = new StringBuffer();
1069
// DOCTITLE attr cleared from the db
1070
//      sql.append("SELECT docname, doctype, rootnodeid, doctitle, ");
1071
      sql.append("SELECT docname, doctype, rootnodeid, ");
1072
      sql.append("date_created, date_updated, user_owner, user_updated, ");
1073
      sql.append("server_location, public_access, rev");
1074
      sql.append(" FROM ").append(table);
1075
      sql.append(" WHERE docid LIKE '").append(docid.getIdentifier());
1076
      sql.append("' and rev like '").append(docid.getRev()).append("'");
1077
      //System.out.println(sql.toString());
1078
      pstmt =
1079
        dbconn.prepareStatement(sql.toString());
1080
      // Bind the values to the query
1081
      //pstmt.setString(1, docid.getIdentifier());
1082
      //pstmt.setString(2, docid.getRev());
1083

    
1084
      pstmt.execute();
1085
      ResultSet rs = pstmt.getResultSet();
1086
      boolean tableHasRows = rs.next();
1087
      if (tableHasRows) {
1088
        this.docname        = rs.getString(1);
1089
        this.doctype        = rs.getString(2);
1090
        this.rootnodeid     = rs.getLong(3);
1091
// DOCTITLE attr cleared from the db
1092
//        this.doctitle       = rs.getString(4);
1093
        this.createdate     = rs.getString(4);
1094
        this.updatedate     = rs.getString(5);
1095
        this.userowner      = rs.getString(6);
1096
        this.userupdated    = rs.getString(7);
1097
        this.serverlocation = rs.getInt(8);
1098
        this.publicaccess   = rs.getString(9);
1099
        this.rev            = rs.getInt(10);
1100
      } 
1101
      pstmt.close();
1102
      
1103
      //get doc  home server name
1104
      
1105
      pstmt = dbconn.prepareStatement("select server " +
1106
                        "from xml_replication where serverid = ?");
1107
      //because connection use twise here, so we need to increase one
1108
      dbconn.increaseUsageCount(1);
1109
      pstmt.setInt(1, serverlocation);
1110
      pstmt.execute();
1111
      rs = pstmt.getResultSet();
1112
      tableHasRows = rs.next();
1113
      if (tableHasRows)
1114
      {
1115
        
1116
          String server = rs.getString(1);
1117
          //get homeserver name
1118
          if(!server.equals("localhost"))
1119
          {
1120
            this.docHomeServer=server;
1121
          }
1122
          else
1123
          {
1124
            this.docHomeServer=MetaCatUtil.getLocalReplicationServerName();
1125
          }
1126
          MetaCatUtil.debugMessage("server: "+docHomeServer, 50);
1127
        
1128
      }
1129
      pstmt.close();
1130
      if (this.doctype != null) {
1131
        pstmt =
1132
          dbconn.prepareStatement("SELECT system_id " +
1133
                                  "FROM xml_catalog " +
1134
                                 "WHERE public_id = ?");
1135
        //should increase usage count again
1136
        dbconn.increaseUsageCount(1);
1137
        // Bind the values to the query
1138
        pstmt.setString(1, doctype);
1139
  
1140
        pstmt.execute();
1141
        rs = pstmt.getResultSet();
1142
        tableHasRows = rs.next();
1143
        if (tableHasRows) {
1144
          this.system_id  = rs.getString(1);
1145
        } 
1146
        pstmt.close();
1147
      }
1148
    } catch (SQLException e) {
1149
      System.out.println("error in DocumentImpl.getDocumentInfo: " + 
1150
                          e.getMessage());
1151
      e.printStackTrace(System.out);
1152
      throw new McdbException("Error accessing database connection in " +
1153
                              "DocumentImpl.getDocumentInfo: ", e);
1154
    }
1155
    finally
1156
    {
1157
      try
1158
      {
1159
        pstmt.close();
1160
      }
1161
      catch (SQLException ee)
1162
      {
1163
        MetaCatUtil.debugMessage("error in DocumentImple.getDocumentInfo: "
1164
                                    +ee.getMessage(), 30);
1165
      }//catch
1166
      finally
1167
      {
1168
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1169
      }
1170
    }
1171

    
1172
    if (this.docname == null) {
1173
      throw new McdbDocNotFoundException("Document not found: " + docid,
1174
                                 docid.getIdentifier(), docid.getRev());
1175
    }
1176
  }
1177

    
1178
  /**
1179
   * Look up the node data from the database
1180
   *
1181
   * @param rootnodeid the id of the root node of the node tree to look up
1182
   */
1183
  private TreeSet getNodeRecordList(long rootnodeid) throws McdbException
1184
  {
1185
    PreparedStatement pstmt = null;
1186
    DBConnection dbconn = null;
1187
    int serialNumber = -1;
1188
    TreeSet nodeRecordList = new TreeSet(new NodeComparator());
1189
    long nodeid = 0;
1190
    long parentnodeid = 0;
1191
    long nodeindex = 0;
1192
    String nodetype = null;
1193
    String nodename = null;
1194
    String nodeprefix = null;
1195
    String nodedata = null;
1196
    String quotechar = dbAdapter.getStringDelimiter();
1197

    
1198
    try {
1199
      dbconn=DBConnectionPool.
1200
                    getDBConnection("DocumentImpl.getNodeRecordList");
1201
      serialNumber=dbconn.getCheckOutSerialNumber();
1202
      pstmt =
1203
      dbconn.prepareStatement("SELECT nodeid,parentnodeid,nodeindex, " +
1204
           "nodetype,nodename,nodeprefix,nodedata " +               
1205
           "FROM xml_nodes WHERE rootnodeid = ?");
1206

    
1207
      // Bind the values to the query
1208
      pstmt.setLong(1, rootnodeid);
1209

    
1210
      pstmt.execute();
1211
      ResultSet rs = pstmt.getResultSet();
1212
      boolean tableHasRows = rs.next();
1213
      while (tableHasRows) {
1214
        nodeid = rs.getLong(1);
1215
        parentnodeid = rs.getLong(2);
1216
        nodeindex = rs.getLong(3);
1217
        nodetype = rs.getString(4);
1218
        nodename = rs.getString(5);
1219
        nodeprefix = rs.getString(6);
1220
        nodedata = rs.getString(7);
1221
        nodedata = MetaCatUtil.normalize(nodedata);
1222
        // add the data to the node record list hashtable
1223
        NodeRecord currentRecord = new NodeRecord(nodeid,parentnodeid,nodeindex,
1224
                                      nodetype, nodename, nodeprefix, nodedata);
1225
        nodeRecordList.add(currentRecord);
1226

    
1227
        // Advance to the next node
1228
        tableHasRows = rs.next();
1229
      } 
1230
      pstmt.close();
1231

    
1232
    } catch (SQLException e) {
1233
      throw new McdbException("Error in DocumentImpl.getNodeRecordList " +
1234
                              e.getMessage());
1235
    }
1236
    finally
1237
    {
1238
      try
1239
      {
1240
        pstmt.close();
1241
      }
1242
      catch (SQLException ee)
1243
      {
1244
        MetaCatUtil.debugMessage("error in DocumentImpl.getNodeRecordList: "
1245
                                    +ee.getMessage(), 30);
1246
      }
1247
      finally
1248
      {
1249
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1250
      }
1251
    }
1252
      
1253

    
1254
    if (nodeRecordList != null) {
1255
      return nodeRecordList;
1256
    } else {
1257
      throw new McdbException("Error getting node data: " + docid);
1258
    }
1259
  }
1260
  
1261
// NOT USED ANY MORE
1262
//  /** creates SQL code and inserts new document into DB connection 
1263
//   default serverCode of 1*/
1264
//  private void writeDocumentToDB(String action, String user)
1265
//               throws SQLException, Exception
1266
//  {
1267
//    writeDocumentToDB(action, user, null, 1);
1268
//  }
1269

    
1270
 /** creates SQL code and inserts new document into DB connection */
1271
  private void writeDocumentToDB(String action, String user, String pub, 
1272
                                 String catalogid, int serverCode) 
1273
               throws SQLException, Exception {
1274
    String sysdate = dbAdapter.getDateTimeFunction();
1275

    
1276
    try {
1277
      PreparedStatement pstmt = null;
1278

    
1279
      if (action.equals("INSERT")) {
1280
        //AccessionNumber ac = new AccessionNumber();
1281
        //this.docid = ac.generate(docid, "INSERT");
1282
        
1283
        pstmt = connection.prepareStatement(
1284
                "INSERT INTO xml_documents " +
1285
                "(docid, rootnodeid, docname, doctype, " + 
1286
                "user_owner, user_updated, date_created, date_updated, " + 
1287
                "public_access, catalog_id, server_location, rev) " +
1288
                "VALUES (?, ?, ?, ?, ?, ?, " + sysdate + ", " + sysdate + 
1289
                ", ?, ?, ?, ?)");
1290
        // Increase dbconnection usage count
1291
        connection.increaseUsageCount(1);
1292
        
1293
        //note that the server_location is set to 1. 
1294
        //this means that "localhost" in the xml_replication table must
1295
        //always be the first entry!!!!!
1296
        
1297
        // Bind the values to the query
1298
        pstmt.setString(1, this.docid);
1299
        pstmt.setLong(2, rootnodeid);
1300
        pstmt.setString(3, docname);
1301
        pstmt.setString(4, doctype);
1302
        pstmt.setString(5, user);
1303
        pstmt.setString(6, user);
1304
        //public access is usefulless, so set it to null
1305
        pstmt.setString(7, null);
1306
        /*if ( pub == null ) {
1307
          pstmt.setString(7, null);
1308
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
1309
          pstmt.setInt(7, 1);
1310
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
1311
          pstmt.setInt(7, 0);
1312
        }*/
1313
        pstmt.setString(8, catalogid);
1314
        pstmt.setInt(9, serverCode);
1315
        pstmt.setInt(10, Integer.parseInt(updatedVersion)); 
1316
      } else if (action.equals("UPDATE")) {
1317

    
1318
        // Save the old document publicaccessentry in a backup table
1319
        DocumentImpl.archiveDocRevision(connection, docid, user );
1320
        DocumentImpl thisdoc = new DocumentImpl(docid, false);
1321
        int thisrev = thisdoc.getRev();
1322
        
1323
        //if the updated vesion is not greater than current one,
1324
        //throw it into a exception
1325
        if (Integer.parseInt(updatedVersion)<=thisrev)
1326
        {
1327
          throw new Exception("Next revision number couldn't be less"
1328
                               +" than or equal "+ thisrev);
1329
        }
1330
        else
1331
        {
1332
          //set the user specified revision 
1333
          thisrev=Integer.parseInt(updatedVersion);
1334
        }
1335
        
1336
        // Delete index for the old version of docid
1337
        // The new index is inserting on the next calls to DBSAXNode
1338
        pstmt = connection.prepareStatement(
1339
                "DELETE FROM xml_index WHERE docid='" + this.docid + "'");
1340
        // Increase dbconnection usage count
1341
        connection.increaseUsageCount(1);
1342
        
1343
        pstmt.execute();
1344
        pstmt.close();
1345

    
1346
        // Update the new document to reflect the new node tree
1347
        pstmt = connection.prepareStatement(
1348
            "UPDATE xml_documents " +
1349
            "SET rootnodeid = ?, docname = ?, doctype = ?, " +
1350
            "user_updated = ?, date_updated = " + sysdate + ", " +
1351
            "server_location = ?, rev = ?, public_access = ?, catalog_id = ? " +
1352
            "WHERE docid = ?");
1353
        // Increase dbconnection usage count
1354
        connection.increaseUsageCount(1);
1355
        // Bind the values to the query
1356
        pstmt.setLong(1, rootnodeid);
1357
        pstmt.setString(2, docname);
1358
        pstmt.setString(3, doctype);
1359
        pstmt.setString(4, user);
1360
        pstmt.setInt(5, serverCode);
1361
        pstmt.setInt(6, thisrev);
1362
        pstmt.setString(7, null);
1363
        /*if ( pub == null ) {
1364
          pstmt.setString(7, null);
1365
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
1366
          pstmt .setInt(7, 1);
1367
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
1368
          pstmt.setInt(7, 0);
1369
        }*/
1370
        pstmt.setString(8, catalogid);
1371
        pstmt.setString(9, this.docid);
1372

    
1373
      } else {
1374
        System.err.println("Action not supported: " + action);
1375
      }
1376

    
1377
      // Do the insertion
1378
      pstmt.execute();
1379
      
1380
      pstmt.close();
1381

    
1382
    } catch (SQLException sqle) {
1383
      throw sqle;
1384
    } catch (Exception e) {
1385
      throw e;
1386
    }
1387
  }
1388

    
1389
  /**
1390
   * Write an XML file to the database, given a filename
1391
   *
1392
   * @param conn the JDBC connection to the database
1393
   * @param filename the filename to be loaded into the database
1394
   * @param pub flag for public "read" access on document
1395
   * @param dtdfilename the dtd to be uploaded on server's file system
1396
   * @param action the action to be performed (INSERT OR UPDATE)
1397
   * @param docid the docid to use for the INSERT OR UPDATE
1398
   * @param user the user that owns the document
1399
   * @param groups the groups to which user belongs
1400
   */
1401
  /*public static String write(DBConnection conn,String filename,
1402
                             String pub, String dtdfilename,
1403
                             String action, String docid, String user,
1404
                             String[] groups )
1405
                throws Exception {
1406
                  
1407
    Reader dtd = null;
1408
    if ( dtdfilename != null ) {
1409
      dtd = new FileReader(new File(dtdfilename).toString());
1410
    }
1411
    return write ( conn, new FileReader(new File(filename).toString()),
1412
                   pub, dtd, action, docid, user, groups, false);
1413
  }*/
1414

    
1415
  public static String write(DBConnection conn,Reader xml,String pub,Reader dtd,
1416
                             String action, String docid, String user,
1417
                             String[] groups, String ruleBase, 
1418
                             boolean needValidation)
1419
                throws Exception {
1420
    //this method will be called in handleUpdateOrInsert method 
1421
    //in MetacatServlet class and now is wrapper into documentImple
1422
    // get server location for this doc
1423
    int serverLocation=getServerLocationNumber(docid);
1424
    return write(conn,xml,pub,dtd,action,docid,user,groups,serverLocation,false,
1425
                 ruleBase, needValidation);
1426
  }
1427

    
1428
 
1429
  
1430
  /**
1431
   * Write an XML file to the database, given a Reader
1432
   *
1433
   * @param conn the JDBC connection to the database
1434
   * @param xml the xml stream to be loaded into the database
1435
   * @param pub flag for public "read" access on xml document
1436
   * @param dtd the dtd to be uploaded on server's file system
1437
   * @param action the action to be performed (INSERT or UPDATE)
1438
   * @param accnum the docid + rev# to use on INSERT or UPDATE
1439
   * @param user the user that owns the document
1440
   * @param groups the groups to which user belongs
1441
   * @param serverCode the serverid from xml_replication on which this document
1442
   *        resides.
1443
   * @param override flag to stop insert replication checking.
1444
   *        if override = true then a document not belonging to the local server
1445
   *        will not be checked upon update for a file lock.
1446
   *        if override = false then a document not from this server, upon 
1447
   *        update will be locked and version checked.
1448
   */
1449

    
1450
  public static String write(DBConnection conn, Reader xml,String pub,
1451
                         Reader dtd, String action, String accnum, String user,
1452
                         String[] groups, int serverCode, boolean override,
1453
                         String ruleBase, boolean needValidation)
1454
                throws Exception
1455
  {
1456
    // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1457
    //MetaCatUtil util = new MetaCatUtil();
1458
    MetaCatUtil.debugMessage("conn usage count before writting: "
1459
                                      +conn.getUsageCount(), 50);
1460
    AccessionNumber ac = new AccessionNumber(accnum, action);
1461
    String docid = ac.getDocid();
1462
    String rev = ac.getRev();
1463
    MetaCatUtil.debugMessage("action: " + action + " servercode: " + 
1464
                             serverCode + " override: " + override, 10);
1465
                     
1466
    if((serverCode != 1 && action.equals("UPDATE")) && !override)
1467
    { //if this document being written is not a resident of this server then
1468
      //we need to try to get a lock from it's resident server.  If the
1469
      //resident server will not give a lock then we send the user a message
1470
      //saying that he/she needs to download a new copy of the file and
1471
      //merge the differences manually.
1472
      int istreamInt; 
1473
      char istreamChar;
1474
     
1475
      // check for 'write' permission for 'user' to update this document
1476
      if ( !hasPermission(user, groups, docid) ) {
1477
        throw new Exception("User " + user + 
1478
              " does not have permission to update XML Document #" + accnum);
1479
      }        
1480
  
1481
      DocumentIdentifier id = new DocumentIdentifier(accnum);
1482
      String updaterev = id.getRev();
1483
      String server=MetacatReplication.getServerNameForServerCode(serverCode);
1484
      MetacatReplication.replLog("attempting to lock " + accnum);
1485
      URL u = new URL("https://" + server + "?server="+
1486
        MetaCatUtil.getLocalReplicationServerName()+"&action=getlock&updaterev=" 
1487
           +updaterev + "&docid=" + docid);
1488
      //System.out.println("sending message: " + u.toString());
1489
      String serverResStr = MetacatReplication.getURLContent(u);
1490
      String openingtag =serverResStr.substring(0, serverResStr.indexOf(">")+1);
1491
      if(openingtag.equals("<lockgranted>"))
1492
      {//the lock was granted go ahead with the insert
1493
        try 
1494
        {
1495
          //System.out.println("In lockgranted");
1496
          MetacatReplication.replLog("lock granted for " + accnum + " from " +
1497
                                      server);
1498
          /*XMLReader parser = initializeParser(conn, action, docid, updaterev,
1499
                               validate, user, groups, pub, serverCode, dtd);*/
1500
          XMLReader parser = initializeParser(conn, action, docid, updaterev,
1501
                                        user, groups, pub, serverCode, 
1502
                                        dtd,ruleBase, needValidation); 
1503
          conn.setAutoCommit(false);
1504
          parser.parse(new InputSource(xml)); 
1505
          conn.commit();
1506
          conn.setAutoCommit(true);
1507
        } 
1508
        catch (Exception e) 
1509
        {
1510
          conn.rollback();
1511
          conn.setAutoCommit(true);
1512
          throw e;
1513
        }
1514
                
1515
        
1516
        
1517
        // Force replication the docid
1518
        ForceReplicationHandler frh = new ForceReplicationHandler
1519
                                                          (accnum, true, null);
1520
        return(accnum);
1521
   
1522
      }
1523

    
1524
      else if(openingtag.equals("<filelocked>"))
1525
      {//the file is currently locked by another user
1526
       //notify our user to wait a few minutes, check out a new copy and try
1527
       //again.
1528
        //System.out.println("file locked");
1529
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1530
                                   server + " reason: file already locked");
1531
        throw new Exception("The file specified is already locked by another " +
1532
                            "user.  Please wait 30 seconds, checkout the " +
1533
                            "newer document, merge your changes and try " +
1534
                            "again.");
1535
      }
1536
      else if(openingtag.equals("<outdatedfile>"))
1537
      {//our file is outdated.  notify our user to check out a new copy of the
1538
       //file and merge his version with the new version.
1539
        //System.out.println("outdated file");
1540
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1541
                                    server + " reason: local file outdated");
1542
        throw new Exception("The file you are trying to update is an outdated" +
1543
                            " version.  Please checkout the newest document, " +
1544
                            "merge your changes and try again.");
1545
      }
1546
    }
1547
    
1548
    if ( action.equals("UPDATE") ) {
1549
      // check for 'write' permission for 'user' to update this document
1550

    
1551
      if ( !hasPermission(user, groups, docid) ) {
1552
        throw new Exception("User " + user + 
1553
              " does not have permission to update XML Document #" + accnum);
1554
      }          
1555
    }
1556

    
1557
    try 
1558
    { 
1559
      
1560
      XMLReader parser = initializeParser(conn, action, docid, rev, 
1561
                                          user, groups, pub, serverCode, 
1562
                                          dtd, ruleBase, needValidation);
1563
   
1564
      conn.setAutoCommit(false);
1565
      parser.parse(new InputSource(xml));
1566
      conn.commit();
1567
      conn.setAutoCommit(true);
1568
    } 
1569
    catch (Exception e) 
1570
    {
1571
      conn.rollback();
1572
      conn.setAutoCommit(true);
1573
      throw e;
1574
    }
1575
    
1576
    // Force replicate out the new document to each server in our server list.
1577
    // Start the thread to replicate this new document out to the other servers
1578
    // true mean it is xml document
1579
    // null is because no metacat notify the force replication.
1580
    ForceReplicationHandler frh = new ForceReplicationHandler
1581
                                                  (accnum, action, true, null);
1582
      
1583
   
1584
    MetaCatUtil.debugMessage("Conn Usage count after writting: "
1585
                                                      +conn.getUsageCount(),50); 
1586
    return(accnum);
1587
  }
1588

    
1589
  /**
1590
   * Write an XML file to the database during replication
1591
   *
1592
   * @param conn the JDBC connection to the database
1593
   * @param xml the xml stream to be loaded into the database
1594
   * @param pub flag for public "read" access on xml document
1595
   * @param dtd the dtd to be uploaded on server's file system
1596
   * @param action the action to be performed (INSERT or UPDATE)
1597
   * @param accnum the docid + rev# to use on INSERT or UPDATE
1598
   * @param user the user that owns the document
1599
   * @param groups the groups to which user belongs
1600
   * @param homeServer the name of server which the document origanlly create
1601
   * @param validate, if the xml document is valid or not
1602
   * @param notifyServer, the server which notify local server the force 
1603
   *                       replication command
1604
   */
1605

    
1606
  public static String writeReplication(DBConnection conn, Reader xml, 
1607
                                        String pub, Reader dtd, String action, 
1608
                                        String accnum, String user,
1609
                                        String[] groups,String homeServer, 
1610
                                        String notifyServer,
1611
                                        String ruleBase, boolean needValidation)
1612
                                        throws Exception
1613
  {
1614
    // Docid without revision
1615
    String docid=MetaCatUtil.getDocIdFromString(accnum);
1616
    // Revision specified by user (int)
1617
    int userSpecifyRev=MetaCatUtil.getVersionFromString(accnum);
1618
    // Revision for this docid in current database
1619
    int revInDataBase=getLatestRevisionNumber(docid);
1620
    // String to store the revision
1621
    String rev = null;
1622
   
1623
    
1624
    //revIndataBase=-1, there is no record in xml_documents table
1625
    //the document is a new one for local server, inert it into table
1626
    //user specified rev should be great than 0
1627
    if (revInDataBase==-1 && userSpecifyRev>0 )
1628
    {
1629
        // rev equals user specified
1630
        rev=(new Integer(userSpecifyRev)).toString();
1631
        // action should be INSERT
1632
        action = "INSERT";
1633
    }
1634
    //rev is greater the last revsion number and revInDataBase isn't -1
1635
    // it is a updated  file
1636
    else if (userSpecifyRev>revInDataBase && revInDataBase>0)
1637
    {
1638
       // rev equals user specified
1639
       rev=(new Integer(userSpecifyRev)).toString();
1640
       // action should be update
1641
       action = "UPDATE";
1642
    }
1643
    // local server has newer version, then notify the remote server
1644
    else if ( userSpecifyRev < revInDataBase && revInDataBase > 0)
1645
    {
1646
      throw new Exception("Local server: "+MetaCatUtil.getOption("server")+
1647
                " has newer revision of doc: "+docid+"."+revInDataBase
1648
                 +". Please notify it.");
1649
    }
1650
    //other situation
1651
    else
1652
    {
1653
        
1654
        throw new Exception("The docid"+docid+"'s revision number couldn't be "
1655
                    +userSpecifyRev);
1656
    }
1657
    // Variable to store homeserver code
1658
    int serverCode=-2;
1659
    
1660
     // If server is not int the xml replication talbe, insert it into
1661
    // xml_replication table
1662
    //serverList.addToServerListIfItIsNot(homeServer);
1663
    insertServerIntoReplicationTable(homeServer);
1664
    // Get server code again
1665
    serverCode = getServerCode(homeServer);
1666
    
1667
    
1668
    MetaCatUtil.debugMessage("Document "+docid+"."+rev+" "+action+ " into local"
1669
                               +" metacat with servercode: "+ serverCode, 10);
1670
                        
1671
  
1672
    // insert into xml_nodes and xml_index table
1673
    try 
1674
    { 
1675
      
1676
      XMLReader parser = initializeParser(conn, action, docid, rev,
1677
                                          user, groups, pub, serverCode, dtd,
1678
                                          ruleBase, needValidation);
1679
      conn.setAutoCommit(false);
1680
      parser.parse(new InputSource(xml));
1681
      conn.commit();
1682
      conn.setAutoCommit(true);
1683
    } 
1684
    catch (Exception e) 
1685
    {
1686
      conn.rollback();
1687
      conn.setAutoCommit(true);
1688
      throw e;
1689
    }
1690
    
1691
    //Force replication to other server
1692
    ForceReplicationHandler forceReplication = new ForceReplicationHandler
1693
                                  (accnum, action, true, notifyServer);
1694
    
1695

    
1696
    return(accnum);
1697
  }
1698

    
1699
  
1700
  /**
1701
   * Delete an XML file from the database (actually, just make it a revision
1702
   * in the xml_revisions table)
1703
   *
1704
   * @param docid the ID of the document to be deleted from the database
1705
   */
1706
  public static void delete(String accnum,
1707
                                 String user, String[] groups )
1708
                throws Exception 
1709
  {
1710
    // OLD
1711
    //DocumentIdentifier id = new DocumentIdentifier(accnum);
1712
    //String docid = id.getIdentifier();
1713
    //String rev = id.getRev();
1714
    
1715
    // OLD
1716
    // Determine if the docid,rev are OK for DELETE
1717
    //AccessionNumber ac = new AccessionNumber(conn);
1718
    //docid = ac.generate(docid, rev, "DELETE");
1719
    DBConnection conn = null;
1720
    int serialNumber = -1;
1721
    PreparedStatement pstmt =null;
1722
    try
1723
    {
1724
      //check out DBConnection
1725
      conn=DBConnectionPool.
1726
                    getDBConnection("DocumentImpl.delete");
1727
      serialNumber=conn.getCheckOutSerialNumber();
1728

    
1729
      // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1730
      AccessionNumber ac = new AccessionNumber(accnum, "DELETE");
1731
      String docid = ac.getDocid();
1732
      String rev = ac.getRev();
1733
    
1734

    
1735
    // check for 'write' permission for 'user' to delete this document
1736
      if ( !hasPermission(user, groups, docid) ) {
1737
        throw new Exception("User " + user + 
1738
              " does not have permission to delete XML Document #" + accnum);
1739
      }
1740

    
1741
      conn.setAutoCommit(false);
1742
      // Copy the record to the xml_revisions table
1743
      DocumentImpl.archiveDocRevision(conn, docid, user );
1744

    
1745
      // Now delete it from the xml_index table
1746
      pstmt = conn.prepareStatement("DELETE FROM xml_index WHERE docid = ?");
1747
      pstmt.setString(1,docid);
1748
      pstmt.execute();
1749
      pstmt.close();
1750
      conn.increaseUsageCount(1);
1751
      
1752
      //stmt.execute("DELETE FROM xml_access WHERE docid = '" + docid + "'");
1753
      // Now delete it from xml_access table
1754
      pstmt = conn.
1755
              prepareStatement("DELETE FROM xml_access WHERE accessfileid = ?");
1756
      pstmt.setString(1, docid);
1757
      pstmt.execute();
1758
      pstmt.close();
1759
      conn.increaseUsageCount(1);
1760
      
1761
      // Delete it from relation table
1762
      pstmt = conn.
1763
               prepareStatement("DELETE FROM xml_relation WHERE docid = ?");
1764
      //increase usage count
1765
      conn.increaseUsageCount(1);
1766
      pstmt.setString(1, docid);
1767
      pstmt.execute();
1768
      pstmt.close();
1769
      
1770
      // Delete it from xml_doucments table
1771
      pstmt =conn.prepareStatement("DELETE FROM xml_documents WHERE docid = ?");
1772
      pstmt.setString(1, docid);
1773
      pstmt.execute();
1774
      pstmt.close();
1775
      //Usaga count increase 1
1776
      conn.increaseUsageCount(1);
1777
      
1778
      conn.commit();
1779
      conn.setAutoCommit(true);
1780
    }//try
1781
    finally
1782
    {
1783
      
1784
      try
1785
      {
1786
        // close preparedStatement
1787
        pstmt.close();
1788
      }//try
1789
      finally
1790
      {
1791
        //check in DBonnection
1792
        DBConnectionPool.returnDBConnection(conn, serialNumber);
1793
      }//finally
1794
    }//finally
1795
    //IF this is a package document:
1796
    //delete all of the relations that this document created.
1797
    //if the deleted document is a package document its relations should 
1798
    //no longer be active if it has been deleted from the system.
1799
    
1800
  }
1801

    
1802
  /** 
1803
    * Check for "WRITE" permission on @docid for @user and/or @groups 
1804
    * from DB connection 
1805
    */
1806
  private static boolean hasPermission (String user,
1807
                                  String[] groups, String docid ) 
1808
                  throws SQLException, Exception
1809
  {
1810
    // Check for WRITE permission on @docid for @user and/or @groups
1811
    //AccessControlList aclobj = new AccessControlList(dbconn);
1812
    return AccessControlList.hasPermission("WRITE", user, groups, docid);
1813
    //return aclobj.hasPermission("WRITE", user, groups, docid);
1814
  }
1815

    
1816
  /** 
1817
    * Check for "READ" permission base on docid, user and group
1818
    *@docid, the document
1819
    *@user, user name
1820
    *@group, user's group
1821
    * 
1822
    */
1823
  public static boolean hasReadPermission (String user,
1824
                                  String[] groups, String docId ) 
1825
                  throws SQLException, Exception
1826
  {
1827
    // Check for READ permission on @docid for @user and/or @groups
1828
    //AccessControlList aclObj = new AccessControlList(conn);
1829
    //return aclObj.hasPermission("READ", user, groups, docId);
1830
    return AccessControlList.hasPermission("READ", user, groups, docId);
1831
  }  
1832

    
1833
  
1834
   /**
1835
   * Set up the parser handlers for writing the document to the database
1836
   */
1837
  private static XMLReader initializeParser(DBConnection dbconn, String action,
1838
                                            String docid, String rev, 
1839
                                            String user, 
1840
                                            String[] groups, String pub, 
1841
                                            int serverCode, Reader dtd,
1842
                                            String ruleBase, 
1843
                                            boolean needValidation) 
1844
                                            throws Exception 
1845
  {
1846
    XMLReader parser = null;
1847
    try 
1848
    {
1849
 
1850
      //create a DBSAXHandler object which has the revision specification
1851
      ContentHandler chandler = new DBSAXHandler(dbconn, action, 
1852
                                    docid, rev, user, groups, pub, serverCode);
1853
      EntityResolver eresolver;
1854
      DTDHandler dtdhandler;  
1855
    
1856
      // Get an instance of the parser
1857
      String parserName = MetaCatUtil.getOption("saxparser");
1858
      parser = XMLReaderFactory.createXMLReader(parserName);
1859
      parser.setContentHandler((ContentHandler)chandler);
1860
      parser.setErrorHandler((ErrorHandler)chandler);
1861
      parser.setProperty(DECLARATIONHANDLERPROPERTY, chandler);
1862
      parser.setProperty(LEXICALPROPERTY, chandler);
1863
      
1864
      if (ruleBase != null && ruleBase.equals(SCHEMA) && needValidation)
1865
      {
1866
        // turn on schema validation feature
1867
        parser.setFeature(VALIDATIONFEATURE, true);
1868
        parser.setFeature(NAMESPACEFEATURE, true);
1869
        parser.setFeature(NAMESPACEPREFIXESFEATURE, true);
1870
        parser.setFeature(SCHEMAVALIDATIONFEATURE, true);
1871
        parser.setProperty(EXTERNALSCHEMALOCATIONPROPERTY,
1872
                           EXTERNALSCHEMALOCATION);
1873
     
1874
      }
1875
      else if (ruleBase != null && ruleBase.equals(DTD) && needValidation)
1876
      {
1877
        // turn on dtd validaton feature
1878
        parser.setFeature(VALIDATIONFEATURE, true);
1879
        eresolver= new DBEntityResolver(dbconn, (DBSAXHandler)chandler, dtd);
1880
        dtdhandler = new DBDTDHandler(dbconn);
1881
        parser.setEntityResolver((EntityResolver)eresolver);
1882
        parser.setDTDHandler((DTDHandler)dtdhandler);
1883
      }
1884
      else
1885
      {
1886
        // non validation
1887
         parser.setFeature(VALIDATIONFEATURE, false);
1888
         eresolver= new DBEntityResolver(dbconn, (DBSAXHandler)chandler, dtd);
1889
         dtdhandler = new DBDTDHandler(dbconn);
1890
         parser.setEntityResolver((EntityResolver)eresolver);
1891
         parser.setDTDHandler((DTDHandler)dtdhandler);
1892
      }
1893
  
1894
    } 
1895
    catch (Exception e) 
1896
    {
1897
      throw e;
1898
    }
1899
    return parser;
1900
  }
1901

    
1902
  
1903
  /**
1904
   * Set up the parser handlers for writing the document to the database
1905
   */
1906
  /*private static XMLReader initializeParser(DBConnection dbconn, String action,
1907
                               String docid, String rev, boolean validate, 
1908
                                   String user, String[] groups, String pub, 
1909
                                   int serverCode, Reader dtd) 
1910
                           throws Exception 
1911
  {
1912
    XMLReader parser = null;
1913
    //DBConnection conn = null;
1914
    //int serialNumber = -1;
1915
    //
1916
    // Set up the SAX document handlers for parsing
1917
    //
1918
    try {
1919
       //check out DBConnection
1920
     
1921
      //create a DBSAXHandler object which has the revision specification
1922
      ContentHandler chandler = new DBSAXHandler(dbconn, action, 
1923
                                    docid, rev, user, groups, pub, serverCode);
1924
      EntityResolver eresolver= new DBEntityResolver(dbconn,
1925
                                                 (DBSAXHandler)chandler, dtd);
1926
      DTDHandler dtdhandler   = new DBDTDHandler(dbconn);
1927

    
1928
      // Get an instance of the parser
1929
      String parserName = MetaCatUtil.getOption("saxparser");
1930
      parser = XMLReaderFactory.createXMLReader(parserName);
1931

    
1932
      // Turn on validation
1933
      parser.setFeature("http://xml.org/sax/features/validation", validate);
1934
      // Turn off Including all external parameter entities
1935
      // (the external DTD subset also)
1936
      // Doesn't work well, probably the feature name is not correct
1937
      // parser.setFeature(
1938
      //  "http://xml.org/sax/features/external-parameter-entities", false);
1939
      
1940
      // Set Handlers in the parser
1941
      parser.setProperty("http://xml.org/sax/properties/declaration-handler",
1942
                         chandler);
1943
      parser.setProperty("http://xml.org/sax/properties/lexical-handler",
1944
                         chandler);
1945
      parser.setContentHandler((ContentHandler)chandler);
1946
      parser.setEntityResolver((EntityResolver)eresolver);
1947
      parser.setDTDHandler((DTDHandler)dtdhandler);
1948
      parser.setErrorHandler((ErrorHandler)chandler);
1949

    
1950
    } catch (Exception e) {
1951
      throw e;
1952
    }
1953
    //finally
1954
    //{
1955
      //DBConnectionPool.returnDBConnection(conn, serialNumber);
1956
    //}
1957

    
1958
    return parser;
1959
  }*/
1960

    
1961
  /**
1962
   * Save a document entry in the xml_revisions table 
1963
   * Connection use as a paramter is in order to rollback feature
1964
   */
1965
  private static void archiveDocRevision(DBConnection dbconn, String docid, 
1966
                                                    String user) 
1967
 {
1968
    String sysdate = dbAdapter.getDateTimeFunction();
1969
    //DBConnection conn = null;
1970
    //int serialNumber = -1;
1971
    PreparedStatement pstmt = null;
1972
    
1973
    // create a record in xml_revisions table 
1974
    // for that document as selected from xml_documents
1975
   
1976
   try
1977
   {
1978
     //check out DBConnection
1979
     /*conn=DBConnectionPool.
1980
                    getDBConnection("DocumentImpl.archiveDocRevision");
1981
     serialNumber=conn.getCheckOutSerialNumber();*/
1982
     pstmt = dbconn.prepareStatement(
1983
      "INSERT INTO xml_revisions " +
1984
        "(docid, rootnodeid, docname, doctype, " +
1985
        "user_owner, user_updated, date_created, date_updated, " +
1986
        "server_location, rev, public_access, catalog_id) " +
1987
      "SELECT ?, rootnodeid, docname, doctype, " + 
1988
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
1989
        "server_location, rev, public_access, catalog_id " +
1990
      "FROM xml_documents " +
1991
      "WHERE docid = ?");
1992
      // Increase dbconnection usage count
1993
      dbconn.increaseUsageCount(1);
1994
      // Bind the values to the query and execute it
1995
      pstmt.setString(1, docid);
1996
      pstmt.setString(2, user);
1997
      pstmt.setString(3, docid);
1998
      pstmt.execute();
1999
      pstmt.close();
2000
   }//try
2001
   catch (SQLException e)
2002
   {
2003
     MetaCatUtil.debugMessage("Error in DocumentImpl.archiveDocRevision : "+
2004
                                e.getMessage(), 30);
2005
   }//catch
2006
   finally
2007
   {
2008
     try
2009
     {
2010
       pstmt.close();
2011
     }//try
2012
     catch (SQLException ee)
2013
     {
2014
       MetaCatUtil.debugMessage("Error in DocumnetImpl.archiveDocRevision: "+
2015
                                  ee.getMessage(), 50);
2016
     }//catch
2017
     //finally
2018
     //{
2019
       
2020
       //check in DBConnection
2021
       //DBConnectionPool.returnDBConnection(conn, serialNumber);
2022
     //}//finally
2023
   }//finnally
2024
                                  
2025

    
2026
  }//achiveDocRevision
2027
  
2028
  /** Save a document entry in the xml_revisions table */
2029
  private static void archiveDocRevision(String docid, String user) 
2030
 {
2031
    String sysdate = dbAdapter.getDateTimeFunction();
2032
    DBConnection conn = null;
2033
    int serialNumber = -1;
2034
    PreparedStatement pstmt = null;
2035
    
2036
    // create a record in xml_revisions table 
2037
    // for that document as selected from xml_documents
2038
   
2039
   try
2040
   {
2041
     //check out DBConnection
2042
     conn=DBConnectionPool.
2043
                    getDBConnection("DocumentImpl.archiveDocRevision");
2044
     serialNumber=conn.getCheckOutSerialNumber();
2045
     pstmt = conn.prepareStatement(
2046
      "INSERT INTO xml_revisions " +
2047
        "(docid, rootnodeid, docname, doctype, " +
2048
        "user_owner, user_updated, date_created, date_updated, " +
2049
        "server_location, rev, public_access, catalog_id) " +
2050
      "SELECT ?, rootnodeid, docname, doctype, " + 
2051
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
2052
        "server_location, rev, public_access, catalog_id " +
2053
      "FROM xml_documents " +
2054
      "WHERE docid = ?");
2055
      // Bind the values to the query and execute it
2056
      pstmt.setString(1, docid);
2057
      pstmt.setString(2, user);
2058
      pstmt.setString(3, docid);
2059
      pstmt.execute();
2060
      pstmt.close();
2061
   }//try
2062
   catch (SQLException e)
2063
   {
2064
     MetaCatUtil.debugMessage("Error in DocumentImpl.archiveDocRevision : "+
2065
                                e.getMessage(), 30);
2066
   }//catch
2067
   finally
2068
   {
2069
     try
2070
     {
2071
       pstmt.close();
2072
     }//try
2073
     catch (SQLException ee)
2074
     {
2075
       MetaCatUtil.debugMessage("Error in DocumnetImpl.archiveDocRevision: "+
2076
                                  ee.getMessage(), 50);
2077
     }//catch
2078
     finally
2079
     {
2080
       //check in DBConnection
2081
       DBConnectionPool.returnDBConnection(conn, serialNumber);
2082
     }//finally
2083
   }//finnally
2084
                                  
2085

    
2086
  }//achiveDocRevision
2087
  
2088
  /**
2089
    * delete a entry in xml_table for given docid
2090
    * @param docId, the id of the document need to be delete
2091
    */
2092
  private static void deleteXMLDocuments(String docId) 
2093
                                         throws SQLException 
2094
  {
2095
    DBConnection conn = null;
2096
    int serialNumber = -1;
2097
    PreparedStatement pStmt = null;
2098
    try
2099
    {
2100
      //check out DBConnection
2101
      conn=DBConnectionPool.
2102
                    getDBConnection("DocumentImpl.deleteXMLDocuments");
2103
      serialNumber=conn.getCheckOutSerialNumber();
2104
      //delete a record 
2105
      pStmt = 
2106
             conn.prepareStatement("DELETE FROM xml_documents WHERE docid = '" 
2107
                                              + docId + "'");
2108
    pStmt.execute();
2109
    }//try
2110
    finally
2111
    {
2112
      try
2113
      {
2114
        pStmt.close();
2115
      }//try
2116
      catch (SQLException e)
2117
      {
2118
        MetaCatUtil.debugMessage("error in DocumentImpl.deleteXMLDocuments: "+
2119
                                  e.getMessage(), 50);
2120
      }//catch
2121
      finally
2122
      {
2123
        //return back DBconnection
2124
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2125
      }//finally
2126
    }//finally
2127
      
2128

    
2129
  }//deleteXMLDocuments
2130
  
2131
  /**
2132
    * Get last revision number from database for a docid
2133
    * If couldn't find an entry,  -1 will return
2134
    * The return value is integer because we want compare it to there new one
2135
    * @param docid <sitecode>.<uniqueid> part of Accession Number
2136
    */
2137
  private static int getLatestRevisionNumber(String docId)
2138
                                      throws SQLException
2139
  {
2140
    int rev = 1;
2141
    PreparedStatement pStmt = null;
2142
    DBConnection dbConn = null;
2143
    int serialNumber = -1;
2144
    
2145
    try
2146
    {
2147
      //check out DBConnection
2148
      dbConn=DBConnectionPool.
2149
                    getDBConnection("DocumentImpl.getLatestRevisionNumber");
2150
      serialNumber=dbConn.getCheckOutSerialNumber();
2151
     
2152
      pStmt = dbConn.prepareStatement
2153
              ("SELECT rev FROM xml_documents WHERE docid='" + docId + "'");
2154
      pStmt.execute();
2155

    
2156
      ResultSet rs = pStmt.getResultSet();
2157
      boolean hasRow = rs.next();
2158
      if (hasRow)
2159
      {
2160
        rev = rs.getInt(1);
2161
        pStmt.close();
2162
      }
2163
      else
2164
      {
2165
        rev=-1;
2166
        pStmt.close();
2167
      }
2168
    }//try
2169
    finally
2170
    {
2171
      try
2172
      {
2173
        pStmt.close();
2174
      }
2175
      catch (Exception ee)
2176
      {
2177
        MetaCatUtil.debugMessage("Error in DocumentImpl."+
2178
                        "getLatestRevisionNumber: "+ee.getMessage(), 50);
2179
      }
2180
      finally
2181
      {
2182
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2183
      }
2184
    }//finally  
2185
      
2186
    return rev;
2187
  }//getLatestRevisionNumber
2188
  
2189
  /**
2190
   * Get server location form database for a accNum
2191
   * 
2192
   * @param accum <sitecode>.<uniqueid>.<rev>
2193
   */
2194
  private static int getServerLocationNumber(String accNum)
2195
                                            throws SQLException
2196
  {
2197
    //get rid of revNum part
2198
    String docId=MetaCatUtil.getDocIdFromString(accNum);
2199
    PreparedStatement pStmt = null;
2200
    int serverLocation = 1;
2201
    DBConnection conn = null;
2202
    int serialNumber = -1;
2203
    
2204
    try
2205
    {
2206
      //check out DBConnection
2207
      conn=DBConnectionPool.
2208
                    getDBConnection("DocumentImpl.getServerLocationNumber");
2209
      serialNumber=conn.getCheckOutSerialNumber();
2210
     
2211
      pStmt = conn.prepareStatement
2212
      ("SELECT server_location FROM xml_documents WHERE docid='" + docId + "'");
2213
      pStmt.execute();
2214

    
2215
      ResultSet rs = pStmt.getResultSet();
2216
      boolean hasRow = rs.next();
2217
      //if there is entry in xml_documents, get the serverlocation
2218
      if (hasRow)
2219
      {
2220
        serverLocation = rs.getInt(1);
2221
        pStmt.close();
2222
      }
2223
      else
2224
      {
2225
        //if htere is no entry in xml_documents, we consider it is new document
2226
        //the server location is local host and value is 1
2227
        serverLocation=1;
2228
        pStmt.close();
2229
      }
2230
    }//try
2231
    finally
2232
    {
2233
      try
2234
      {
2235
        pStmt.close();
2236
      }//try
2237
      catch (Exception ee)
2238
      {
2239
        MetaCatUtil.debugMessage("Error in DocumentImpl.getServerLocationNu(): "
2240
                                    +ee.getMessage(), 50);
2241
      }//catch
2242
      finally
2243
      {
2244
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2245
      }//finally
2246
    }//finally
2247
      
2248
    return serverLocation;
2249
  }
2250
  
2251
  /**
2252
   * Given a server name, return its servercode in xml_replication table.
2253
   * If no server is found, -1 will return
2254
   * @param serverName, 
2255
   */
2256
  private static int getServerCode(String serverName) 
2257
  {
2258
    PreparedStatement pStmt=null;
2259
    int serverLocation=-2;
2260
    DBConnection dbConn = null;
2261
    int serialNumber = -1;
2262
    //MetaCatUtil util = new MetaCatUtil();
2263
    
2264
    
2265
    //we should consider about local host too
2266
    if (serverName.equals(MetaCatUtil.getLocalReplicationServerName()))
2267
    { 
2268
      serverLocation=1;
2269
      return serverLocation;
2270
    }
2271
    
2272
   
2273
    try
2274
    {
2275
      //check xml_replication table
2276
      //dbConn=util.openDBConnection();
2277
      //check out DBConnection
2278
      dbConn=DBConnectionPool.getDBConnection("DocumentImpl.getServerCode");
2279
      serialNumber=dbConn.getCheckOutSerialNumber();
2280
      pStmt = dbConn.prepareStatement
2281
      ("SELECT serverid FROM xml_replication WHERE server='" + serverName +"'");
2282
      pStmt.execute();
2283

    
2284
      ResultSet rs = pStmt.getResultSet();
2285
      boolean hasRow = rs.next();
2286
      //if there is entry in xml_replication, get the serverid
2287
      if (hasRow)
2288
      {
2289
        serverLocation = rs.getInt(1);
2290
        pStmt.close();
2291
      }
2292
      else
2293
      {
2294
        // if htere is no entry in xml_replication, -1 will return
2295
        serverLocation=-1;
2296
        pStmt.close();
2297
      }
2298
    }
2299
    catch (Exception e)
2300
    {
2301
      MetaCatUtil.debugMessage("Error in DocumentImpl.getServerCode(): "
2302
                                    +e.getMessage(), 30);
2303
    }
2304
    finally
2305
    {
2306
      try
2307
      {
2308
        pStmt.close();
2309
      }
2310
      catch (Exception ee)
2311
      {
2312
        MetaCatUtil.debugMessage("Error in DocumentImpl.getServerCode(): "
2313
                                    +ee.getMessage(), 50);
2314
      }
2315
      finally
2316
      {
2317
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2318
      }
2319
    }
2320
                 
2321
      
2322
    return serverLocation;
2323
  }
2324
  
2325
  /**
2326
   * Insert a server into xml_replcation table
2327
   * @param server, the name of server 
2328
   */
2329
  private static synchronized void 
2330
                                insertServerIntoReplicationTable(String server)
2331
  {
2332
    PreparedStatement pStmt=null;
2333
    DBConnection dbConn = null;
2334
    int serialNumber = -1;
2335
    
2336
    // Initial value for the server
2337
    int replicate = 0;
2338
    int dataReplicate = 0;
2339
    int hub = 0;
2340
   
2341
    try
2342
    {
2343
       // Get DBConnection
2344
       dbConn=DBConnectionPool.
2345
                getDBConnection("DocumentImpl.insertServIntoReplicationTable");
2346
       serialNumber=dbConn.getCheckOutSerialNumber();
2347
      
2348
      // Compare the server to dabase
2349
      pStmt = dbConn.prepareStatement
2350
      ("SELECT serverid FROM xml_replication WHERE server='" + server +"'");
2351
      pStmt.execute();
2352
      ResultSet rs = pStmt.getResultSet();
2353
      boolean hasRow = rs.next();
2354
      // Close preparedstatement and result set
2355
      pStmt.close();
2356
      rs.close();
2357
      
2358
      // If the server is not in the table, and server is not local host,
2359
      // insert it
2360
      if ( !hasRow 
2361
         && !server.equals(MetaCatUtil.getLocalReplicationServerName()))
2362
      {
2363
        // Set auto commit false
2364
        dbConn.setAutoCommit(false);
2365
        pStmt = dbConn.prepareStatement("INSERT INTO xml_replication " +
2366
                      "(server, last_checked, replicate, datareplicate, hub) " +
2367
                       "VALUES ('" + server + "', to_date(" +
2368
                       "'01/01/00', 'MM/DD/YY'), '" +
2369
                       replicate +"', '"+dataReplicate+"','"+ hub + "')");
2370
        pStmt.execute();
2371
        dbConn.commit();
2372
        // Increase usage number
2373
        dbConn.increaseUsageCount(1);
2374
        pStmt.close();
2375
        
2376
      }
2377
    }//try
2378
    catch (Exception e)
2379
    {
2380
      MetaCatUtil.debugMessage("Error in DocumentImpl.insertServerIntoRepli(): "
2381
                                    +e.getMessage(), 30);
2382
    }//catch
2383
    finally
2384
    {
2385
     
2386
      try
2387
      {
2388
        // Set auto commit true
2389
        dbConn.setAutoCommit(true);
2390
        pStmt.close();
2391
        
2392
      }//try
2393
      catch (Exception ee)
2394
      {
2395
        MetaCatUtil.debugMessage("Error in DocumentImpl.insetServerIntoRepl(): "
2396
                                    +ee.getMessage(), 50);
2397
      }//catch
2398
      finally
2399
      {
2400
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2401
      }
2402
    
2403
    }//finally
2404

    
2405
  }
2406
  
2407
  
2408
  /**
2409
   * the main routine used to test the DBWriter utility.
2410
   * <p>
2411
   * Usage: java DocumentImpl <-f filename -a action -d docid>
2412
   *
2413
   * @param filename the filename to be loaded into the database
2414
   * @param action the action to perform (READ, INSERT, UPDATE, DELETE)
2415
   * @param docid the id of the document to process
2416
   */
2417
  static public void main(String[] args) {
2418
    DBConnection dbconn = null;
2419
    int serialNumber = -1;
2420
    try {
2421
      String filename    = null;
2422
      String dtdfilename = null;
2423
      String action      = null;
2424
      String docid       = null;
2425
      boolean showRuntime = false;
2426
      boolean useOldReadAlgorithm = false;
2427

    
2428
      // Parse the command line arguments
2429
      for ( int i=0 ; i < args.length; ++i ) {
2430
        if ( args[i].equals( "-f" ) ) {
2431
          filename =  args[++i];
2432
        } else if ( args[i].equals( "-r" ) ) {
2433
          dtdfilename =  args[++i];
2434
        } else if ( args[i].equals( "-a" ) ) {
2435
          action =  args[++i];
2436
        } else if ( args[i].equals( "-d" ) ) {
2437
          docid =  args[++i];
2438
        } else if ( args[i].equals( "-t" ) ) {
2439
          showRuntime = true;
2440
        } else if ( args[i].equals( "-old" ) ) {
2441
          useOldReadAlgorithm = true;
2442
        } else {
2443
          System.err.println
2444
            ( "   args[" +i+ "] '" +args[i]+ "' ignored." );
2445
        }
2446
      }
2447
      
2448
      // Check if the required arguments are provided
2449
      boolean argsAreValid = false;
2450
      if (action != null) {
2451
        if (action.equals("INSERT")) {
2452
          if (filename != null) {
2453
            argsAreValid = true;
2454
          } 
2455
        } else if (action.equals("UPDATE")) {
2456
          if ((filename != null) && (docid != null)) {
2457
            argsAreValid = true;
2458
          } 
2459
        } else if (action.equals("DELETE")) {
2460
          if (docid != null) {
2461
            argsAreValid = true;
2462
          } 
2463
        } else if (action.equals("READ")) {
2464
          if (docid != null) {
2465
            argsAreValid = true;
2466
          } 
2467
        } 
2468
      } 
2469

    
2470
      // Print usage message if the arguments are not valid
2471
      if (!argsAreValid) {
2472
        System.err.println("Wrong number of arguments!!!");
2473
        System.err.println(
2474
          "USAGE: java DocumentImpl [-t] <-a INSERT> [-d docid] <-f filename> "+
2475
          "[-r dtdfilename]");
2476
        System.err.println(
2477
          "   OR: java DocumentImpl [-t] <-a UPDATE -d docid -f filename> " +
2478
          "[-r dtdfilename]");
2479
        System.err.println(
2480
          "   OR: java DocumentImpl [-t] <-a DELETE -d docid>");
2481
        System.err.println(
2482
          "   OR: java DocumentImpl [-t] [-old] <-a READ -d docid>");
2483
        return;
2484
      }
2485
      
2486
      // Time the request if asked for
2487
      double startTime = System.currentTimeMillis();
2488
      
2489
      // Open a connection to the database
2490
      MetaCatUtil util = new MetaCatUtil();
2491
     
2492
      dbconn=DBConnectionPool.getDBConnection("DocumentImpl.main");
2493
      serialNumber=dbconn.getCheckOutSerialNumber();
2494

    
2495
      double connTime = System.currentTimeMillis();
2496
      // Execute the action requested (READ, INSERT, UPDATE, DELETE)
2497
      if (action.equals("READ")) {
2498
          DocumentImpl xmldoc = new DocumentImpl(docid );
2499
          if (useOldReadAlgorithm) {
2500
            System.out.println(xmldoc.readUsingSlowAlgorithm());
2501
          } else {
2502
            xmldoc.toXml(new PrintWriter(System.out));
2503
          }
2504
      } else if (action.equals("DELETE")) {
2505
        DocumentImpl.delete(docid, null, null);
2506
        System.out.println("Document deleted: " + docid);
2507
      } else {
2508
        /*String newdocid = DocumentImpl.write(dbconn, filename, null,
2509
                                             dtdfilename, action, docid,
2510
                                             null, null);
2511
        if ((docid != null) && (!docid.equals(newdocid))) {
2512
          if (action.equals("INSERT")) {
2513
            System.out.println("New document ID generated!!! ");
2514
          } else if (action.equals("UPDATE")) {
2515
            System.out.println("ERROR: Couldn't update document!!! ");
2516
          }
2517
        } else if ((docid == null) && (action.equals("UPDATE"))) {
2518
          System.out.println("ERROR: Couldn't update document!!! ");
2519
        }
2520
        System.out.println("Document processing finished for: " + filename
2521
              + " (" + newdocid + ")");*/
2522
      }
2523

    
2524
      double stopTime = System.currentTimeMillis();
2525
      double dbOpenTime = (connTime - startTime)/1000;
2526
      double insertTime = (stopTime - connTime)/1000;
2527
      double executionTime = (stopTime - startTime)/1000;
2528
      if (showRuntime) {
2529
        System.out.println("\n\nTotal Execution time was: " + 
2530
                           executionTime + " seconds.");
2531
        System.out.println("Time to open DB connection was: " + dbOpenTime + 
2532
                           " seconds.");
2533
        System.out.println("Time to insert document was: " + insertTime +
2534
                           " seconds.");
2535
      }
2536
      dbconn.close();
2537
    } catch (McdbException me) {
2538
      me.toXml(new PrintWriter(System.err));
2539
    } catch (AccessionNumberException ane) {
2540
      System.out.println(ane.getMessage());
2541
    } catch (Exception e) {
2542
      System.err.println("EXCEPTION HANDLING REQUIRED");
2543
      System.err.println(e.getMessage());
2544
      e.printStackTrace(System.err);
2545
    }
2546
    finally
2547
    {
2548
      // Return db connection
2549
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
2550
    }
2551
  }
2552
}
(27-27/48)