Project

General

Profile

1 393 jones
/**
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$'
10
 *     '$Date$'
11
 * '$Revision$'
12 669 jones
 *
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 393 jones
 */
27
28
package edu.ucsb.nceas.metacat;
29
30
import java.sql.*;
31 429 jones
import java.io.File;
32
import java.io.FileReader;
33
import java.io.IOException;
34 393 jones
import java.io.PrintWriter;
35 429 jones
import java.io.Reader;
36
import java.io.StringWriter;
37
import java.io.Writer;
38 561 berkley
import java.io.InputStreamReader;
39 1029 tao
import java.io.*;
40 798 jones
import java.text.SimpleDateFormat;
41
42
import java.util.Date;
43 1432 tao
import java.util.Hashtable;
44 429 jones
import java.util.Iterator;
45 407 jones
import java.util.Stack;
46 429 jones
import java.util.TreeSet;
47 1432 tao
import java.util.Vector;
48 577 berkley
import java.util.Enumeration;
49 407 jones
50
import org.xml.sax.AttributeList;
51
import org.xml.sax.ContentHandler;
52
import org.xml.sax.DTDHandler;
53
import org.xml.sax.EntityResolver;
54
import org.xml.sax.ErrorHandler;
55
import org.xml.sax.InputSource;
56
import org.xml.sax.XMLReader;
57
import org.xml.sax.SAXException;
58
import org.xml.sax.SAXParseException;
59
import org.xml.sax.helpers.XMLReaderFactory;
60
61 561 berkley
import java.net.URL;
62
63 777 bojilova
import edu.ucsb.nceas.dbadapter.AbstractDatabase;
64 747 bojilova
65 393 jones
/**
66
 * A class that represents an XML document. It can be created with a simple
67 407 jones
 * document identifier from a database connection.  It also will write an
68
 * XML text document to a database connection using SAX.
69 393 jones
 */
70
public class DocumentImpl {
71
72 1407 tao
   /* Constants */
73 1441 tao
   public static final String SCHEMA                 = "Schema";
74
   public static final String DTD                    = "DTD";
75 1407 tao
   public static final String EML2                   = "eml2";
76 1383 tao
   public static final String EXTERNALSCHEMALOCATIONPROPERTY =
77
              "http://apache.org/xml/properties/schema/external-schemaLocation";
78 1407 tao
   /*public static final String EXTERNALSCHEMALOCATION =
79 1390 tao
     "eml://ecoinformatics.org/eml-2.0.0 http://dev.nceas.ucsb.edu/tao/schema/eml.xsd"+
80 1407 tao
      " http://www.xml-cml.org/schema/stmml http://dev.nceas.ucsb.edu/tao/schema/stmml.xsd";*/
81 1383 tao
   public static final String DECLARATIONHANDLERPROPERTY =
82
                            "http://xml.org/sax/properties/declaration-handler";
83
   public static final String LEXICALPROPERTY =
84
                             "http://xml.org/sax/properties/lexical-handler";
85
   public static final String VALIDATIONFEATURE =
86
                             "http://xml.org/sax/features/validation";
87
   public static final String SCHEMAVALIDATIONFEATURE =
88
                             "http://apache.org/xml/features/validation/schema";
89
   public static final String NAMESPACEFEATURE =
90
                              "http://xml.org/sax/features/namespaces";
91
   public static final String NAMESPACEPREFIXESFEATURE =
92
                              "http://xml.org/sax/features/namespace-prefixes";
93 1554 tao
   public static final String EMLNAMESPACE =
94 1551 tao
                                         MetaCatUtil.getOption("eml2namespace");
95
                                         // "eml://ecoinformatics.org/eml-2.0.0";
96 1383 tao
97
98 425 bojilova
  static final int ALL = 1;
99
  static final int WRITE = 2;
100
  static final int READ = 4;
101 777 bojilova
  private static final AbstractDatabase dbAdapter = MetaCatUtil.dbAdapter;
102 425 bojilova
103 1217 tao
  private DBConnection connection = null;
104 393 jones
  private String docid = null;
105 956 tao
  private String updatedVersion=null;
106 393 jones
  private String docname = null;
107
  private String doctype = null;
108 1441 tao
  private String validateType = null; //base on dtd or schema
109 691 bojilova
// DOCTITLE attr cleared from the db
110
//  private String doctitle = null;
111 465 berkley
  private String createdate = null;
112
  private String updatedate = null;
113 393 jones
  private String system_id = null;
114 561 berkley
  private String userowner = null;
115
  private String userupdated = null;
116 575 berkley
  private int rev;
117 561 berkley
  private int serverlocation;
118 1059 tao
  private String docHomeServer;
119 697 bojilova
  private String publicaccess;
120 393 jones
  private long rootnodeid;
121
  private ElementNode rootNode = null;
122 429 jones
  private TreeSet nodeRecordList = null;
123 1292 tao
  //private static
124
  //ReplicationServerList serverList = new ReplicationServerList();
125 790 bojilova
126
  /**
127 800 jones
   * Constructor used to create a document and read the document information
128
   * from the database.  If readNodes is false, then the node data is not
129
   * read at this time, but is deferred until it is needed (such as when a
130
   * call to toXml() is made).
131 790 bojilova
   *
132
   * @param conn the database connection from which to read the document
133 800 jones
   * @param docid the identifier of the document to be created
134
   * @param readNodes flag indicating whether the xmlnodes should be read
135 790 bojilova
   */
136 1217 tao
  public DocumentImpl(String docid, boolean readNodes)
137 802 bojilova
         throws McdbException
138 790 bojilova
  {
139 801 jones
    try {
140 1217 tao
      //this.conn = conn;
141 801 jones
      this.docid = docid;
142
143
      // Look up the document information
144
      getDocumentInfo(docid);
145 1217 tao
146 801 jones
      if (readNodes) {
147 800 jones
        // Download all of the document nodes using a single SQL query
148
        // The sort order of the records is determined by the NodeComparator
149
        // class, and needs to represent a depth-first traversal for the
150
        // toXml() method to work properly
151
        nodeRecordList = getNodeRecordList(rootnodeid);
152 1217 tao
153 801 jones
      }
154 800 jones
155 801 jones
    } catch (McdbException ex) {
156
      throw ex;
157
    } catch (Throwable t) {
158
      throw new McdbException("Error reading document from " +
159
                              "DocumentImpl.DocumentImpl: " + docid);
160 800 jones
    }
161 790 bojilova
  }
162 393 jones
163
  /**
164 396 jones
   * Constructor, creates document from database connection, used
165
   * for reading the document
166 393 jones
   *
167
   * @param conn the database connection from which to read the document
168
   * @param docid the identifier of the document to be created
169
   */
170 1217 tao
  public DocumentImpl(String docid) throws McdbException
171 393 jones
  {
172 1217 tao
    this(docid, true);
173 393 jones
  }
174
175 1441 tao
176 549 berkley
177 956 tao
  /**
178
   * Construct a new document instance, writing the contents to the database.
179
   * This method is called from DBSAXHandler because we need to know the
180
   * root element name for documents without a DOCTYPE before creating it.
181
   *
182
   * In this constructor, the docid is without rev. There is a string rev to
183
   * specify the revision user want to upadate. The revion is only need to be
184
   * greater than current one. It is not need to be sequent number just after
185
   * current one. So it is only used in update action
186
   * @param conn the JDBC Connection to which all information is written
187
   * @param rootnodeid - sequence id of the root node in the document
188
   * @param docname - the name of DTD, i.e. the name immediately following
189
   *        the DOCTYPE keyword ( should be the root element name ) or
190
   *        the root element name if no DOCTYPE declaration provided
191
   *        (Oracle's and IBM parsers are not aware if it is not the
192
   *        root element name)
193
   * @param doctype - Public ID of the DTD, i.e. the name immediately
194
   *                  following the PUBLIC keyword in DOCTYPE declaration or
195
   *                  the docname if no Public ID provided or
196
   *                  null if no DOCTYPE declaration provided
197
   * @param docid the docid to use for the UPDATE, no version number
198
   * @param version, need to be update
199
   * @param action the action to be performed (INSERT OR UPDATE)
200
   * @param user the user that owns the document
201
   * @param pub flag for public "read" access on document
202
   * @param serverCode the serverid from xml_replication on which this document
203
   *        resides.
204
   *
205
   */
206 1217 tao
  public DocumentImpl(DBConnection conn, long rootNodeId, String docName,
207 956 tao
                      String docType, String docId, String newRevision,
208
                      String action, String user,
209
                      String pub, String catalogId, int serverCode)
210
                      throws SQLException, Exception
211
  {
212 1217 tao
    this.connection = conn;
213 956 tao
    this.rootnodeid = rootNodeId;
214
    this.docname = docName;
215
    this.doctype = docType;
216
    this.docid = docId;
217
    this.updatedVersion = newRevision;
218
    writeDocumentToDB(action, user, pub, catalogId, serverCode);
219
  }
220
221 798 jones
  /**
222 1026 tao
   * This method will be call in handleUploadRequest in MetacatServlet class
223
   */
224
  public static void registerDocument(
225
                     String docname, String doctype, String accnum, String user)
226
                     throws SQLException, AccessionNumberException, Exception
227
  {
228 1217 tao
229 1063 tao
    try
230
    {
231 1217 tao
       // get server location for this doc
232
      int serverLocation=getServerLocationNumber(accnum);
233 1063 tao
      registerDocument(docname, doctype,accnum, user, serverLocation);
234
    }
235
    catch (Exception e)
236
    {
237
      throw e;
238
    }
239 1217 tao
240 1026 tao
241
  }
242
  /**
243 798 jones
   * Register a document that resides on the filesystem with the database.
244
   * (ie, just an entry in xml_documents, nothing in xml_nodes).
245
   * Creates a reference to a filesystem document (used for non-xml data files).
246 1055 tao
   * This class only be called in MetaCatServerlet.
247 798 jones
   * @param conn the JDBC Connection to which all information is written
248
   * @param docname - the name of DTD, i.e. the name immediately following
249
   *        the DOCTYPE keyword ( should be the root element name ) or
250
   *        the root element name if no DOCTYPE declaration provided
251
   *        (Oracle's and IBM parsers are not aware if it is not the
252
   *        root element name)
253
   * @param doctype - Public ID of the DTD, i.e. the name immediately
254
   *                  following the PUBLIC keyword in DOCTYPE declaration or
255
   *                  the docname if no Public ID provided or
256
   *                  null if no DOCTYPE declaration provided
257
   * @param accnum the accession number to use for the INSERT OR UPDATE, which
258
   *               includes a revision number for this revision of the document
259
   *               (e.g., knb.1.1)
260
   * @param user the user that owns the document
261
   * @param serverCode the serverid from xml_replication on which this document
262
   *        resides.
263
   */
264
  public static void registerDocument(
265
                     String docname, String doctype, String accnum,
266
                     String user, int serverCode)
267
                     throws SQLException, AccessionNumberException, Exception
268
  {
269 1217 tao
    DBConnection dbconn = null;
270
    int serialNumber = -1;
271
    PreparedStatement pstmt = null;
272
    //MetaCatUtil util = new MetaCatUtil();
273 965 tao
    AccessionNumber ac;
274 798 jones
    try {
275 1217 tao
      //dbconn = util.openDBConnection();
276
      //check out DBConnection
277
      dbconn=DBConnectionPool.
278
                    getDBConnection("DocumentImpl.registerDocument");
279
      serialNumber=dbconn.getCheckOutSerialNumber();
280 965 tao
      String docIdWithoutRev=MetaCatUtil.getDocIdFromString(accnum);
281
      int userSpecifyRev=MetaCatUtil.getVersionFromString(accnum);
282 1217 tao
      int revInDataBase=getLatestRevisionNumber(docIdWithoutRev);
283 965 tao
      //revIndataBase=-1, there is no record in xml_documents table
284
      //the data file is a new one, inert it into table
285
      //user specified rev should be great than 0
286
      if (revInDataBase==-1 && userSpecifyRev>0 )
287
      {
288 1217 tao
        ac = new AccessionNumber(accnum, "insert");
289 965 tao
      }
290
      //rev is greater the last revsion number and revInDataBase isn't -1
291
      // it is a updated data file
292
      else if (userSpecifyRev>revInDataBase && revInDataBase>0)
293
      {
294
295
        //archive the old entry
296 1217 tao
        archiveDocRevision(docIdWithoutRev, user);
297 965 tao
        //delete the old entry in xml_documents
298 1217 tao
        deleteXMLDocuments(docIdWithoutRev);
299
        ac = new AccessionNumber(accnum, "update");
300 965 tao
      }
301
      //other situation
302
      else
303
      {
304
305
        throw new Exception("Revision number couldn't be "
306
                    +userSpecifyRev);
307
      }
308 798 jones
      String docid = ac.getDocid();
309
      String rev = ac.getRev();
310
      SimpleDateFormat formatter = new SimpleDateFormat ("yy-MM-dd HH:mm:ss");
311
      Date localtime = new Date();
312
      String dateString = formatter.format(localtime);
313
314 946 tao
      String sqlDateString = "to_date('" + dateString +
315
                                          "', 'YY-MM-DD HH24:MI:SS')";
316 798 jones
317
      StringBuffer sql = new StringBuffer();
318
      sql.append("insert into xml_documents (docid, docname, doctype, ");
319 946 tao
      sql.append("user_owner, user_updated, server_location, rev,date_created");
320 798 jones
      sql.append(", date_updated, public_access) values ('");
321
      sql.append(docid).append("','");
322
      sql.append(docname).append("','");
323
      sql.append(doctype).append("','");
324
      sql.append(user).append("','");
325
      sql.append(user).append("','");
326
      sql.append(serverCode).append("','");
327
      sql.append(rev).append("',");
328
      sql.append(sqlDateString).append(",");
329
      sql.append(sqlDateString).append(",");
330
      sql.append("'0')");
331 1217 tao
      pstmt = dbconn.prepareStatement(sql.toString());
332 798 jones
      pstmt.execute();
333
      pstmt.close();
334 1217 tao
      //dbconn.close();
335 1063 tao
    }
336
    finally
337
    {
338
      try
339
      {
340 1217 tao
        pstmt.close();
341 1063 tao
      }
342 1217 tao
      finally
343 1063 tao
      {
344 1217 tao
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
345 1063 tao
      }
346 798 jones
    }
347
  }
348 1029 tao
349 1055 tao
    /**
350
   * Register a document that resides on the filesystem with the database.
351
   * (ie, just an entry in xml_documents, nothing in xml_nodes).
352
   * Creates a reference to a filesystem document (used for non-xml data files)
353
   * This method will be called for register data file in xml_documents in
354
   * Replication.
355
   * This method is revised from registerDocument.
356
   *
357
   * @param conn the JDBC Connection to which all information is written
358
   * @param docname - the name of DTD, i.e. the name immediately following
359
   *        the DOCTYPE keyword ( should be the root element name ) or
360
   *        the root element name if no DOCTYPE declaration provided
361
   *        (Oracle's and IBM parsers are not aware if it is not the
362
   *        root element name)
363
   * @param doctype - Public ID of the DTD, i.e. the name immediately
364
   *                  following the PUBLIC keyword in DOCTYPE declaration or
365
   *                  the docname if no Public ID provided or
366
   *                  null if no DOCTYPE declaration provided
367
   * @param accnum the accession number to use for the INSERT OR UPDATE, which
368
   *               includes a revision number for this revision of the document
369
   *               (e.g., knb.1.1)
370
   * @param user the user that owns the document
371
   * @param serverCode the serverid from xml_replication on which this document
372
   *        resides.
373
   */
374
  public static void registerDocumentInReplication(
375
                     String docname, String doctype, String accnum,
376
                     String user, int serverCode)
377
                     throws SQLException, AccessionNumberException, Exception
378
  {
379 1217 tao
    DBConnection dbconn = null;
380
    int serialNumber = -1;
381
    //MetaCatUtil util = new MetaCatUtil();
382 1055 tao
    AccessionNumber ac;
383 1217 tao
    PreparedStatement pstmt = null;
384 1055 tao
    try {
385 1217 tao
      //dbconn = util.openDBConnection();
386
       dbconn=DBConnectionPool.
387
                  getDBConnection("DocumentImpl.registerDocumentInReplication");
388
      serialNumber=dbconn.getCheckOutSerialNumber();
389 1055 tao
      String docIdWithoutRev=MetaCatUtil.getDocIdFromString(accnum);
390
      int userSpecifyRev=MetaCatUtil.getVersionFromString(accnum);
391 1217 tao
      int revInDataBase=getLatestRevisionNumber(docIdWithoutRev);
392 1055 tao
      //revIndataBase=-1, there is no record in xml_documents table
393
      //the data file is a new one, inert it into table
394
      //user specified rev should be great than 0
395
      if (revInDataBase==-1 && userSpecifyRev>0 )
396
      {
397 1063 tao
398 1217 tao
        ac = new AccessionNumber(accnum, "insert");
399 1055 tao
      }
400
      //rev is greater the last revsion number and revInDataBase isn't -1
401
      // it is a updated data file
402
      else if (userSpecifyRev>revInDataBase && revInDataBase>0)
403
      {
404
405
        //archive the old entry
406 1217 tao
        archiveDocRevision(docIdWithoutRev, user);
407 1055 tao
        //delete the old entry in xml_documents
408 1217 tao
        deleteXMLDocuments(docIdWithoutRev);
409
        ac = new AccessionNumber(accnum, "update");
410 1055 tao
      }
411 1292 tao
      // local server has newer version, then notify the remote server
412
      else if ( userSpecifyRev < revInDataBase && revInDataBase > 0)
413
      {
414
        throw new Exception("Local server: "+MetaCatUtil.getOption("server")+
415
                 " has newer revision of doc: "+docIdWithoutRev+"."
416
                  +revInDataBase+". Please notify it.");
417
      }
418 1055 tao
      //other situation
419
      else
420
      {
421
422
        throw new Exception("Revision number couldn't be "
423
                    +userSpecifyRev);
424
      }
425
      String docid = ac.getDocid();
426
      String rev = ac.getRev();
427
      SimpleDateFormat formatter = new SimpleDateFormat ("yy-MM-dd HH:mm:ss");
428
      Date localtime = new Date();
429
      String dateString = formatter.format(localtime);
430
431
      String sqlDateString = "to_date('" + dateString +
432
                                          "', 'YY-MM-DD HH24:MI:SS')";
433
434
      StringBuffer sql = new StringBuffer();
435
      sql.append("insert into xml_documents (docid, docname, doctype, ");
436
      sql.append("user_owner, user_updated, server_location, rev,date_created");
437
      sql.append(", date_updated, public_access) values ('");
438
      sql.append(docid).append("','");
439
      sql.append(docname).append("','");
440
      sql.append(doctype).append("','");
441
      sql.append(user).append("','");
442
      sql.append(user).append("','");
443
      sql.append(serverCode).append("','");
444
      sql.append(rev).append("',");
445
      sql.append(sqlDateString).append(",");
446
      sql.append(sqlDateString).append(",");
447
      sql.append("'0')");
448 1292 tao
      // Set auto commit fasle
449
      dbconn.setAutoCommit(false);
450 1217 tao
      pstmt = dbconn.prepareStatement(sql.toString());
451 1055 tao
      pstmt.execute();
452 1292 tao
      // Commit the insert
453
      dbconn.commit();
454 1055 tao
      pstmt.close();
455 1217 tao
      //dbconn.close();
456 1063 tao
    }
457
    finally
458
    {
459 1292 tao
      // Set DBConnection auto commit true
460
      dbconn.setAutoCommit(true);
461 1217 tao
      pstmt.close();
462
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
463 1055 tao
    }
464
  }
465
466 1021 tao
 /**
467 1029 tao
   * This method will register a data file entry in xml_documents and save a
468 1292 tao
   * data file input Stream into file system.. It is only used in replication
469 1029 tao
   *
470
   * @param  input, the input stream which contain the file content.
471
   * @param  , the input stream which contain the file content
472
   * @param docname - the name of DTD, for data file, it is a docid number.
473
   * @param doctype - "BIN" for data file
474
   * @param accnum the accession number to use for the INSERT OR UPDATE, which
475
   *               includes a revision number for this revision of the document
476
   *               (e.g., knb.1.1)
477
   * @param user the user that owns the document
478 1292 tao
   * @param docHomeServer, the home server of the docid
479
   * @param notificationServer, the server to notify force replication info to
480
   *                            local metacat
481 1029 tao
   */
482 1292 tao
 public static void writeDataFileInReplication(InputStream input,
483
                 String filePath, String docname, String doctype, String accnum,
484
                   String user, String docHomeServer, String notificationServer)
485 1029 tao
                     throws SQLException, AccessionNumberException, Exception
486
 {
487 1292 tao
    int serverCode=-2;
488
489
490 1029 tao
    if (filePath==null||filePath.equals(""))
491
    {
492
      throw new
493
            Exception("Please specify the directory where file will be store");
494
    }
495
    if (accnum==null||accnum.equals(""))
496
    {
497
      throw new Exception("Please specify the stored file name");
498
    }
499 1063 tao
500 1292 tao
501 1063 tao
502 1292 tao
    // If server is not int the xml replication talbe, insert it into
503
    // xml_replication table
504
    //serverList.addToServerListIfItIsNot(docHomeServer);
505
    insertServerIntoReplicationTable(docHomeServer);
506
507
    // Get server code again
508
    serverCode = getServerCode(docHomeServer);
509
510
511
    //register data file into xml_documents table
512
    registerDocumentInReplication(docname, doctype, accnum, user, serverCode);
513
    //write inputstream into file system.
514
    File dataDirectory = new File(filePath);
515
    File newFile = new File(dataDirectory, accnum);
516 1029 tao
517 1292 tao
    // create a buffered byte output stream
518
    // that uses a default-sized output buffer
519
    FileOutputStream fos = new FileOutputStream(newFile);
520
    BufferedOutputStream outPut = new BufferedOutputStream(fos);
521 1029 tao
522 1292 tao
    BufferedInputStream bis = null;
523
    bis = new BufferedInputStream(input);
524
    byte[] buf = new byte[4 * 1024]; // 4K buffer
525
    int b = bis.read(buf);
526 1029 tao
527 1292 tao
    while (b != -1)
528
    {
529 1029 tao
        outPut.write(buf, 0, b);
530
        b = bis.read(buf);
531 1292 tao
    }
532
    bis.close();
533
	  outPut.close();
534
	  fos.close();
535
536
    // Force replicate data file
537
    ForceReplicationHandler forceReplication = new ForceReplicationHandler
538
                                    (accnum, false, notificationServer);
539
540 1029 tao
 }
541
542 798 jones
543 1026 tao
544
  public static boolean getDataFileLockGrant(String accnum)
545
                                                  throws Exception
546
  {
547 1217 tao
548 1063 tao
    try
549
    {
550 1217 tao
551
      int serverLocation=getServerLocationNumber(accnum);
552
553 1063 tao
      return getDataFileLockGrant(accnum,serverLocation);
554
    }
555
    catch (Exception e)
556
    {
557 1217 tao
558 1063 tao
      throw e;
559
    }
560 1026 tao
  }
561
562 393 jones
  /**
563 1026 tao
   * The method will check if metacat can get data file lock grant
564
   * If server code is 1, it get.
565
   * If server code is not 1 but call replication getlock successfully,
566
   * it get
567
   * else, it didn't get
568
   * @param accnum, the ID of the document
569
   * @param action, the action to the document
570
   * @param serverCode, the server location code
571
   */
572
  public static boolean getDataFileLockGrant(String accnum, int serverCode)
573
                                          throws Exception
574
  {
575
    boolean flag=true;
576 1217 tao
    //MetaCatUtil util = new MetaCatUtil();
577
    String docid = MetaCatUtil.getDocIdFromString(accnum);
578
    int rev = MetaCatUtil.getVersionFromString(accnum);
579 1026 tao
580
    if (serverCode == 1)
581
    {
582
      flag=true;
583
      return flag;
584
    }
585
586
    //if((serverCode != 1 && action.equals("UPDATE")) )
587
    if (serverCode != 1)
588
    { //if this document being written is not a resident of this server then
589
      //we need to try to get a lock from it's resident server.  If the
590
      //resident server will not give a lock then we send the user a message
591
      //saying that he/she needs to download a new copy of the file and
592
      //merge the differences manually.
593
594 1292 tao
      String server=MetacatReplication.getServerNameForServerCode(serverCode);
595 1026 tao
      MetacatReplication.replLog("attempting to lock " + accnum);
596 1217 tao
      URL u = new URL("https://" + server + "?server=" +
597
        MetaCatUtil.getLocalReplicationServerName()+"&action=getlock&updaterev="
598 1026 tao
           +rev + "&docid=" + docid);
599
      //System.out.println("sending message: " + u.toString());
600
      String serverResStr = MetacatReplication.getURLContent(u);
601
      String openingtag =serverResStr.substring(0, serverResStr.indexOf(">")+1);
602
      if(openingtag.equals("<lockgranted>"))
603
      {
604
        //the lock was granted go ahead with the insert
605
        //System.out.println("In lockgranted");
606
        MetacatReplication.replLog("lock granted for " + accnum + " from " +
607
                                      server);
608
        flag=true;
609
        return flag;
610
      }//if
611
612
      else if(openingtag.equals("<filelocked>"))
613
      {//the file is currently locked by another user
614
       //notify our user to wait a few minutes, check out a new copy and try
615
       //again.
616
        //System.out.println("file locked");
617
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
618
                                   server + " reason: file already locked");
619
        throw new Exception("The file specified is already locked by another " +
620
                            "user.  Please wait 30 seconds, checkout the " +
621
                            "newer document, merge your changes and try " +
622
                            "again.");
623
      }
624
      else if(openingtag.equals("<outdatedfile>"))
625
      {//our file is outdated.  notify our user to check out a new copy of the
626
       //file and merge his version with the new version.
627
        //System.out.println("outdated file");
628
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
629
                                    server + " reason: local file outdated");
630
        throw new Exception("The file you are trying to update is an outdated" +
631
                            " version.  Please checkout the newest document, " +
632
                            "merge your changes and try again.");
633
      }//else if
634
    }//if
635
636
   return flag;
637
638
  }//getDataFileLockGrant
639
640
  /**
641 393 jones
   * get the document name
642
   */
643
  public String getDocname() {
644
    return docname;
645
  }
646
647
  /**
648
   * get the document type (which is the PublicID)
649
   */
650
  public String getDoctype() {
651
    return doctype;
652
  }
653
654
  /**
655
   * get the system identifier
656
   */
657
  public String getSystemID() {
658
    return system_id;
659
  }
660
661
  /**
662
   * get the root node identifier
663
   */
664
  public long getRootNodeID() {
665
    return rootnodeid;
666
  }
667 465 berkley
668
  /**
669
   * get the creation date
670
   */
671
  public String getCreateDate() {
672
    return createdate;
673
  }
674
675
  /**
676
   * get the update date
677
   */
678
  public String getUpdateDate() {
679
    return updatedate;
680
  }
681 393 jones
682 396 jones
  /**
683
   * Get the document identifier (docid)
684
   */
685
  public String getDocID() {
686
    return docid;
687
  }
688 465 berkley
689 691 bojilova
// DOCTITLE attr cleared from the db
690
//  /**
691
//   *get the document title
692
//   */
693
//  public String getDocTitle() {
694
//    return doctitle;
695
//  }
696 561 berkley
697
  public String getUserowner() {
698
    return userowner;
699
  }
700
701
  public String getUserupdated() {
702
    return userupdated;
703
  }
704
705
  public int getServerlocation() {
706
    return serverlocation;
707
  }
708
709 1059 tao
  public String getDocHomeServer() {
710
    return docHomeServer;
711 1055 tao
  }
712 1059 tao
713 1055 tao
714 1059 tao
715 697 bojilova
  public String getPublicaccess() {
716 561 berkley
    return publicaccess;
717
  }
718 575 berkley
719
  public int getRev() {
720
    return rev;
721
  }
722 956 tao
723 1441 tao
  public String getValidateType()
724
  {
725
    return validateType;
726
  }
727
728 1435 tao
  /**
729 429 jones
   * Print a string representation of the XML document
730 393 jones
   */
731 1480 tao
  public String toString(String user, String[] groups, boolean withInlinedata)
732 393 jones
  {
733 429 jones
    StringWriter docwriter = new StringWriter();
734 1435 tao
    try
735
    {
736 1480 tao
      this.toXml(docwriter, user, groups, withInlinedata);
737 1435 tao
    }
738
    catch (McdbException mcdbe)
739
    {
740 800 jones
      return null;
741
    }
742 429 jones
    String document = docwriter.toString();
743
    return document;
744
  }
745 1435 tao
746
   /**
747
   * Print a string representation of the XML document
748
   */
749
  public String toString()
750
  {
751
    StringWriter docwriter = new StringWriter();
752
    String userName = null;
753
    String[] groupNames = null;
754 1480 tao
    boolean withInlineData = false;
755 1435 tao
    try
756
    {
757 1480 tao
      this.toXml(docwriter, userName, groupNames, withInlineData);
758 1435 tao
    }
759
    catch (McdbException mcdbe)
760
    {
761
      return null;
762
    }
763
    String document = docwriter.toString();
764
    return document;
765
  }
766 429 jones
767
  /**
768
   * Get a text representation of the XML document as a string
769
   * This older algorithm uses a recursive tree of Objects to represent the
770
   * nodes of the tree.  Each object is passed the data for the document
771
   * and searches all of the document data to find its children nodes and
772
   * recursively build.  Thus, because each node reads the whole document,
773
   * this algorithm is extremely slow for larger documents, and the time
774
   * to completion is O(N^N) wrt the number of nodes.  See toXml() for a
775
   * better algorithm.
776
   */
777 800 jones
  public String readUsingSlowAlgorithm() throws McdbException
778 429 jones
  {
779 393 jones
    StringBuffer doc = new StringBuffer();
780
781 800 jones
    // First, check that we have the needed node data, and get it if not
782
    if (nodeRecordList == null) {
783
      nodeRecordList = getNodeRecordList(rootnodeid);
784
    }
785
786 429 jones
    // Create the elements from the downloaded data in the TreeSet
787
    rootNode = new ElementNode(nodeRecordList, rootnodeid);
788
789 393 jones
    // Append the resulting document to the StringBuffer and return it
790
    doc.append("<?xml version=\"1.0\"?>\n");
791
792
    if (docname != null) {
793
      if ((doctype != null) && (system_id != null)) {
794
        doc.append("<!DOCTYPE " + docname + " PUBLIC \"" + doctype +
795
                   "\" \"" + system_id + "\">\n");
796
      } else {
797
        doc.append("<!DOCTYPE " + docname + ">\n");
798
      }
799
    }
800
    doc.append(rootNode.toString());
801
802
    return (doc.toString());
803
  }
804
805
  /**
806 429 jones
   * Print a text representation of the XML document to a Writer
807
   *
808
   * @param pw the Writer to which we print the document
809
   */
810 1480 tao
  public void toXml(Writer pw, String user, String[] groups, boolean withInLineData)
811 1432 tao
                                                          throws McdbException
812 429 jones
  {
813 1458 tao
    // flag for process  eml2
814
    boolean proccessEml2 = false;
815
    if (doctype != null && doctype.equals(EMLNAMESPACE))
816
    {
817
      proccessEml2 = true;
818
    }
819
    // flag for process inline data
820
    boolean prcocessInlineData = false;
821
822 1439 tao
    TreeSet nodeRecordLists = null;
823 429 jones
    PrintWriter out = null;
824
    if (pw instanceof PrintWriter) {
825
      out = (PrintWriter)pw;
826
    } else {
827
      out = new PrintWriter(pw);
828
    }
829
830
    MetaCatUtil util = new MetaCatUtil();
831
832 1432 tao
    // Here add code to handle subtree access control
833
    PermissionController control = new PermissionController(docid);
834
    Hashtable unaccessableSubTree =control.hasUnaccessableSubTree(user, groups,
835
                                             AccessControlInterface.READSTRING);
836
837
    if (!unaccessableSubTree.isEmpty())
838
    {
839 1439 tao
840
      nodeRecordLists = getPartNodeRecordList(rootnodeid, unaccessableSubTree);
841
842 1432 tao
    }
843 1439 tao
    else
844 1432 tao
    {
845 1439 tao
      nodeRecordLists = getNodeRecordList(rootnodeid);
846 800 jones
    }
847
848 429 jones
    Stack openElements = new Stack();
849
    boolean atRootElement = true;
850
    boolean previousNodeWasElement = false;
851
852
    // Step through all of the node records we were given
853 1439 tao
854
    Iterator it = nodeRecordLists.iterator();
855
856
    while (it.hasNext())
857
    {
858
859 429 jones
      NodeRecord currentNode = (NodeRecord)it.next();
860 1439 tao
      util.debugMessage("[Got Node ID: " + currentNode.nodeid +
861
                          " (" + currentNode.parentnodeid +
862
                          ", " + currentNode.nodeindex +
863
                          ", " + currentNode.nodetype +
864
                          ", " + currentNode.nodename +
865
                          ", " + currentNode.nodedata + ")]", 50);
866 429 jones
      // Print the end tag for the previous node if needed
867
      //
868
      // This is determined by inspecting the parent nodeid for the
869
      // currentNode.  If it is the same as the nodeid of the last element
870
      // that was pushed onto the stack, then we are still in that previous
871
      // parent element, and we do nothing.  However, if it differs, then we
872
      // have returned to a level above the previous parent, so we go into
873
      // a loop and pop off nodes and print out their end tags until we get
874
      // the node on the stack to match the currentNode parentnodeid
875
      //
876
      // So, this of course means that we rely on the list of elements
877
      // having been sorted in a depth first traversal of the nodes, which
878
      // is handled by the NodeComparator class used by the TreeSet
879
      if (!atRootElement) {
880
        NodeRecord currentElement = (NodeRecord)openElements.peek();
881
        if ( currentNode.parentnodeid != currentElement.nodeid ) {
882
          while ( currentNode.parentnodeid != currentElement.nodeid ) {
883
            currentElement = (NodeRecord)openElements.pop();
884 1427 tao
            util.debugMessage("\n POPPED: " + currentElement.nodename, 50);
885 451 bojilova
            if (previousNodeWasElement) {
886
              out.print(">");
887
              previousNodeWasElement = false;
888
            }
889 826 bojilova
            if ( currentElement.nodeprefix != null ) {
890
              out.print("</" + currentElement.nodeprefix + ":" +
891
                        currentElement.nodename + ">" );
892
            } else {
893
              out.print("</" + currentElement.nodename + ">" );
894
            }
895 429 jones
            currentElement = (NodeRecord)openElements.peek();
896
          }
897
        }
898
      }
899
900
      // Handle the DOCUMENT node
901
      if (currentNode.nodetype.equals("DOCUMENT")) {
902
        out.println("<?xml version=\"1.0\"?>");
903 1441 tao
        if (docname != null && validateType != null && validateType.equals(DTD))
904
        {
905
          if ((doctype != null) && (system_id != null))
906
          {
907
908 429 jones
            out.println("<!DOCTYPE " + docname + " PUBLIC \"" + doctype +
909
                       "\" \"" + system_id + "\">");
910 1441 tao
          }
911
          else
912
          {
913
914 429 jones
            out.println("<!DOCTYPE " + docname + ">");
915
          }
916
        }
917
918
      // Handle the ELEMENT nodes
919
      } else if (currentNode.nodetype.equals("ELEMENT")) {
920
        if (atRootElement) {
921
          atRootElement = false;
922
        } else {
923
          if (previousNodeWasElement) {
924
            out.print(">");
925
          }
926
        }
927
        openElements.push(currentNode);
928 1427 tao
        util.debugMessage("\n PUSHED: " + currentNode.nodename, 50);
929 429 jones
        previousNodeWasElement = true;
930 826 bojilova
        if ( currentNode.nodeprefix != null ) {
931
          out.print("<" + currentNode.nodeprefix + ":" + currentNode.nodename);
932
        } else {
933
          out.print("<" + currentNode.nodename);
934
        }
935 1458 tao
936
        // if currentNode is inline and handle eml2, set flag proccess in
937
        if (currentNode.nodename != null &&
938
            currentNode.nodename.equals(EmlSAXHandler.INLINE) && proccessEml2)
939
        {
940
          prcocessInlineData = true;
941
        }
942 429 jones
943
      // Handle the ATTRIBUTE nodes
944
      } else if (currentNode.nodetype.equals("ATTRIBUTE")) {
945 826 bojilova
        if ( currentNode.nodeprefix != null ) {
946
          out.print(" " + currentNode.nodeprefix + ":" + currentNode.nodename +
947
                    "=\"" + currentNode.nodedata + "\"");
948
        } else {
949
          out.print(" " + currentNode.nodename + "=\"" +
950
                    currentNode.nodedata + "\"");
951
        }
952 821 bojilova
953
      // Handle the NAMESPACE nodes
954
      } else if (currentNode.nodetype.equals("NAMESPACE")) {
955
        out.print(" xmlns:" + currentNode.nodename + "=\""
956
                 + currentNode.nodedata + "\"");
957
958
      // Handle the TEXT nodes
959 429 jones
      } else if (currentNode.nodetype.equals("TEXT")) {
960
        if (previousNodeWasElement) {
961
          out.print(">");
962
        }
963 1480 tao
        if (!prcocessInlineData || !withInLineData)
964 1458 tao
        {
965 1480 tao
          // if it is not inline data just out put data or it is line data
966
          // but user don't want it, just put local id in inlinedata
967 1458 tao
          out.print(currentNode.nodedata);
968
        }
969
        else
970
        {
971 1480 tao
          // if it is inline data and user want to see it, pull out from
972
          // file system and output it
973 1458 tao
          // for inline data, the data base only store the file name, so we
974
          // can combine the file name and inline data file path, to get it
975
          String fileName = currentNode.nodedata;
976 1515 tao
          String content = EmlSAXHandler.readInlineDataFromFileSystem(fileName);
977 1458 tao
          out.print(content);
978
        }
979
        // reset proccess inline data false
980
        prcocessInlineData =false;
981 429 jones
        previousNodeWasElement = false;
982
983
      // Handle the COMMENT nodes
984
      } else if (currentNode.nodetype.equals("COMMENT")) {
985
        if (previousNodeWasElement) {
986
          out.print(">");
987
        }
988
        out.print("<!--" + currentNode.nodedata + "-->");
989
        previousNodeWasElement = false;
990
991
      // Handle the PI nodes
992
      } else if (currentNode.nodetype.equals("PI")) {
993
        if (previousNodeWasElement) {
994
          out.print(">");
995
        }
996
        out.print("<?" + currentNode.nodename + " " +
997
                        currentNode.nodedata + "?>");
998
        previousNodeWasElement = false;
999
1000
      // Handle any other node type (do nothing)
1001
      } else {
1002
        // Any other types of nodes are not handled.
1003
        // Probably should throw an exception here to indicate this
1004
      }
1005
      out.flush();
1006
    }
1007 1439 tao
1008 429 jones
    // Print the final end tag for the root element
1009 686 berkley
    while(!openElements.empty())
1010
    {
1011
      NodeRecord currentElement = (NodeRecord)openElements.pop();
1012 1427 tao
      util.debugMessage("\n POPPED: " + currentElement.nodename, 50);
1013 826 bojilova
      if ( currentElement.nodeprefix != null ) {
1014
        out.print("</" + currentElement.nodeprefix + ":" +
1015
                  currentElement.nodename + ">" );
1016
      } else {
1017
        out.print("</" + currentElement.nodename + ">" );
1018
      }
1019 686 berkley
    }
1020 429 jones
    out.flush();
1021
  }
1022 622 berkley
1023 1515 tao
1024 1458 tao
1025 622 berkley
  private boolean isRevisionOnly(DocumentIdentifier docid) throws Exception
1026
  {
1027
    //System.out.println("inRevisionOnly");
1028 1217 tao
    DBConnection dbconn = null;
1029
    int serialNumber = -1;
1030
    PreparedStatement pstmt =null;
1031 622 berkley
    String rev = docid.getRev();
1032
    String newid = docid.getIdentifier();
1033 1217 tao
    try
1034
    {
1035
      dbconn=DBConnectionPool.
1036
                    getDBConnection("DocumentImpl.isRevisionOnly");
1037
      serialNumber=dbconn.getCheckOutSerialNumber();
1038
      pstmt = dbconn.prepareStatement("select rev from xml_documents " +
1039 622 berkley
                                  "where docid like '" + newid + "'");
1040 1217 tao
      pstmt.execute();
1041
      ResultSet rs = pstmt.getResultSet();
1042
      boolean tablehasrows = rs.next();
1043
      if(rev.equals("newest") || rev.equals("all"))
1044
      {
1045 622 berkley
        return false;
1046
      }
1047 1217 tao
1048
      if(tablehasrows)
1049
      {
1050
        int r = rs.getInt(1);
1051
        pstmt.close();
1052
        if(new Integer(rev).intValue() == r)
1053
        { //the current revision in in xml_documents
1054
          //System.out.println("returning false");
1055
          return false;
1056
        }
1057
        else if(new Integer(rev).intValue() < r)
1058
        { //the current revision is in xml_revisions.
1059
          //System.out.println("returning true");
1060
          return true;
1061
        }
1062
        else if(new Integer(rev).intValue() > r)
1063
        { //error, rev cannot be greater than r
1064
          throw new Exception("requested revision cannot be greater than " +
1065 622 berkley
                            "the latest revision number.");
1066 1217 tao
        }
1067 622 berkley
      }
1068 1292 tao
      // Get miss docid and rev, throw to McdDocNotFoundException
1069
      String missDocId = MetaCatUtil.getDocIdFromString(docid.toString());
1070
      String missRevision =
1071
                  MetaCatUtil.getRevisionStringFromString(docid.toString());
1072
      throw new McdbDocNotFoundException("the requested docid '" +
1073
                docid.toString() + "' does not exist", missDocId, missRevision);
1074 1217 tao
    }//try
1075
    finally
1076
    {
1077
      pstmt.close();
1078
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1079
    }//finally
1080 622 berkley
  }
1081 429 jones
1082 800 jones
  private void getDocumentInfo(String docid) throws McdbException,
1083 1292 tao
                                        AccessionNumberException, Exception
1084 622 berkley
  {
1085
    getDocumentInfo(new DocumentIdentifier(docid));
1086
  }
1087
1088 429 jones
  /**
1089 393 jones
   * Look up the document type information from the database
1090
   *
1091
   * @param docid the id of the document to look up
1092
   */
1093 1292 tao
  private void getDocumentInfo(DocumentIdentifier docid) throws McdbException
1094
                                                          , Exception
1095 393 jones
  {
1096 1217 tao
    DBConnection dbconn = null;
1097
    int serialNumber = -1;
1098
    PreparedStatement pstmt = null;
1099 622 berkley
    String table = "xml_documents";
1100 1059 tao
1101 622 berkley
    try
1102
    {
1103
      if(isRevisionOnly(docid))
1104
      { //pull the document from xml_revisions instead of from xml_documents;
1105
        table = "xml_revisions";
1106
      }
1107
    }
1108 1292 tao
    // catch a McdbDocNotFoundException throw it
1109
    catch (McdbDocNotFoundException notFound)
1110 622 berkley
    {
1111 1292 tao
      throw notFound;
1112 622 berkley
    }
1113 1292 tao
    catch(Exception e)
1114 622 berkley
    {
1115
1116 1292 tao
      MetaCatUtil.debugMessage("error in DocumentImpl.getDocumentInfo: " +
1117
                          e.getMessage(), 30);
1118
      throw e;
1119 622 berkley
    }
1120
1121 1292 tao
1122
1123 1217 tao
    try
1124
    {
1125
      dbconn=DBConnectionPool.getDBConnection("DocumentImpl.getDocumentInfo");
1126
      serialNumber=dbconn.getCheckOutSerialNumber();
1127 622 berkley
      StringBuffer sql = new StringBuffer();
1128 691 bojilova
// DOCTITLE attr cleared from the db
1129
//      sql.append("SELECT docname, doctype, rootnodeid, doctitle, ");
1130
      sql.append("SELECT docname, doctype, rootnodeid, ");
1131 697 bojilova
      sql.append("date_created, date_updated, user_owner, user_updated, ");
1132
      sql.append("server_location, public_access, rev");
1133
      sql.append(" FROM ").append(table);
1134 622 berkley
      sql.append(" WHERE docid LIKE '").append(docid.getIdentifier());
1135
      sql.append("' and rev like '").append(docid.getRev()).append("'");
1136
      //System.out.println(sql.toString());
1137 393 jones
      pstmt =
1138 1217 tao
        dbconn.prepareStatement(sql.toString());
1139 393 jones
      // Bind the values to the query
1140 622 berkley
      //pstmt.setString(1, docid.getIdentifier());
1141
      //pstmt.setString(2, docid.getRev());
1142 393 jones
1143
      pstmt.execute();
1144
      ResultSet rs = pstmt.getResultSet();
1145
      boolean tableHasRows = rs.next();
1146
      if (tableHasRows) {
1147 561 berkley
        this.docname        = rs.getString(1);
1148
        this.doctype        = rs.getString(2);
1149
        this.rootnodeid     = rs.getLong(3);
1150 691 bojilova
// DOCTITLE attr cleared from the db
1151
//        this.doctitle       = rs.getString(4);
1152 692 bojilova
        this.createdate     = rs.getString(4);
1153
        this.updatedate     = rs.getString(5);
1154
        this.userowner      = rs.getString(6);
1155
        this.userupdated    = rs.getString(7);
1156
        this.serverlocation = rs.getInt(8);
1157 697 bojilova
        this.publicaccess   = rs.getString(9);
1158
        this.rev            = rs.getInt(10);
1159 393 jones
      }
1160 818 berkley
      pstmt.close();
1161 1059 tao
1162
      //get doc  home server name
1163
1164 1217 tao
      pstmt = dbconn.prepareStatement("select server " +
1165 1059 tao
                        "from xml_replication where serverid = ?");
1166 1217 tao
      //because connection use twise here, so we need to increase one
1167
      dbconn.increaseUsageCount(1);
1168 1059 tao
      pstmt.setInt(1, serverlocation);
1169
      pstmt.execute();
1170
      rs = pstmt.getResultSet();
1171
      tableHasRows = rs.next();
1172
      if (tableHasRows)
1173
      {
1174
1175
          String server = rs.getString(1);
1176
          //get homeserver name
1177
          if(!server.equals("localhost"))
1178
          {
1179
            this.docHomeServer=server;
1180
          }
1181
          else
1182
          {
1183
            this.docHomeServer=MetaCatUtil.getLocalReplicationServerName();
1184
          }
1185
          MetaCatUtil.debugMessage("server: "+docHomeServer, 50);
1186
1187
      }
1188
      pstmt.close();
1189 393 jones
      if (this.doctype != null) {
1190
        pstmt =
1191 1441 tao
          dbconn.prepareStatement("SELECT system_id, entry_type " +
1192 393 jones
                                  "FROM xml_catalog " +
1193 769 bojilova
                                 "WHERE public_id = ?");
1194 1217 tao
        //should increase usage count again
1195
        dbconn.increaseUsageCount(1);
1196 393 jones
        // Bind the values to the query
1197
        pstmt.setString(1, doctype);
1198
1199
        pstmt.execute();
1200
        rs = pstmt.getResultSet();
1201
        tableHasRows = rs.next();
1202
        if (tableHasRows) {
1203
          this.system_id  = rs.getString(1);
1204 1441 tao
          this.validateType = rs.getString(2);
1205
1206 393 jones
        }
1207 818 berkley
        pstmt.close();
1208 393 jones
      }
1209
    } catch (SQLException e) {
1210 675 berkley
      System.out.println("error in DocumentImpl.getDocumentInfo: " +
1211
                          e.getMessage());
1212 622 berkley
      e.printStackTrace(System.out);
1213 675 berkley
      throw new McdbException("Error accessing database connection in " +
1214
                              "DocumentImpl.getDocumentInfo: ", e);
1215 393 jones
    }
1216 1217 tao
    finally
1217
    {
1218
      try
1219
      {
1220
        pstmt.close();
1221
      }
1222
      catch (SQLException ee)
1223
      {
1224
        MetaCatUtil.debugMessage("error in DocumentImple.getDocumentInfo: "
1225
                                    +ee.getMessage(), 30);
1226
      }//catch
1227
      finally
1228
      {
1229
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1230
      }
1231
    }
1232 393 jones
1233
    if (this.docname == null) {
1234 1292 tao
      throw new McdbDocNotFoundException("Document not found: " + docid,
1235
                                 docid.getIdentifier(), docid.getRev());
1236 393 jones
    }
1237
  }
1238 1439 tao
1239
  /**
1240
   * Look up the node data from the database, but some node would be shown
1241
   * because of access control
1242
   * @param rootnodeid the id of the root node of the node tree to look up
1243
   * @param accessControl  the hashtable has control info
1244
   */
1245
  private TreeSet getPartNodeRecordList(long rootnodeid,
1246
                                        Hashtable accessControl)
1247
                                        throws McdbException
1248
  {
1249
    PreparedStatement pstmt = null;
1250
    DBConnection dbconn = null;
1251
    int serialNumber = -1;
1252
    TreeSet nodeRecordList = new TreeSet(new NodeComparator());
1253
    long nodeid = 0;
1254
    long parentnodeid = 0;
1255
    long nodeindex = 0;
1256
    String nodetype = null;
1257
    String nodename = null;
1258
    String nodeprefix = null;
1259
    String nodedata = null;
1260
    String quotechar = dbAdapter.getStringDelimiter();
1261
    String sql = "SELECT nodeid,parentnodeid,nodeindex, " +
1262
                 "nodetype,nodename,nodeprefix,nodedata " +
1263
                  "FROM xml_nodes WHERE rootnodeid = ?";
1264
1265
    // go through the access control for some nodes
1266
     Enumeration en = accessControl.elements();
1267
     while (en.hasMoreElements())
1268
     {
1269
         SubTree tree = (SubTree)en.nextElement();
1270
         long startId = tree.getStartNodeId();
1271
         long endId  = tree.getEndNodeId();
1272
         sql = sql +" AND(nodeid < " + startId + " OR nodeid > " +endId +")";
1273
1274
     }
1275
     MetaCatUtil.debugMessage("The final query to select part node tree: " +
1276
                              sql, 25);
1277 393 jones
1278 1439 tao
    try
1279
    {
1280
      dbconn=DBConnectionPool.
1281
                    getDBConnection("DocumentImpl.getPartNodeRecordList");
1282
      serialNumber=dbconn.getCheckOutSerialNumber();
1283
      pstmt = dbconn.prepareStatement(sql);
1284
1285
      // Bind the values to the query
1286
      pstmt.setLong(1, rootnodeid);
1287
      pstmt.execute();
1288
      ResultSet rs = pstmt.getResultSet();
1289
      boolean tableHasRows = rs.next();
1290
      while (tableHasRows)
1291
      {
1292
        nodeid = rs.getLong(1);
1293
        parentnodeid = rs.getLong(2);
1294
        nodeindex = rs.getLong(3);
1295
        nodetype = rs.getString(4);
1296
        nodename = rs.getString(5);
1297
        nodeprefix = rs.getString(6);
1298
        nodedata = rs.getString(7);
1299
        nodedata = MetaCatUtil.normalize(nodedata);
1300
        // add the data to the node record list hashtable
1301
        NodeRecord currentRecord = new NodeRecord(nodeid,parentnodeid,nodeindex,
1302
                                      nodetype, nodename, nodeprefix, nodedata);
1303
        nodeRecordList.add(currentRecord);
1304
1305
        // Advance to the next node
1306
        tableHasRows = rs.next();
1307
      }
1308
      pstmt.close();
1309
1310
    }
1311
    catch (SQLException e)
1312
    {
1313
      throw new McdbException("Error in DocumentImpl.getPartNodeRecordList " +
1314
                              e.getMessage());
1315
    }
1316
    finally
1317
    {
1318
      try
1319
      {
1320
        pstmt.close();
1321
      }
1322
      catch (SQLException ee)
1323
      {
1324
        MetaCatUtil.debugMessage("error in DocumentImpl.getPartNodeRecordList: "
1325
                                    +ee.getMessage(), 30);
1326
      }
1327
      finally
1328
      {
1329
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1330
      }
1331
    }
1332
1333
1334
    if (!nodeRecordList.isEmpty())
1335
    {
1336
1337
      return nodeRecordList;
1338
    }
1339
    else
1340
    {
1341
1342
      throw new McdbException("Error getting node data: " + docid);
1343
    }
1344
  }
1345
1346 393 jones
  /**
1347
   * Look up the node data from the database
1348
   *
1349 396 jones
   * @param rootnodeid the id of the root node of the node tree to look up
1350 393 jones
   */
1351 1217 tao
  private TreeSet getNodeRecordList(long rootnodeid) throws McdbException
1352 393 jones
  {
1353 1217 tao
    PreparedStatement pstmt = null;
1354
    DBConnection dbconn = null;
1355
    int serialNumber = -1;
1356 393 jones
    TreeSet nodeRecordList = new TreeSet(new NodeComparator());
1357
    long nodeid = 0;
1358
    long parentnodeid = 0;
1359
    long nodeindex = 0;
1360
    String nodetype = null;
1361
    String nodename = null;
1362 826 bojilova
    String nodeprefix = null;
1363 393 jones
    String nodedata = null;
1364 899 berkley
    String quotechar = dbAdapter.getStringDelimiter();
1365 393 jones
1366
    try {
1367 1217 tao
      dbconn=DBConnectionPool.
1368
                    getDBConnection("DocumentImpl.getNodeRecordList");
1369
      serialNumber=dbconn.getCheckOutSerialNumber();
1370 393 jones
      pstmt =
1371 1217 tao
      dbconn.prepareStatement("SELECT nodeid,parentnodeid,nodeindex, " +
1372 899 berkley
           "nodetype,nodename,nodeprefix,nodedata " +
1373 396 jones
           "FROM xml_nodes WHERE rootnodeid = ?");
1374 393 jones
1375
      // Bind the values to the query
1376 396 jones
      pstmt.setLong(1, rootnodeid);
1377 393 jones
1378
      pstmt.execute();
1379
      ResultSet rs = pstmt.getResultSet();
1380
      boolean tableHasRows = rs.next();
1381
      while (tableHasRows) {
1382
        nodeid = rs.getLong(1);
1383
        parentnodeid = rs.getLong(2);
1384
        nodeindex = rs.getLong(3);
1385
        nodetype = rs.getString(4);
1386
        nodename = rs.getString(5);
1387 826 bojilova
        nodeprefix = rs.getString(6);
1388
        nodedata = rs.getString(7);
1389 899 berkley
        nodedata = MetaCatUtil.normalize(nodedata);
1390 393 jones
        // add the data to the node record list hashtable
1391 826 bojilova
        NodeRecord currentRecord = new NodeRecord(nodeid,parentnodeid,nodeindex,
1392 946 tao
                                      nodetype, nodename, nodeprefix, nodedata);
1393 393 jones
        nodeRecordList.add(currentRecord);
1394
1395
        // Advance to the next node
1396
        tableHasRows = rs.next();
1397
      }
1398
      pstmt.close();
1399
1400
    } catch (SQLException e) {
1401 826 bojilova
      throw new McdbException("Error in DocumentImpl.getNodeRecordList " +
1402
                              e.getMessage());
1403 393 jones
    }
1404 1217 tao
    finally
1405
    {
1406
      try
1407
      {
1408
        pstmt.close();
1409
      }
1410
      catch (SQLException ee)
1411
      {
1412
        MetaCatUtil.debugMessage("error in DocumentImpl.getNodeRecordList: "
1413
                                    +ee.getMessage(), 30);
1414
      }
1415
      finally
1416
      {
1417
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1418
      }
1419
    }
1420 1467 tao
1421
    return nodeRecordList;
1422
1423 393 jones
  }
1424 549 berkley
1425 697 bojilova
// NOT USED ANY MORE
1426
//  /** creates SQL code and inserts new document into DB connection
1427
//   default serverCode of 1*/
1428
//  private void writeDocumentToDB(String action, String user)
1429
//               throws SQLException, Exception
1430
//  {
1431
//    writeDocumentToDB(action, user, null, 1);
1432
//  }
1433 393 jones
1434 459 bojilova
 /** creates SQL code and inserts new document into DB connection */
1435 680 bojilova
  private void writeDocumentToDB(String action, String user, String pub,
1436 697 bojilova
                                 String catalogid, int serverCode)
1437 459 bojilova
               throws SQLException, Exception {
1438 754 bojilova
    String sysdate = dbAdapter.getDateTimeFunction();
1439 747 bojilova
1440 459 bojilova
    try {
1441
      PreparedStatement pstmt = null;
1442
1443
      if (action.equals("INSERT")) {
1444
        //AccessionNumber ac = new AccessionNumber();
1445
        //this.docid = ac.generate(docid, "INSERT");
1446 1217 tao
1447
        pstmt = connection.prepareStatement(
1448 697 bojilova
                "INSERT INTO xml_documents " +
1449
                "(docid, rootnodeid, docname, doctype, " +
1450
                "user_owner, user_updated, date_created, date_updated, " +
1451 1072 tao
                "public_access, catalog_id, server_location, rev) " +
1452 747 bojilova
                "VALUES (?, ?, ?, ?, ?, ?, " + sysdate + ", " + sysdate +
1453 1072 tao
                ", ?, ?, ?, ?)");
1454 1217 tao
        // Increase dbconnection usage count
1455
        connection.increaseUsageCount(1);
1456
1457 549 berkley
        //note that the server_location is set to 1.
1458
        //this means that "localhost" in the xml_replication table must
1459
        //always be the first entry!!!!!
1460
1461 459 bojilova
        // Bind the values to the query
1462
        pstmt.setString(1, this.docid);
1463
        pstmt.setLong(2, rootnodeid);
1464
        pstmt.setString(3, docname);
1465
        pstmt.setString(4, doctype);
1466
        pstmt.setString(5, user);
1467
        pstmt.setString(6, user);
1468 1069 tao
        //public access is usefulless, so set it to null
1469
        pstmt.setString(7, null);
1470
        /*if ( pub == null ) {
1471 680 bojilova
          pstmt.setString(7, null);
1472 697 bojilova
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
1473 680 bojilova
          pstmt.setInt(7, 1);
1474 697 bojilova
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
1475 680 bojilova
          pstmt.setInt(7, 0);
1476 1069 tao
        }*/
1477 697 bojilova
        pstmt.setString(8, catalogid);
1478
        pstmt.setInt(9, serverCode);
1479 1072 tao
        pstmt.setInt(10, Integer.parseInt(updatedVersion));
1480 459 bojilova
      } else if (action.equals("UPDATE")) {
1481
1482 1072 tao
        // Save the old document publicaccessentry in a backup table
1483 1217 tao
        DocumentImpl.archiveDocRevision(connection, docid, user );
1484 1292 tao
        DocumentImpl thisdoc = new DocumentImpl(docid, false);
1485 575 berkley
        int thisrev = thisdoc.getRev();
1486 956 tao
1487
        //if the updated vesion is not greater than current one,
1488
        //throw it into a exception
1489
        if (Integer.parseInt(updatedVersion)<=thisrev)
1490
        {
1491
          throw new Exception("Next revision number couldn't be less"
1492
                               +" than or equal "+ thisrev);
1493
        }
1494
        else
1495
        {
1496
          //set the user specified revision
1497
          thisrev=Integer.parseInt(updatedVersion);
1498
        }
1499
1500 459 bojilova
        // Delete index for the old version of docid
1501
        // The new index is inserting on the next calls to DBSAXNode
1502 1217 tao
        pstmt = connection.prepareStatement(
1503 459 bojilova
                "DELETE FROM xml_index WHERE docid='" + this.docid + "'");
1504 1217 tao
        // Increase dbconnection usage count
1505
        connection.increaseUsageCount(1);
1506
1507 459 bojilova
        pstmt.execute();
1508 818 berkley
        pstmt.close();
1509 459 bojilova
1510
        // Update the new document to reflect the new node tree
1511 1217 tao
        pstmt = connection.prepareStatement(
1512 459 bojilova
            "UPDATE xml_documents " +
1513
            "SET rootnodeid = ?, docname = ?, doctype = ?, " +
1514 747 bojilova
            "user_updated = ?, date_updated = " + sysdate + ", " +
1515 697 bojilova
            "server_location = ?, rev = ?, public_access = ?, catalog_id = ? " +
1516 769 bojilova
            "WHERE docid = ?");
1517 1217 tao
        // Increase dbconnection usage count
1518
        connection.increaseUsageCount(1);
1519 459 bojilova
        // Bind the values to the query
1520
        pstmt.setLong(1, rootnodeid);
1521
        pstmt.setString(2, docname);
1522
        pstmt.setString(3, doctype);
1523
        pstmt.setString(4, user);
1524 549 berkley
        pstmt.setInt(5, serverCode);
1525 575 berkley
        pstmt.setInt(6, thisrev);
1526 1069 tao
        pstmt.setString(7, null);
1527
        /*if ( pub == null ) {
1528 680 bojilova
          pstmt.setString(7, null);
1529 697 bojilova
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
1530 680 bojilova
          pstmt .setInt(7, 1);
1531 697 bojilova
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
1532 680 bojilova
          pstmt.setInt(7, 0);
1533 1069 tao
        }*/
1534 697 bojilova
        pstmt.setString(8, catalogid);
1535
        pstmt.setString(9, this.docid);
1536 575 berkley
1537 459 bojilova
      } else {
1538
        System.err.println("Action not supported: " + action);
1539
      }
1540
1541
      // Do the insertion
1542
      pstmt.execute();
1543 1217 tao
1544 459 bojilova
      pstmt.close();
1545
1546
    } catch (SQLException sqle) {
1547
      throw sqle;
1548
    } catch (Exception e) {
1549
      throw e;
1550
    }
1551
  }
1552
1553
  /**
1554 407 jones
   * Write an XML file to the database, given a filename
1555 393 jones
   *
1556 408 jones
   * @param conn the JDBC connection to the database
1557 407 jones
   * @param filename the filename to be loaded into the database
1558 680 bojilova
   * @param pub flag for public "read" access on document
1559
   * @param dtdfilename the dtd to be uploaded on server's file system
1560 407 jones
   * @param action the action to be performed (INSERT OR UPDATE)
1561
   * @param docid the docid to use for the INSERT OR UPDATE
1562 680 bojilova
   * @param user the user that owns the document
1563 802 bojilova
   * @param groups the groups to which user belongs
1564 393 jones
   */
1565 1383 tao
  /*public static String write(DBConnection conn,String filename,
1566 680 bojilova
                             String pub, String dtdfilename,
1567 598 bojilova
                             String action, String docid, String user,
1568 802 bojilova
                             String[] groups )
1569 457 bojilova
                throws Exception {
1570 598 bojilova
1571
    Reader dtd = null;
1572
    if ( dtdfilename != null ) {
1573
      dtd = new FileReader(new File(dtdfilename).toString());
1574
    }
1575 555 bojilova
    return write ( conn, new FileReader(new File(filename).toString()),
1576 802 bojilova
                   pub, dtd, action, docid, user, groups, false);
1577 1383 tao
  }*/
1578 598 bojilova
1579 1217 tao
  public static String write(DBConnection conn,Reader xml,String pub,Reader dtd,
1580 598 bojilova
                             String action, String docid, String user,
1581 1383 tao
                             String[] groups, String ruleBase,
1582
                             boolean needValidation)
1583 549 berkley
                throws Exception {
1584 1012 tao
    //this method will be called in handleUpdateOrInsert method
1585 1383 tao
    //in MetacatServlet class and now is wrapper into documentImple
1586 1012 tao
    // get server location for this doc
1587 1217 tao
    int serverLocation=getServerLocationNumber(docid);
1588 1012 tao
    return write(conn,xml,pub,dtd,action,docid,user,groups,serverLocation,false,
1589 1383 tao
                 ruleBase, needValidation);
1590 598 bojilova
  }
1591
1592 1383 tao
1593 549 berkley
1594 407 jones
  /**
1595
   * Write an XML file to the database, given a Reader
1596
   *
1597 408 jones
   * @param conn the JDBC connection to the database
1598 407 jones
   * @param xml the xml stream to be loaded into the database
1599 680 bojilova
   * @param pub flag for public "read" access on xml document
1600
   * @param dtd the dtd to be uploaded on server's file system
1601 734 bojilova
   * @param action the action to be performed (INSERT or UPDATE)
1602
   * @param accnum the docid + rev# to use on INSERT or UPDATE
1603 580 berkley
   * @param user the user that owns the document
1604 802 bojilova
   * @param groups the groups to which user belongs
1605 580 berkley
   * @param serverCode the serverid from xml_replication on which this document
1606
   *        resides.
1607
   * @param override flag to stop insert replication checking.
1608
   *        if override = true then a document not belonging to the local server
1609
   *        will not be checked upon update for a file lock.
1610
   *        if override = false then a document not from this server, upon
1611
   *        update will be locked and version checked.
1612 407 jones
   */
1613 559 berkley
1614 1217 tao
  public static String write(DBConnection conn, Reader xml,String pub,
1615
                         Reader dtd, String action, String accnum, String user,
1616
                         String[] groups, int serverCode, boolean override,
1617 1383 tao
                         String ruleBase, boolean needValidation)
1618 598 bojilova
                throws Exception
1619 573 berkley
  {
1620 779 bojilova
    // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1621 1217 tao
    //MetaCatUtil util = new MetaCatUtil();
1622
    MetaCatUtil.debugMessage("conn usage count before writting: "
1623
                                      +conn.getUsageCount(), 50);
1624
    AccessionNumber ac = new AccessionNumber(accnum, action);
1625 779 bojilova
    String docid = ac.getDocid();
1626
    String rev = ac.getRev();
1627 590 berkley
    MetaCatUtil.debugMessage("action: " + action + " servercode: " +
1628 1055 tao
                             serverCode + " override: " + override, 10);
1629 1383 tao
1630 577 berkley
    if((serverCode != 1 && action.equals("UPDATE")) && !override)
1631 559 berkley
    { //if this document being written is not a resident of this server then
1632
      //we need to try to get a lock from it's resident server.  If the
1633
      //resident server will not give a lock then we send the user a message
1634
      //saying that he/she needs to download a new copy of the file and
1635
      //merge the differences manually.
1636 567 berkley
      int istreamInt;
1637 561 berkley
      char istreamChar;
1638 1081 tao
1639
      // check for 'write' permission for 'user' to update this document
1640 1427 tao
      if ( !hasWritePermission(user, groups, docid) ) {
1641 1081 tao
        throw new Exception("User " + user +
1642
              " does not have permission to update XML Document #" + accnum);
1643
      }
1644
1645 779 bojilova
      DocumentIdentifier id = new DocumentIdentifier(accnum);
1646
      String updaterev = id.getRev();
1647 1292 tao
      String server=MetacatReplication.getServerNameForServerCode(serverCode);
1648 734 bojilova
      MetacatReplication.replLog("attempting to lock " + accnum);
1649 1217 tao
      URL u = new URL("https://" + server + "?server="+
1650
        MetaCatUtil.getLocalReplicationServerName()+"&action=getlock&updaterev="
1651 1012 tao
           +updaterev + "&docid=" + docid);
1652
      //System.out.println("sending message: " + u.toString());
1653 569 berkley
      String serverResStr = MetacatReplication.getURLContent(u);
1654 946 tao
      String openingtag =serverResStr.substring(0, serverResStr.indexOf(">")+1);
1655 561 berkley
      if(openingtag.equals("<lockgranted>"))
1656
      {//the lock was granted go ahead with the insert
1657 571 berkley
        try
1658
        {
1659 1012 tao
          //System.out.println("In lockgranted");
1660 734 bojilova
          MetacatReplication.replLog("lock granted for " + accnum + " from " +
1661 584 berkley
                                      server);
1662 1383 tao
          /*XMLReader parser = initializeParser(conn, action, docid, updaterev,
1663
                               validate, user, groups, pub, serverCode, dtd);*/
1664 956 tao
          XMLReader parser = initializeParser(conn, action, docid, updaterev,
1665 1383 tao
                                        user, groups, pub, serverCode,
1666
                                        dtd,ruleBase, needValidation);
1667 571 berkley
          conn.setAutoCommit(false);
1668 695 bojilova
          parser.parse(new InputSource(xml));
1669 571 berkley
          conn.commit();
1670
          conn.setAutoCommit(true);
1671
        }
1672
        catch (Exception e)
1673
        {
1674
          conn.rollback();
1675
          conn.setAutoCommit(true);
1676
          throw e;
1677
        }
1678 1591 tao
        // run write into access db base one relation table and access object
1679
        runRelationAndAccessHandler(accnum, user, groups, serverCode);
1680 590 berkley
1681 1292 tao
        // Force replication the docid
1682
        ForceReplicationHandler frh = new ForceReplicationHandler
1683
                                                          (accnum, true, null);
1684
        return(accnum);
1685
1686 561 berkley
      }
1687 734 bojilova
1688 561 berkley
      else if(openingtag.equals("<filelocked>"))
1689
      {//the file is currently locked by another user
1690
       //notify our user to wait a few minutes, check out a new copy and try
1691
       //again.
1692 584 berkley
        //System.out.println("file locked");
1693 734 bojilova
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1694 584 berkley
                                   server + " reason: file already locked");
1695 571 berkley
        throw new Exception("The file specified is already locked by another " +
1696
                            "user.  Please wait 30 seconds, checkout the " +
1697
                            "newer document, merge your changes and try " +
1698
                            "again.");
1699 561 berkley
      }
1700
      else if(openingtag.equals("<outdatedfile>"))
1701
      {//our file is outdated.  notify our user to check out a new copy of the
1702
       //file and merge his version with the new version.
1703 584 berkley
        //System.out.println("outdated file");
1704 734 bojilova
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1705 584 berkley
                                    server + " reason: local file outdated");
1706 571 berkley
        throw new Exception("The file you are trying to update is an outdated" +
1707
                            " version.  Please checkout the newest document, " +
1708
                            "merge your changes and try again.");
1709 561 berkley
      }
1710 559 berkley
    }
1711 571 berkley
1712 425 bojilova
    if ( action.equals("UPDATE") ) {
1713 441 bojilova
      // check for 'write' permission for 'user' to update this document
1714 628 berkley
1715 1427 tao
      if ( !hasWritePermission(user, groups, docid) ) {
1716 441 bojilova
        throw new Exception("User " + user +
1717 734 bojilova
              " does not have permission to update XML Document #" + accnum);
1718 425 bojilova
      }
1719
    }
1720
1721 571 berkley
    try
1722 638 bojilova
    {
1723 956 tao
1724 1383 tao
      XMLReader parser = initializeParser(conn, action, docid, rev,
1725
                                          user, groups, pub, serverCode,
1726
                                          dtd, ruleBase, needValidation);
1727 1217 tao
1728 555 bojilova
      conn.setAutoCommit(false);
1729
      parser.parse(new InputSource(xml));
1730
      conn.commit();
1731
      conn.setAutoCommit(true);
1732 571 berkley
    }
1733
    catch (Exception e)
1734
    {
1735 555 bojilova
      conn.rollback();
1736
      conn.setAutoCommit(true);
1737
      throw e;
1738
    }
1739 577 berkley
1740 1591 tao
    // run access db base on relation table and access object
1741
    runRelationAndAccessHandler(accnum, user, groups, serverCode);
1742 1575 tao
1743 1292 tao
    // Force replicate out the new document to each server in our server list.
1744
    // Start the thread to replicate this new document out to the other servers
1745
    // true mean it is xml document
1746
    // null is because no metacat notify the force replication.
1747
    ForceReplicationHandler frh = new ForceReplicationHandler
1748
                                                  (accnum, action, true, null);
1749 1012 tao
1750 1292 tao
1751 1217 tao
    MetaCatUtil.debugMessage("Conn Usage count after writting: "
1752
                                                      +conn.getUsageCount(),50);
1753 779 bojilova
    return(accnum);
1754 393 jones
  }
1755 396 jones
1756 407 jones
  /**
1757 1055 tao
   * Write an XML file to the database during replication
1758
   *
1759
   * @param conn the JDBC connection to the database
1760
   * @param xml the xml stream to be loaded into the database
1761
   * @param pub flag for public "read" access on xml document
1762
   * @param dtd the dtd to be uploaded on server's file system
1763
   * @param action the action to be performed (INSERT or UPDATE)
1764
   * @param accnum the docid + rev# to use on INSERT or UPDATE
1765
   * @param user the user that owns the document
1766
   * @param groups the groups to which user belongs
1767
   * @param homeServer the name of server which the document origanlly create
1768
   * @param validate, if the xml document is valid or not
1769 1292 tao
   * @param notifyServer, the server which notify local server the force
1770
   *                       replication command
1771 1055 tao
   */
1772
1773 1217 tao
  public static String writeReplication(DBConnection conn, Reader xml,
1774 1383 tao
                                        String pub, Reader dtd, String action,
1775
                                        String accnum, String user,
1776
                                        String[] groups,String homeServer,
1777
                                        String notifyServer,
1778
                                        String ruleBase, boolean needValidation)
1779
                                        throws Exception
1780 1055 tao
  {
1781 1292 tao
    // Docid without revision
1782
    String docid=MetaCatUtil.getDocIdFromString(accnum);
1783
    // Revision specified by user (int)
1784
    int userSpecifyRev=MetaCatUtil.getVersionFromString(accnum);
1785
    // Revision for this docid in current database
1786
    int revInDataBase=getLatestRevisionNumber(docid);
1787
    // String to store the revision
1788
    String rev = null;
1789 1217 tao
1790 1069 tao
1791 1292 tao
    //revIndataBase=-1, there is no record in xml_documents table
1792
    //the document is a new one for local server, inert it into table
1793
    //user specified rev should be great than 0
1794
    if (revInDataBase==-1 && userSpecifyRev>0 )
1795 1069 tao
    {
1796 1292 tao
        // rev equals user specified
1797
        rev=(new Integer(userSpecifyRev)).toString();
1798
        // action should be INSERT
1799
        action = "INSERT";
1800 1069 tao
    }
1801 1292 tao
    //rev is greater the last revsion number and revInDataBase isn't -1
1802
    // it is a updated  file
1803
    else if (userSpecifyRev>revInDataBase && revInDataBase>0)
1804 1055 tao
    {
1805 1292 tao
       // rev equals user specified
1806
       rev=(new Integer(userSpecifyRev)).toString();
1807
       // action should be update
1808
       action = "UPDATE";
1809 1055 tao
    }
1810 1292 tao
    // local server has newer version, then notify the remote server
1811
    else if ( userSpecifyRev < revInDataBase && revInDataBase > 0)
1812
    {
1813
      throw new Exception("Local server: "+MetaCatUtil.getOption("server")+
1814
                " has newer revision of doc: "+docid+"."+revInDataBase
1815
                 +". Please notify it.");
1816
    }
1817
    //other situation
1818
    else
1819
    {
1820
1821
        throw new Exception("The docid"+docid+"'s revision number couldn't be "
1822
                    +userSpecifyRev);
1823
    }
1824
    // Variable to store homeserver code
1825
    int serverCode=-2;
1826
1827
     // If server is not int the xml replication talbe, insert it into
1828
    // xml_replication table
1829
    //serverList.addToServerListIfItIsNot(homeServer);
1830
    insertServerIntoReplicationTable(homeServer);
1831
    // Get server code again
1832
    serverCode = getServerCode(homeServer);
1833
1834
1835
    MetaCatUtil.debugMessage("Document "+docid+"."+rev+" "+action+ " into local"
1836
                               +" metacat with servercode: "+ serverCode, 10);
1837 1055 tao
1838 1217 tao
1839 1292 tao
    // insert into xml_nodes and xml_index table
1840 1055 tao
    try
1841
    {
1842
1843 1383 tao
      XMLReader parser = initializeParser(conn, action, docid, rev,
1844
                                          user, groups, pub, serverCode, dtd,
1845
                                          ruleBase, needValidation);
1846 1055 tao
      conn.setAutoCommit(false);
1847
      parser.parse(new InputSource(xml));
1848
      conn.commit();
1849
      conn.setAutoCommit(true);
1850
    }
1851
    catch (Exception e)
1852
    {
1853
      conn.rollback();
1854
      conn.setAutoCommit(true);
1855
      throw e;
1856
    }
1857 1292 tao
1858 1591 tao
    // run write into access db base on relation table and access rule
1859
    try
1860
    {
1861
      runRelationAndAccessHandler(accnum, user, groups, serverCode);
1862
    }
1863
    catch (Exception ee)
1864
    {
1865
      MetacatReplication.replErrorLog("Failed to " +
1866
                                       "create access " +
1867
                                       "rule for package: " + accnum +
1868
                                       " because " +ee.getMessage());
1869
      MetaCatUtil.debugMessage("Failed to  " +
1870
                                       "create access " +
1871
                                       "rule for package: "+ accnum +
1872
                                       " because " +ee.getMessage(), 30);
1873
    }
1874 1292 tao
    //Force replication to other server
1875
    ForceReplicationHandler forceReplication = new ForceReplicationHandler
1876
                                  (accnum, action, true, notifyServer);
1877
1878 1055 tao
1879
    return(accnum);
1880
  }
1881
1882 1575 tao
  /* Running write record to xml_relation and xml_access*/
1883 1591 tao
  private static void runRelationAndAccessHandler(String accnumber,
1884 1575 tao
                                                  String userName,
1885
                                                  String[]group, int servercode)
1886
                                                   throws Exception
1887
  {
1888
    DBConnection dbconn = null;
1889
    int serialNumber = -1;
1890
    PreparedStatement pstmt =null;
1891
    String documenttype = getDocTypeFromDBForCurrentDocument(accnumber);
1892
    try
1893
    {
1894
      String packagedoctype = MetaCatUtil.getOption("packagedoctype");
1895
      Vector packagedoctypes = new Vector();
1896
      packagedoctypes = MetaCatUtil.getOptionList(packagedoctype);
1897
      String docIdWithoutRev = MetaCatUtil.getDocIdFromString(accnumber);
1898
      if (documenttype != null && packagedoctypes.contains(documenttype) )
1899
      {
1900
        dbconn=DBConnectionPool.
1901 1591 tao
           getDBConnection("DocumentImpl.runRelationAndAccessHandeler");
1902 1575 tao
        serialNumber=dbconn.getCheckOutSerialNumber();
1903
        dbconn.setAutoCommit(false);
1904
        // from the relations get the access file id for that package
1905 1591 tao
        String aclid = RelationHandler.getAccessFileID(docIdWithoutRev);
1906 1575 tao
        // if there are access file, write ACL for that package
1907
        if ( aclid != null )
1908
        {
1909
          runAccessControlList(dbconn, aclid, userName, group, servercode);
1910
        }
1911
        dbconn.commit();
1912
        dbconn.setAutoCommit(true);
1913
      }
1914
        // if it is an access file
1915
      else if ( documenttype != null && MetaCatUtil.getOptionList(
1916
                 MetaCatUtil.getOption("accessdoctype")).contains(documenttype))
1917
      {
1918
        dbconn=DBConnectionPool.
1919 1591 tao
           getDBConnection("DocumentImpl.runRelationAndAccessHandeler");
1920 1575 tao
        serialNumber=dbconn.getCheckOutSerialNumber();
1921
        dbconn.setAutoCommit(false);
1922
        // write ACL for the package
1923
        runAccessControlList(dbconn, docIdWithoutRev,
1924
                             userName, group, servercode);
1925
        dbconn.commit();
1926
        dbconn.setAutoCommit(true);
1927
1928
      }
1929
1930
    }
1931
    catch (Exception e)
1932
    {
1933
      if( dbconn != null)
1934
      {
1935
        dbconn.rollback();
1936
        dbconn.setAutoCommit(true);
1937
      }
1938 1591 tao
      MetaCatUtil.debugMessage("Error in DocumentImple.runRelationAndAccessHandler " +
1939 1575 tao
                                e.getMessage(), 30);
1940
      throw e;
1941
    }
1942
    finally
1943
    {
1944
      if (dbconn != null)
1945
      {
1946
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1947
      }
1948
    }//
1949
  }
1950
1951
  // It runs in xmlIndex thread. It writes ACL for a package.
1952
  private static void runAccessControlList (DBConnection conn, String aclid,
1953
                                    String users, String[]group, int servercode)
1954
                                                throws Exception
1955
  {
1956
    // read the access file from xml_nodes
1957
    // parse the access file and store the access info into xml_access
1958
    AccessControlList aclobj =
1959
    new AccessControlList(conn, aclid, users, group, servercode);
1960
1961
  }
1962
1963
  /* Method get document type from db*/
1964
  private static String getDocTypeFromDBForCurrentDocument(String accnumber)
1965
                                                  throws SQLException
1966
  {
1967
    String docoumentType = null;
1968
    String docid = null;
1969
    PreparedStatement pstate = null;
1970
    ResultSet rs = null;
1971
    String sql = "SELECT doctype FROM xml_documents where docid = ?";
1972
    DBConnection dbConnection = null;
1973
    int serialNumber = -1;
1974
    try
1975
    {
1976
      //get rid of revision number
1977
      docid = MetaCatUtil.getDocIdFromString(accnumber);
1978
      dbConnection=DBConnectionPool.
1979
           getDBConnection("DocumentImpl.getDocTypeFromDBForCurrentDoc");
1980
      serialNumber=dbConnection.getCheckOutSerialNumber();
1981
      pstate = dbConnection.prepareStatement(sql);
1982
      //bind variable
1983
      pstate.setString(1, docid);
1984
      //excute query
1985
      pstate.execute();
1986
      //handle resultset
1987
      rs = pstate.getResultSet();
1988
      if (rs.next())
1989
      {
1990
        docoumentType = rs.getString(1);
1991
      }
1992
      rs.close();
1993
      pstate.close();
1994
    }//try
1995
    catch (SQLException e)
1996
    {
1997
      MetaCatUtil.debugMessage("error in DocumentImpl."+
1998
                      "getDocTypeFromDBForCurrentDocument "+e.getMessage(), 30);
1999
      throw e;
2000
    }//catch
2001
    finally
2002
    {
2003
      pstate.close();
2004
      DBConnectionPool.returnDBConnection(dbConnection, serialNumber);
2005
    }//
2006
    MetaCatUtil.debugMessage("The current doctype from db is: "+
2007
                              docoumentType, 35);
2008
    return docoumentType;
2009
  }
2010 1055 tao
  /**
2011 407 jones
   * Delete an XML file from the database (actually, just make it a revision
2012
   * in the xml_revisions table)
2013
   *
2014
   * @param docid the ID of the document to be deleted from the database
2015
   */
2016 1217 tao
  public static void delete(String accnum,
2017 802 bojilova
                                 String user, String[] groups )
2018 734 bojilova
                throws Exception
2019
  {
2020 779 bojilova
    // OLD
2021
    //DocumentIdentifier id = new DocumentIdentifier(accnum);
2022
    //String docid = id.getIdentifier();
2023
    //String rev = id.getRev();
2024 628 berkley
2025 779 bojilova
    // OLD
2026 734 bojilova
    // Determine if the docid,rev are OK for DELETE
2027 779 bojilova
    //AccessionNumber ac = new AccessionNumber(conn);
2028
    //docid = ac.generate(docid, rev, "DELETE");
2029 1217 tao
    DBConnection conn = null;
2030
    int serialNumber = -1;
2031
    PreparedStatement pstmt =null;
2032
    try
2033
    {
2034
      //check out DBConnection
2035
      conn=DBConnectionPool.
2036
                    getDBConnection("DocumentImpl.delete");
2037
      serialNumber=conn.getCheckOutSerialNumber();
2038 396 jones
2039 1217 tao
      // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
2040
      AccessionNumber ac = new AccessionNumber(accnum, "DELETE");
2041
      String docid = ac.getDocid();
2042
      String rev = ac.getRev();
2043 779 bojilova
2044 1621 tao
      MetaCatUtil.debugMessage("Start deleting doc "+docid+ "...", 20);
2045 441 bojilova
    // check for 'write' permission for 'user' to delete this document
2046 1427 tao
      if ( !hasWritePermission(user, groups, docid) ) {
2047 1217 tao
        throw new Exception("User " + user +
2048 734 bojilova
              " does not have permission to delete XML Document #" + accnum);
2049 1217 tao
      }
2050 425 bojilova
2051 1217 tao
      conn.setAutoCommit(false);
2052
      // Copy the record to the xml_revisions table
2053
      DocumentImpl.archiveDocRevision(conn, docid, user );
2054 396 jones
2055 1217 tao
      // Now delete it from the xml_index table
2056
      pstmt = conn.prepareStatement("DELETE FROM xml_index WHERE docid = ?");
2057
      pstmt.setString(1,docid);
2058
      pstmt.execute();
2059
      pstmt.close();
2060
      conn.increaseUsageCount(1);
2061
2062
      //stmt.execute("DELETE FROM xml_access WHERE docid = '" + docid + "'");
2063
      // Now delete it from xml_access table
2064
      pstmt = conn.
2065
              prepareStatement("DELETE FROM xml_access WHERE accessfileid = ?");
2066
      pstmt.setString(1, docid);
2067
      pstmt.execute();
2068
      pstmt.close();
2069
      conn.increaseUsageCount(1);
2070
2071
      // Delete it from relation table
2072
      pstmt = conn.
2073
               prepareStatement("DELETE FROM xml_relation WHERE docid = ?");
2074
      //increase usage count
2075
      conn.increaseUsageCount(1);
2076
      pstmt.setString(1, docid);
2077
      pstmt.execute();
2078
      pstmt.close();
2079
2080 1618 tao
      // Delete it from xml_accesssubtree table
2081
      pstmt = conn.
2082
               prepareStatement("DELETE FROM xml_accesssubtree WHERE docid = ?");
2083
      //increase usage count
2084
      conn.increaseUsageCount(1);
2085
      pstmt.setString(1, docid);
2086
      pstmt.execute();
2087
      pstmt.close();
2088
2089 1217 tao
      // Delete it from xml_doucments table
2090
      pstmt =conn.prepareStatement("DELETE FROM xml_documents WHERE docid = ?");
2091
      pstmt.setString(1, docid);
2092
      pstmt.execute();
2093
      pstmt.close();
2094
      //Usaga count increase 1
2095
      conn.increaseUsageCount(1);
2096
2097
      conn.commit();
2098
      conn.setAutoCommit(true);
2099
    }//try
2100 1621 tao
    catch (Exception e)
2101
    {
2102
      MetaCatUtil.debugMessage("error in DocumentImpl.delete: " +
2103
                                e.getMessage(), 30);
2104
      throw e;
2105
    }
2106 1217 tao
    finally
2107
    {
2108
2109
      try
2110
      {
2111
        // close preparedStatement
2112
        pstmt.close();
2113
      }//try
2114
      finally
2115
      {
2116
        //check in DBonnection
2117
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2118
      }//finally
2119
    }//finally
2120 634 berkley
    //IF this is a package document:
2121
    //delete all of the relations that this document created.
2122
    //if the deleted document is a package document its relations should
2123
    //no longer be active if it has been deleted from the system.
2124 645 bojilova
2125 407 jones
  }
2126 638 bojilova
2127 570 bojilova
  /**
2128 802 bojilova
    * Check for "WRITE" permission on @docid for @user and/or @groups
2129 570 bojilova
    * from DB connection
2130
    */
2131 1427 tao
  private static boolean hasWritePermission (String user,
2132 802 bojilova
                                  String[] groups, String docid )
2133 958 tao
                  throws SQLException, Exception
2134 570 bojilova
  {
2135 802 bojilova
    // Check for WRITE permission on @docid for @user and/or @groups
2136 1427 tao
    PermissionController controller = new PermissionController(docid);
2137
    return controller.hasPermission(user,groups,
2138
                                    AccessControlInterface.WRITESTRING);
2139 425 bojilova
  }
2140
2141 946 tao
  /**
2142
    * Check for "READ" permission base on docid, user and group
2143
    *@docid, the document
2144
    *@user, user name
2145
    *@group, user's group
2146
    *
2147
    */
2148 1217 tao
  public static boolean hasReadPermission (String user,
2149 946 tao
                                  String[] groups, String docId )
2150 958 tao
                  throws SQLException, Exception
2151 946 tao
  {
2152
    // Check for READ permission on @docid for @user and/or @groups
2153 1427 tao
    PermissionController controller =
2154
                        new PermissionController(docId);
2155
    return controller.hasPermission(user,groups,
2156
                                            AccessControlInterface.READSTRING);
2157 946 tao
  }
2158
2159 1383 tao
2160
   /**
2161
   * Set up the parser handlers for writing the document to the database
2162
   */
2163
  private static XMLReader initializeParser(DBConnection dbconn, String action,
2164
                                            String docid, String rev,
2165
                                            String user,
2166
                                            String[] groups, String pub,
2167
                                            int serverCode, Reader dtd,
2168
                                            String ruleBase,
2169
                                            boolean needValidation)
2170
                                            throws Exception
2171
  {
2172
    XMLReader parser = null;
2173
    try
2174
    {
2175 1407 tao
      // handler
2176
      ContentHandler chandler;
2177 1383 tao
      EntityResolver eresolver;
2178
      DTDHandler dtdhandler;
2179
      // Get an instance of the parser
2180
      String parserName = MetaCatUtil.getOption("saxparser");
2181
      parser = XMLReaderFactory.createXMLReader(parserName);
2182 1407 tao
      if (ruleBase != null && ruleBase.equals(EML2))
2183 1383 tao
      {
2184 1407 tao
        MetaCatUtil.debugMessage("eml 2 parser", 20);
2185
        chandler = new EmlSAXHandler(dbconn, action,
2186
                                    docid, rev, user, groups, pub, serverCode);
2187
        parser.setContentHandler((ContentHandler)chandler);
2188
        parser.setErrorHandler((ErrorHandler)chandler);
2189
        parser.setProperty(DECLARATIONHANDLERPROPERTY, chandler);
2190
        parser.setProperty(LEXICALPROPERTY, chandler);
2191 1383 tao
        // turn on schema validation feature
2192
        parser.setFeature(VALIDATIONFEATURE, true);
2193
        parser.setFeature(NAMESPACEFEATURE, true);
2194 1431 tao
        //parser.setFeature(NAMESPACEPREFIXESFEATURE, true);
2195 1383 tao
        parser.setFeature(SCHEMAVALIDATIONFEATURE, true);
2196 1396 tao
        // From DB to find the register external schema location
2197
        String externalSchemaLocation = null;
2198
        SchemaLocationResolver resolver = new SchemaLocationResolver();
2199
        externalSchemaLocation = resolver.getNameSpaceAndLocationString();
2200
        // Set external schemalocation.
2201
        if (externalSchemaLocation != null &&
2202
            !(externalSchemaLocation.trim()).equals(""))
2203
        {
2204 1407 tao
            parser.setProperty(EXTERNALSCHEMALOCATIONPROPERTY,
2205 1396 tao
                             externalSchemaLocation);
2206
        }
2207 1383 tao
      }
2208
      else
2209
      {
2210 1407 tao
        //create a DBSAXHandler object which has the revision specification
2211
        chandler = new DBSAXHandler(dbconn, action,
2212
                                    docid, rev, user, groups, pub, serverCode);
2213
        parser.setContentHandler((ContentHandler)chandler);
2214
        parser.setErrorHandler((ErrorHandler)chandler);
2215
        parser.setProperty(DECLARATIONHANDLERPROPERTY, chandler);
2216
        parser.setProperty(LEXICALPROPERTY, chandler);
2217
2218
        if (ruleBase != null && ruleBase.equals(SCHEMA) && needValidation)
2219
        {
2220
          MetaCatUtil.debugMessage("General schema parser", 20);
2221
          // turn on schema validation feature
2222
          parser.setFeature(VALIDATIONFEATURE, true);
2223
          parser.setFeature(NAMESPACEFEATURE, true);
2224 1431 tao
          //parser.setFeature(NAMESPACEPREFIXESFEATURE, true);
2225 1407 tao
          parser.setFeature(SCHEMAVALIDATIONFEATURE, true);
2226
          // From DB to find the register external schema location
2227
          String externalSchemaLocation = null;
2228
          SchemaLocationResolver resolver = new SchemaLocationResolver();
2229
          externalSchemaLocation = resolver.getNameSpaceAndLocationString();
2230
          // Set external schemalocation.
2231
          if (externalSchemaLocation != null &&
2232
            !(externalSchemaLocation.trim()).equals(""))
2233
          {
2234
            parser.setProperty(EXTERNALSCHEMALOCATIONPROPERTY,
2235
                             externalSchemaLocation);
2236
          }
2237
2238
        }
2239
        else if (ruleBase != null && ruleBase.equals(DTD) && needValidation)
2240
        {
2241
          MetaCatUtil.debugMessage("dtd parser", 20);
2242
          // turn on dtd validaton feature
2243
          parser.setFeature(VALIDATIONFEATURE, true);
2244
          eresolver= new DBEntityResolver(dbconn, (DBSAXHandler)chandler, dtd);
2245
          dtdhandler = new DBDTDHandler(dbconn);
2246
          parser.setEntityResolver((EntityResolver)eresolver);
2247
          parser.setDTDHandler((DTDHandler)dtdhandler);
2248
        }
2249
        else
2250
        {
2251
          MetaCatUtil.debugMessage("other parser", 20);
2252
          // non validation
2253
          parser.setFeature(VALIDATIONFEATURE, false);
2254
          eresolver= new DBEntityResolver(dbconn, (DBSAXHandler)chandler, dtd);
2255
          dtdhandler = new DBDTDHandler(dbconn);
2256
          parser.setEntityResolver((EntityResolver)eresolver);
2257
          parser.setDTDHandler((DTDHandler)dtdhandler);
2258
        }
2259
      }//else
2260 1383 tao
    }
2261
    catch (Exception e)
2262
    {
2263
      throw e;
2264
    }
2265
    return parser;
2266
  }
2267
2268
2269 396 jones
  /**
2270 407 jones
   * Set up the parser handlers for writing the document to the database
2271
   */
2272 1383 tao
  /*private static XMLReader initializeParser(DBConnection dbconn, String action,
2273 956 tao
                               String docid, String rev, boolean validate,
2274 802 bojilova
                                   String user, String[] groups, String pub,
2275 695 bojilova
                                   int serverCode, Reader dtd)
2276 598 bojilova
                           throws Exception
2277
  {
2278 407 jones
    XMLReader parser = null;
2279 1217 tao
    //DBConnection conn = null;
2280
    //int serialNumber = -1;
2281 407 jones
    //
2282
    // Set up the SAX document handlers for parsing
2283
    //
2284
    try {
2285 1217 tao
       //check out DBConnection
2286 1383 tao
2287 956 tao
      //create a DBSAXHandler object which has the revision specification
2288 1217 tao
      ContentHandler chandler = new DBSAXHandler(dbconn, action,
2289
                                    docid, rev, user, groups, pub, serverCode);
2290
      EntityResolver eresolver= new DBEntityResolver(dbconn,
2291 645 bojilova
                                                 (DBSAXHandler)chandler, dtd);
2292 1217 tao
      DTDHandler dtdhandler   = new DBDTDHandler(dbconn);
2293 407 jones
2294
      // Get an instance of the parser
2295 802 bojilova
      String parserName = MetaCatUtil.getOption("saxparser");
2296 407 jones
      parser = XMLReaderFactory.createXMLReader(parserName);
2297
2298 660 bojilova
      // Turn on validation
2299 695 bojilova
      parser.setFeature("http://xml.org/sax/features/validation", validate);
2300 660 bojilova
      // Turn off Including all external parameter entities
2301
      // (the external DTD subset also)
2302
      // Doesn't work well, probably the feature name is not correct
2303
      // parser.setFeature(
2304
      //  "http://xml.org/sax/features/external-parameter-entities", false);
2305 407 jones
2306
      // Set Handlers in the parser
2307
      parser.setProperty("http://xml.org/sax/properties/declaration-handler",
2308
                         chandler);
2309
      parser.setProperty("http://xml.org/sax/properties/lexical-handler",
2310
                         chandler);
2311
      parser.setContentHandler((ContentHandler)chandler);
2312 598 bojilova
      parser.setEntityResolver((EntityResolver)eresolver);
2313 407 jones
      parser.setDTDHandler((DTDHandler)dtdhandler);
2314
      parser.setErrorHandler((ErrorHandler)chandler);
2315
2316
    } catch (Exception e) {
2317 457 bojilova
      throw e;
2318 407 jones
    }
2319 1217 tao
    //finally
2320
    //{
2321
      //DBConnectionPool.returnDBConnection(conn, serialNumber);
2322
    //}
2323 407 jones
2324
    return parser;
2325 1383 tao
  }*/
2326 407 jones
2327 1217 tao
  /**
2328
   * Save a document entry in the xml_revisions table
2329
   * Connection use as a paramter is in order to rollback feature
2330
   */
2331
  private static void archiveDocRevision(DBConnection dbconn, String docid,
2332
                                                    String user)
2333
 {
2334
    String sysdate = dbAdapter.getDateTimeFunction();
2335
    //DBConnection conn = null;
2336
    //int serialNumber = -1;
2337
    PreparedStatement pstmt = null;
2338
2339
    // create a record in xml_revisions table
2340
    // for that document as selected from xml_documents
2341
2342
   try
2343
   {
2344
     //check out DBConnection
2345
     /*conn=DBConnectionPool.
2346
                    getDBConnection("DocumentImpl.archiveDocRevision");
2347
     serialNumber=conn.getCheckOutSerialNumber();*/
2348
     pstmt = dbconn.prepareStatement(
2349
      "INSERT INTO xml_revisions " +
2350
        "(docid, rootnodeid, docname, doctype, " +
2351
        "user_owner, user_updated, date_created, date_updated, " +
2352
        "server_location, rev, public_access, catalog_id) " +
2353
      "SELECT ?, rootnodeid, docname, doctype, " +
2354
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
2355
        "server_location, rev, public_access, catalog_id " +
2356
      "FROM xml_documents " +
2357
      "WHERE docid = ?");
2358
      // Increase dbconnection usage count
2359
      dbconn.increaseUsageCount(1);
2360
      // Bind the values to the query and execute it
2361
      pstmt.setString(1, docid);
2362
      pstmt.setString(2, user);
2363
      pstmt.setString(3, docid);
2364
      pstmt.execute();
2365
      pstmt.close();
2366
   }//try
2367
   catch (SQLException e)
2368
   {
2369
     MetaCatUtil.debugMessage("Error in DocumentImpl.archiveDocRevision : "+
2370
                                e.getMessage(), 30);
2371
   }//catch
2372
   finally
2373
   {
2374
     try
2375
     {
2376
       pstmt.close();
2377
     }//try
2378
     catch (SQLException ee)
2379
     {
2380
       MetaCatUtil.debugMessage("Error in DocumnetImpl.archiveDocRevision: "+
2381
                                  ee.getMessage(), 50);
2382
     }//catch
2383
     //finally
2384
     //{
2385
2386
       //check in DBConnection
2387
       //DBConnectionPool.returnDBConnection(conn, serialNumber);
2388
     //}//finally
2389
   }//finnally
2390
2391
2392
  }//achiveDocRevision
2393
2394 459 bojilova
  /** Save a document entry in the xml_revisions table */
2395 1217 tao
  private static void archiveDocRevision(String docid, String user)
2396 1063 tao
 {
2397 754 bojilova
    String sysdate = dbAdapter.getDateTimeFunction();
2398 1217 tao
    DBConnection conn = null;
2399
    int serialNumber = -1;
2400
    PreparedStatement pstmt = null;
2401
2402 459 bojilova
    // create a record in xml_revisions table
2403
    // for that document as selected from xml_documents
2404 1063 tao
2405
   try
2406
   {
2407 1217 tao
     //check out DBConnection
2408
     conn=DBConnectionPool.
2409
                    getDBConnection("DocumentImpl.archiveDocRevision");
2410
     serialNumber=conn.getCheckOutSerialNumber();
2411
     pstmt = conn.prepareStatement(
2412 459 bojilova
      "INSERT INTO xml_revisions " +
2413 771 bojilova
        "(docid, rootnodeid, docname, doctype, " +
2414 697 bojilova
        "user_owner, user_updated, date_created, date_updated, " +
2415
        "server_location, rev, public_access, catalog_id) " +
2416 771 bojilova
      "SELECT ?, rootnodeid, docname, doctype, " +
2417 747 bojilova
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
2418
        "server_location, rev, public_access, catalog_id " +
2419 459 bojilova
      "FROM xml_documents " +
2420
      "WHERE docid = ?");
2421 1063 tao
      // Bind the values to the query and execute it
2422
      pstmt.setString(1, docid);
2423
      pstmt.setString(2, user);
2424
      pstmt.setString(3, docid);
2425
      pstmt.execute();
2426
      pstmt.close();
2427 1217 tao
   }//try
2428 1063 tao
   catch (SQLException e)
2429
   {
2430 1217 tao
     MetaCatUtil.debugMessage("Error in DocumentImpl.archiveDocRevision : "+
2431
                                e.getMessage(), 30);
2432
   }//catch
2433
   finally
2434
   {
2435
     try
2436
     {
2437
       pstmt.close();
2438
     }//try
2439
     catch (SQLException ee)
2440
     {
2441
       MetaCatUtil.debugMessage("Error in DocumnetImpl.archiveDocRevision: "+
2442
                                  ee.getMessage(), 50);
2443
     }//catch
2444
     finally
2445
     {
2446
       //check in DBConnection
2447
       DBConnectionPool.returnDBConnection(conn, serialNumber);
2448
     }//finally
2449
   }//finnally
2450
2451 459 bojilova
2452 1217 tao
  }//achiveDocRevision
2453 965 tao
2454
  /**
2455
    * delete a entry in xml_table for given docid
2456
    * @param docId, the id of the document need to be delete
2457
    */
2458 1217 tao
  private static void deleteXMLDocuments(String docId)
2459 965 tao
                                         throws SQLException
2460
  {
2461 1217 tao
    DBConnection conn = null;
2462
    int serialNumber = -1;
2463
    PreparedStatement pStmt = null;
2464
    try
2465
    {
2466
      //check out DBConnection
2467
      conn=DBConnectionPool.
2468
                    getDBConnection("DocumentImpl.deleteXMLDocuments");
2469
      serialNumber=conn.getCheckOutSerialNumber();
2470
      //delete a record
2471
      pStmt =
2472 965 tao
             conn.prepareStatement("DELETE FROM xml_documents WHERE docid = '"
2473
                                              + docId + "'");
2474
    pStmt.execute();
2475 1217 tao
    }//try
2476
    finally
2477
    {
2478
      try
2479
      {
2480
        pStmt.close();
2481
      }//try
2482
      catch (SQLException e)
2483
      {
2484
        MetaCatUtil.debugMessage("error in DocumentImpl.deleteXMLDocuments: "+
2485
                                  e.getMessage(), 50);
2486
      }//catch
2487
      finally
2488
      {
2489
        //return back DBconnection
2490
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2491
      }//finally
2492
    }//finally
2493
2494 459 bojilova
2495 965 tao
  }//deleteXMLDocuments
2496
2497 407 jones
  /**
2498 965 tao
    * Get last revision number from database for a docid
2499
    * If couldn't find an entry,  -1 will return
2500
    * The return value is integer because we want compare it to there new one
2501
    * @param docid <sitecode>.<uniqueid> part of Accession Number
2502
    */
2503 1582 tao
  public static int getLatestRevisionNumber(String docId)
2504 965 tao
                                      throws SQLException
2505
  {
2506
    int rev = 1;
2507 1217 tao
    PreparedStatement pStmt = null;
2508
    DBConnection dbConn = null;
2509
    int serialNumber = -1;
2510 1582 tao
    // get rid of rev
2511
    docId = MetaCatUtil.getDocIdFromString(docId);
2512 1217 tao
    try
2513
    {
2514
      //check out DBConnection
2515
      dbConn=DBConnectionPool.
2516
                    getDBConnection("DocumentImpl.getLatestRevisionNumber");
2517
      serialNumber=dbConn.getCheckOutSerialNumber();
2518 965 tao
2519 1217 tao
      pStmt = dbConn.prepareStatement
2520 965 tao
              ("SELECT rev FROM xml_documents WHERE docid='" + docId + "'");
2521 1217 tao
      pStmt.execute();
2522 965 tao
2523 1217 tao
      ResultSet rs = pStmt.getResultSet();
2524
      boolean hasRow = rs.next();
2525
      if (hasRow)
2526
      {
2527
        rev = rs.getInt(1);
2528
        pStmt.close();
2529
      }
2530
      else
2531
      {
2532
        rev=-1;
2533
        pStmt.close();
2534
      }
2535
    }//try
2536
    finally
2537 965 tao
    {
2538 1217 tao
      try
2539
      {
2540
        pStmt.close();
2541
      }
2542
      catch (Exception ee)
2543
      {
2544
        MetaCatUtil.debugMessage("Error in DocumentImpl."+
2545
                        "getLatestRevisionNumber: "+ee.getMessage(), 50);
2546
      }
2547
      finally
2548
      {
2549
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2550
      }
2551
    }//finally
2552 965 tao
2553
    return rev;
2554
  }//getLatestRevisionNumber
2555
2556
  /**
2557 1012 tao
   * Get server location form database for a accNum
2558
   *
2559
   * @param accum <sitecode>.<uniqueid>.<rev>
2560
   */
2561 1217 tao
  private static int getServerLocationNumber(String accNum)
2562 1012 tao
                                            throws SQLException
2563
  {
2564
    //get rid of revNum part
2565
    String docId=MetaCatUtil.getDocIdFromString(accNum);
2566 1217 tao
    PreparedStatement pStmt = null;
2567
    int serverLocation = 1;
2568
    DBConnection conn = null;
2569
    int serialNumber = -1;
2570
2571
    try
2572
    {
2573
      //check out DBConnection
2574
      conn=DBConnectionPool.
2575
                    getDBConnection("DocumentImpl.getServerLocationNumber");
2576
      serialNumber=conn.getCheckOutSerialNumber();
2577 1012 tao
2578 1217 tao
      pStmt = conn.prepareStatement
2579 1012 tao
      ("SELECT server_location FROM xml_documents WHERE docid='" + docId + "'");
2580 1217 tao
      pStmt.execute();
2581 1012 tao
2582 1217 tao
      ResultSet rs = pStmt.getResultSet();
2583
      boolean hasRow = rs.next();
2584
      //if there is entry in xml_documents, get the serverlocation
2585
      if (hasRow)
2586
      {
2587
        serverLocation = rs.getInt(1);
2588
        pStmt.close();
2589
      }
2590
      else
2591
      {
2592
        //if htere is no entry in xml_documents, we consider it is new document
2593
        //the server location is local host and value is 1
2594
        serverLocation=1;
2595
        pStmt.close();
2596
      }
2597
    }//try
2598
    finally
2599 1012 tao
    {
2600 1217 tao
      try
2601
      {
2602
        pStmt.close();
2603
      }//try
2604
      catch (Exception ee)
2605
      {
2606
        MetaCatUtil.debugMessage("Error in DocumentImpl.getServerLocationNu(): "
2607
                                    +ee.getMessage(), 50);
2608
      }//catch
2609
      finally
2610
      {
2611
        DBConnectionPool.returnDBConnection(conn, serialNumber);
2612
      }//finally
2613
    }//finally
2614 1012 tao
2615
    return serverLocation;
2616
  }
2617 1055 tao
2618 1012 tao
  /**
2619 1055 tao
   * Given a server name, return its servercode in xml_replication table.
2620
   * If no server is found, -1 will return
2621
   * @param serverName,
2622
   */
2623
  private static int getServerCode(String serverName)
2624
  {
2625
    PreparedStatement pStmt=null;
2626
    int serverLocation=-2;
2627 1217 tao
    DBConnection dbConn = null;
2628
    int serialNumber = -1;
2629
    //MetaCatUtil util = new MetaCatUtil();
2630 1055 tao
2631
2632
    //we should consider about local host too
2633 1217 tao
    if (serverName.equals(MetaCatUtil.getLocalReplicationServerName()))
2634 1055 tao
    {
2635
      serverLocation=1;
2636
      return serverLocation;
2637
    }
2638
2639
2640
    try
2641
    {
2642
      //check xml_replication table
2643 1217 tao
      //dbConn=util.openDBConnection();
2644
      //check out DBConnection
2645
      dbConn=DBConnectionPool.getDBConnection("DocumentImpl.getServerCode");
2646
      serialNumber=dbConn.getCheckOutSerialNumber();
2647 1055 tao
      pStmt = dbConn.prepareStatement
2648
      ("SELECT serverid FROM xml_replication WHERE server='" + serverName +"'");
2649
      pStmt.execute();
2650
2651
      ResultSet rs = pStmt.getResultSet();
2652
      boolean hasRow = rs.next();
2653
      //if there is entry in xml_replication, get the serverid
2654
      if (hasRow)
2655
      {
2656
        serverLocation = rs.getInt(1);
2657
        pStmt.close();
2658
      }
2659
      else
2660
      {
2661
        // if htere is no entry in xml_replication, -1 will return
2662
        serverLocation=-1;
2663
        pStmt.close();
2664
      }
2665
    }
2666
    catch (Exception e)
2667
    {
2668 1217 tao
      MetaCatUtil.debugMessage("Error in DocumentImpl.getServerCode(): "
2669 1055 tao
                                    +e.getMessage(), 30);
2670
    }
2671
    finally
2672
    {
2673
      try
2674
      {
2675 1217 tao
        pStmt.close();
2676 1055 tao
      }
2677
      catch (Exception ee)
2678 1217 tao
      {
2679
        MetaCatUtil.debugMessage("Error in DocumentImpl.getServerCode(): "
2680
                                    +ee.getMessage(), 50);
2681
      }
2682
      finally
2683
      {
2684
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2685
      }
2686 1055 tao
    }
2687
2688
2689
    return serverLocation;
2690
  }
2691
2692
  /**
2693
   * Insert a server into xml_replcation table
2694
   * @param server, the name of server
2695
   */
2696 1292 tao
  private static synchronized void
2697
                                insertServerIntoReplicationTable(String server)
2698 1055 tao
  {
2699
    PreparedStatement pStmt=null;
2700 1217 tao
    DBConnection dbConn = null;
2701
    int serialNumber = -1;
2702 1292 tao
2703
    // Initial value for the server
2704
    int replicate = 0;
2705
    int dataReplicate = 0;
2706
    int hub = 0;
2707
2708 1055 tao
    try
2709
    {
2710 1292 tao
       // Get DBConnection
2711 1217 tao
       dbConn=DBConnectionPool.
2712
                getDBConnection("DocumentImpl.insertServIntoReplicationTable");
2713
       serialNumber=dbConn.getCheckOutSerialNumber();
2714 1292 tao
2715
      // Compare the server to dabase
2716
      pStmt = dbConn.prepareStatement
2717
      ("SELECT serverid FROM xml_replication WHERE server='" + server +"'");
2718
      pStmt.execute();
2719
      ResultSet rs = pStmt.getResultSet();
2720
      boolean hasRow = rs.next();
2721
      // Close preparedstatement and result set
2722
      pStmt.close();
2723
      rs.close();
2724
2725
      // If the server is not in the table, and server is not local host,
2726
      // insert it
2727
      if ( !hasRow
2728
         && !server.equals(MetaCatUtil.getLocalReplicationServerName()))
2729
      {
2730
        // Set auto commit false
2731
        dbConn.setAutoCommit(false);
2732
        pStmt = dbConn.prepareStatement("INSERT INTO xml_replication " +
2733
                      "(server, last_checked, replicate, datareplicate, hub) " +
2734
                       "VALUES ('" + server + "', to_date(" +
2735
                       "'01/01/00', 'MM/DD/YY'), '" +
2736
                       replicate +"', '"+dataReplicate+"','"+ hub + "')");
2737 1055 tao
        pStmt.execute();
2738 1292 tao
        dbConn.commit();
2739
        // Increase usage number
2740
        dbConn.increaseUsageCount(1);
2741 1055 tao
        pStmt.close();
2742 1292 tao
2743
      }
2744 1217 tao
    }//try
2745 1055 tao
    catch (Exception e)
2746
    {
2747 1217 tao
      MetaCatUtil.debugMessage("Error in DocumentImpl.insertServerIntoRepli(): "
2748 1055 tao
                                    +e.getMessage(), 30);
2749 1217 tao
    }//catch
2750 1055 tao
    finally
2751
    {
2752 1217 tao
2753 1055 tao
      try
2754
      {
2755 1292 tao
        // Set auto commit true
2756
        dbConn.setAutoCommit(true);
2757 1055 tao
        pStmt.close();
2758 1292 tao
2759 1217 tao
      }//try
2760
      catch (Exception ee)
2761
      {
2762
        MetaCatUtil.debugMessage("Error in DocumentImpl.insetServerIntoRepl(): "
2763
                                    +ee.getMessage(), 50);
2764
      }//catch
2765
      finally
2766
      {
2767
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2768 1055 tao
      }
2769 1217 tao
2770
    }//finally
2771 1055 tao
2772
  }
2773
2774
2775
  /**
2776 407 jones
   * the main routine used to test the DBWriter utility.
2777
   * <p>
2778
   * Usage: java DocumentImpl <-f filename -a action -d docid>
2779
   *
2780
   * @param filename the filename to be loaded into the database
2781
   * @param action the action to perform (READ, INSERT, UPDATE, DELETE)
2782
   * @param docid the id of the document to process
2783
   */
2784
  static public void main(String[] args) {
2785 1217 tao
    DBConnection dbconn = null;
2786
    int serialNumber = -1;
2787 407 jones
    try {
2788 555 bojilova
      String filename    = null;
2789 598 bojilova
      String dtdfilename = null;
2790 555 bojilova
      String action      = null;
2791
      String docid       = null;
2792 429 jones
      boolean showRuntime = false;
2793
      boolean useOldReadAlgorithm = false;
2794 407 jones
2795 408 jones
      // Parse the command line arguments
2796 407 jones
      for ( int i=0 ; i < args.length; ++i ) {
2797
        if ( args[i].equals( "-f" ) ) {
2798
          filename =  args[++i];
2799 598 bojilova
        } else if ( args[i].equals( "-r" ) ) {
2800
          dtdfilename =  args[++i];
2801 407 jones
        } else if ( args[i].equals( "-a" ) ) {
2802
          action =  args[++i];
2803
        } else if ( args[i].equals( "-d" ) ) {
2804
          docid =  args[++i];
2805 429 jones
        } else if ( args[i].equals( "-t" ) ) {
2806
          showRuntime = true;
2807
        } else if ( args[i].equals( "-old" ) ) {
2808
          useOldReadAlgorithm = true;
2809 407 jones
        } else {
2810
          System.err.println
2811
            ( "   args[" +i+ "] '" +args[i]+ "' ignored." );
2812
        }
2813
      }
2814
2815 408 jones
      // Check if the required arguments are provided
2816 407 jones
      boolean argsAreValid = false;
2817
      if (action != null) {
2818
        if (action.equals("INSERT")) {
2819
          if (filename != null) {
2820
            argsAreValid = true;
2821
          }
2822
        } else if (action.equals("UPDATE")) {
2823
          if ((filename != null) && (docid != null)) {
2824
            argsAreValid = true;
2825
          }
2826
        } else if (action.equals("DELETE")) {
2827
          if (docid != null) {
2828
            argsAreValid = true;
2829
          }
2830
        } else if (action.equals("READ")) {
2831
          if (docid != null) {
2832
            argsAreValid = true;
2833
          }
2834
        }
2835
      }
2836
2837 408 jones
      // Print usage message if the arguments are not valid
2838 407 jones
      if (!argsAreValid) {
2839
        System.err.println("Wrong number of arguments!!!");
2840
        System.err.println(
2841 598 bojilova
          "USAGE: java DocumentImpl [-t] <-a INSERT> [-d docid] <-f filename> "+
2842 680 bojilova
          "[-r dtdfilename]");
2843 407 jones
        System.err.println(
2844 598 bojilova
          "   OR: java DocumentImpl [-t] <-a UPDATE -d docid -f filename> " +
2845 680 bojilova
          "[-r dtdfilename]");
2846 407 jones
        System.err.println(
2847 429 jones
          "   OR: java DocumentImpl [-t] <-a DELETE -d docid>");
2848 407 jones
        System.err.println(
2849 429 jones
          "   OR: java DocumentImpl [-t] [-old] <-a READ -d docid>");
2850 407 jones
        return;
2851
      }
2852 429 jones
2853
      // Time the request if asked for
2854
      double startTime = System.currentTimeMillis();
2855
2856 407 jones
      // Open a connection to the database
2857
      MetaCatUtil util = new MetaCatUtil();
2858 1217 tao
2859
      dbconn=DBConnectionPool.getDBConnection("DocumentImpl.main");
2860
      serialNumber=dbconn.getCheckOutSerialNumber();
2861 407 jones
2862 463 berkley
      double connTime = System.currentTimeMillis();
2863 408 jones
      // Execute the action requested (READ, INSERT, UPDATE, DELETE)
2864 407 jones
      if (action.equals("READ")) {
2865 1217 tao
          DocumentImpl xmldoc = new DocumentImpl(docid );
2866 429 jones
          if (useOldReadAlgorithm) {
2867
            System.out.println(xmldoc.readUsingSlowAlgorithm());
2868
          } else {
2869 1480 tao
            xmldoc.toXml(new PrintWriter(System.out), null, null, true);
2870 429 jones
          }
2871 408 jones
      } else if (action.equals("DELETE")) {
2872 1217 tao
        DocumentImpl.delete(docid, null, null);
2873 408 jones
        System.out.println("Document deleted: " + docid);
2874 407 jones
      } else {
2875 1383 tao
        /*String newdocid = DocumentImpl.write(dbconn, filename, null,
2876 598 bojilova
                                             dtdfilename, action, docid,
2877
                                             null, null);
2878 408 jones
        if ((docid != null) && (!docid.equals(newdocid))) {
2879
          if (action.equals("INSERT")) {
2880
            System.out.println("New document ID generated!!! ");
2881
          } else if (action.equals("UPDATE")) {
2882
            System.out.println("ERROR: Couldn't update document!!! ");
2883 407 jones
          }
2884 408 jones
        } else if ((docid == null) && (action.equals("UPDATE"))) {
2885
          System.out.println("ERROR: Couldn't update document!!! ");
2886 407 jones
        }
2887 408 jones
        System.out.println("Document processing finished for: " + filename
2888 1383 tao
              + " (" + newdocid + ")");*/
2889 407 jones
      }
2890
2891 429 jones
      double stopTime = System.currentTimeMillis();
2892 463 berkley
      double dbOpenTime = (connTime - startTime)/1000;
2893
      double insertTime = (stopTime - connTime)/1000;
2894 429 jones
      double executionTime = (stopTime - startTime)/1000;
2895
      if (showRuntime) {
2896 463 berkley
        System.out.println("\n\nTotal Execution time was: " +
2897
                           executionTime + " seconds.");
2898
        System.out.println("Time to open DB connection was: " + dbOpenTime +
2899
                           " seconds.");
2900
        System.out.println("Time to insert document was: " + insertTime +
2901
                           " seconds.");
2902 429 jones
      }
2903 463 berkley
      dbconn.close();
2904 407 jones
    } catch (McdbException me) {
2905
      me.toXml(new PrintWriter(System.err));
2906
    } catch (AccessionNumberException ane) {
2907
      System.out.println(ane.getMessage());
2908
    } catch (Exception e) {
2909
      System.err.println("EXCEPTION HANDLING REQUIRED");
2910
      System.err.println(e.getMessage());
2911
      e.printStackTrace(System.err);
2912
    }
2913 1217 tao
    finally
2914
    {
2915
      // Return db connection
2916
      DBConnectionPool.returnDBConnection(dbconn, serialNumber);
2917
    }
2918 407 jones
  }
2919 393 jones
}