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: sgarg $'
10
 *     '$Date: 2004-07-22 15:29:13 -0700 (Thu, 22 Jul 2004) $'
11
 * '$Revision: 2224 $'
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.io.BufferedInputStream;
31
import java.io.BufferedOutputStream;
32
import java.io.File;
33
import java.io.FileOutputStream;
34
import java.io.IOException;
35
import java.io.InputStream;
36
import java.io.PrintWriter;
37
import java.io.Reader;
38
import java.io.StringWriter;
39
import java.io.Writer;
40
import java.net.URL;
41
import java.sql.PreparedStatement;
42
import java.sql.ResultSet;
43
import java.sql.SQLException;
44
import java.util.Enumeration;
45
import java.util.Hashtable;
46
import java.util.Iterator;
47
import java.util.Stack;
48
import java.util.TreeSet;
49
import java.util.Vector;
50

    
51
import edu.ucsb.nceas.dbadapter.AbstractDatabase;
52

    
53
import org.xml.sax.ContentHandler;
54
import org.xml.sax.DTDHandler;
55
import org.xml.sax.EntityResolver;
56
import org.xml.sax.ErrorHandler;
57
import org.xml.sax.InputSource;
58
import org.xml.sax.XMLReader;
59
import org.xml.sax.helpers.XMLReaderFactory;
60

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

    
68
   /* Constants */
69
   public static final String SCHEMA                 = "Schema";
70
   public static final String DTD                    = "DTD";
71
   public static final String EML200                 = "eml200";
72
   public static final String EML210                 = "eml210";
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
      " http://www.xml-cml.org/schema/stmml http://dev.nceas.ucsb.edu/tao/schema/stmml.xsd";*/
78
   public static final String DECLARATIONHANDLERPROPERTY =
79
                            "http://xml.org/sax/properties/declaration-handler";
80
   public static final String LEXICALPROPERTY =
81
                             "http://xml.org/sax/properties/lexical-handler";
82
   public static final String VALIDATIONFEATURE =
83
                             "http://xml.org/sax/features/validation";
84
   public static final String SCHEMAVALIDATIONFEATURE =
85
                             "http://apache.org/xml/features/validation/schema";
86
   public static final String NAMESPACEFEATURE =
87
                              "http://xml.org/sax/features/namespaces";
88
   public static final String NAMESPACEPREFIXESFEATURE =
89
                              "http://xml.org/sax/features/namespace-prefixes";
90
   public static final String EML2_1_0NAMESPACE =
91
                                         MetaCatUtil.getOption("eml2_1_0namespace");
92
                                         // "eml://ecoinformatics.org/eml-2.1.0";
93
   public static final String EML2_0_1NAMESPACE =
94
                                         MetaCatUtil.getOption("eml2_0_1namespace");
95
                                         // "eml://ecoinformatics.org/eml-2.0.1";
96
   public static final String EML2_0_0NAMESPACE =
97
                                         MetaCatUtil.getOption("eml2_0_0namespace");
98
                                         // "eml://ecoinformatics.org/eml-2.0.0";
99

    
100

    
101
  public static final String DOCNAME = "docname";
102
  public static final String PUBLICID = "publicid";
103
  public static final String SYSTEMID = "systemid";
104
  static final int ALL = 1;
105
  static final int WRITE = 2;
106
  static final int READ = 4;
107
  private static final AbstractDatabase dbAdapter = MetaCatUtil.dbAdapter;
108

    
109
  private DBConnection connection = null;
110
  private String docid = null;
111
  private String updatedVersion=null;
112
  private String docname = null;
113
  private String doctype = null;
114
  private String validateType = null; //base on dtd or schema
115
// DOCTITLE attr cleared from the db
116
//  private String doctitle = null;
117
  private String createdate = null;
118
  private String updatedate = null;
119
  private String system_id = null;
120
  private String userowner = null;
121
  private String userupdated = null;
122
  private int rev;
123
  private int serverlocation;
124
  private String docHomeServer;
125
  private String publicaccess;
126
  private long rootnodeid;
127
  private ElementNode rootNode = null;
128
  private TreeSet nodeRecordList = null;
129
  //private static
130
  //ReplicationServerList serverList = new ReplicationServerList();
131

    
132
  /**
133
   * Constructor used to create a document and read the document information
134
   * from the database.  If readNodes is false, then the node data is not
135
   * read at this time, but is deferred until it is needed (such as when a
136
   * call to toXml() is made).
137
   *
138
   * @param conn the database connection from which to read the document
139
   * @param docid the identifier of the document to be created
140
   * @param readNodes flag indicating whether the xmlnodes should be read
141
   */
142
  public DocumentImpl(String docid, boolean readNodes)
143
         throws McdbException
144
  {
145
    try {
146
      //this.conn = conn;
147
      this.docid = docid;
148

    
149
      // Look up the document information
150
      getDocumentInfo(docid);
151

    
152
      if (readNodes) {
153
        // Download all of the document nodes using a single SQL query
154
        // The sort order of the records is determined by the NodeComparator
155
        // class, and needs to represent a depth-first traversal for the
156
        // toXml() method to work properly
157
        nodeRecordList = getNodeRecordList(rootnodeid);
158

    
159
      }
160

    
161
    } catch (McdbException ex) {
162
      throw ex;
163
    } catch (Throwable t) {
164
      throw new McdbException("Error reading document from " +
165
                              "DocumentImpl.DocumentImpl: " + docid);
166
    }
167
  }
168

    
169
  /**
170
   * Constructor, creates document from database connection, used
171
   * for reading the document
172
   *
173
   * @param conn the database connection from which to read the document
174
   * @param docid the identifier of the document to be created
175
   */
176
  public DocumentImpl(String docid) throws McdbException
177
  {
178
    this(docid, true);
179
  }
180

    
181

    
182

    
183
  /**
184
   * Construct a new document instance, writing the contents to the database.
185
   * This method is called from DBSAXHandler because we need to know the
186
   * root element name for documents without a DOCTYPE before creating it.
187
   *
188
   * In this constructor, the docid is without rev. There is a string rev to
189
   * specify the revision user want to upadate. The revion is only need to be
190
   * greater than current one. It is not need to be sequent number just after
191
   * current one. So it is only used in update action
192
   * @param conn the JDBC Connection to which all information is written
193
   * @param rootnodeid - sequence id of the root node in the document
194
   * @param docname - the name of DTD, i.e. the name immediately following
195
   *        the DOCTYPE keyword ( should be the root element name ) or
196
   *        the root element name if no DOCTYPE declaration provided
197
   *        (Oracle's and IBM parsers are not aware if it is not the
198
   *        root element name)
199
   * @param doctype - Public ID of the DTD, i.e. the name immediately
200
   *                  following the PUBLIC keyword in DOCTYPE declaration or
201
   *                  the docname if no Public ID provided or
202
   *                  null if no DOCTYPE declaration provided
203
   * @param docid the docid to use for the UPDATE, no version number
204
   * @param version, need to be update
205
   * @param action the action to be performed (INSERT OR UPDATE)
206
   * @param user the user that owns the document
207
   * @param pub flag for public "read" access on document
208
   * @param serverCode the serverid from xml_replication on which this document
209
   *        resides.
210
   *
211
   */
212
  public DocumentImpl(DBConnection conn, long rootNodeId, String docName,
213
                      String docType, String docId, String newRevision,
214
                      String action, String user,
215
                      String pub, String catalogId, int serverCode)
216
                      throws SQLException, Exception
217
  {
218
    this.connection = conn;
219
    this.rootnodeid = rootNodeId;
220
    this.docname = docName;
221
    this.doctype = docType;
222
    this.docid = docId;
223
    this.updatedVersion = newRevision;
224
    writeDocumentToDB(action, user, pub, catalogId, serverCode);
225
  }
226

    
227
  /**
228
   * This method will be call in handleUploadRequest in MetacatServlet class
229
   */
230
  public static void registerDocument(
231
                     String docname, String doctype, String accnum, String user)
232
                     throws SQLException, AccessionNumberException, Exception
233
  {
234

    
235
    try
236
    {
237
       // get server location for this doc
238
      int serverLocation=getServerLocationNumber(accnum);
239
      registerDocument(docname, doctype,accnum, user, serverLocation);
240
    }
241
    catch (Exception e)
242
    {
243
      throw e;
244
    }
245

    
246

    
247
  }
248
  /**
249
   * Register a document that resides on the filesystem with the database.
250
   * (ie, just an entry in xml_documents, nothing in xml_nodes).
251
   * Creates a reference to a filesystem document (used for non-xml data files).
252
   * This class only be called in MetaCatServerlet.
253
   * @param conn the JDBC Connection to which all information is written
254
   * @param docname - the name of DTD, i.e. the name immediately following
255
   *        the DOCTYPE keyword ( should be the root element name ) or
256
   *        the root element name if no DOCTYPE declaration provided
257
   *        (Oracle's and IBM parsers are not aware if it is not the
258
   *        root element name)
259
   * @param doctype - Public ID of the DTD, i.e. the name immediately
260
   *                  following the PUBLIC keyword in DOCTYPE declaration or
261
   *                  the docname if no Public ID provided or
262
   *                  null if no DOCTYPE declaration provided
263
   * @param accnum the accession number to use for the INSERT OR UPDATE, which
264
   *               includes a revision number for this revision of the document
265
   *               (e.g., knb.1.1)
266
   * @param user the user that owns the document
267
   * @param serverCode the serverid from xml_replication on which this document
268
   *        resides.
269
   */
270
  public static void registerDocument(
271
                     String docname, String doctype, String accnum,
272
                     String user, int serverCode)
273
                     throws SQLException, AccessionNumberException, Exception
274
  {
275
    DBConnection dbconn = null;
276
    int serialNumber = -1;
277
    PreparedStatement pstmt = null;
278
    //MetaCatUtil util = new MetaCatUtil();
279
    AccessionNumber ac;
280
    String action = null;
281
    try {
282
      //dbconn = util.openDBConnection();
283
      //check out DBConnection
284
      dbconn=DBConnectionPool.
285
                    getDBConnection("DocumentImpl.registerDocument");
286
      serialNumber=dbconn.getCheckOutSerialNumber();
287
      String docIdWithoutRev=MetaCatUtil.getDocIdFromString(accnum);
288
      int userSpecifyRev=MetaCatUtil.getVersionFromString(accnum);
289
      int revInDataBase=getLatestRevisionNumber(docIdWithoutRev);
290
      //revIndataBase=-1, there is no record in xml_documents table
291
      //the data file is a new one, inert it into table
292
      //user specified rev should be great than 0
293
      if (revInDataBase==-1 && userSpecifyRev>0 )
294
      {
295
        ac = new AccessionNumber(accnum, "insert");
296
        action = "insert";
297
      }
298
      //rev is greater the last revsion number and revInDataBase isn't -1
299
      // it is a updated data file
300
      else if (userSpecifyRev>revInDataBase && revInDataBase>0)
301
      {
302

    
303
        //archive the old entry
304
        archiveDocRevision(docIdWithoutRev, user);
305
        //delete the old entry in xml_documents
306
        //deleteXMLDocuments(docIdWithoutRev);
307
        ac = new AccessionNumber(accnum, "update");
308
        action = "update";
309
      }
310
      //other situation
311
      else
312
      {
313

    
314
        throw new Exception("Revision number couldn't be "
315
                    +userSpecifyRev);
316
      }
317
      String docid = ac.getDocid();
318
      String rev = ac.getRev();
319
      /*SimpleDateFormat formatter = new SimpleDateFormat ("MM/dd/yy HH:mm:ss");
320
      Date localtime = new Date();
321
      String dateString = formatter.format(localtime);
322
      String sqlDateString=dbAdapter.toDate(dateString, "MM/DD/YY HH24:MI:SS");*/
323
      String  sqlDateString = dbAdapter.getDateTimeFunction();
324

    
325
      StringBuffer sql = new StringBuffer();
326
      if (action != null && action.equals("insert"))
327
      {
328
        sql.append("insert into xml_documents (docid, docname, doctype, ");
329
        sql.append("user_owner, user_updated, server_location, rev,date_created");
330
        sql.append(", date_updated, public_access) values ('");
331
        sql.append(docid).append("','");
332
        sql.append(docname).append("','");
333
        sql.append(doctype).append("','");
334
        sql.append(user).append("','");
335
        sql.append(user).append("','");
336
        sql.append(serverCode).append("','");
337
        sql.append(rev).append("',");
338
        sql.append(sqlDateString).append(",");
339
        sql.append(sqlDateString).append(",");
340
        sql.append("'0')");
341
      }
342
      else if (action != null && action.equals("update"))
343
      {
344
        sql.append("update xml_documents set docname ='");
345
        sql.append(docname).append("', ");
346
        sql.append("user_updated='");
347
        sql.append(user).append("', ");
348
        sql.append("server_location='");
349
        sql.append(serverCode).append("',");
350
        sql.append("rev='");
351
        sql.append(rev).append("',");
352
        sql.append("date_updated=");
353
        sql.append(sqlDateString);
354
        sql.append(" where docid='");
355
        sql.append(docid).append("'");
356
      }
357
      pstmt = dbconn.prepareStatement(sql.toString());
358
      pstmt.execute();
359
      pstmt.close();
360
      //dbconn.close();
361
    }
362
    finally
363
    {
364
      try
365
      {
366
        pstmt.close();
367
      }
368
      finally
369
      {
370
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
371
      }
372
    }
373
  }
374

    
375
    /**
376
   * Register a document that resides on the filesystem with the database.
377
   * (ie, just an entry in xml_documents, nothing in xml_nodes).
378
   * Creates a reference to a filesystem document (used for non-xml data files)
379
   * This method will be called for register data file in xml_documents in
380
   * Replication.
381
   * This method is revised from registerDocument.
382
   *
383
   * @param conn the JDBC Connection to which all information is written
384
   * @param docname - the name of DTD, i.e. the name immediately following
385
   *        the DOCTYPE keyword ( should be the root element name ) or
386
   *        the root element name if no DOCTYPE declaration provided
387
   *        (Oracle's and IBM parsers are not aware if it is not the
388
   *        root element name)
389
   * @param doctype - Public ID of the DTD, i.e. the name immediately
390
   *                  following the PUBLIC keyword in DOCTYPE declaration or
391
   *                  the docname if no Public ID provided or
392
   *                  null if no DOCTYPE declaration provided
393
   * @param accnum the accession number to use for the INSERT OR UPDATE, which
394
   *               includes a revision number for this revision of the document
395
   *               (e.g., knb.1.1)
396
   * @param user the user that owns the document
397
   * @param serverCode the serverid from xml_replication on which this document
398
   *        resides.
399
   */
400
  public static void registerDocumentInReplication(
401
                     String docname, String doctype, String accnum,
402
                     String user, int serverCode)
403
                     throws SQLException, AccessionNumberException, Exception
404
  {
405
    DBConnection dbconn = null;
406
    int serialNumber = -1;
407
    //MetaCatUtil util = new MetaCatUtil();
408
    AccessionNumber ac;
409
    PreparedStatement pstmt = null;
410
    String action = null;
411
    try {
412
      //dbconn = util.openDBConnection();
413
       dbconn=DBConnectionPool.
414
                  getDBConnection("DocumentImpl.registerDocumentInReplication");
415
      serialNumber=dbconn.getCheckOutSerialNumber();
416
      String docIdWithoutRev=MetaCatUtil.getDocIdFromAccessionNumber(accnum);
417
      int userSpecifyRev=MetaCatUtil.getRevisionFromAccessionNumber(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
        action = "insert";
427
      }
428
      //rev is greater the last revsion number and revInDataBase isn't -1
429
      // it is a updated data file
430
      else if (userSpecifyRev>revInDataBase && revInDataBase>=0)
431
      {
432

    
433
        //archive the old entry
434
        archiveDocRevision(docIdWithoutRev, user);
435
        //delete the old entry in xml_documents
436
        //deleteXMLDocuments(docIdWithoutRev);
437
        ac = new AccessionNumber(accnum, "update");
438
        action = "update";
439
      }
440
      // local server has newer version, then notify the remote server
441
      else if ( userSpecifyRev < revInDataBase && revInDataBase > 0)
442
      {
443
        throw new Exception("Local server: "+MetaCatUtil.getOption("server")+
444
                 " has newer revision of doc: "+docIdWithoutRev+"."
445
                  +revInDataBase+". Please notify it.");
446
      }
447
      //other situation
448
      else
449
      {
450

    
451
        throw new Exception("Revision number couldn't be "
452
                    +userSpecifyRev);
453
      }
454
      String docid = ac.getDocid();
455
      String rev = ac.getRev();
456
      /*SimpleDateFormat formatter = new SimpleDateFormat ("MM/dd/yy HH:mm:ss");
457
      Date localtime = new Date();
458
      String dateString = formatter.format(localtime);
459
      String sqlDateString=dbAdapter.toDate(dateString, "MM/DD/YY HH24:MI:SS");*/
460
      String sqlDateString = dbAdapter.getDateTimeFunction();
461

    
462
      StringBuffer sql = new StringBuffer();
463
      if (action != null && action.equals("insert"))
464
      {
465
        sql.append("insert into xml_documents (docid, docname, doctype, ");
466
        sql.append("user_owner, user_updated, server_location, rev,date_created");
467
        sql.append(", date_updated, public_access) values ('");
468
        sql.append(docid).append("','");
469
        sql.append(docname).append("','");
470
        sql.append(doctype).append("','");
471
        sql.append(user).append("','");
472
        sql.append(user).append("','");
473
        sql.append(serverCode).append("','");
474
        sql.append(rev).append("',");
475
        sql.append(sqlDateString).append(",");
476
        sql.append(sqlDateString).append(",");
477
        sql.append("'0')");
478
      }
479
      else if (action != null && action.equals("update"))
480
      {
481
        sql.append("update xml_documents set docname ='");
482
        sql.append(docname).append("', ");
483
        sql.append("user_updated='");
484
        sql.append(user).append("', ");
485
        sql.append("server_location='");
486
        sql.append(serverCode).append("',");
487
        sql.append("rev='");
488
        sql.append(rev).append("',");
489
        sql.append("date_updated=");
490
        sql.append(sqlDateString);
491
        sql.append(" where docid='");
492
        sql.append(docid).append("'");
493
      }
494
      // Set auto commit fasle
495
      dbconn.setAutoCommit(false);
496
      pstmt = dbconn.prepareStatement(sql.toString());
497

    
498
      pstmt.execute();
499
      // Commit the insert
500
      dbconn.commit();
501
      pstmt.close();
502
      //dbconn.close();
503
    }
504
    finally
505
    {
506
      // Set DBConnection auto commit true
507
      dbconn.setAutoCommit(true);
508
      pstmt.close();
509
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
510
    }
511
  }
512

    
513
 /**
514
   * This method will register a data file entry in xml_documents and save a
515
   * data file input Stream into file system.. It is only used in replication
516
   *
517
   * @param  input, the input stream which contain the file content.
518
   * @param  , the input stream which contain the file content
519
   * @param docname - the name of DTD, for data file, it is a docid number.
520
   * @param doctype - "BIN" for data file
521
   * @param accnum the accession number to use for the INSERT OR UPDATE, which
522
   *               includes a revision number for this revision of the document
523
   *               (e.g., knb.1.1)
524
   * @param user the user that owns the document
525
   * @param docHomeServer, the home server of the docid
526
   * @param notificationServer, the server to notify force replication info to
527
   *                            local metacat
528
   */
529
 public static void writeDataFileInReplication(InputStream input,
530
                 String filePath, String docname, String doctype, String accnum,
531
                   String user, String docHomeServer, String notificationServer)
532
                     throws SQLException, AccessionNumberException, Exception
533
 {
534
    int serverCode=-2;
535

    
536

    
537
    if (filePath==null||filePath.equals(""))
538
    {
539
      throw new
540
            Exception("Please specify the directory where file will be store");
541
    }
542
    if (accnum==null||accnum.equals(""))
543
    {
544
      throw new Exception("Please specify the stored file name");
545
    }
546

    
547

    
548

    
549
    // If server is not int the xml replication talbe, insert it into
550
    // xml_replication table
551
    //serverList.addToServerListIfItIsNot(docHomeServer);
552
    insertServerIntoReplicationTable(docHomeServer);
553

    
554
    // Get server code again
555
    serverCode = getServerCode(docHomeServer);
556

    
557

    
558
    //register data file into xml_documents table
559
    registerDocumentInReplication(docname, doctype, accnum, user, serverCode);
560
    //write inputstream into file system.
561
    File dataDirectory = new File(filePath);
562
    File newFile = new File(dataDirectory, accnum);
563

    
564
    // create a buffered byte output stream
565
    // that uses a default-sized output buffer
566
    FileOutputStream fos = new FileOutputStream(newFile);
567
    BufferedOutputStream outPut = new BufferedOutputStream(fos);
568

    
569
    BufferedInputStream bis = null;
570
    bis = new BufferedInputStream(input);
571
    byte[] buf = new byte[4 * 1024]; // 4K buffer
572
    int b = bis.read(buf);
573

    
574
    while (b != -1)
575
    {
576
        outPut.write(buf, 0, b);
577
        b = bis.read(buf);
578
    }
579
    bis.close();
580
          outPut.close();
581
          fos.close();
582

    
583
    // Force replicate data file
584
    ForceReplicationHandler forceReplication = new ForceReplicationHandler
585
                                    (accnum, false, notificationServer);
586

    
587
 }
588

    
589

    
590

    
591
  public static boolean getDataFileLockGrant(String accnum)
592
                                                  throws Exception
593
  {
594

    
595
    try
596
    {
597

    
598
      int serverLocation=getServerLocationNumber(accnum);
599

    
600
      return getDataFileLockGrant(accnum,serverLocation);
601
    }
602
    catch (Exception e)
603
    {
604

    
605
      throw e;
606
    }
607
  }
608

    
609
  /**
610
   * The method will check if metacat can get data file lock grant
611
   * If server code is 1, it get.
612
   * If server code is not 1 but call replication getlock successfully,
613
   * it get
614
   * else, it didn't get
615
   * @param accnum, the ID of the document
616
   * @param action, the action to the document
617
   * @param serverCode, the server location code
618
   */
619
  public static boolean getDataFileLockGrant(String accnum, int serverCode)
620
                                          throws Exception
621
  {
622
    boolean flag=true;
623
    //MetaCatUtil util = new MetaCatUtil();
624
    String docid = MetaCatUtil.getDocIdFromString(accnum);
625
    int rev = MetaCatUtil.getVersionFromString(accnum);
626

    
627
    if (serverCode == 1)
628
    {
629
      flag=true;
630
      return flag;
631
    }
632

    
633
    //if((serverCode != 1 && action.equals("UPDATE")) )
634
    if (serverCode != 1)
635
    { //if this document being written is not a resident of this server then
636
      //we need to try to get a lock from it's resident server.  If the
637
      //resident server will not give a lock then we send the user a message
638
      //saying that he/she needs to download a new copy of the file and
639
      //merge the differences manually.
640

    
641
      String server=MetacatReplication.getServerNameForServerCode(serverCode);
642
      MetacatReplication.replLog("attempting to lock " + accnum);
643
      URL u = new URL("https://" + server + "?server=" +
644
        MetaCatUtil.getLocalReplicationServerName()+"&action=getlock&updaterev="
645
           +rev + "&docid=" + docid);
646
      //System.out.println("sending message: " + u.toString());
647
      String serverResStr = MetacatReplication.getURLContent(u);
648
      String openingtag =serverResStr.substring(0, serverResStr.indexOf(">")+1);
649
      if(openingtag.equals("<lockgranted>"))
650
      {
651
        //the lock was granted go ahead with the insert
652
        //System.out.println("In lockgranted");
653
        MetacatReplication.replLog("lock granted for " + accnum + " from " +
654
                                      server);
655
        flag=true;
656
        return flag;
657
      }//if
658

    
659
      else if(openingtag.equals("<filelocked>"))
660
      {//the file is currently locked by another user
661
       //notify our user to wait a few minutes, check out a new copy and try
662
       //again.
663
        //System.out.println("file locked");
664
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
665
                                   server + " reason: file already locked");
666
        throw new Exception("The file specified is already locked by another " +
667
                            "user.  Please wait 30 seconds, checkout the " +
668
                            "newer document, merge your changes and try " +
669
                            "again.");
670
      }
671
      else if(openingtag.equals("<outdatedfile>"))
672
      {//our file is outdated.  notify our user to check out a new copy of the
673
       //file and merge his version with the new version.
674
        //System.out.println("outdated file");
675
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
676
                                    server + " reason: local file outdated");
677
        throw new Exception("The file you are trying to update is an outdated" +
678
                            " version.  Please checkout the newest document, " +
679
                            "merge your changes and try again.");
680
      }//else if
681
    }//if
682

    
683
   return flag;
684

    
685
  }//getDataFileLockGrant
686

    
687
  /**
688
   * get the document name
689
   */
690
  public String getDocname() {
691
    return docname;
692
  }
693

    
694
  /**
695
   * get the document type (which is the PublicID)
696
   */
697
  public String getDoctype() {
698
    return doctype;
699
  }
700

    
701
  /**
702
   * get the system identifier
703
   */
704
  public String getSystemID() {
705
    return system_id;
706
  }
707

    
708
  /**
709
   * get the root node identifier
710
   */
711
  public long getRootNodeID() {
712
    return rootnodeid;
713
  }
714

    
715
  /**
716
   * get the creation date
717
   */
718
  public String getCreateDate() {
719
    return createdate;
720
  }
721

    
722
  /**
723
   * get the update date
724
   */
725
  public String getUpdateDate() {
726
    return updatedate;
727
  }
728

    
729
  /**
730
   * Get the document identifier (docid)
731
   */
732
  public String getDocID() {
733
    return docid;
734
  }
735

    
736
// DOCTITLE attr cleared from the db
737
//  /**
738
//   *get the document title
739
//   */
740
//  public String getDocTitle() {
741
//    return doctitle;
742
//  }
743

    
744
  public String getUserowner() {
745
    return userowner;
746
  }
747

    
748
  public String getUserupdated() {
749
    return userupdated;
750
  }
751

    
752
  public int getServerlocation() {
753
    return serverlocation;
754
  }
755

    
756
  public String getDocHomeServer() {
757
    return docHomeServer;
758
  }
759

    
760

    
761

    
762
  public String getPublicaccess() {
763
    return publicaccess;
764
  }
765

    
766
  public int getRev() {
767
    return rev;
768
  }
769

    
770
  public String getValidateType()
771
  {
772
    return validateType;
773
  }
774

    
775
  /**
776
   * Print a string representation of the XML document
777
   */
778
  public String toString(String user, String[] groups, boolean withInlinedata)
779
  {
780
    StringWriter docwriter = new StringWriter();
781
    try
782
    {
783
      this.toXml(docwriter, user, groups, withInlinedata);
784
    }
785
    catch (McdbException mcdbe)
786
    {
787
      return null;
788
    }
789
    String document = docwriter.toString();
790
    return document;
791
  }
792

    
793
   /**
794
   * Print a string representation of the XML document
795
   */
796
  public String toString()
797
  {
798
    StringWriter docwriter = new StringWriter();
799
    String userName = null;
800
    String[] groupNames = null;
801
    boolean withInlineData = false;
802
    try
803
    {
804
      this.toXml(docwriter, userName, groupNames, withInlineData);
805
    }
806
    catch (McdbException mcdbe)
807
    {
808
      return null;
809
    }
810
    String document = docwriter.toString();
811
    return document;
812
  }
813

    
814
  /**
815
   * Get a text representation of the XML document as a string
816
   * This older algorithm uses a recursive tree of Objects to represent the
817
   * nodes of the tree.  Each object is passed the data for the document
818
   * and searches all of the document data to find its children nodes and
819
   * recursively build.  Thus, because each node reads the whole document,
820
   * this algorithm is extremely slow for larger documents, and the time
821
   * to completion is O(N^N) wrt the number of nodes.  See toXml() for a
822
   * better algorithm.
823
   */
824
  public String readUsingSlowAlgorithm() throws McdbException
825
  {
826
    StringBuffer doc = new StringBuffer();
827

    
828
    // First, check that we have the needed node data, and get it if not
829
    if (nodeRecordList == null) {
830
      nodeRecordList = getNodeRecordList(rootnodeid);
831
    }
832

    
833
    // Create the elements from the downloaded data in the TreeSet
834
    rootNode = new ElementNode(nodeRecordList, rootnodeid);
835

    
836
    // Append the resulting document to the StringBuffer and return it
837
    doc.append("<?xml version=\"1.0\"?>\n");
838

    
839
    if (docname != null) {
840
      if ((doctype != null) && (system_id != null)) {
841
        doc.append("<!DOCTYPE " + docname + " PUBLIC \"" + doctype +
842
                   "\" \"" + system_id + "\">\n");
843
      } else {
844
        doc.append("<!DOCTYPE " + docname + ">\n");
845
      }
846
    }
847
    doc.append(rootNode.toString());
848

    
849
    return (doc.toString());
850
  }
851

    
852
  /**
853
   * Print a text representation of the XML document to a Writer
854
   *
855
   * @param pw the Writer to which we print the document
856
   */
857
  public void toXml(Writer pw, String user, String[] groups, boolean withInLineData)
858
                                                          throws McdbException
859
  {
860
    // flag for process  eml2
861
    boolean proccessEml2 = false;
862
    boolean storedDTD = false;//flag to inidate publicid or system
863
                              // id stored in db or not
864
    boolean firstElement = true;
865
    String dbDocName = null;
866
    String dbPublicID = null;
867
    String dbSystemID = null;
868

    
869
    if (doctype != null && doctype.equals(EML2_0_0NAMESPACE))
870
    {
871
      proccessEml2 = true;
872
    }
873
    // flag for process inline data
874
    boolean prcocessInlineData = false;
875

    
876
    TreeSet nodeRecordLists = null;
877
    PrintWriter out = null;
878
    if (pw instanceof PrintWriter) {
879
      out = (PrintWriter)pw;
880
    } else {
881
      out = new PrintWriter(pw);
882
    }
883

    
884
    MetaCatUtil util = new MetaCatUtil();
885

    
886
    // Here add code to handle subtree access control
887
    PermissionController control = new PermissionController(docid);
888
    Hashtable unaccessableSubTree =control.hasUnaccessableSubTree(user, groups,
889
                                             AccessControlInterface.READSTRING);
890

    
891
    if (!unaccessableSubTree.isEmpty())
892
    {
893

    
894
      nodeRecordLists = getPartNodeRecordList(rootnodeid, unaccessableSubTree);
895

    
896
    }
897
    else
898
    {
899
      nodeRecordLists = getNodeRecordList(rootnodeid);
900
    }
901

    
902
    Stack openElements = new Stack();
903
    boolean atRootElement = true;
904
    boolean previousNodeWasElement = false;
905

    
906
    // Step through all of the node records we were given
907

    
908
    Iterator it = nodeRecordLists.iterator();
909

    
910
    while (it.hasNext())
911
    {
912

    
913
      NodeRecord currentNode = (NodeRecord)it.next();
914
      util.debugMessage("[Got Node ID: " + currentNode.nodeid +
915
                          " (" + currentNode.parentnodeid +
916
                          ", " + currentNode.nodeindex +
917
                          ", " + currentNode.nodetype +
918
                          ", " + currentNode.nodename +
919
                          ", " + currentNode.nodedata + ")]", 50);
920
      // Print the end tag for the previous node if needed
921
      //
922
      // This is determined by inspecting the parent nodeid for the
923
      // currentNode.  If it is the same as the nodeid of the last element
924
      // that was pushed onto the stack, then we are still in that previous
925
      // parent element, and we do nothing.  However, if it differs, then we
926
      // have returned to a level above the previous parent, so we go into
927
      // a loop and pop off nodes and print out their end tags until we get
928
      // the node on the stack to match the currentNode parentnodeid
929
      //
930
      // So, this of course means that we rely on the list of elements
931
      // having been sorted in a depth first traversal of the nodes, which
932
      // is handled by the NodeComparator class used by the TreeSet
933
      if (!atRootElement) {
934
        NodeRecord currentElement = (NodeRecord)openElements.peek();
935
        if ( currentNode.parentnodeid != currentElement.nodeid ) {
936
          while ( currentNode.parentnodeid != currentElement.nodeid ) {
937
            currentElement = (NodeRecord)openElements.pop();
938
            util.debugMessage("\n POPPED: " + currentElement.nodename, 50);
939
            if (previousNodeWasElement) {
940
              out.print(">");
941
              previousNodeWasElement = false;
942
            }
943
            if ( currentElement.nodeprefix != null ) {
944
              out.print("</" + currentElement.nodeprefix + ":" +
945
                        currentElement.nodename + ">" );
946
            } else {
947
              out.print("</" + currentElement.nodename + ">" );
948
            }
949
            currentElement = (NodeRecord)openElements.peek();
950
          }
951
        }
952
      }
953

    
954
      // Handle the DOCUMENT node
955
      if (currentNode.nodetype.equals("DOCUMENT")) {
956
        out.print("<?xml version=\"1.0\"?>");
957

    
958

    
959
      // Handle the ELEMENT nodes
960
      } else if (currentNode.nodetype.equals("ELEMENT")) {
961
        if (atRootElement) {
962
          atRootElement = false;
963
        } else {
964
          if (previousNodeWasElement) {
965
            out.print(">");
966
          }
967
        }
968

    
969
        // if publicid or system is not stored into db send it out by default
970
        if ( !storedDTD & firstElement )
971
        {
972
           if (docname != null && validateType != null && validateType.equals(DTD))
973
           {
974
              if ((doctype != null) && (system_id != null))
975
              {
976

    
977
                  out.print("<!DOCTYPE " + docname + " PUBLIC \"" + doctype +
978
                       "\" \"" + system_id + "\">");
979
               }
980
               else
981
               {
982

    
983
                  out.print("<!DOCTYPE " + docname + ">");
984
               }
985
           }
986
        }
987
        firstElement = false;
988
        openElements.push(currentNode);
989
        util.debugMessage("\n PUSHED: " + currentNode.nodename, 50);
990
        previousNodeWasElement = true;
991
        if ( currentNode.nodeprefix != null ) {
992
          out.print("<" + currentNode.nodeprefix + ":" + currentNode.nodename);
993
        } else {
994
          out.print("<" + currentNode.nodename);
995
        }
996

    
997
        // if currentNode is inline and handle eml2, set flag proccess in
998
        if (currentNode.nodename != null &&
999
            currentNode.nodename.equals(Eml200SAXHandler.INLINE) && proccessEml2)
1000
        {
1001
          prcocessInlineData = true;
1002
        }
1003

    
1004
      // Handle the ATTRIBUTE nodes
1005
      } else if (currentNode.nodetype.equals("ATTRIBUTE")) {
1006
        if ( currentNode.nodeprefix != null ) {
1007
          out.print(" " + currentNode.nodeprefix + ":" + currentNode.nodename +
1008
                    "=\"" + currentNode.nodedata + "\"");
1009
        } else {
1010
          out.print(" " + currentNode.nodename + "=\"" +
1011
                    currentNode.nodedata + "\"");
1012
        }
1013

    
1014
      // Handle the NAMESPACE nodes
1015
      } else if (currentNode.nodetype.equals("NAMESPACE")) {
1016
        out.print(" xmlns:" + currentNode.nodename + "=\""
1017
                 + currentNode.nodedata + "\"");
1018

    
1019
      // Handle the TEXT nodes
1020
      } else if (currentNode.nodetype.equals("TEXT")) {
1021
        if (previousNodeWasElement) {
1022
          out.print(">");
1023
        }
1024
        if (!prcocessInlineData || !withInLineData)
1025
        {
1026
          // if it is not inline data just out put data or it is line data
1027
          // but user don't want it, just put local id in inlinedata
1028
          out.print(currentNode.nodedata);
1029
        }
1030
        else
1031
        {
1032
          // if it is inline data and user want to see it, pull out from
1033
          // file system and output it
1034
          // for inline data, the data base only store the file name, so we
1035
          // can combine the file name and inline data file path, to get it
1036
          String fileName = currentNode.nodedata;
1037
          Reader reader =
1038
                        Eml200SAXHandler.readInlineDataFromFileSystem(fileName);
1039
          char [] characterArray = new char [4*1024];
1040
          try
1041
          {
1042
            int length = reader.read(characterArray);
1043
            while ( length != -1)
1044
            {
1045
              out.print(new String(characterArray, 0, length));
1046
              out.flush();
1047
              length = reader.read(characterArray);
1048
            }
1049
            reader.close();
1050
          }
1051
          catch (IOException e)
1052
          {
1053
            throw new McdbException(e.getMessage());
1054
          }
1055
        }
1056

    
1057
        // reset proccess inline data false
1058
        prcocessInlineData =false;
1059
        previousNodeWasElement = false;
1060

    
1061
      // Handle the COMMENT nodes
1062
      } else if (currentNode.nodetype.equals("COMMENT")) {
1063
        if (previousNodeWasElement) {
1064
          out.print(">");
1065
        }
1066
        out.print("<!--" + currentNode.nodedata + "-->");
1067
        previousNodeWasElement = false;
1068

    
1069
      // Handle the PI nodes
1070
      } else if (currentNode.nodetype.equals("PI")) {
1071
        if (previousNodeWasElement) {
1072
          out.print(">");
1073
        }
1074
        out.print("<?" + currentNode.nodename + " " +
1075
                        currentNode.nodedata + "?>");
1076
        previousNodeWasElement = false;
1077
     // Handle the DTD nodes (docname, publicid, systemid)
1078
     } else if (currentNode.nodetype.equals(DTD)) {
1079
         storedDTD = true;
1080
         if (currentNode.getNodeName().equals(DOCNAME))
1081
         {
1082
           dbDocName = currentNode.getNodeData();
1083
         }
1084
         if (currentNode.getNodeName().equals(PUBLICID))
1085
         {
1086
           dbPublicID = currentNode.getNodeData();
1087
         }
1088
         if (currentNode.getNodeName().equals(SYSTEMID))
1089
         {
1090
           dbSystemID = currentNode.getNodeData();
1091
           // send out <!doctype .../>
1092
           if (dbDocName != null )
1093
           {
1094
              if ((dbPublicID!= null) && (dbSystemID != null))
1095
              {
1096

    
1097
                 out.print("<!DOCTYPE " + dbDocName+" PUBLIC \""+dbPublicID +
1098
                       "\" \"" + dbSystemID + "\">");
1099
              }
1100
              else
1101
              {
1102

    
1103
                out.print("<!DOCTYPE " + dbDocName + ">");
1104
              }
1105
           }
1106

    
1107
           //reset these variable
1108
           dbDocName = null;
1109
           dbPublicID = null;
1110
           dbSystemID = null;
1111
         }
1112

    
1113
      // Handle any other node type (do nothing)
1114
      } else {
1115
        // Any other types of nodes are not handled.
1116
        // Probably should throw an exception here to indicate this
1117
      }
1118
      out.flush();
1119
    }
1120

    
1121
    // Print the final end tag for the root element
1122
    while(!openElements.empty())
1123
    {
1124
      NodeRecord currentElement = (NodeRecord)openElements.pop();
1125
      util.debugMessage("\n POPPED: " + currentElement.nodename, 50);
1126
      if ( currentElement.nodeprefix != null ) {
1127
        out.print("</" + currentElement.nodeprefix + ":" +
1128
                  currentElement.nodename + ">" );
1129
      } else {
1130
        out.print("</" + currentElement.nodename + ">" );
1131
      }
1132
    }
1133
    out.flush();
1134
  }
1135

    
1136

    
1137

    
1138
  private boolean isRevisionOnly(DocumentIdentifier docid) throws Exception
1139
  {
1140
    //System.out.println("inRevisionOnly");
1141
    DBConnection dbconn = null;
1142
    int serialNumber = -1;
1143
    PreparedStatement pstmt =null;
1144
    String rev = docid.getRev();
1145
    String newid = docid.getIdentifier();
1146
    try
1147
    {
1148
      dbconn=DBConnectionPool.
1149
                    getDBConnection("DocumentImpl.isRevisionOnly");
1150
      serialNumber=dbconn.getCheckOutSerialNumber();
1151
      pstmt = dbconn.prepareStatement("select rev from xml_documents " +
1152
                                  "where docid like '" + newid + "'");
1153
      pstmt.execute();
1154
      ResultSet rs = pstmt.getResultSet();
1155
      boolean tablehasrows = rs.next();
1156
      if(rev.equals("newest") || rev.equals("all"))
1157
      {
1158
        return false;
1159
      }
1160

    
1161
      if(tablehasrows)
1162
      {
1163
        int r = rs.getInt(1);
1164
        pstmt.close();
1165
        if(new Integer(rev).intValue() == r)
1166
        { //the current revision in in xml_documents
1167
          //System.out.println("returning false");
1168
          return false;
1169
        }
1170
        else if(new Integer(rev).intValue() < r)
1171
        { //the current revision is in xml_revisions.
1172
          //System.out.println("returning true");
1173
          return true;
1174
        }
1175
        else if(new Integer(rev).intValue() > r)
1176
        { //error, rev cannot be greater than r
1177
          throw new Exception("requested revision cannot be greater than " +
1178
                            "the latest revision number.");
1179
        }
1180
      }
1181
      // Get miss docid and rev, throw to McdDocNotFoundException
1182
      String missDocId = MetaCatUtil.getDocIdFromString(docid.toString());
1183
      String missRevision =
1184
                  MetaCatUtil.getRevisionStringFromString(docid.toString());
1185
      throw new McdbDocNotFoundException("the requested docid '" +
1186
                docid.toString() + "' does not exist", missDocId, missRevision);
1187
    }//try
1188
    finally
1189
    {
1190
      pstmt.close();
1191
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1192
    }//finally
1193
  }
1194

    
1195
  private void getDocumentInfo(String docid) throws McdbException,
1196
                                        AccessionNumberException, Exception
1197
  {
1198
    getDocumentInfo(new DocumentIdentifier(docid));
1199
  }
1200

    
1201
  /**
1202
   * Look up the document type information from the database
1203
   *
1204
   * @param docid the id of the document to look up
1205
   */
1206
  private void getDocumentInfo(DocumentIdentifier docid) throws McdbException
1207
                                                          , Exception
1208
  {
1209
    DBConnection dbconn = null;
1210
    int serialNumber = -1;
1211
    PreparedStatement pstmt = null;
1212
    String table = "xml_documents";
1213

    
1214
    try
1215
    {
1216
      if(isRevisionOnly(docid))
1217
      { //pull the document from xml_revisions instead of from xml_documents;
1218
        table = "xml_revisions";
1219
      }
1220
    }
1221
    // catch a McdbDocNotFoundException throw it
1222
    catch (McdbDocNotFoundException notFound)
1223
    {
1224
      throw notFound;
1225
    }
1226
    catch(Exception e)
1227
    {
1228

    
1229
      MetaCatUtil.debugMessage("error in DocumentImpl.getDocumentInfo: " +
1230
                          e.getMessage(), 30);
1231
      throw e;
1232
    }
1233

    
1234

    
1235

    
1236
    try
1237
    {
1238
      dbconn=DBConnectionPool.getDBConnection("DocumentImpl.getDocumentInfo");
1239
      serialNumber=dbconn.getCheckOutSerialNumber();
1240
      StringBuffer sql = new StringBuffer();
1241
// DOCTITLE attr cleared from the db
1242
//      sql.append("SELECT docname, doctype, rootnodeid, doctitle, ");
1243
      sql.append("SELECT docname, doctype, rootnodeid, ");
1244
      sql.append("date_created, date_updated, user_owner, user_updated, ");
1245
      sql.append("server_location, public_access, rev");
1246
      sql.append(" FROM ").append(table);
1247
      sql.append(" WHERE docid LIKE '").append(docid.getIdentifier());
1248
      sql.append("' and rev like '").append(docid.getRev()).append("'");
1249
      //System.out.println(sql.toString());
1250
      pstmt =
1251
        dbconn.prepareStatement(sql.toString());
1252
      // Bind the values to the query
1253
      //pstmt.setString(1, docid.getIdentifier());
1254
      //pstmt.setString(2, docid.getRev());
1255

    
1256
      pstmt.execute();
1257
      ResultSet rs = pstmt.getResultSet();
1258
      boolean tableHasRows = rs.next();
1259
      if (tableHasRows) {
1260
        this.docname        = rs.getString(1);
1261
        this.doctype        = rs.getString(2);
1262
        this.rootnodeid     = rs.getLong(3);
1263
// DOCTITLE attr cleared from the db
1264
//        this.doctitle       = rs.getString(4);
1265
        this.createdate     = rs.getString(4);
1266
        this.updatedate     = rs.getString(5);
1267
        this.userowner      = rs.getString(6);
1268
        this.userupdated    = rs.getString(7);
1269
        this.serverlocation = rs.getInt(8);
1270
        this.publicaccess   = rs.getString(9);
1271
        this.rev            = rs.getInt(10);
1272
      }
1273
      pstmt.close();
1274

    
1275
      //get doc  home server name
1276

    
1277
      pstmt = dbconn.prepareStatement("select server " +
1278
                        "from xml_replication where serverid = ?");
1279
      //because connection use twise here, so we need to increase one
1280
      dbconn.increaseUsageCount(1);
1281
      pstmt.setInt(1, serverlocation);
1282
      pstmt.execute();
1283
      rs = pstmt.getResultSet();
1284
      tableHasRows = rs.next();
1285
      if (tableHasRows)
1286
      {
1287

    
1288
          String server = rs.getString(1);
1289
          //get homeserver name
1290
          if(!server.equals("localhost"))
1291
          {
1292
            this.docHomeServer=server;
1293
          }
1294
          else
1295
          {
1296
            this.docHomeServer=MetaCatUtil.getLocalReplicationServerName();
1297
          }
1298
          MetaCatUtil.debugMessage("server: "+docHomeServer, 50);
1299

    
1300
      }
1301
      pstmt.close();
1302
      if (this.doctype != null) {
1303
        pstmt =
1304
          dbconn.prepareStatement("SELECT system_id, entry_type " +
1305
                                  "FROM xml_catalog " +
1306
                                 "WHERE public_id = ?");
1307
        //should increase usage count again
1308
        dbconn.increaseUsageCount(1);
1309
        // Bind the values to the query
1310
        pstmt.setString(1, doctype);
1311

    
1312
        pstmt.execute();
1313
        rs = pstmt.getResultSet();
1314
        tableHasRows = rs.next();
1315
        if (tableHasRows) {
1316
          this.system_id  = rs.getString(1);
1317
          this.validateType = rs.getString(2);
1318

    
1319
        }
1320
        pstmt.close();
1321
      }
1322
    } catch (SQLException e) {
1323
      System.out.println("error in DocumentImpl.getDocumentInfo: " +
1324
                          e.getMessage());
1325
      e.printStackTrace(System.out);
1326
      throw new McdbException("Error accessing database connection in " +
1327
                              "DocumentImpl.getDocumentInfo: ", e);
1328
    }
1329
    finally
1330
    {
1331
      try
1332
      {
1333
        pstmt.close();
1334
      }
1335
      catch (SQLException ee)
1336
      {
1337
        MetaCatUtil.debugMessage("error in DocumentImple.getDocumentInfo: "
1338
                                    +ee.getMessage(), 30);
1339
      }//catch
1340
      finally
1341
      {
1342
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1343
      }
1344
    }
1345

    
1346
    if (this.docname == null) {
1347
      throw new McdbDocNotFoundException("Document not found: " + docid,
1348
                                 docid.getIdentifier(), docid.getRev());
1349
    }
1350
  }
1351

    
1352
  /**
1353
   * Look up the node data from the database, but some node would be shown
1354
   * because of access control
1355
   * @param rootnodeid the id of the root node of the node tree to look up
1356
   * @param accessControl  the hashtable has control info
1357
   */
1358
  private TreeSet getPartNodeRecordList(long rootnodeid,
1359
                                        Hashtable accessControl)
1360
                                        throws McdbException
1361
  {
1362
    PreparedStatement pstmt = null;
1363
    DBConnection dbconn = null;
1364
    int serialNumber = -1;
1365
    TreeSet nodeRecordList = new TreeSet(new NodeComparator());
1366
    long nodeid = 0;
1367
    long parentnodeid = 0;
1368
    long nodeindex = 0;
1369
    String nodetype = null;
1370
    String nodename = null;
1371
    String nodeprefix = null;
1372
    String nodedata = null;
1373
    String quotechar = dbAdapter.getStringDelimiter();
1374
    String sql = "SELECT nodeid,parentnodeid,nodeindex, " +
1375
                 "nodetype,nodename,nodeprefix,nodedata " +
1376
                  "FROM xml_nodes WHERE rootnodeid = ?";
1377

    
1378
    // go through the access control for some nodes
1379
     Enumeration en = accessControl.elements();
1380
     while (en.hasMoreElements())
1381
     {
1382
         SubTree tree = (SubTree)en.nextElement();
1383
         long startId = tree.getStartNodeId();
1384
         long endId  = tree.getEndNodeId();
1385
         sql = sql +" AND(nodeid < " + startId + " OR nodeid > " +endId +")";
1386

    
1387
     }
1388
     MetaCatUtil.debugMessage("The final query to select part node tree: " +
1389
                              sql, 25);
1390

    
1391
    try
1392
    {
1393
      dbconn=DBConnectionPool.
1394
                    getDBConnection("DocumentImpl.getPartNodeRecordList");
1395
      serialNumber=dbconn.getCheckOutSerialNumber();
1396
      pstmt = dbconn.prepareStatement(sql);
1397

    
1398
      // Bind the values to the query
1399
      pstmt.setLong(1, rootnodeid);
1400
      pstmt.execute();
1401
      ResultSet rs = pstmt.getResultSet();
1402
      boolean tableHasRows = rs.next();
1403
      while (tableHasRows)
1404
      {
1405
        nodeid = rs.getLong(1);
1406
        parentnodeid = rs.getLong(2);
1407
        nodeindex = rs.getLong(3);
1408
        nodetype = rs.getString(4);
1409
        nodename = rs.getString(5);
1410
        nodeprefix = rs.getString(6);
1411
        nodedata = rs.getString(7);
1412
        nodedata = MetaCatUtil.normalize(nodedata);
1413
        // add the data to the node record list hashtable
1414
        NodeRecord currentRecord = new NodeRecord(nodeid,parentnodeid,nodeindex,
1415
                                      nodetype, nodename, nodeprefix, nodedata);
1416
        nodeRecordList.add(currentRecord);
1417

    
1418
        // Advance to the next node
1419
        tableHasRows = rs.next();
1420
      }
1421
      pstmt.close();
1422

    
1423
    }
1424
    catch (SQLException e)
1425
    {
1426
      throw new McdbException("Error in DocumentImpl.getPartNodeRecordList " +
1427
                              e.getMessage());
1428
    }
1429
    finally
1430
    {
1431
      try
1432
      {
1433
        pstmt.close();
1434
      }
1435
      catch (SQLException ee)
1436
      {
1437
        MetaCatUtil.debugMessage("error in DocumentImpl.getPartNodeRecordList: "
1438
                                    +ee.getMessage(), 30);
1439
      }
1440
      finally
1441
      {
1442
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1443
      }
1444
    }
1445

    
1446

    
1447
    if (!nodeRecordList.isEmpty())
1448
    {
1449

    
1450
      return nodeRecordList;
1451
    }
1452
    else
1453
    {
1454

    
1455
      throw new McdbException("Error getting node data: " + docid);
1456
    }
1457
  }
1458

    
1459
  /**
1460
   * Look up the node data from the database
1461
   *
1462
   * @param rootnodeid the id of the root node of the node tree to look up
1463
   */
1464
  private TreeSet getNodeRecordList(long rootnodeid) throws McdbException
1465
  {
1466
    PreparedStatement pstmt = null;
1467
    DBConnection dbconn = null;
1468
    int serialNumber = -1;
1469
    TreeSet nodeRecordList = new TreeSet(new NodeComparator());
1470
    long nodeid = 0;
1471
    long parentnodeid = 0;
1472
    long nodeindex = 0;
1473
    String nodetype = null;
1474
    String nodename = null;
1475
    String nodeprefix = null;
1476
    String nodedata = null;
1477
    String quotechar = dbAdapter.getStringDelimiter();
1478

    
1479
    try {
1480
      dbconn=DBConnectionPool.
1481
                    getDBConnection("DocumentImpl.getNodeRecordList");
1482
      serialNumber=dbconn.getCheckOutSerialNumber();
1483
      pstmt =
1484
      dbconn.prepareStatement("SELECT nodeid,parentnodeid,nodeindex, " +
1485
           "nodetype,nodename,nodeprefix,nodedata " +
1486
           "FROM xml_nodes WHERE rootnodeid = ?");
1487

    
1488
      // Bind the values to the query
1489
      pstmt.setLong(1, rootnodeid);
1490

    
1491
      pstmt.execute();
1492
      ResultSet rs = pstmt.getResultSet();
1493
      boolean tableHasRows = rs.next();
1494
      while (tableHasRows) {
1495
        nodeid = rs.getLong(1);
1496
        parentnodeid = rs.getLong(2);
1497
        nodeindex = rs.getLong(3);
1498
        nodetype = rs.getString(4);
1499
        nodename = rs.getString(5);
1500
        nodeprefix = rs.getString(6);
1501
        nodedata = rs.getString(7);
1502
        nodedata = MetaCatUtil.normalize(nodedata);
1503
        // add the data to the node record list hashtable
1504
        NodeRecord currentRecord = new NodeRecord(nodeid,parentnodeid,nodeindex,
1505
                                      nodetype, nodename, nodeprefix, nodedata);
1506
        nodeRecordList.add(currentRecord);
1507

    
1508
        // Advance to the next node
1509
        tableHasRows = rs.next();
1510
      }
1511
      pstmt.close();
1512

    
1513
    } catch (SQLException e) {
1514
      throw new McdbException("Error in DocumentImpl.getNodeRecordList " +
1515
                              e.getMessage());
1516
    }
1517
    finally
1518
    {
1519
      try
1520
      {
1521
        pstmt.close();
1522
      }
1523
      catch (SQLException ee)
1524
      {
1525
        MetaCatUtil.debugMessage("error in DocumentImpl.getNodeRecordList: "
1526
                                    +ee.getMessage(), 30);
1527
      }
1528
      finally
1529
      {
1530
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1531
      }
1532
    }
1533

    
1534
    return nodeRecordList;
1535

    
1536
  }
1537

    
1538
// NOT USED ANY MORE
1539
//  /** creates SQL code and inserts new document into DB connection
1540
//   default serverCode of 1*/
1541
//  private void writeDocumentToDB(String action, String user)
1542
//               throws SQLException, Exception
1543
//  {
1544
//    writeDocumentToDB(action, user, null, 1);
1545
//  }
1546

    
1547
 /** creates SQL code and inserts new document into DB connection */
1548
  private void writeDocumentToDB(String action, String user, String pub,
1549
                                 String catalogid, int serverCode)
1550
               throws SQLException, Exception {
1551
    String sysdate = dbAdapter.getDateTimeFunction();
1552

    
1553
    try {
1554
      PreparedStatement pstmt = null;
1555

    
1556
      if (action.equals("INSERT")) {
1557
        //AccessionNumber ac = new AccessionNumber();
1558
        //this.docid = ac.generate(docid, "INSERT");
1559

    
1560
        pstmt = connection.prepareStatement(
1561
                "INSERT INTO xml_documents " +
1562
                "(docid, rootnodeid, docname, doctype, " +
1563
                "user_owner, user_updated, date_created, date_updated, " +
1564
                "public_access, catalog_id, server_location, rev) " +
1565
                "VALUES (?, ?, ?, ?, ?, ?, " + sysdate + ", " + sysdate +
1566
                ", ?, ?, ?, ?)");
1567
        // Increase dbconnection usage count
1568
        connection.increaseUsageCount(1);
1569

    
1570
        //note that the server_location is set to 1.
1571
        //this means that "localhost" in the xml_replication table must
1572
        //always be the first entry!!!!!
1573

    
1574
        // Bind the values to the query
1575
        pstmt.setString(1, this.docid);
1576
        pstmt.setLong(2, rootnodeid);
1577
        pstmt.setString(3, docname);
1578
        pstmt.setString(4, doctype);
1579
        pstmt.setString(5, user);
1580
        pstmt.setString(6, user);
1581
        //public access is usefulless, so set it to null
1582
        pstmt.setString(7, null);
1583
        /*if ( pub == null ) {
1584
          pstmt.setString(7, null);
1585
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
1586
          pstmt.setInt(7, 1);
1587
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
1588
          pstmt.setInt(7, 0);
1589
        }*/
1590
        pstmt.setString(8, catalogid);
1591
        pstmt.setInt(9, serverCode);
1592
        pstmt.setInt(10, Integer.parseInt(updatedVersion));
1593
      } else if (action.equals("UPDATE")) {
1594

    
1595
        // Save the old document publicaccessentry in a backup table
1596
        DocumentImpl.archiveDocRevision(connection, docid, user );
1597
        MetaCatUtil.debugMessage("after archiveDoc", 40);
1598
        DocumentImpl thisdoc = new DocumentImpl(docid, false);
1599
        int thisrev = thisdoc.getRev();
1600
        MetaCatUtil.debugMessage("this revsion is: "+thisrev, 40);
1601
        //if the updated vesion is not greater than current one,
1602
        //throw it into a exception
1603
        if (Integer.parseInt(updatedVersion)<=thisrev)
1604
        {
1605
          throw new Exception("Next revision number couldn't be less"
1606
                               +" than or equal "+ thisrev);
1607
        }
1608
        else
1609
        {
1610
          //set the user specified revision
1611
          thisrev=Integer.parseInt(updatedVersion);
1612
        }
1613
        MetaCatUtil.debugMessage("final revsion is: "+thisrev, 40);
1614
        boolean useXMLIndex =
1615
            (new Boolean(MetaCatUtil.getOption("usexmlindex"))).booleanValue();
1616
        if (useXMLIndex) {
1617
            MetaCatUtil.debugMessage("before delete", 40);
1618
            // Delete index for the old version of docid
1619
            // The new index is inserting on the next calls to DBSAXNode
1620
            pstmt = connection.prepareStatement(
1621
                    "DELETE FROM xml_index WHERE docid='" + this.docid + "'");
1622
            MetaCatUtil.debugMessage("after delete", 40);
1623
            // Increase dbconnection usage count
1624
            connection.increaseUsageCount(1);
1625

    
1626
            pstmt.execute();
1627
            pstmt.close();
1628
        }
1629

    
1630
        // Update the new document to reflect the new node tree
1631
        pstmt = connection.prepareStatement(
1632
            "UPDATE xml_documents " +
1633
            "SET rootnodeid = ?, docname = ?, doctype = ?, " +
1634
            "user_updated = ?, date_updated = " + sysdate + ", " +
1635
            "server_location = ?, rev = ?, public_access = ?, catalog_id = ? " +
1636
            "WHERE docid = ?");
1637
        // Increase dbconnection usage count
1638
        connection.increaseUsageCount(1);
1639
        // Bind the values to the query
1640
        pstmt.setLong(1, rootnodeid);
1641
        pstmt.setString(2, docname);
1642
        pstmt.setString(3, doctype);
1643
        pstmt.setString(4, user);
1644
        pstmt.setInt(5, serverCode);
1645
        pstmt.setInt(6, thisrev);
1646
        pstmt.setString(7, null);
1647
        /*if ( pub == null ) {
1648
          pstmt.setString(7, null);
1649
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
1650
          pstmt .setInt(7, 1);
1651
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
1652
          pstmt.setInt(7, 0);
1653
        }*/
1654
        pstmt.setString(8, catalogid);
1655
        pstmt.setString(9, this.docid);
1656

    
1657
      } else {
1658
        System.err.println("Action not supported: " + action);
1659
      }
1660

    
1661
      // Do the insertion
1662
      pstmt.execute();
1663

    
1664
      pstmt.close();
1665

    
1666
    } catch (SQLException sqle) {
1667
      throw sqle;
1668
    } catch (Exception e) {
1669
      throw e;
1670
    }
1671
  }
1672

    
1673
  /**
1674
   * Write an XML file to the database, given a filename
1675
   *
1676
   * @param conn the JDBC connection to the database
1677
   * @param filename the filename to be loaded into the database
1678
   * @param pub flag for public "read" access on document
1679
   * @param dtdfilename the dtd to be uploaded on server's file system
1680
   * @param action the action to be performed (INSERT OR UPDATE)
1681
   * @param docid the docid to use for the INSERT OR UPDATE
1682
   * @param user the user that owns the document
1683
   * @param groups the groups to which user belongs
1684
   */
1685
  /*public static String write(DBConnection conn,String filename,
1686
                             String pub, String dtdfilename,
1687
                             String action, String docid, String user,
1688
                             String[] groups )
1689
                throws Exception {
1690

    
1691
    Reader dtd = null;
1692
    if ( dtdfilename != null ) {
1693
      dtd = new FileReader(new File(dtdfilename).toString());
1694
    }
1695
    return write ( conn, new FileReader(new File(filename).toString()),
1696
                   pub, dtd, action, docid, user, groups, false);
1697
  }*/
1698

    
1699
  public static String write(DBConnection conn,Reader xml,String pub,Reader dtd,
1700
                             String action, String docid, String user,
1701
                             String[] groups, String ruleBase,
1702
                             boolean needValidation)
1703
                throws Exception {
1704
    //this method will be called in handleUpdateOrInsert method
1705
    //in MetacatServlet class and now is wrapper into documentImple
1706
    // get server location for this doc
1707
    int serverLocation=getServerLocationNumber(docid);
1708
    return write(conn,xml,pub,dtd,action,docid,user,groups,serverLocation,false,
1709
                 ruleBase, needValidation);
1710
  }
1711

    
1712

    
1713

    
1714
  /**
1715
   * Write an XML file to the database, given a Reader
1716
   *
1717
   * @param conn the JDBC connection to the database
1718
   * @param xml the xml stream to be loaded into the database
1719
   * @param pub flag for public "read" access on xml document
1720
   * @param dtd the dtd to be uploaded on server's file system
1721
   * @param action the action to be performed (INSERT or UPDATE)
1722
   * @param accnum the docid + rev# to use on INSERT or UPDATE
1723
   * @param user the user that owns the document
1724
   * @param groups the groups to which user belongs
1725
   * @param serverCode the serverid from xml_replication on which this document
1726
   *        resides.
1727
   * @param override flag to stop insert replication checking.
1728
   *        if override = true then a document not belonging to the local server
1729
   *        will not be checked upon update for a file lock.
1730
   *        if override = false then a document not from this server, upon
1731
   *        update will be locked and version checked.
1732
   */
1733

    
1734
  public static String write(DBConnection conn, Reader xml,String pub,
1735
                         Reader dtd, String action, String accnum, String user,
1736
                         String[] groups, int serverCode, boolean override,
1737
                         String ruleBase, boolean needValidation)
1738
                throws Exception
1739
  {
1740
    // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1741
    //MetaCatUtil util = new MetaCatUtil();
1742
    MetaCatUtil.debugMessage("conn usage count before writting: "
1743
                                      +conn.getUsageCount(), 50);
1744
    AccessionNumber ac = new AccessionNumber(accnum, action);
1745
    String docid = ac.getDocid();
1746
    String rev = ac.getRev();
1747
    MetaCatUtil.debugMessage("action: " + action + " servercode: " +
1748
                             serverCode + " override: " + override, 10);
1749

    
1750
    if((serverCode != 1 && action.equals("UPDATE")) && !override)
1751
    { //if this document being written is not a resident of this server then
1752
      //we need to try to get a lock from it's resident server.  If the
1753
      //resident server will not give a lock then we send the user a message
1754
      //saying that he/she needs to download a new copy of the file and
1755
      //merge the differences manually.
1756
      int istreamInt;
1757
      char istreamChar;
1758

    
1759
      // check for 'write' permission for 'user' to update this document
1760
      if ( !hasWritePermission(user, groups, accnum) ) {
1761
        throw new Exception("User " + user +
1762
              " does not have permission to update XML Document #" + accnum);
1763
      }
1764

    
1765
      DocumentIdentifier id = new DocumentIdentifier(accnum);
1766
      String updaterev = id.getRev();
1767
      String server=MetacatReplication.getServerNameForServerCode(serverCode);
1768
      MetacatReplication.replLog("attempting to lock " + accnum);
1769
      URL u = new URL("https://" + server + "?server="+
1770
        MetaCatUtil.getLocalReplicationServerName()+"&action=getlock&updaterev="
1771
           +updaterev + "&docid=" + docid);
1772
      //System.out.println("sending message: " + u.toString());
1773
      String serverResStr = MetacatReplication.getURLContent(u);
1774
      String openingtag =serverResStr.substring(0, serverResStr.indexOf(">")+1);
1775
      if(openingtag.equals("<lockgranted>"))
1776
      {//the lock was granted go ahead with the insert
1777
        XMLReader parser = null;
1778
        try
1779
        {
1780
          //System.out.println("In lockgranted");
1781
          MetacatReplication.replLog("lock granted for " + accnum + " from " +
1782
                                      server);
1783
          /*XMLReader parser = initializeParser(conn, action, docid, updaterev,
1784
                               validate, user, groups, pub, serverCode, dtd);*/
1785
          parser = initializeParser(conn, action, docid, updaterev,
1786
                                        user, groups, pub, serverCode,
1787
                                        dtd,ruleBase, needValidation);
1788
          conn.setAutoCommit(false);
1789
          parser.parse(new InputSource(xml));
1790
          conn.commit();
1791
          conn.setAutoCommit(true);
1792
        }
1793
        catch (Exception e)
1794
        {
1795
          conn.rollback();
1796
          conn.setAutoCommit(true);
1797
          //if it is a eml2 document, we need delete online data
1798
          if ( parser != null)
1799
          {
1800
            ContentHandler handler = parser.getContentHandler();
1801
            if (handler instanceof Eml200SAXHandler)
1802
            {
1803
              Eml200SAXHandler eml = (Eml200SAXHandler) handler;
1804
              eml.deleteInlineFiles();
1805
            }
1806
          }
1807
          throw e;
1808
        }
1809
        // run write into access db base one relation table and access object
1810
        runRelationAndAccessHandler(accnum, user, groups, serverCode);
1811

    
1812
        // Force replication the docid
1813
        ForceReplicationHandler frh = new ForceReplicationHandler
1814
                                                          (accnum, true, null);
1815
        return(accnum);
1816

    
1817
      }
1818

    
1819
      else if(openingtag.equals("<filelocked>"))
1820
      {//the file is currently locked by another user
1821
       //notify our user to wait a few minutes, check out a new copy and try
1822
       //again.
1823
        //System.out.println("file locked");
1824
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1825
                                   server + " reason: file already locked");
1826
        throw new Exception("The file specified is already locked by another " +
1827
                            "user.  Please wait 30 seconds, checkout the " +
1828
                            "newer document, merge your changes and try " +
1829
                            "again.");
1830
      }
1831
      else if(openingtag.equals("<outdatedfile>"))
1832
      {//our file is outdated.  notify our user to check out a new copy of the
1833
       //file and merge his version with the new version.
1834
        //System.out.println("outdated file");
1835
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1836
                                    server + " reason: local file outdated");
1837
        throw new Exception("The file you are trying to update is an outdated" +
1838
                            " version.  Please checkout the newest document, " +
1839
                            "merge your changes and try again.");
1840
      }
1841
    }
1842

    
1843
    if ( action.equals("UPDATE") ) {
1844
      // check for 'write' permission for 'user' to update this document
1845

    
1846
      if ( !hasWritePermission(user, groups, accnum) ) {
1847
        throw new Exception("User " + user +
1848
              " does not have permission to update XML Document #" + accnum);
1849
      }
1850
    }
1851
    XMLReader parser = null;
1852
    try
1853
    {
1854

    
1855
      parser = initializeParser(conn, action, docid, rev,
1856
                                          user, groups, pub, serverCode,
1857
                                          dtd, ruleBase, needValidation);
1858

    
1859
      conn.setAutoCommit(false);
1860
      parser.parse(new InputSource(xml));
1861
      conn.commit();
1862
      conn.setAutoCommit(true);
1863
    }
1864
    catch (Exception e)
1865
    {
1866
      conn.rollback();
1867
      conn.setAutoCommit(true);
1868
       //if it is a eml2 document, we need delete online data
1869
       if ( parser != null)
1870
       {
1871
          ContentHandler handler = parser.getContentHandler();
1872
          if (handler instanceof Eml200SAXHandler)
1873
          {
1874
            Eml200SAXHandler eml = (Eml200SAXHandler) handler;
1875
            eml.deleteInlineFiles();
1876
          }
1877
       }
1878
      throw e;
1879
    }
1880

    
1881
    // run access db base on relation table and access object
1882
    runRelationAndAccessHandler(accnum, user, groups, serverCode);
1883

    
1884
    // Force replicate out the new document to each server in our server list.
1885
    // Start the thread to replicate this new document out to the other servers
1886
    // true mean it is xml document
1887
    // null is because no metacat notify the force replication.
1888
    ForceReplicationHandler frh = new ForceReplicationHandler
1889
                                                  (accnum, action, true, null);
1890

    
1891

    
1892
    MetaCatUtil.debugMessage("Conn Usage count after writting: "
1893
                                                      +conn.getUsageCount(),50);
1894
    return(accnum);
1895
  }
1896

    
1897
  /**
1898
   * Write an XML file to the database during replication
1899
   *
1900
   * @param conn the JDBC connection to the database
1901
   * @param xml the xml stream to be loaded into the database
1902
   * @param pub flag for public "read" access on xml document
1903
   * @param dtd the dtd to be uploaded on server's file system
1904
   * @param action the action to be performed (INSERT or UPDATE)
1905
   * @param accnum the docid + rev# to use on INSERT or UPDATE
1906
   * @param user the user that owns the document
1907
   * @param groups the groups to which user belongs
1908
   * @param homeServer the name of server which the document origanlly create
1909
   * @param validate, if the xml document is valid or not
1910
   * @param notifyServer, the server which notify local server the force
1911
   *                       replication command
1912
   */
1913

    
1914
  public static String writeReplication(DBConnection conn, Reader xml,
1915
                                        String pub, Reader dtd, String action,
1916
                                        String accnum, String user,
1917
                                        String[] groups,String homeServer,
1918
                                        String notifyServer,
1919
                                        String ruleBase, boolean needValidation)
1920
                                        throws Exception
1921
  {
1922
    MetaCatUtil.debugMessage("user in replication"+ user, 30);
1923
    // Docid without revision
1924
    String docid=MetaCatUtil.getDocIdFromAccessionNumber(accnum);
1925
    // Revision specified by user (int)
1926
    int userSpecifyRev=MetaCatUtil.getRevisionFromAccessionNumber(accnum);
1927
    MetaCatUtil.debugMessage("The user specifyRev: " + userSpecifyRev, 30);
1928
    // Revision for this docid in current database
1929
    int revInDataBase=getLatestRevisionNumber(docid);
1930
    MetaCatUtil.debugMessage("The rev in data base: "+revInDataBase, 30);
1931
    // String to store the revision
1932
    String rev = null;
1933

    
1934

    
1935
    //revIndataBase=-1, there is no record in xml_documents table
1936
    //the document is a new one for local server, inert it into table
1937
    //user specified rev should be great than 0
1938
    if (revInDataBase==-1 && userSpecifyRev>=0 )
1939
    {
1940
        // rev equals user specified
1941
        rev=(new Integer(userSpecifyRev)).toString();
1942
        // action should be INSERT
1943
        action = "INSERT";
1944
    }
1945
    //rev is greater the last revsion number and revInDataBase isn't -1
1946
    // it is a updated  file
1947
    else if (userSpecifyRev>revInDataBase && revInDataBase>=0)
1948
    {
1949
       // rev equals user specified
1950
       rev=(new Integer(userSpecifyRev)).toString();
1951
       // action should be update
1952
       action = "UPDATE";
1953
    }
1954
    // local server has newer version, then notify the remote server
1955
    else if ( userSpecifyRev < revInDataBase && revInDataBase > 0)
1956
    {
1957
      throw new Exception("Local server: "+MetaCatUtil.getOption("server")+
1958
                " has newer revision of doc: "+docid+"."+revInDataBase
1959
                 +". Please notify it.");
1960
    }
1961
    //other situation
1962
    else
1963
    {
1964

    
1965
        throw new Exception("The docid"+docid+"'s revision number couldn't be "
1966
                    +userSpecifyRev);
1967
    }
1968
    // Variable to store homeserver code
1969
    int serverCode=-2;
1970

    
1971
     // If server is not int the xml replication talbe, insert it into
1972
    // xml_replication table
1973
    //serverList.addToServerListIfItIsNot(homeServer);
1974
    insertServerIntoReplicationTable(homeServer);
1975
    // Get server code again
1976
    serverCode = getServerCode(homeServer);
1977

    
1978

    
1979
    MetaCatUtil.debugMessage("Document "+docid+"."+rev+" "+action+ " into local"
1980
                               +" metacat with servercode: "+ serverCode, 10);
1981

    
1982

    
1983
    // insert into xml_nodes table
1984
    XMLReader parser = null;
1985
    try
1986
    {
1987

    
1988
      parser = initializeParser(conn, action, docid, rev,
1989
                                          user, groups, pub, serverCode, dtd,
1990
                                          ruleBase, needValidation);
1991
      conn.setAutoCommit(false);
1992
      parser.parse(new InputSource(xml));
1993
      conn.commit();
1994
      conn.setAutoCommit(true);
1995
    }
1996
    catch (Exception e)
1997
    {
1998
      conn.rollback();
1999
      conn.setAutoCommit(true);
2000
      if ( parser != null)
2001
      {
2002
          ContentHandler handler = parser.getContentHandler();
2003
          if (handler instanceof Eml200SAXHandler)
2004
          {
2005
            Eml200SAXHandler eml = (Eml200SAXHandler) handler;
2006
            eml.deleteInlineFiles();
2007
          }
2008
       }
2009
      throw e;
2010
    }
2011

    
2012
    // run write into access db base on relation table and access rule
2013
    try
2014
    {
2015
      runRelationAndAccessHandler(accnum, user, groups, serverCode);
2016
    }
2017
    catch (Exception ee)
2018
    {
2019
      MetacatReplication.replErrorLog("Failed to " +
2020
                                       "create access " +
2021
                                       "rule for package: " + accnum +
2022
                                       " because " +ee.getMessage());
2023
      MetaCatUtil.debugMessage("Failed to  " +
2024
                                       "create access " +
2025
                                       "rule for package: "+ accnum +
2026
                                       " because " +ee.getMessage(), 30);
2027
    }
2028
    //Force replication to other server
2029
    ForceReplicationHandler forceReplication = new ForceReplicationHandler
2030
                                  (accnum, action, true, notifyServer);
2031

    
2032

    
2033
    return(accnum);
2034
  }
2035

    
2036
  /* Running write record to xml_relation and xml_access*/
2037
  private static void runRelationAndAccessHandler(String accnumber,
2038
                                                  String userName,
2039
                                                  String[]group, int servercode)
2040
                                                   throws Exception
2041
  {
2042
    DBConnection dbconn = null;
2043
    int serialNumber = -1;
2044
    PreparedStatement pstmt =null;
2045
    String documenttype = getDocTypeFromDBForCurrentDocument(accnumber);
2046
    try
2047
    {
2048
      String packagedoctype = MetaCatUtil.getOption("packagedoctype");
2049
      Vector packagedoctypes = new Vector();
2050
      packagedoctypes = MetaCatUtil.getOptionList(packagedoctype);
2051
      String docIdWithoutRev = MetaCatUtil.getDocIdFromString(accnumber);
2052
      if (documenttype != null && packagedoctypes.contains(documenttype) )
2053
      {
2054
        dbconn=DBConnectionPool.
2055
           getDBConnection("DocumentImpl.runRelationAndAccessHandeler");
2056
        serialNumber=dbconn.getCheckOutSerialNumber();
2057
        dbconn.setAutoCommit(false);
2058
        // from the relations get the access file id for that package
2059
        String aclid = RelationHandler.getAccessFileID(docIdWithoutRev);
2060
        // if there are access file, write ACL for that package
2061
        if ( aclid != null )
2062
        {
2063
          runAccessControlList(dbconn, aclid, userName, group, servercode);
2064
        }
2065
        dbconn.commit();
2066
        dbconn.setAutoCommit(true);
2067
      }
2068
        // if it is an access file
2069
      else if ( documenttype != null && MetaCatUtil.getOptionList(
2070
                 MetaCatUtil.getOption("accessdoctype")).contains(documenttype))
2071
      {
2072
        dbconn=DBConnectionPool.
2073
           getDBConnection("DocumentImpl.runRelationAndAccessHandeler");
2074
        serialNumber=dbconn.getCheckOutSerialNumber();
2075
        dbconn.setAutoCommit(false);
2076
        // write ACL for the package
2077
        runAccessControlList(dbconn, docIdWithoutRev,
2078
                             userName, group, servercode);
2079
        dbconn.commit();
2080
        dbconn.setAutoCommit(true);
2081

    
2082
      }
2083

    
2084
    }
2085
    catch (Exception e)
2086
    {
2087
      if( dbconn != null)
2088
      {
2089
        dbconn.rollback();
2090
        dbconn.setAutoCommit(true);
2091
      }
2092
      MetaCatUtil.debugMessage("Error in DocumentImple.runRelationAndAccessHandler " +
2093
                                e.getMessage(), 30);
2094
      throw e;
2095
    }
2096
    finally
2097
    {
2098
      if (dbconn != null)
2099
      {
2100
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
2101
      }
2102
    }//
2103
  }
2104

    
2105
  // It runs in xmlIndex thread. It writes ACL for a package.
2106
  private static void runAccessControlList (DBConnection conn, String aclid,
2107
                                    String users, String[]group, int servercode)
2108
                                                throws Exception
2109
  {
2110
    // read the access file from xml_nodes
2111
    // parse the access file and store the access info into xml_access
2112
    AccessControlList aclobj =
2113
    new AccessControlList(conn, aclid, users, group, servercode);
2114

    
2115
  }
2116

    
2117
  /* Method get document type from db*/
2118
  private static String getDocTypeFromDBForCurrentDocument(String accnumber)
2119
                                                  throws SQLException
2120
  {
2121
    String docoumentType = null;
2122
    String docid = null;
2123
    PreparedStatement pstate = null;
2124
    ResultSet rs = null;
2125
    String sql = "SELECT doctype FROM xml_documents where docid = ?";
2126
    DBConnection dbConnection = null;
2127
    int serialNumber = -1;
2128
    try
2129
    {
2130
      //get rid of revision number
2131
      docid = MetaCatUtil.getDocIdFromString(accnumber);
2132
      dbConnection=DBConnectionPool.
2133
           getDBConnection("DocumentImpl.getDocTypeFromDBForCurrentDoc");
2134
      serialNumber=dbConnection.getCheckOutSerialNumber();
2135
      pstate = dbConnection.prepareStatement(sql);
2136
      //bind variable
2137
      pstate.setString(1, docid);
2138
      //excute query
2139
      pstate.execute();
2140
      //handle resultset
2141
      rs = pstate.getResultSet();
2142
      if (rs.next())
2143
      {
2144
        docoumentType = rs.getString(1);
2145
      }
2146
      rs.close();
2147
      pstate.close();
2148
    }//try
2149
    catch (SQLException e)
2150
    {
2151
      MetaCatUtil.debugMessage("error in DocumentImpl."+
2152
                      "getDocTypeFromDBForCurrentDocument "+e.getMessage(), 30);
2153
      throw e;
2154
    }//catch
2155
    finally
2156
    {
2157
      pstate.close();
2158
      DBConnectionPool.returnDBConnection(dbConnection, serialNumber);
2159
    }//
2160
    MetaCatUtil.debugMessage("The current doctype from db is: "+
2161
                              docoumentType, 35);
2162
    return docoumentType;
2163
  }
2164
  /**
2165
   * Delete an XML file from the database (actually, just make it a revision
2166
   * in the xml_revisions table)
2167
   *
2168
   * @param docid the ID of the document to be deleted from the database
2169
   */
2170
  public static void delete(String accnum,
2171
                                 String user, String[] groups )
2172
                throws Exception
2173
  {
2174
    // OLD
2175
    //DocumentIdentifier id = new DocumentIdentifier(accnum);
2176
    //String docid = id.getIdentifier();
2177
    //String rev = id.getRev();
2178

    
2179
    // OLD
2180
    // Determine if the docid,rev are OK for DELETE
2181
    //AccessionNumber ac = new AccessionNumber(conn);
2182
    //docid = ac.generate(docid, rev, "DELETE");
2183
    DBConnection conn = null;
2184
    int serialNumber = -1;
2185
    PreparedStatement pstmt =null;
2186
    try
2187
    {
2188
      //check out DBConnection
2189
      conn=DBConnectionPool.
2190
                    getDBConnection("DocumentImpl.delete");
2191
      serialNumber=conn.getCheckOutSerialNumber();
2192

    
2193
      // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
2194
      AccessionNumber ac = new AccessionNumber(accnum, "DELETE");
2195
      String docid = ac.getDocid();
2196
      String rev = ac.getRev();
2197

    
2198
      MetaCatUtil.debugMessage("Start deleting doc "+docid+ "...", 20);
2199
    // check for 'write' permission for 'user' to delete this document
2200
      if ( !hasWritePermission(user, groups, accnum) ) {
2201
        throw new Exception("User " + user +
2202
              " does not have permission to delete XML Document #" + accnum);
2203
      }
2204

    
2205
      conn.setAutoCommit(false);
2206
      // Copy the record to the xml_revisions table
2207
      DocumentImpl.archiveDocRevision(conn, docid, user );
2208

    
2209
      // Now delete it from the xml_index table
2210
      boolean useXMLIndex =
2211
          (new Boolean(MetaCatUtil.getOption("usexmlindex"))).booleanValue();
2212
      //if (useXMLIndex) {
2213
          pstmt = conn.prepareStatement("DELETE FROM xml_index WHERE docid = ?");
2214
          pstmt.setString(1,docid);
2215
          pstmt.execute();
2216
          pstmt.close();
2217
          conn.increaseUsageCount(1);
2218
      //}
2219

    
2220
      //stmt.execute("DELETE FROM xml_access WHERE docid = '" + docid + "'");
2221
      // Now delete it from xml_access table
2222
      pstmt = conn.
2223
              prepareStatement("DELETE FROM xml_access WHERE accessfileid = ?");
2224
      pstmt.setString(1, docid);
2225
      pstmt.execute();
2226
      pstmt.close();
2227
      conn.increaseUsageCount(1);
2228

    
2229
      // Delete it from relation table
2230
      pstmt = conn.
2231
               prepareStatement("DELETE FROM xml_relation WHERE docid = ?");
2232
      //increase usage count
2233
      conn.increaseUsageCount(1);
2234
      pstmt.setString(1, docid);
2235
      pstmt.execute();
2236
      pstmt.close();
2237

    
2238
      // Delete it from xml_accesssubtree table
2239
      pstmt = conn.
2240
               prepareStatement("DELETE FROM xml_accesssubtree WHERE docid = ?");
2241
      //increase usage count
2242
      conn.increaseUsageCount(1);
2243
      pstmt.setString(1, docid);
2244
      pstmt.execute();
2245
      pstmt.close();
2246

    
2247
      // Delete it from xml_doucments table
2248
      pstmt =conn.prepareStatement("DELETE FROM xml_documents WHERE docid = ?");
2249
      pstmt.setString(1, docid);
2250
      pstmt.execute();
2251
      pstmt.close();
2252
      //Usaga count increase 1
2253
      conn.increaseUsageCount(1);
2254

    
2255
      conn.commit();
2256
      conn.setAutoCommit(true);
2257
    }//try
2258
    catch (Exception e)
2259
    {
2260
      MetaCatUtil.debugMessage("error in DocumentImpl.delete: " +
2261
                                e.getMessage(), 30);
2262
      throw e;
2263
    }
2264
    finally
2265
    {
2266

    
2267
      try
2268
      {
2269
        // close preparedStatement
2270
        pstmt.close();
2271
      }//try
2272
      finally
2273
      {
2274
        //check in DBonnection
2275
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2276
      }//finally
2277
    }//finally
2278
    //IF this is a package document:
2279
    //delete all of the relations that this document created.
2280
    //if the deleted document is a package document its relations should
2281
    //no longer be active if it has been deleted from the system.
2282

    
2283
  }
2284

    
2285
  /**
2286
    * Check for "WRITE" permission on @docid for @user and/or @groups
2287
    * from DB connection
2288
    */
2289
  private static boolean hasWritePermission (String user,
2290
                                  String[] groups, String docid )
2291
                  throws SQLException, Exception
2292
  {
2293
    // Check for WRITE permission on @docid for @user and/or @groups
2294
    PermissionController controller = new PermissionController(docid);
2295
    return controller.hasPermission(user,groups,
2296
                                    AccessControlInterface.WRITESTRING);
2297
  }
2298

    
2299
  /**
2300
    * Check for "READ" permission base on docid, user and group
2301
    *@docid, the document
2302
    *@user, user name
2303
    *@group, user's group
2304
    *
2305
    */
2306
  public static boolean hasReadPermission (String user,
2307
                                  String[] groups, String docId )
2308
                  throws SQLException, Exception
2309
  {
2310
    // Check for READ permission on @docid for @user and/or @groups
2311
    PermissionController controller =
2312
                        new PermissionController(docId);
2313
    return controller.hasPermission(user,groups,
2314
                                            AccessControlInterface.READSTRING);
2315
  }
2316

    
2317

    
2318
   /**
2319
   * Set up the parser handlers for writing the document to the database
2320
   */
2321
  private static XMLReader initializeParser(DBConnection dbconn, String action,
2322
                                            String docid, String rev,
2323
                                            String user,
2324
                                            String[] groups, String pub,
2325
                                            int serverCode, Reader dtd,
2326
                                            String ruleBase,
2327
                                            boolean needValidation)
2328
                                            throws Exception
2329
  {
2330
    XMLReader parser = null;
2331
    try
2332
    {
2333
      // handler
2334
      ContentHandler chandler;
2335
      EntityResolver eresolver;
2336
      DTDHandler dtdhandler;
2337
      // Get an instance of the parser
2338
      String parserName = MetaCatUtil.getOption("saxparser");
2339
      parser = XMLReaderFactory.createXMLReader(parserName);
2340
      if (ruleBase != null && ruleBase.equals(EML200))
2341
      {
2342
        MetaCatUtil.debugMessage("eml 2.0.0 parser", 20);
2343
        chandler = new Eml200SAXHandler(dbconn, action,
2344
                                    docid, rev, user, groups, pub, serverCode);
2345
        parser.setContentHandler((ContentHandler)chandler);
2346
        parser.setErrorHandler((ErrorHandler)chandler);
2347
        parser.setProperty(DECLARATIONHANDLERPROPERTY, chandler);
2348
        parser.setProperty(LEXICALPROPERTY, chandler);
2349
        // turn on schema validation feature
2350
        parser.setFeature(VALIDATIONFEATURE, true);
2351
        parser.setFeature(NAMESPACEFEATURE, true);
2352
        //parser.setFeature(NAMESPACEPREFIXESFEATURE, true);
2353
        parser.setFeature(SCHEMAVALIDATIONFEATURE, true);
2354
        // From DB to find the register external schema location
2355
        String externalSchemaLocation = null;
2356
        SchemaLocationResolver resolver = new SchemaLocationResolver();
2357
        externalSchemaLocation = resolver.getNameSpaceAndLocationString();
2358
        // Set external schemalocation.
2359
        if (externalSchemaLocation != null &&
2360
            !(externalSchemaLocation.trim()).equals(""))
2361
        {
2362
            parser.setProperty(EXTERNALSCHEMALOCATIONPROPERTY,
2363
                             externalSchemaLocation);
2364
        }
2365
      } else if (ruleBase != null && ruleBase.equals(EML210))
2366
      {
2367
        MetaCatUtil.debugMessage("eml 2.1.0 parser", 20);
2368
        chandler = new Eml210SAXHandler(dbconn, action,
2369
                                    docid, rev, user, groups, pub, serverCode);
2370
        parser.setContentHandler((ContentHandler)chandler);
2371
        parser.setErrorHandler((ErrorHandler)chandler);
2372
        parser.setProperty(DECLARATIONHANDLERPROPERTY, chandler);
2373
        parser.setProperty(LEXICALPROPERTY, chandler);
2374
        // turn on schema validation feature
2375
        parser.setFeature(VALIDATIONFEATURE, true);
2376
        parser.setFeature(NAMESPACEFEATURE, true);
2377
        //parser.setFeature(NAMESPACEPREFIXESFEATURE, true);
2378
        parser.setFeature(SCHEMAVALIDATIONFEATURE, true);
2379
        // From DB to find the register external schema location
2380
        String externalSchemaLocation = null;
2381
        SchemaLocationResolver resolver = new SchemaLocationResolver();
2382
        externalSchemaLocation = resolver.getNameSpaceAndLocationString();
2383
        // Set external schemalocation.
2384
        if (externalSchemaLocation != null &&
2385
            !(externalSchemaLocation.trim()).equals(""))
2386
        {
2387
            parser.setProperty(EXTERNALSCHEMALOCATIONPROPERTY,
2388
                             externalSchemaLocation);
2389
        }
2390
      }
2391
      else
2392
      {
2393
        //create a DBSAXHandler object which has the revision specification
2394
        chandler = new DBSAXHandler(dbconn, action,
2395
                                    docid, rev, user, groups, pub, serverCode);
2396
        parser.setContentHandler((ContentHandler)chandler);
2397
        parser.setErrorHandler((ErrorHandler)chandler);
2398
        parser.setProperty(DECLARATIONHANDLERPROPERTY, chandler);
2399
        parser.setProperty(LEXICALPROPERTY, chandler);
2400

    
2401
        if (ruleBase != null && ruleBase.equals(SCHEMA) && needValidation)
2402
        {
2403
          MetaCatUtil.debugMessage("General schema parser", 20);
2404
          // turn on schema validation feature
2405
          parser.setFeature(VALIDATIONFEATURE, true);
2406
          parser.setFeature(NAMESPACEFEATURE, true);
2407
          //parser.setFeature(NAMESPACEPREFIXESFEATURE, true);
2408
          parser.setFeature(SCHEMAVALIDATIONFEATURE, true);
2409
          // From DB to find the register external schema location
2410
          String externalSchemaLocation = null;
2411
          SchemaLocationResolver resolver = new SchemaLocationResolver();
2412
          externalSchemaLocation = resolver.getNameSpaceAndLocationString();
2413
          // Set external schemalocation.
2414
          if (externalSchemaLocation != null &&
2415
            !(externalSchemaLocation.trim()).equals(""))
2416
          {
2417
            parser.setProperty(EXTERNALSCHEMALOCATIONPROPERTY,
2418
                             externalSchemaLocation);
2419
          }
2420

    
2421
        }
2422
        else if (ruleBase != null && ruleBase.equals(DTD) && needValidation)
2423
        {
2424
          MetaCatUtil.debugMessage("dtd parser", 20);
2425
          // turn on dtd validaton feature
2426
          parser.setFeature(VALIDATIONFEATURE, true);
2427
          eresolver= new DBEntityResolver(dbconn, (DBSAXHandler)chandler, dtd);
2428
          dtdhandler = new DBDTDHandler(dbconn);
2429
          parser.setEntityResolver((EntityResolver)eresolver);
2430
          parser.setDTDHandler((DTDHandler)dtdhandler);
2431
        }
2432
        else
2433
        {
2434
          MetaCatUtil.debugMessage("other parser", 20);
2435
          // non validation
2436
          parser.setFeature(VALIDATIONFEATURE, false);
2437
          eresolver= new DBEntityResolver(dbconn, (DBSAXHandler)chandler, dtd);
2438
          dtdhandler = new DBDTDHandler(dbconn);
2439
          parser.setEntityResolver((EntityResolver)eresolver);
2440
          parser.setDTDHandler((DTDHandler)dtdhandler);
2441
        }
2442
      }//else
2443
    }
2444
    catch (Exception e)
2445
    {
2446
      throw e;
2447
    }
2448
    return parser;
2449
  }
2450

    
2451

    
2452
  /**
2453
   * Set up the parser handlers for writing the document to the database
2454
   */
2455
  /*private static XMLReader initializeParser(DBConnection dbconn, String action,
2456
                               String docid, String rev, boolean validate,
2457
                                   String user, String[] groups, String pub,
2458
                                   int serverCode, Reader dtd)
2459
                           throws Exception
2460
  {
2461
    XMLReader parser = null;
2462
    //DBConnection conn = null;
2463
    //int serialNumber = -1;
2464
    //
2465
    // Set up the SAX document handlers for parsing
2466
    //
2467
    try {
2468
       //check out DBConnection
2469

    
2470
      //create a DBSAXHandler object which has the revision specification
2471
      ContentHandler chandler = new DBSAXHandler(dbconn, action,
2472
                                    docid, rev, user, groups, pub, serverCode);
2473
      EntityResolver eresolver= new DBEntityResolver(dbconn,
2474
                                                 (DBSAXHandler)chandler, dtd);
2475
      DTDHandler dtdhandler   = new DBDTDHandler(dbconn);
2476

    
2477
      // Get an instance of the parser
2478
      String parserName = MetaCatUtil.getOption("saxparser");
2479
      parser = XMLReaderFactory.createXMLReader(parserName);
2480

    
2481
      // Turn on validation
2482
      parser.setFeature("http://xml.org/sax/features/validation", validate);
2483
      // Turn off Including all external parameter entities
2484
      // (the external DTD subset also)
2485
      // Doesn't work well, probably the feature name is not correct
2486
      // parser.setFeature(
2487
      //  "http://xml.org/sax/features/external-parameter-entities", false);
2488

    
2489
      // Set Handlers in the parser
2490
      parser.setProperty("http://xml.org/sax/properties/declaration-handler",
2491
                         chandler);
2492
      parser.setProperty("http://xml.org/sax/properties/lexical-handler",
2493
                         chandler);
2494
      parser.setContentHandler((ContentHandler)chandler);
2495
      parser.setEntityResolver((EntityResolver)eresolver);
2496
      parser.setDTDHandler((DTDHandler)dtdhandler);
2497
      parser.setErrorHandler((ErrorHandler)chandler);
2498

    
2499
    } catch (Exception e) {
2500
      throw e;
2501
    }
2502
    //finally
2503
    //{
2504
      //DBConnectionPool.returnDBConnection(conn, serialNumber);
2505
    //}
2506

    
2507
    return parser;
2508
  }*/
2509

    
2510
  /**
2511
   * Save a document entry in the xml_revisions table
2512
   * Connection use as a paramter is in order to rollback feature
2513
   */
2514
  private static void archiveDocRevision(DBConnection dbconn, String docid,
2515
                                                    String user)
2516
 {
2517
    String sysdate = dbAdapter.getDateTimeFunction();
2518
    //DBConnection conn = null;
2519
    //int serialNumber = -1;
2520
    PreparedStatement pstmt = null;
2521

    
2522
    // create a record in xml_revisions table
2523
    // for that document as selected from xml_documents
2524

    
2525
   try
2526
   {
2527
     //check out DBConnection
2528
     /*conn=DBConnectionPool.
2529
                    getDBConnection("DocumentImpl.archiveDocRevision");
2530
     serialNumber=conn.getCheckOutSerialNumber();*/
2531
     pstmt = dbconn.prepareStatement(
2532
      "INSERT INTO xml_revisions " +
2533
        "(docid, rootnodeid, docname, doctype, " +
2534
        "user_owner, user_updated, date_created, date_updated, " +
2535
        "server_location, rev, public_access, catalog_id) " +
2536
      "SELECT ?, rootnodeid, docname, doctype, " +
2537
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
2538
        "server_location, rev, public_access, catalog_id " +
2539
      "FROM xml_documents " +
2540
      "WHERE docid = ?");
2541
      // Increase dbconnection usage count
2542
      dbconn.increaseUsageCount(1);
2543
      // Bind the values to the query and execute it
2544
      pstmt.setString(1, docid);
2545
      pstmt.setString(2, user);
2546
      pstmt.setString(3, docid);
2547
      pstmt.execute();
2548
      pstmt.close();
2549
   }//try
2550
   catch (SQLException e)
2551
   {
2552
     MetaCatUtil.debugMessage("Error in DocumentImpl.archiveDocRevision : "+
2553
                                e.getMessage(), 30);
2554
   }//catch
2555
   finally
2556
   {
2557
     try
2558
     {
2559
       pstmt.close();
2560
     }//try
2561
     catch (SQLException ee)
2562
     {
2563
       MetaCatUtil.debugMessage("Error in DocumnetImpl.archiveDocRevision: "+
2564
                                  ee.getMessage(), 50);
2565
     }//catch
2566
     //finally
2567
     //{
2568

    
2569
       //check in DBConnection
2570
       //DBConnectionPool.returnDBConnection(conn, serialNumber);
2571
     //}//finally
2572
   }//finnally
2573

    
2574

    
2575
  }//achiveDocRevision
2576

    
2577
  /** Save a document entry in the xml_revisions table */
2578
  private static void archiveDocRevision(String docid, String user)
2579
 {
2580
    String sysdate = dbAdapter.getDateTimeFunction();
2581
    DBConnection conn = null;
2582
    int serialNumber = -1;
2583
    PreparedStatement pstmt = null;
2584

    
2585
    // create a record in xml_revisions table
2586
    // for that document as selected from xml_documents
2587

    
2588
   try
2589
   {
2590
     //check out DBConnection
2591
     conn=DBConnectionPool.
2592
                    getDBConnection("DocumentImpl.archiveDocRevision");
2593
     serialNumber=conn.getCheckOutSerialNumber();
2594
     pstmt = conn.prepareStatement(
2595
      "INSERT INTO xml_revisions " +
2596
        "(docid, rootnodeid, docname, doctype, " +
2597
        "user_owner, user_updated, date_created, date_updated, " +
2598
        "server_location, rev, public_access, catalog_id) " +
2599
      "SELECT ?, rootnodeid, docname, doctype, " +
2600
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
2601
        "server_location, rev, public_access, catalog_id " +
2602
      "FROM xml_documents " +
2603
      "WHERE docid = ?");
2604
      // Bind the values to the query and execute it
2605
      pstmt.setString(1, docid);
2606
      pstmt.setString(2, user);
2607
      pstmt.setString(3, docid);
2608
      pstmt.execute();
2609
      pstmt.close();
2610
   }//try
2611
   catch (SQLException e)
2612
   {
2613
     MetaCatUtil.debugMessage("Error in DocumentImpl.archiveDocRevision : "+
2614
                                e.getMessage(), 30);
2615
   }//catch
2616
   finally
2617
   {
2618
     try
2619
     {
2620
       pstmt.close();
2621
     }//try
2622
     catch (SQLException ee)
2623
     {
2624
       MetaCatUtil.debugMessage("Error in DocumnetImpl.archiveDocRevision: "+
2625
                                  ee.getMessage(), 50);
2626
     }//catch
2627
     finally
2628
     {
2629
       //check in DBConnection
2630
       DBConnectionPool.returnDBConnection(conn, serialNumber);
2631
     }//finally
2632
   }//finnally
2633

    
2634

    
2635
  }//achiveDocRevision
2636

    
2637
  /**
2638
    * delete a entry in xml_table for given docid
2639
    * @param docId, the id of the document need to be delete
2640
    */
2641
  private static void deleteXMLDocuments(String docId)
2642
                                         throws SQLException
2643
  {
2644
    DBConnection conn = null;
2645
    int serialNumber = -1;
2646
    PreparedStatement pStmt = null;
2647
    try
2648
    {
2649
      //check out DBConnection
2650
      conn=DBConnectionPool.
2651
                    getDBConnection("DocumentImpl.deleteXMLDocuments");
2652
      serialNumber=conn.getCheckOutSerialNumber();
2653
      //delete a record
2654
      pStmt =
2655
             conn.prepareStatement("DELETE FROM xml_documents WHERE docid = '"
2656
                                              + docId + "'");
2657
    pStmt.execute();
2658
    }//try
2659
    finally
2660
    {
2661
      try
2662
      {
2663
        pStmt.close();
2664
      }//try
2665
      catch (SQLException e)
2666
      {
2667
        MetaCatUtil.debugMessage("error in DocumentImpl.deleteXMLDocuments: "+
2668
                                  e.getMessage(), 50);
2669
      }//catch
2670
      finally
2671
      {
2672
        //return back DBconnection
2673
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2674
      }//finally
2675
    }//finally
2676

    
2677

    
2678
  }//deleteXMLDocuments
2679

    
2680
  /**
2681
    * Get last revision number from database for a docid
2682
    * If couldn't find an entry,  -1 will return
2683
    * The return value is integer because we want compare it to there new one
2684
    * @param docid <sitecode>.<uniqueid> part of Accession Number
2685
    */
2686
  public static int getLatestRevisionNumber(String docId)
2687
                                      throws SQLException
2688
  {
2689
    int rev = 1;
2690
    PreparedStatement pStmt = null;
2691
    DBConnection dbConn = null;
2692
    int serialNumber = -1;
2693
    // get rid of rev
2694
    docId = MetaCatUtil.getDocIdFromString(docId);
2695
    try
2696
    {
2697
      //check out DBConnection
2698
      dbConn=DBConnectionPool.
2699
                    getDBConnection("DocumentImpl.getLatestRevisionNumber");
2700
      serialNumber=dbConn.getCheckOutSerialNumber();
2701

    
2702
      pStmt = dbConn.prepareStatement
2703
              ("SELECT rev FROM xml_documents WHERE docid='" + docId + "'");
2704
      pStmt.execute();
2705

    
2706
      ResultSet rs = pStmt.getResultSet();
2707
      boolean hasRow = rs.next();
2708
      if (hasRow)
2709
      {
2710
        rev = rs.getInt(1);
2711
        pStmt.close();
2712
      }
2713
      else
2714
      {
2715
        rev=-1;
2716
        pStmt.close();
2717
      }
2718
    }//try
2719
    finally
2720
    {
2721
      try
2722
      {
2723
        pStmt.close();
2724
      }
2725
      catch (Exception ee)
2726
      {
2727
        MetaCatUtil.debugMessage("Error in DocumentImpl."+
2728
                        "getLatestRevisionNumber: "+ee.getMessage(), 50);
2729
      }
2730
      finally
2731
      {
2732
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2733
      }
2734
    }//finally
2735

    
2736
    return rev;
2737
  }//getLatestRevisionNumber
2738

    
2739
  /**
2740
   * Get server location form database for a accNum
2741
   *
2742
   * @param accum <sitecode>.<uniqueid>.<rev>
2743
   */
2744
  private static int getServerLocationNumber(String accNum)
2745
                                            throws SQLException
2746
  {
2747
    //get rid of revNum part
2748
    String docId=MetaCatUtil.getDocIdFromString(accNum);
2749
    PreparedStatement pStmt = null;
2750
    int serverLocation = 1;
2751
    DBConnection conn = null;
2752
    int serialNumber = -1;
2753

    
2754
    try
2755
    {
2756
      //check out DBConnection
2757
      conn=DBConnectionPool.
2758
                    getDBConnection("DocumentImpl.getServerLocationNumber");
2759
      serialNumber=conn.getCheckOutSerialNumber();
2760

    
2761
      pStmt = conn.prepareStatement
2762
      ("SELECT server_location FROM xml_documents WHERE docid='" + docId + "'");
2763
      pStmt.execute();
2764

    
2765
      ResultSet rs = pStmt.getResultSet();
2766
      boolean hasRow = rs.next();
2767
      //if there is entry in xml_documents, get the serverlocation
2768
      if (hasRow)
2769
      {
2770
        serverLocation = rs.getInt(1);
2771
        pStmt.close();
2772
      }
2773
      else
2774
      {
2775
        //if htere is no entry in xml_documents, we consider it is new document
2776
        //the server location is local host and value is 1
2777
        serverLocation=1;
2778
        pStmt.close();
2779
      }
2780
    }//try
2781
    finally
2782
    {
2783
      try
2784
      {
2785
        pStmt.close();
2786
      }//try
2787
      catch (Exception ee)
2788
      {
2789
        MetaCatUtil.debugMessage("Error in DocumentImpl.getServerLocationNu(): "
2790
                                    +ee.getMessage(), 50);
2791
      }//catch
2792
      finally
2793
      {
2794
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2795
      }//finally
2796
    }//finally
2797

    
2798
    return serverLocation;
2799
  }
2800

    
2801
  /**
2802
   * Given a server name, return its servercode in xml_replication table.
2803
   * If no server is found, -1 will return
2804
   * @param serverName,
2805
   */
2806
  private static int getServerCode(String serverName)
2807
  {
2808
    PreparedStatement pStmt=null;
2809
    int serverLocation=-2;
2810
    DBConnection dbConn = null;
2811
    int serialNumber = -1;
2812
    //MetaCatUtil util = new MetaCatUtil();
2813

    
2814

    
2815
    //we should consider about local host too
2816
    if (serverName.equals(MetaCatUtil.getLocalReplicationServerName()))
2817
    {
2818
      serverLocation=1;
2819
      return serverLocation;
2820
    }
2821

    
2822

    
2823
    try
2824
    {
2825
      //check xml_replication table
2826
      //dbConn=util.openDBConnection();
2827
      //check out DBConnection
2828
      dbConn=DBConnectionPool.getDBConnection("DocumentImpl.getServerCode");
2829
      serialNumber=dbConn.getCheckOutSerialNumber();
2830
      pStmt = dbConn.prepareStatement
2831
      ("SELECT serverid FROM xml_replication WHERE server='" + serverName +"'");
2832
      pStmt.execute();
2833

    
2834
      ResultSet rs = pStmt.getResultSet();
2835
      boolean hasRow = rs.next();
2836
      //if there is entry in xml_replication, get the serverid
2837
      if (hasRow)
2838
      {
2839
        serverLocation = rs.getInt(1);
2840
        pStmt.close();
2841
      }
2842
      else
2843
      {
2844
        // if htere is no entry in xml_replication, -1 will return
2845
        serverLocation=-1;
2846
        pStmt.close();
2847
      }
2848
    }
2849
    catch (Exception e)
2850
    {
2851
      MetaCatUtil.debugMessage("Error in DocumentImpl.getServerCode(): "
2852
                                    +e.getMessage(), 30);
2853
    }
2854
    finally
2855
    {
2856
      try
2857
      {
2858
        pStmt.close();
2859
      }
2860
      catch (Exception ee)
2861
      {
2862
        MetaCatUtil.debugMessage("Error in DocumentImpl.getServerCode(): "
2863
                                    +ee.getMessage(), 50);
2864
      }
2865
      finally
2866
      {
2867
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2868
      }
2869
    }
2870

    
2871

    
2872
    return serverLocation;
2873
  }
2874

    
2875
  /**
2876
   * Insert a server into xml_replcation table
2877
   * @param server, the name of server
2878
   */
2879
  private static synchronized void
2880
                                insertServerIntoReplicationTable(String server)
2881
  {
2882
    PreparedStatement pStmt=null;
2883
    DBConnection dbConn = null;
2884
    int serialNumber = -1;
2885

    
2886
    // Initial value for the server
2887
    int replicate = 0;
2888
    int dataReplicate = 0;
2889
    int hub = 0;
2890

    
2891
    try
2892
    {
2893
       // Get DBConnection
2894
       dbConn=DBConnectionPool.
2895
                getDBConnection("DocumentImpl.insertServIntoReplicationTable");
2896
       serialNumber=dbConn.getCheckOutSerialNumber();
2897

    
2898
      // Compare the server to dabase
2899
      pStmt = dbConn.prepareStatement
2900
      ("SELECT serverid FROM xml_replication WHERE server='" + server +"'");
2901
      pStmt.execute();
2902
      ResultSet rs = pStmt.getResultSet();
2903
      boolean hasRow = rs.next();
2904
      // Close preparedstatement and result set
2905
      pStmt.close();
2906
      rs.close();
2907

    
2908
      // If the server is not in the table, and server is not local host,
2909
      // insert it
2910
      if ( !hasRow
2911
         && !server.equals(MetaCatUtil.getLocalReplicationServerName()))
2912
      {
2913
        // Set auto commit false
2914
        dbConn.setAutoCommit(false);
2915
        /*pStmt = dbConn.prepareStatement("INSERT INTO xml_replication " +
2916
                      "(server, last_checked, replicate, datareplicate, hub) " +
2917
                       "VALUES ('" + server + "', to_date(" +
2918
                       "'01/01/00', 'MM/DD/YY'), '" +
2919
                       replicate +"', '"+dataReplicate+"','"+ hub + "')");*/
2920
        pStmt = dbConn.prepareStatement("INSERT INTO xml_replication " +
2921
                      "(server, last_checked, replicate, datareplicate, hub) " +
2922
                       "VALUES ('" + server + "', " +
2923
                       dbAdapter.toDate("01/01/1980", "MM/DD/YYYY") + ", '" +
2924
                       replicate +"', '"+dataReplicate+"','"+ hub + "')");
2925

    
2926

    
2927
        pStmt.execute();
2928
        dbConn.commit();
2929
        // Increase usage number
2930
        dbConn.increaseUsageCount(1);
2931
        pStmt.close();
2932

    
2933
      }
2934
    }//try
2935
    catch (Exception e)
2936
    {
2937
      MetaCatUtil.debugMessage("Error in DocumentImpl.insertServerIntoRepli(): "
2938
                                    +e.getMessage(), 30);
2939
    }//catch
2940
    finally
2941
    {
2942

    
2943
      try
2944
      {
2945
        // Set auto commit true
2946
        dbConn.setAutoCommit(true);
2947
        pStmt.close();
2948

    
2949
      }//try
2950
      catch (Exception ee)
2951
      {
2952
        MetaCatUtil.debugMessage("Error in DocumentImpl.insetServerIntoRepl(): "
2953
                                    +ee.getMessage(), 50);
2954
      }//catch
2955
      finally
2956
      {
2957
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2958
      }
2959

    
2960
    }//finally
2961

    
2962
  }
2963

    
2964

    
2965
  /**
2966
   * the main routine used to test the DBWriter utility.
2967
   * <p>
2968
   * Usage: java DocumentImpl <-f filename -a action -d docid>
2969
   *
2970
   * @param filename the filename to be loaded into the database
2971
   * @param action the action to perform (READ, INSERT, UPDATE, DELETE)
2972
   * @param docid the id of the document to process
2973
   */
2974
  static public void main(String[] args) {
2975
    DBConnection dbconn = null;
2976
    int serialNumber = -1;
2977
    try {
2978
      String filename    = null;
2979
      String dtdfilename = null;
2980
      String action      = null;
2981
      String docid       = null;
2982
      boolean showRuntime = false;
2983
      boolean useOldReadAlgorithm = false;
2984

    
2985
      // Parse the command line arguments
2986
      for ( int i=0 ; i < args.length; ++i ) {
2987
        if ( args[i].equals( "-f" ) ) {
2988
          filename =  args[++i];
2989
        } else if ( args[i].equals( "-r" ) ) {
2990
          dtdfilename =  args[++i];
2991
        } else if ( args[i].equals( "-a" ) ) {
2992
          action =  args[++i];
2993
        } else if ( args[i].equals( "-d" ) ) {
2994
          docid =  args[++i];
2995
        } else if ( args[i].equals( "-t" ) ) {
2996
          showRuntime = true;
2997
        } else if ( args[i].equals( "-old" ) ) {
2998
          useOldReadAlgorithm = true;
2999
        } else {
3000
          System.err.println
3001
            ( "   args[" +i+ "] '" +args[i]+ "' ignored." );
3002
        }
3003
      }
3004

    
3005
      // Check if the required arguments are provided
3006
      boolean argsAreValid = false;
3007
      if (action != null) {
3008
        if (action.equals("INSERT")) {
3009
          if (filename != null) {
3010
            argsAreValid = true;
3011
          }
3012
        } else if (action.equals("UPDATE")) {
3013
          if ((filename != null) && (docid != null)) {
3014
            argsAreValid = true;
3015
          }
3016
        } else if (action.equals("DELETE")) {
3017
          if (docid != null) {
3018
            argsAreValid = true;
3019
          }
3020
        } else if (action.equals("READ")) {
3021
          if (docid != null) {
3022
            argsAreValid = true;
3023
          }
3024
        }
3025
      }
3026

    
3027
      // Print usage message if the arguments are not valid
3028
      if (!argsAreValid) {
3029
        System.err.println("Wrong number of arguments!!!");
3030
        System.err.println(
3031
          "USAGE: java DocumentImpl [-t] <-a INSERT> [-d docid] <-f filename> "+
3032
          "[-r dtdfilename]");
3033
        System.err.println(
3034
          "   OR: java DocumentImpl [-t] <-a UPDATE -d docid -f filename> " +
3035
          "[-r dtdfilename]");
3036
        System.err.println(
3037
          "   OR: java DocumentImpl [-t] <-a DELETE -d docid>");
3038
        System.err.println(
3039
          "   OR: java DocumentImpl [-t] [-old] <-a READ -d docid>");
3040
        return;
3041
      }
3042

    
3043
      // Time the request if asked for
3044
      double startTime = System.currentTimeMillis();
3045

    
3046
      // Open a connection to the database
3047
      MetaCatUtil util = new MetaCatUtil();
3048

    
3049
      dbconn=DBConnectionPool.getDBConnection("DocumentImpl.main");
3050
      serialNumber=dbconn.getCheckOutSerialNumber();
3051

    
3052
      double connTime = System.currentTimeMillis();
3053
      // Execute the action requested (READ, INSERT, UPDATE, DELETE)
3054
      if (action.equals("READ")) {
3055
          DocumentImpl xmldoc = new DocumentImpl(docid );
3056
          if (useOldReadAlgorithm) {
3057
            System.out.println(xmldoc.readUsingSlowAlgorithm());
3058
          } else {
3059
            xmldoc.toXml(new PrintWriter(System.out), null, null, true);
3060
          }
3061
      } else if (action.equals("DELETE")) {
3062
        DocumentImpl.delete(docid, null, null);
3063
        System.out.println("Document deleted: " + docid);
3064
      } else {
3065
        /*String newdocid = DocumentImpl.write(dbconn, filename, null,
3066
                                             dtdfilename, action, docid,
3067
                                             null, null);
3068
        if ((docid != null) && (!docid.equals(newdocid))) {
3069
          if (action.equals("INSERT")) {
3070
            System.out.println("New document ID generated!!! ");
3071
          } else if (action.equals("UPDATE")) {
3072
            System.out.println("ERROR: Couldn't update document!!! ");
3073
          }
3074
        } else if ((docid == null) && (action.equals("UPDATE"))) {
3075
          System.out.println("ERROR: Couldn't update document!!! ");
3076
        }
3077
        System.out.println("Document processing finished for: " + filename
3078
              + " (" + newdocid + ")");*/
3079
      }
3080

    
3081
      double stopTime = System.currentTimeMillis();
3082
      double dbOpenTime = (connTime - startTime)/1000;
3083
      double insertTime = (stopTime - connTime)/1000;
3084
      double executionTime = (stopTime - startTime)/1000;
3085
      if (showRuntime) {
3086
        System.out.println("\n\nTotal Execution time was: " +
3087
                           executionTime + " seconds.");
3088
        System.out.println("Time to open DB connection was: " + dbOpenTime +
3089
                           " seconds.");
3090
        System.out.println("Time to insert document was: " + insertTime +
3091
                           " seconds.");
3092
      }
3093
      dbconn.close();
3094
    } catch (McdbException me) {
3095
      me.toXml(new PrintWriter(System.err));
3096
    } catch (AccessionNumberException ane) {
3097
      System.out.println(ane.getMessage());
3098
    } catch (Exception e) {
3099
      System.err.println("EXCEPTION HANDLING REQUIRED");
3100
      System.err.println(e.getMessage());
3101
      e.printStackTrace(System.err);
3102
    }
3103
    finally
3104
    {
3105
      // Return db connection
3106
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
3107
    }
3108
  }
3109
}
(31-31/62)