Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that represents an XML document
4
 *  Copyright: 2000 Regents of the University of California and the
5
 *             National Center for Ecological Analysis and Synthesis
6
 *    Authors: Matt Jones
7
 *    Release: @release@
8
 *
9
 *   '$Author: tao $'
10
 *     '$Date: 2002-05-12 18:30:34 -0700 (Sun, 12 May 2002) $'
11
 * '$Revision: 1081 $'
12
 *
13
 * This program is free software; you can redistribute it and/or modify
14
 * it under the terms of the GNU General Public License as published by
15
 * the Free Software Foundation; either version 2 of the License, or
16
 * (at your option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU General Public License
24
 * along with this program; if not, write to the Free Software
25
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
 */
27

    
28
package edu.ucsb.nceas.metacat;
29

    
30
import java.sql.*;
31
import java.io.File;
32
import java.io.FileReader;
33
import java.io.IOException;
34
import java.io.PrintWriter;
35
import java.io.Reader;
36
import java.io.StringWriter;
37
import java.io.Writer;
38
import java.io.InputStreamReader;
39
import java.io.*;
40
import java.text.SimpleDateFormat;
41

    
42
import java.util.Date;
43
import java.util.Iterator;
44
import java.util.Stack;
45
import java.util.TreeSet;
46
import java.util.Enumeration;
47

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

    
59
import java.net.URL;
60

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

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

    
70
  static final int ALL = 1;
71
  static final int WRITE = 2;
72
  static final int READ = 4;
73
  private static final AbstractDatabase dbAdapter = MetaCatUtil.dbAdapter;
74

    
75
  private Connection conn = null;
76
  private String docid = null;
77
  private String updatedVersion=null;
78
  private String docname = null;
79
  private String doctype = null;
80
// DOCTITLE attr cleared from the db
81
//  private String doctitle = null;
82
  private String createdate = null;
83
  private String updatedate = null;
84
  private String system_id = null;
85
  private String userowner = null;
86
  private String userupdated = null;
87
  private int rev;
88
  private int serverlocation;
89
  private String docHomeServer;
90
  private String publicaccess; 
91
  private long rootnodeid;
92
  private ElementNode rootNode = null;
93
  private TreeSet nodeRecordList = null;
94
  
95
  /**
96
   * Constructor used to create a document and read the document information
97
   * from the database.  If readNodes is false, then the node data is not 
98
   * read at this time, but is deferred until it is needed (such as when a 
99
   * call to toXml() is made).  
100
   *
101
   * @param conn the database connection from which to read the document
102
   * @param docid the identifier of the document to be created
103
   * @param readNodes flag indicating whether the xmlnodes should be read
104
   */
105
  public DocumentImpl(Connection conn, String docid, boolean readNodes) 
106
         throws McdbException 
107
  {
108
    try {
109
      this.conn = conn;
110
      this.docid = docid;
111
      
112
      // Look up the document information
113
      getDocumentInfo(docid);
114

    
115
      if (readNodes) {
116
        // Download all of the document nodes using a single SQL query
117
        // The sort order of the records is determined by the NodeComparator
118
        // class, and needs to represent a depth-first traversal for the
119
        // toXml() method to work properly
120
        nodeRecordList = getNodeRecordList(rootnodeid);
121
      }
122
    
123
    } catch (McdbException ex) {
124
      throw ex;
125
    } catch (Throwable t) {
126
      throw new McdbException("Error reading document from " +
127
                              "DocumentImpl.DocumentImpl: " + docid);
128
    }
129
  }
130

    
131
  /**
132
   * Constructor, creates document from database connection, used 
133
   * for reading the document
134
   *
135
   * @param conn the database connection from which to read the document
136
   * @param docid the identifier of the document to be created
137
   */
138
  public DocumentImpl(Connection conn, String docid) throws McdbException 
139
  {
140
    this(conn, docid, true);
141
  }
142

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

    
520
      BufferedInputStream bis = null;
521
      bis = new BufferedInputStream(input);
522
      byte[] buf = new byte[4 * 1024]; // 4K buffer
523
      int b = bis.read(buf);
524
       
525
      while (b != -1) 
526
      {
527
        outPut.write(buf, 0, b);
528
        b = bis.read(buf);
529
      }
530
      bis.close();
531
	    outPut.close();
532
	    fos.close();
533
    
534
    //}//if
535
 }
536
  
537

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

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

    
648
  /**
649
   * get the document type (which is the PublicID)
650
   */
651
  public String getDoctype() {
652
    return doctype;
653
  }
654

    
655
  /**
656
   * get the system identifier
657
   */
658
  public String getSystemID() {
659
    return system_id;
660
  }
661

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

    
683
  /** 
684
   * Get the document identifier (docid)
685
   */
686
  public String getDocID() {
687
    return docid;
688
  }
689
  
690
// DOCTITLE attr cleared from the db
691
//  /**
692
//   *get the document title
693
//   */
694
//  public String getDocTitle() {
695
//    return doctitle;
696
//  }
697
  
698
  public String getUserowner() {
699
    return userowner;
700
  }
701
  
702
  public String getUserupdated() {
703
    return userupdated;
704
  }
705
  
706
  public int getServerlocation() {
707
    return serverlocation;
708
  }
709
  
710
  public String getDocHomeServer() {
711
    return docHomeServer;
712
  }
713
  
714
 
715
 
716
  public String getPublicaccess() {
717
    return publicaccess;
718
  }
719
  
720
  public int getRev() {
721
    return rev;
722
  }
723
  
724
   /**
725
   * Print a string representation of the XML document
726
   */
727
  public String toString()
728
  {
729
    StringWriter docwriter = new StringWriter();
730
    try {
731
      this.toXml(docwriter);
732
    } catch (McdbException mcdbe) {
733
      return null;
734
    }
735
    String document = docwriter.toString();
736
    return document;
737
  }
738

    
739
  /**
740
   * Get a text representation of the XML document as a string
741
   * This older algorithm uses a recursive tree of Objects to represent the
742
   * nodes of the tree.  Each object is passed the data for the document 
743
   * and searches all of the document data to find its children nodes and
744
   * recursively build.  Thus, because each node reads the whole document,
745
   * this algorithm is extremely slow for larger documents, and the time
746
   * to completion is O(N^N) wrt the number of nodes.  See toXml() for a
747
   * better algorithm.
748
   */
749
  public String readUsingSlowAlgorithm() throws McdbException
750
  {
751
    StringBuffer doc = new StringBuffer();
752

    
753
    // First, check that we have the needed node data, and get it if not
754
    if (nodeRecordList == null) {
755
      nodeRecordList = getNodeRecordList(rootnodeid);
756
    }
757

    
758
    // Create the elements from the downloaded data in the TreeSet
759
    rootNode = new ElementNode(nodeRecordList, rootnodeid);
760

    
761
    // Append the resulting document to the StringBuffer and return it
762
    doc.append("<?xml version=\"1.0\"?>\n");
763
      
764
    if (docname != null) {
765
      if ((doctype != null) && (system_id != null)) {
766
        doc.append("<!DOCTYPE " + docname + " PUBLIC \"" + doctype + 
767
                   "\" \"" + system_id + "\">\n");
768
      } else {
769
        doc.append("<!DOCTYPE " + docname + ">\n");
770
      }
771
    }
772
    doc.append(rootNode.toString());
773
  
774
    return (doc.toString());
775
  }
776

    
777
  /**
778
   * Print a text representation of the XML document to a Writer
779
   *
780
   * @param pw the Writer to which we print the document
781
   */
782
  public void toXml(Writer pw) throws McdbException
783
  {
784
    PrintWriter out = null;
785
    if (pw instanceof PrintWriter) {
786
      out = (PrintWriter)pw;
787
    } else {
788
      out = new PrintWriter(pw);
789
    }
790

    
791
    MetaCatUtil util = new MetaCatUtil();
792
    
793
    // First, check that we have the needed node data, and get it if not
794
    if (nodeRecordList == null) {
795
      nodeRecordList = getNodeRecordList(rootnodeid);
796
    }
797

    
798
    Stack openElements = new Stack();
799
    boolean atRootElement = true;
800
    boolean previousNodeWasElement = false;
801

    
802
    // Step through all of the node records we were given
803
    Iterator it = nodeRecordList.iterator();
804
    while (it.hasNext()) {
805
      NodeRecord currentNode = (NodeRecord)it.next();
806
      //util.debugMessage("[Got Node ID: " + currentNode.nodeid +
807
                          //" (" + currentNode.parentnodeid +
808
                          //", " + currentNode.nodeindex + 
809
                          //", " + currentNode.nodetype + 
810
                          //", " + currentNode.nodename + 
811
                          //", " + currentNode.nodedata + ")]");
812
      // Print the end tag for the previous node if needed
813
      //
814
      // This is determined by inspecting the parent nodeid for the
815
      // currentNode.  If it is the same as the nodeid of the last element
816
      // that was pushed onto the stack, then we are still in that previous
817
      // parent element, and we do nothing.  However, if it differs, then we
818
      // have returned to a level above the previous parent, so we go into
819
      // a loop and pop off nodes and print out their end tags until we get
820
      // the node on the stack to match the currentNode parentnodeid
821
      //
822
      // So, this of course means that we rely on the list of elements
823
      // having been sorted in a depth first traversal of the nodes, which
824
      // is handled by the NodeComparator class used by the TreeSet
825
      if (!atRootElement) {
826
        NodeRecord currentElement = (NodeRecord)openElements.peek();
827
        if ( currentNode.parentnodeid != currentElement.nodeid ) {
828
          while ( currentNode.parentnodeid != currentElement.nodeid ) {
829
            currentElement = (NodeRecord)openElements.pop();
830
            util.debugMessage("\n POPPED: " + currentElement.nodename);
831
            if (previousNodeWasElement) {
832
              out.print(">");
833
              previousNodeWasElement = false;
834
            }  
835
            if ( currentElement.nodeprefix != null ) {
836
              out.print("</" + currentElement.nodeprefix + ":" + 
837
                        currentElement.nodename + ">" );
838
            } else {
839
              out.print("</" + currentElement.nodename + ">" );
840
            }
841
            currentElement = (NodeRecord)openElements.peek();
842
          }
843
        }
844
      }
845

    
846
      // Handle the DOCUMENT node
847
      if (currentNode.nodetype.equals("DOCUMENT")) {
848
        out.println("<?xml version=\"1.0\"?>");
849
      
850
        if (docname != null) {
851
          if ((doctype != null) && (system_id != null)) {
852
            out.println("<!DOCTYPE " + docname + " PUBLIC \"" + doctype + 
853
                       "\" \"" + system_id + "\">");
854
          } else {
855
            out.println("<!DOCTYPE " + docname + ">");
856
          }
857
        }
858

    
859
      // Handle the ELEMENT nodes
860
      } else if (currentNode.nodetype.equals("ELEMENT")) {
861
        if (atRootElement) {
862
          atRootElement = false;
863
        } else {
864
          if (previousNodeWasElement) {
865
            out.print(">");
866
          }
867
        }
868
        openElements.push(currentNode);
869
        util.debugMessage("\n PUSHED: " + currentNode.nodename);
870
        previousNodeWasElement = true;
871
        if ( currentNode.nodeprefix != null ) {
872
          out.print("<" + currentNode.nodeprefix + ":" + currentNode.nodename);
873
        } else {
874
          out.print("<" + currentNode.nodename);
875
        }
876

    
877
      // Handle the ATTRIBUTE nodes
878
      } else if (currentNode.nodetype.equals("ATTRIBUTE")) {
879
        if ( currentNode.nodeprefix != null ) {
880
          out.print(" " + currentNode.nodeprefix + ":" + currentNode.nodename +
881
                    "=\"" + currentNode.nodedata + "\"");
882
        } else {
883
          out.print(" " + currentNode.nodename + "=\"" +
884
                    currentNode.nodedata + "\"");
885
        }
886

    
887
      // Handle the NAMESPACE nodes
888
      } else if (currentNode.nodetype.equals("NAMESPACE")) {
889
        out.print(" xmlns:" + currentNode.nodename + "=\""
890
                 + currentNode.nodedata + "\"");
891

    
892
      // Handle the TEXT nodes
893
      } else if (currentNode.nodetype.equals("TEXT")) {
894
        if (previousNodeWasElement) {
895
          out.print(">");
896
        }
897
        out.print(currentNode.nodedata);
898
        previousNodeWasElement = false;
899

    
900
      // Handle the COMMENT nodes
901
      } else if (currentNode.nodetype.equals("COMMENT")) {
902
        if (previousNodeWasElement) {
903
          out.print(">");
904
        }
905
        out.print("<!--" + currentNode.nodedata + "-->");
906
        previousNodeWasElement = false;
907

    
908
      // Handle the PI nodes
909
      } else if (currentNode.nodetype.equals("PI")) {
910
        if (previousNodeWasElement) {
911
          out.print(">");
912
        }
913
        out.print("<?" + currentNode.nodename + " " +
914
                        currentNode.nodedata + "?>");
915
        previousNodeWasElement = false;
916

    
917
      // Handle any other node type (do nothing)
918
      } else {
919
        // Any other types of nodes are not handled.
920
        // Probably should throw an exception here to indicate this
921
      }
922
      out.flush();
923
    }
924

    
925
    // Print the final end tag for the root element
926
    while(!openElements.empty())
927
    {
928
      NodeRecord currentElement = (NodeRecord)openElements.pop();
929
      util.debugMessage("\n POPPED: " + currentElement.nodename);
930
      if ( currentElement.nodeprefix != null ) {
931
        out.print("</" + currentElement.nodeprefix + ":" + 
932
                  currentElement.nodename + ">" );
933
      } else {
934
        out.print("</" + currentElement.nodename + ">" );
935
      }
936
    }
937
    out.flush();
938
  }
939
  
940
  private boolean isRevisionOnly(DocumentIdentifier docid) throws Exception
941
  {
942
    //System.out.println("inRevisionOnly");
943
    PreparedStatement pstmt;
944
    String rev = docid.getRev();
945
    String newid = docid.getIdentifier();
946
    pstmt = conn.prepareStatement("select rev from xml_documents " +
947
                                  "where docid like '" + newid + "'");
948
    pstmt.execute();
949
    ResultSet rs = pstmt.getResultSet();
950
    boolean tablehasrows = rs.next();
951
    if(rev.equals("newest") || rev.equals("all"))
952
    {
953
      return false;
954
    }
955
    
956
    if(tablehasrows)
957
    {
958
      int r = rs.getInt(1);
959
      pstmt.close();
960
      if(new Integer(rev).intValue() == r)
961
      { //the current revision in in xml_documents
962
        //System.out.println("returning false");
963
        return false;
964
      }
965
      else if(new Integer(rev).intValue() < r)
966
      { //the current revision is in xml_revisions.
967
        //System.out.println("returning true");
968
        return true;
969
      }
970
      else if(new Integer(rev).intValue() > r)
971
      { //error, rev cannot be greater than r
972
        throw new Exception("requested revision cannot be greater than " +
973
                            "the latest revision number.");
974
      }
975
    }
976
    throw new Exception("the requested docid '" + docid.toString() + 
977
                        "' does not exist");
978
  }
979

    
980
  private void getDocumentInfo(String docid) throws McdbException, 
981
                                                    AccessionNumberException
982
  {
983
    getDocumentInfo(new DocumentIdentifier(docid));
984
  }
985
  
986
  /**
987
   * Look up the document type information from the database
988
   *
989
   * @param docid the id of the document to look up
990
   */
991
  private void getDocumentInfo(DocumentIdentifier docid) throws McdbException 
992
  {
993
    PreparedStatement pstmt;
994
    String table = "xml_documents";
995
        
996
    try
997
    {
998
      if(isRevisionOnly(docid))
999
      { //pull the document from xml_revisions instead of from xml_documents;
1000
        table = "xml_revisions";
1001
      }
1002
    }
1003
    catch(Exception e)
1004
    {
1005
      System.out.println("error in DocumentImpl.getDocumentInfo: " + 
1006
                          e.getMessage());
1007
    }
1008
    
1009
    //deal with the key words here.
1010
    
1011
    if(docid.getRev().equals("all"))
1012
    {
1013
      
1014
    }
1015
    
1016
    try {
1017
      StringBuffer sql = new StringBuffer();
1018
// DOCTITLE attr cleared from the db
1019
//      sql.append("SELECT docname, doctype, rootnodeid, doctitle, ");
1020
      sql.append("SELECT docname, doctype, rootnodeid, ");
1021
      sql.append("date_created, date_updated, user_owner, user_updated, ");
1022
      sql.append("server_location, public_access, rev");
1023
      sql.append(" FROM ").append(table);
1024
      sql.append(" WHERE docid LIKE '").append(docid.getIdentifier());
1025
      sql.append("' and rev like '").append(docid.getRev()).append("'");
1026
      //System.out.println(sql.toString());
1027
      pstmt =
1028
        conn.prepareStatement(sql.toString());
1029
      // Bind the values to the query
1030
      //pstmt.setString(1, docid.getIdentifier());
1031
      //pstmt.setString(2, docid.getRev());
1032

    
1033
      pstmt.execute();
1034
      ResultSet rs = pstmt.getResultSet();
1035
      boolean tableHasRows = rs.next();
1036
      if (tableHasRows) {
1037
        this.docname        = rs.getString(1);
1038
        this.doctype        = rs.getString(2);
1039
        this.rootnodeid     = rs.getLong(3);
1040
// DOCTITLE attr cleared from the db
1041
//        this.doctitle       = rs.getString(4);
1042
        this.createdate     = rs.getString(4);
1043
        this.updatedate     = rs.getString(5);
1044
        this.userowner      = rs.getString(6);
1045
        this.userupdated    = rs.getString(7);
1046
        this.serverlocation = rs.getInt(8);
1047
        this.publicaccess   = rs.getString(9);
1048
        this.rev            = rs.getInt(10);
1049
      } 
1050
      pstmt.close();
1051
      
1052
      //get doc  home server name
1053
      
1054
      pstmt = conn.prepareStatement("select server " +
1055
                        "from xml_replication where serverid = ?");
1056
                        
1057
      
1058
      pstmt.setInt(1, serverlocation);
1059
      pstmt.execute();
1060
      rs = pstmt.getResultSet();
1061
      tableHasRows = rs.next();
1062
      if (tableHasRows)
1063
      {
1064
        
1065
          String server = rs.getString(1);
1066
          //get homeserver name
1067
          if(!server.equals("localhost"))
1068
          {
1069
            this.docHomeServer=server;
1070
          }
1071
          else
1072
          {
1073
            this.docHomeServer=MetaCatUtil.getLocalReplicationServerName();
1074
          }
1075
          MetaCatUtil.debugMessage("server: "+docHomeServer, 50);
1076
        
1077
      }
1078
      pstmt.close();
1079
      if (this.doctype != null) {
1080
        pstmt =
1081
          conn.prepareStatement("SELECT system_id " +
1082
                                  "FROM xml_catalog " +
1083
                                 "WHERE public_id = ?");
1084
        // Bind the values to the query
1085
        pstmt.setString(1, doctype);
1086
  
1087
        pstmt.execute();
1088
        rs = pstmt.getResultSet();
1089
        tableHasRows = rs.next();
1090
        if (tableHasRows) {
1091
          this.system_id  = rs.getString(1);
1092
        } 
1093
        pstmt.close();
1094
      }
1095
    } catch (SQLException e) {
1096
      System.out.println("error in DocumentImpl.getDocumentInfo: " + 
1097
                          e.getMessage());
1098
      e.printStackTrace(System.out);
1099
      throw new McdbException("Error accessing database connection in " +
1100
                              "DocumentImpl.getDocumentInfo: ", e);
1101
    }
1102

    
1103
    if (this.docname == null) {
1104
      throw new McdbDocNotFoundException("Document not found: " + docid);
1105
    }
1106
  }
1107

    
1108
  /**
1109
   * Look up the node data from the database
1110
   *
1111
   * @param rootnodeid the id of the root node of the node tree to look up
1112
   */
1113
  private TreeSet getNodeRecordList(long rootnodeid) throws McdbException 
1114
  {
1115
    PreparedStatement pstmt;
1116
    TreeSet nodeRecordList = new TreeSet(new NodeComparator());
1117
    long nodeid = 0;
1118
    long parentnodeid = 0;
1119
    long nodeindex = 0;
1120
    String nodetype = null;
1121
    String nodename = null;
1122
    String nodeprefix = null;
1123
    String nodedata = null;
1124
    String quotechar = dbAdapter.getStringDelimiter();
1125

    
1126
    try {
1127
      pstmt =
1128
      conn.prepareStatement("SELECT nodeid,parentnodeid,nodeindex, " +
1129
           "nodetype,nodename,nodeprefix,nodedata " +               
1130
           "FROM xml_nodes WHERE rootnodeid = ?");
1131

    
1132
      // Bind the values to the query
1133
      pstmt.setLong(1, rootnodeid);
1134

    
1135
      pstmt.execute();
1136
      ResultSet rs = pstmt.getResultSet();
1137
      boolean tableHasRows = rs.next();
1138
      while (tableHasRows) {
1139
        nodeid = rs.getLong(1);
1140
        parentnodeid = rs.getLong(2);
1141
        nodeindex = rs.getLong(3);
1142
        nodetype = rs.getString(4);
1143
        nodename = rs.getString(5);
1144
        nodeprefix = rs.getString(6);
1145
        nodedata = rs.getString(7);
1146
        nodedata = MetaCatUtil.normalize(nodedata);
1147
        // add the data to the node record list hashtable
1148
        NodeRecord currentRecord = new NodeRecord(nodeid,parentnodeid,nodeindex,
1149
                                      nodetype, nodename, nodeprefix, nodedata);
1150
        nodeRecordList.add(currentRecord);
1151

    
1152
        // Advance to the next node
1153
        tableHasRows = rs.next();
1154
      } 
1155
      pstmt.close();
1156

    
1157
    } catch (SQLException e) {
1158
      throw new McdbException("Error in DocumentImpl.getNodeRecordList " +
1159
                              e.getMessage());
1160
    }
1161

    
1162
    if (nodeRecordList != null) {
1163
      return nodeRecordList;
1164
    } else {
1165
      throw new McdbException("Error getting node data: " + docid);
1166
    }
1167
  }
1168
  
1169
// NOT USED ANY MORE
1170
//  /** creates SQL code and inserts new document into DB connection 
1171
//   default serverCode of 1*/
1172
//  private void writeDocumentToDB(String action, String user)
1173
//               throws SQLException, Exception
1174
//  {
1175
//    writeDocumentToDB(action, user, null, 1);
1176
//  }
1177

    
1178
 /** creates SQL code and inserts new document into DB connection */
1179
  private void writeDocumentToDB(String action, String user, String pub, 
1180
                                 String catalogid, int serverCode) 
1181
               throws SQLException, Exception {
1182
    String sysdate = dbAdapter.getDateTimeFunction();
1183

    
1184
    try {
1185
      PreparedStatement pstmt = null;
1186

    
1187
      if (action.equals("INSERT")) {
1188
        //AccessionNumber ac = new AccessionNumber();
1189
        //this.docid = ac.generate(docid, "INSERT");
1190
        System.out.println("before pstmt");
1191
        pstmt = conn.prepareStatement(
1192
                "INSERT INTO xml_documents " +
1193
                "(docid, rootnodeid, docname, doctype, " + 
1194
                "user_owner, user_updated, date_created, date_updated, " + 
1195
                "public_access, catalog_id, server_location, rev) " +
1196
                "VALUES (?, ?, ?, ?, ?, ?, " + sysdate + ", " + sysdate + 
1197
                ", ?, ?, ?, ?)");
1198
        //note that the server_location is set to 1. 
1199
        //this means that "localhost" in the xml_replication table must
1200
        //always be the first entry!!!!!
1201
        
1202
        // Bind the values to the query
1203
        pstmt.setString(1, this.docid);
1204
        pstmt.setLong(2, rootnodeid);
1205
        pstmt.setString(3, docname);
1206
        pstmt.setString(4, doctype);
1207
        pstmt.setString(5, user);
1208
        pstmt.setString(6, user);
1209
        //public access is usefulless, so set it to null
1210
        pstmt.setString(7, null);
1211
        /*if ( pub == null ) {
1212
          pstmt.setString(7, null);
1213
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
1214
          pstmt.setInt(7, 1);
1215
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
1216
          pstmt.setInt(7, 0);
1217
        }*/
1218
        pstmt.setString(8, catalogid);
1219
        pstmt.setInt(9, serverCode);
1220
        pstmt.setInt(10, Integer.parseInt(updatedVersion)); 
1221
      } else if (action.equals("UPDATE")) {
1222

    
1223
        // Save the old document publicaccessentry in a backup table
1224
        DocumentImpl.archiveDocRevision( conn, docid, user );
1225
        DocumentImpl thisdoc = new DocumentImpl(conn, docid);
1226
        int thisrev = thisdoc.getRev();
1227
        
1228
        //if the updated vesion is not greater than current one,
1229
        //throw it into a exception
1230
        if (Integer.parseInt(updatedVersion)<=thisrev)
1231
        {
1232
          throw new Exception("Next revision number couldn't be less"
1233
                               +" than or equal "+ thisrev);
1234
        }
1235
        else
1236
        {
1237
          //set the user specified revision 
1238
          thisrev=Integer.parseInt(updatedVersion);
1239
        }
1240
        
1241
        // Delete index for the old version of docid
1242
        // The new index is inserting on the next calls to DBSAXNode
1243
        pstmt = conn.prepareStatement(
1244
                "DELETE FROM xml_index WHERE docid='" + this.docid + "'");
1245
        pstmt.execute();
1246
        pstmt.close();
1247

    
1248
        // Update the new document to reflect the new node tree
1249
        pstmt = conn.prepareStatement(
1250
            "UPDATE xml_documents " +
1251
            "SET rootnodeid = ?, docname = ?, doctype = ?, " +
1252
            "user_updated = ?, date_updated = " + sysdate + ", " +
1253
            "server_location = ?, rev = ?, public_access = ?, catalog_id = ? " +
1254
            "WHERE docid = ?");
1255
        // Bind the values to the query
1256
        pstmt.setLong(1, rootnodeid);
1257
        pstmt.setString(2, docname);
1258
        pstmt.setString(3, doctype);
1259
        pstmt.setString(4, user);
1260
        pstmt.setInt(5, serverCode);
1261
        pstmt.setInt(6, thisrev);
1262
        pstmt.setString(7, null);
1263
        /*if ( pub == null ) {
1264
          pstmt.setString(7, null);
1265
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
1266
          pstmt .setInt(7, 1);
1267
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
1268
          pstmt.setInt(7, 0);
1269
        }*/
1270
        pstmt.setString(8, catalogid);
1271
        pstmt.setString(9, this.docid);
1272

    
1273
      } else {
1274
        System.err.println("Action not supported: " + action);
1275
      }
1276

    
1277
      // Do the insertion
1278
      pstmt.execute();
1279
      System.out.println("after excecute");
1280
      pstmt.close();
1281

    
1282
    } catch (SQLException sqle) {
1283
      throw sqle;
1284
    } catch (Exception e) {
1285
      throw e;
1286
    }
1287
  }
1288

    
1289
  /**
1290
   * Write an XML file to the database, given a filename
1291
   *
1292
   * @param conn the JDBC connection to the database
1293
   * @param filename the filename to be loaded into the database
1294
   * @param pub flag for public "read" access on document
1295
   * @param dtdfilename the dtd to be uploaded on server's file system
1296
   * @param action the action to be performed (INSERT OR UPDATE)
1297
   * @param docid the docid to use for the INSERT OR UPDATE
1298
   * @param user the user that owns the document
1299
   * @param groups the groups to which user belongs
1300
   */
1301
  public static String write(Connection conn,String filename,
1302
                             String pub, String dtdfilename,
1303
                             String action, String docid, String user,
1304
                             String[] groups )
1305
                throws Exception {
1306
                  
1307
    Reader dtd = null;
1308
    if ( dtdfilename != null ) {
1309
      dtd = new FileReader(new File(dtdfilename).toString());
1310
    }
1311
    return write ( conn, new FileReader(new File(filename).toString()),
1312
                   pub, dtd, action, docid, user, groups, false);
1313
  }
1314

    
1315
  public static String write(Connection conn,Reader xml,String pub,Reader dtd,
1316
                             String action, String docid, String user,
1317
                             String[] groups, boolean validate)
1318
                throws Exception {
1319
    //this method will be called in handleUpdateOrInsert method 
1320
    //in MetacatServlet class
1321
    // get server location for this doc
1322
    int serverLocation=getServerLocationNumber(conn,docid);
1323
    //System.out.println("server location: "+serverLocation);
1324
    return write(conn,xml,pub,dtd,action,docid,user,groups,serverLocation,false,
1325
                 validate);
1326
  }
1327

    
1328
  public static String write(Connection conn, Reader xml, String pub,
1329
                             String action, String docid, String user,
1330
                             String[] groups )
1331
                throws Exception {
1332
    if(action.equals("UPDATE"))
1333
    {//if the document is being updated then use the servercode from the 
1334
     //originally inserted document.
1335
      DocumentImpl doc = new DocumentImpl(conn, docid);
1336
      int servercode = doc.getServerlocation();
1337
      return write(conn, xml, pub, action, docid, user, groups, servercode);
1338
    }
1339
    else
1340
    {//if the file is being inserted then the servercode is always 1
1341
      return write(conn, xml, pub, action, docid, user, groups, 1);
1342
    }
1343
  }
1344
  
1345
  public static String write( Connection conn, Reader xml,
1346
                              String action, String docid, String user,
1347
                              String[] groups, int serverCode )
1348
                throws Exception
1349
  {
1350
    return write(conn,xml,null,action,docid,user,groups,serverCode);
1351
  }
1352
  
1353
  public static String write( Connection conn, Reader xml, String pub,
1354
                              String action, String docid, String user,
1355
                              String[] groups, int serverCode) 
1356
                throws Exception
1357
  {
1358
    return write(conn,xml,pub,null,action,docid,user,groups,
1359
                 serverCode,false,false);
1360
  }
1361
  
1362
  public static String write( Connection conn, Reader xml, String pub,
1363
                              String action, String docid, String user,
1364
                              String[] groups, int serverCode, boolean override)
1365
                throws Exception
1366
  {
1367
    return write(conn,xml,pub,null,action,docid,user,groups,
1368
                 serverCode,override,false);
1369
  }
1370
  
1371
  /**
1372
   * Write an XML file to the database, given a Reader
1373
   *
1374
   * @param conn the JDBC connection to the database
1375
   * @param xml the xml stream to be loaded into the database
1376
   * @param pub flag for public "read" access on xml document
1377
   * @param dtd the dtd to be uploaded on server's file system
1378
   * @param action the action to be performed (INSERT or UPDATE)
1379
   * @param accnum the docid + rev# to use on INSERT or UPDATE
1380
   * @param user the user that owns the document
1381
   * @param groups the groups to which user belongs
1382
   * @param serverCode the serverid from xml_replication on which this document
1383
   *        resides.
1384
   * @param override flag to stop insert replication checking.
1385
   *        if override = true then a document not belonging to the local server
1386
   *        will not be checked upon update for a file lock.
1387
   *        if override = false then a document not from this server, upon 
1388
   *        update will be locked and version checked.
1389
   */
1390

    
1391
  public static String write( Connection conn,Reader xml,String pub,Reader dtd,
1392
                              String action, String accnum, String user,
1393
                              String[] groups, int serverCode, boolean override,
1394
                              boolean validate)
1395
                throws Exception
1396
  {
1397
    // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1398
    MetaCatUtil util = new MetaCatUtil();
1399
    AccessionNumber ac = new AccessionNumber(conn, accnum, action);
1400
    String docid = ac.getDocid();
1401
    String rev = ac.getRev();
1402
    MetaCatUtil.debugMessage("action: " + action + " servercode: " + 
1403
                             serverCode + " override: " + override, 10);
1404
                        
1405
    if((serverCode != 1 && action.equals("UPDATE")) && !override)
1406
    { //if this document being written is not a resident of this server then
1407
      //we need to try to get a lock from it's resident server.  If the
1408
      //resident server will not give a lock then we send the user a message
1409
      //saying that he/she needs to download a new copy of the file and
1410
      //merge the differences manually.
1411
      int istreamInt; 
1412
      char istreamChar;
1413
     
1414
      // check for 'write' permission for 'user' to update this document
1415
      if ( !hasPermission(conn, user, groups, docid) ) {
1416
        throw new Exception("User " + user + 
1417
              " does not have permission to update XML Document #" + accnum);
1418
      }        
1419
  
1420
      DocumentIdentifier id = new DocumentIdentifier(accnum);
1421
      String updaterev = id.getRev();
1422
      String server = MetacatReplication.getServer(serverCode);
1423
      MetacatReplication.replLog("attempting to lock " + accnum);
1424
      URL u = new URL("https://" + server + "?server="
1425
           +util.getLocalReplicationServerName()+"&action=getlock&updaterev=" 
1426
           +updaterev + "&docid=" + docid);
1427
      //System.out.println("sending message: " + u.toString());
1428
      String serverResStr = MetacatReplication.getURLContent(u);
1429
      String openingtag =serverResStr.substring(0, serverResStr.indexOf(">")+1);
1430
      if(openingtag.equals("<lockgranted>"))
1431
      {//the lock was granted go ahead with the insert
1432
        try 
1433
        {
1434
          //System.out.println("In lockgranted");
1435
          MetacatReplication.replLog("lock granted for " + accnum + " from " +
1436
                                      server);
1437
          XMLReader parser = initializeParser(conn, action, docid, updaterev,
1438
                                  validate, user, groups, pub, serverCode, dtd);
1439
          conn.setAutoCommit(false);
1440
          parser.parse(new InputSource(xml)); 
1441
          conn.commit();
1442
          conn.setAutoCommit(true);
1443
        } 
1444
        catch (Exception e) 
1445
        {
1446
          conn.rollback();
1447
          conn.setAutoCommit(true);
1448
          throw e;
1449
        }
1450
                
1451
        
1452
        
1453
        //If Metacat is super hub, tell all servers in its server list to get 
1454
        //the new document, ture mean it is xml document
1455
        if ((util.getOption("hub")).equals("super"))
1456
        {
1457
          ForceReplicationHandler frh = new ForceReplicationHandler(accnum, 
1458
                true, ReplicationHandler.buildServerList(conn));
1459
        }
1460
        else
1461
        {
1462
          //after inserting the document locally, tell the document's homeserver
1463
          //to come get a copy from here.
1464
         
1465
          ForceReplicationHandler frh = new ForceReplicationHandler(accnum, 
1466
                true, ReplicationHandler.getHomeServer(docid));
1467
        }
1468
        return (accnum);
1469
      }
1470

    
1471
      else if(openingtag.equals("<filelocked>"))
1472
      {//the file is currently locked by another user
1473
       //notify our user to wait a few minutes, check out a new copy and try
1474
       //again.
1475
        //System.out.println("file locked");
1476
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1477
                                   server + " reason: file already locked");
1478
        throw new Exception("The file specified is already locked by another " +
1479
                            "user.  Please wait 30 seconds, checkout the " +
1480
                            "newer document, merge your changes and try " +
1481
                            "again.");
1482
      }
1483
      else if(openingtag.equals("<outdatedfile>"))
1484
      {//our file is outdated.  notify our user to check out a new copy of the
1485
       //file and merge his version with the new version.
1486
        //System.out.println("outdated file");
1487
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1488
                                    server + " reason: local file outdated");
1489
        throw new Exception("The file you are trying to update is an outdated" +
1490
                            " version.  Please checkout the newest document, " +
1491
                            "merge your changes and try again.");
1492
      }
1493
    }
1494
    
1495
    if ( action.equals("UPDATE") ) {
1496
      // check for 'write' permission for 'user' to update this document
1497

    
1498
      if ( !hasPermission(conn, user, groups, docid) ) {
1499
        throw new Exception("User " + user + 
1500
              " does not have permission to update XML Document #" + accnum);
1501
      }          
1502
    }
1503

    
1504
    try 
1505
    { 
1506
      
1507
      XMLReader parser = initializeParser(conn, action, docid, rev, validate,
1508
                                          user, groups, pub, serverCode, dtd);
1509
      conn.setAutoCommit(false);
1510
      parser.parse(new InputSource(xml));
1511
      conn.commit();
1512
      conn.setAutoCommit(true);
1513
    } 
1514
    catch (Exception e) 
1515
    {
1516
      conn.rollback();
1517
      conn.setAutoCommit(true);
1518
      throw e;
1519
    }
1520
    
1521
    //force replicate out the new document to each server in our server list.
1522
    if(serverCode == 1)
1523
    { 
1524
      
1525
      //start the thread to replicate this new document out to the other servers
1526
      //true mean it is xml document
1527
      ForceReplicationHandler frh = new ForceReplicationHandler
1528
                (accnum, action, true,ReplicationHandler.buildServerList(conn));
1529
      
1530
    }
1531
      
1532
    return(accnum);
1533
  }
1534

    
1535
  /**
1536
   * Write an XML file to the database during replication
1537
   *
1538
   * @param conn the JDBC connection to the database
1539
   * @param xml the xml stream to be loaded into the database
1540
   * @param pub flag for public "read" access on xml document
1541
   * @param dtd the dtd to be uploaded on server's file system
1542
   * @param action the action to be performed (INSERT or UPDATE)
1543
   * @param accnum the docid + rev# to use on INSERT or UPDATE
1544
   * @param user the user that owns the document
1545
   * @param groups the groups to which user belongs
1546
   * @param homeServer the name of server which the document origanlly create
1547
   * @param validate, if the xml document is valid or not
1548
   */
1549

    
1550
  public static String writeReplication( Connection conn,Reader xml,String pub,
1551
                Reader dtd, String action, String accnum, String user,
1552
                            String[] groups,String homeServer, boolean validate)
1553
                throws Exception
1554
  {
1555
    // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1556
    MetaCatUtil util = new MetaCatUtil();
1557
    //AccessionNumber ac = new AccessionNumber(conn, accnum, action);
1558
    //String docid = ac.getDocid();
1559
    // String rev = ac.getRev();
1560
    String docid=util.getDocIdFromString(accnum);
1561
    String rev=(new Integer(util.getVersionFromString(accnum))).toString();
1562
    
1563
    //check if xml_documents table has the document or not
1564
    //if not, set action to insert
1565
    if (getLatestRevisionNumber(conn,docid)==-1)
1566
    {
1567
      action="INSERT";
1568
    }
1569
    
1570
    int serverCode=-2;
1571
    //get server code for the home server
1572
    serverCode=getServerCode(homeServer);
1573
    //if the server is not in the xml replication table, insert it.
1574
    if (serverCode==-1)
1575
    {
1576
      insertServerIntoReplicationTable(homeServer);
1577
      //get server code again
1578
      serverCode=getServerCode(homeServer);
1579
    }
1580
      
1581
    MetaCatUtil.debugMessage("action: " + action + " servercode: " + 
1582
                             serverCode, 10);
1583
                        
1584
    /*if((serverCode != 1 && action.equals("UPDATE")) )
1585
    { 
1586
      int istreamInt; 
1587
      char istreamChar;
1588
      DocumentIdentifier id = new DocumentIdentifier(accnum);
1589
      String updaterev = id.getRev();
1590
      String server = MetacatReplication.getServer(serverCode);
1591
      MetacatReplication.replLog("attempting to lock " + accnum);
1592
      URL u = new URL("https://" + server + "?server="
1593
           +util.getLocalReplicationServerName()+"&action=getlock&updaterev=" 
1594
           +updaterev + "&docid=" + docid);
1595
     
1596
      String serverResStr = MetacatReplication.getURLContent(u);
1597
      String openingtag =serverResStr.substring(0, serverResStr.indexOf(">")+1);
1598
      if(openingtag.equals("<lockgranted>"))
1599
      {
1600
        try 
1601
        {
1602
          
1603
          MetacatReplication.replLog("lock granted for " + accnum + " from " +
1604
                                      server);
1605
          XMLReader parser = initializeParser(conn, action, docid, updaterev,
1606
                                  validate, user, groups, pub, serverCode, dtd);
1607
          conn.setAutoCommit(false);
1608
          parser.parse(new InputSource(xml)); 
1609
          conn.commit();
1610
          conn.setAutoCommit(true);
1611
        } 
1612
        catch (Exception e) 
1613
        {
1614
          conn.rollback();
1615
          conn.setAutoCommit(true);
1616
          throw e;
1617
        }
1618
        return (accnum);
1619
      }
1620

    
1621
      else if(openingtag.equals("<filelocked>"))
1622
      {
1623
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1624
                                   server + " reason: file already locked");
1625
        throw new Exception("The file specified is already locked by another " +
1626
                            "user.  Please wait 30 seconds, checkout the " +
1627
                            "newer document, merge your changes and try " +
1628
                            "again.");
1629
      }
1630
      else if(openingtag.equals("<outdatedfile>"))
1631
      {
1632
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1633
                                    server + " reason: local file outdated");
1634
        throw new Exception("The file you are trying to update is an outdated" +
1635
                            " version.  Please checkout the newest document, " +
1636
                            "merge your changes and try again.");
1637
      }
1638
    }*/
1639
    
1640
    /*if ( action.equals("UPDATE") ) {
1641
      
1642
      if ( !hasPermission(conn, user, groups, docid) ) {
1643
        throw new Exception("User " + user + 
1644
              " does not have permission to update XML Document #" + accnum);
1645
      }          
1646
    }*/
1647

    
1648
    try 
1649
    { 
1650
      
1651
      XMLReader parser = initializeParser(conn, action, docid, rev, validate,
1652
                                          user, groups, pub, serverCode, dtd);
1653
      conn.setAutoCommit(false);
1654
      parser.parse(new InputSource(xml));
1655
      conn.commit();
1656
      conn.setAutoCommit(true);
1657
    } 
1658
    catch (Exception e) 
1659
    {
1660
      conn.rollback();
1661
      conn.setAutoCommit(true);
1662
      throw e;
1663
    }
1664

    
1665
    return(accnum);
1666
  }
1667

    
1668
  
1669
  /**
1670
   * Delete an XML file from the database (actually, just make it a revision
1671
   * in the xml_revisions table)
1672
   *
1673
   * @param docid the ID of the document to be deleted from the database
1674
   */
1675
  public static void delete( Connection conn, String accnum,
1676
                                 String user, String[] groups )
1677
                throws Exception 
1678
  {
1679
    // OLD
1680
    //DocumentIdentifier id = new DocumentIdentifier(accnum);
1681
    //String docid = id.getIdentifier();
1682
    //String rev = id.getRev();
1683
    
1684
    // OLD
1685
    // Determine if the docid,rev are OK for DELETE
1686
    //AccessionNumber ac = new AccessionNumber(conn);
1687
    //docid = ac.generate(docid, rev, "DELETE");
1688

    
1689
    // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1690
    AccessionNumber ac = new AccessionNumber(conn, accnum, "DELETE");
1691
    String docid = ac.getDocid();
1692
    String rev = ac.getRev();
1693
    
1694

    
1695
    // check for 'write' permission for 'user' to delete this document
1696
    if ( !hasPermission(conn, user, groups, docid) ) {
1697
      throw new Exception("User " + user + 
1698
              " does not have permission to delete XML Document #" + accnum);
1699
    }
1700

    
1701
    conn.setAutoCommit(false);
1702
    // Copy the record to the xml_revisions table
1703
    DocumentImpl.archiveDocRevision( conn, docid, user );
1704

    
1705
    // Now delete it from the xml_documents table
1706
    
1707
    Statement stmt = conn.createStatement();
1708
    stmt.execute("DELETE FROM xml_index WHERE docid = '" + docid + "'");
1709
    //stmt.execute("DELETE FROM xml_access WHERE docid = '" + docid + "'");
1710
    stmt.execute("DELETE FROM xml_access WHERE accessfileid = '" + docid + "'");
1711
    stmt.execute("DELETE FROM xml_relation WHERE docid = '" + docid + "'");
1712
    stmt.execute("DELETE FROM xml_documents WHERE docid = '" + docid + "'");
1713
    stmt.close();
1714
    conn.commit();
1715
    conn.setAutoCommit(true);
1716
    //IF this is a package document:
1717
    //delete all of the relations that this document created.
1718
    //if the deleted document is a package document its relations should 
1719
    //no longer be active if it has been deleted from the system.
1720
    
1721
  }
1722

    
1723
  /** 
1724
    * Check for "WRITE" permission on @docid for @user and/or @groups 
1725
    * from DB connection 
1726
    */
1727
  private static boolean hasPermission ( Connection conn, String user,
1728
                                  String[] groups, String docid ) 
1729
                  throws SQLException, Exception
1730
  {
1731
    // Check for WRITE permission on @docid for @user and/or @groups
1732
    AccessControlList aclobj = new AccessControlList(conn);
1733
    return aclobj.hasPermission("WRITE", user, groups, docid);
1734
  }
1735

    
1736
  /** 
1737
    * Check for "READ" permission base on docid, user and group
1738
    *@docid, the document
1739
    *@user, user name
1740
    *@group, user's group
1741
    * 
1742
    */
1743
  public boolean hasReadPermission ( Connection conn, String user,
1744
                                  String[] groups, String docId ) 
1745
                  throws SQLException, Exception
1746
  {
1747
    // Check for READ permission on @docid for @user and/or @groups
1748
    AccessControlList aclObj = new AccessControlList(conn);
1749
    return aclObj.hasPermission("READ", user, groups, docId);
1750
  }  
1751

    
1752
  /**
1753
   * Set up the parser handlers for writing the document to the database
1754
   */
1755
  private static XMLReader initializeParser(Connection conn, String action,
1756
                               String docid, String rev, boolean validate, 
1757
                                   String user, String[] groups, String pub, 
1758
                                   int serverCode, Reader dtd) 
1759
                           throws Exception 
1760
  {
1761
    XMLReader parser = null;
1762
    //
1763
    // Set up the SAX document handlers for parsing
1764
    //
1765
    try {
1766
      //create a DBSAXHandler object which has the revision specification
1767
      ContentHandler chandler = new DBSAXHandler(conn, action, docid, rev,
1768
                                                 user, groups, pub, serverCode);
1769
      EntityResolver eresolver= new DBEntityResolver(conn,
1770
                                                 (DBSAXHandler)chandler, dtd);
1771
      DTDHandler dtdhandler   = new DBDTDHandler(conn);
1772

    
1773
      // Get an instance of the parser
1774
      String parserName = MetaCatUtil.getOption("saxparser");
1775
      parser = XMLReaderFactory.createXMLReader(parserName);
1776

    
1777
      // Turn on validation
1778
      parser.setFeature("http://xml.org/sax/features/validation", validate);
1779
      // Turn off Including all external parameter entities
1780
      // (the external DTD subset also)
1781
      // Doesn't work well, probably the feature name is not correct
1782
      // parser.setFeature(
1783
      //  "http://xml.org/sax/features/external-parameter-entities", false);
1784
      
1785
      // Set Handlers in the parser
1786
      parser.setProperty("http://xml.org/sax/properties/declaration-handler",
1787
                         chandler);
1788
      parser.setProperty("http://xml.org/sax/properties/lexical-handler",
1789
                         chandler);
1790
      parser.setContentHandler((ContentHandler)chandler);
1791
      parser.setEntityResolver((EntityResolver)eresolver);
1792
      parser.setDTDHandler((DTDHandler)dtdhandler);
1793
      parser.setErrorHandler((ErrorHandler)chandler);
1794

    
1795
    } catch (Exception e) {
1796
      throw e;
1797
    }
1798

    
1799
    return parser;
1800
  }
1801

    
1802
  /** Save a document entry in the xml_revisions table */
1803
  private static void archiveDocRevision(Connection conn, String docid,
1804
                                         String user) 
1805
 {
1806
    String sysdate = dbAdapter.getDateTimeFunction();
1807
    // create a record in xml_revisions table 
1808
    // for that document as selected from xml_documents
1809
   
1810
   try
1811
   {
1812
     PreparedStatement pstmt = conn.prepareStatement(
1813
      "INSERT INTO xml_revisions " +
1814
        "(docid, rootnodeid, docname, doctype, " +
1815
        "user_owner, user_updated, date_created, date_updated, " +
1816
        "server_location, rev, public_access, catalog_id) " +
1817
      "SELECT ?, rootnodeid, docname, doctype, " + 
1818
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
1819
        "server_location, rev, public_access, catalog_id " +
1820
      "FROM xml_documents " +
1821
      "WHERE docid = ?");
1822
      // Bind the values to the query and execute it
1823
      pstmt.setString(1, docid);
1824
      pstmt.setString(2, user);
1825
      pstmt.setString(3, docid);
1826
      pstmt.execute();
1827
      pstmt.close();
1828
   }
1829
   catch (SQLException e)
1830
   {
1831
   }
1832
   
1833

    
1834
  }
1835
  
1836
  /**
1837
    * delete a entry in xml_table for given docid
1838
    * @param docId, the id of the document need to be delete
1839
    */
1840
  private static void deleteXMLDocuments(Connection conn, String docId) 
1841
                                         throws SQLException 
1842
  {
1843
    //delete a record 
1844
    PreparedStatement pStmt = 
1845
             conn.prepareStatement("DELETE FROM xml_documents WHERE docid = '" 
1846
                                              + docId + "'");
1847
    pStmt.execute();
1848
    pStmt.close();
1849

    
1850
  }//deleteXMLDocuments
1851
  
1852
  /**
1853
    * Get last revision number from database for a docid
1854
    * If couldn't find an entry,  -1 will return
1855
    * The return value is integer because we want compare it to there new one
1856
    * @param docid <sitecode>.<uniqueid> part of Accession Number
1857
    */
1858
  private static int getLatestRevisionNumber(Connection conn, String docId)
1859
                                      throws SQLException
1860
  {
1861
    int rev = 1;
1862
    PreparedStatement pStmt;
1863
     
1864
    pStmt = conn.prepareStatement
1865
              ("SELECT rev FROM xml_documents WHERE docid='" + docId + "'");
1866
    pStmt.execute();
1867

    
1868
    ResultSet rs = pStmt.getResultSet();
1869
    boolean hasRow = rs.next();
1870
    if (hasRow)
1871
    {
1872
      rev = rs.getInt(1);
1873
      pStmt.close();
1874
    }
1875
    else
1876
    {
1877
      rev=-1;
1878
      pStmt.close();
1879
    }
1880
      
1881
    return rev;
1882
  }//getLatestRevisionNumber
1883
  
1884
  /**
1885
   * Get server location form database for a accNum
1886
   * 
1887
   * @param accum <sitecode>.<uniqueid>.<rev>
1888
   */
1889
  private static int getServerLocationNumber(Connection conn, String accNum)
1890
                                            throws SQLException
1891
  {
1892
    //get rid of revNum part
1893
    String docId=MetaCatUtil.getDocIdFromString(accNum);
1894
    PreparedStatement pStmt;
1895
    int serverLocation;
1896
     
1897
    pStmt = conn.prepareStatement
1898
      ("SELECT server_location FROM xml_documents WHERE docid='" + docId + "'");
1899
    pStmt.execute();
1900

    
1901
    ResultSet rs = pStmt.getResultSet();
1902
    boolean hasRow = rs.next();
1903
    //if there is entry in xml_documents, get the serverlocation
1904
    if (hasRow)
1905
    {
1906
      serverLocation = rs.getInt(1);
1907
      pStmt.close();
1908
    }
1909
    else
1910
    {
1911
      // if htere is no entry in xml_documents, we consider it is new document
1912
      // the server location is local host and value is 1
1913
      serverLocation=1;
1914
      pStmt.close();
1915
    }
1916
      
1917
    return serverLocation;
1918
  }
1919
  
1920
  /**
1921
   * Given a server name, return its servercode in xml_replication table.
1922
   * If no server is found, -1 will return
1923
   * @param serverName, 
1924
   */
1925
  private static int getServerCode(String serverName) 
1926
  {
1927
    PreparedStatement pStmt=null;
1928
    int serverLocation=-2;
1929
    Connection dbConn = null;
1930
    MetaCatUtil util = new MetaCatUtil();
1931
    
1932
    
1933
    //we should consider about local host too
1934
    if (serverName.equals(util.getLocalReplicationServerName()))
1935
    { 
1936
      serverLocation=1;
1937
      return serverLocation;
1938
    }
1939
    
1940
   
1941
    try
1942
    {
1943
      //check xml_replication table
1944
      dbConn=util.openDBConnection();
1945
      pStmt = dbConn.prepareStatement
1946
      ("SELECT serverid FROM xml_replication WHERE server='" + serverName +"'");
1947
      pStmt.execute();
1948

    
1949
      ResultSet rs = pStmt.getResultSet();
1950
      boolean hasRow = rs.next();
1951
      //if there is entry in xml_replication, get the serverid
1952
      if (hasRow)
1953
      {
1954
        serverLocation = rs.getInt(1);
1955
        pStmt.close();
1956
      }
1957
      else
1958
      {
1959
        // if htere is no entry in xml_replication, -1 will return
1960
        serverLocation=-1;
1961
        pStmt.close();
1962
      }
1963
    }
1964
    catch (Exception e)
1965
    {
1966
      util.debugMessage("Error in DocumentImpl.getServerCode(): "
1967
                                    +e.getMessage(), 30);
1968
    }
1969
    finally
1970
    {
1971
      try
1972
      {
1973
        dbConn.close();
1974
      }
1975
      catch (Exception ee)
1976
      {}
1977
    }
1978
                 
1979
      
1980
    return serverLocation;
1981
  }
1982
  
1983
  /**
1984
   * Insert a server into xml_replcation table
1985
   * @param server, the name of server 
1986
   */
1987
  private static void  insertServerIntoReplicationTable(String server)
1988
  {
1989
    PreparedStatement pStmt=null;
1990
    Connection dbConn = null;
1991
    int replicate = 1;
1992
    MetaCatUtil util = new MetaCatUtil();
1993
    try
1994
    {
1995
       dbConn=util.openDBConnection();
1996
       pStmt = dbConn.prepareStatement("INSERT INTO xml_replication " +
1997
                                      "(server, last_checked, replicate) " +
1998
                                      "VALUES ('" + server + "', to_date(" +
1999
                                      "'01/01/00', 'MM/DD/YY'), '" +
2000
                                      replicate + "')");
2001
        pStmt.execute();
2002
        pStmt.close();
2003
        dbConn.commit();
2004
    }
2005
    catch (Exception e)
2006
    {
2007
      util.debugMessage("Error in DocumentImpl.getServerCode(): "
2008
                                    +e.getMessage(), 30);
2009
    }
2010
    finally
2011
    {
2012
      try
2013
      {
2014
        pStmt.close();
2015
        dbConn.close();
2016
      }
2017
      catch (Exception ee)
2018
      {}
2019
    }
2020

    
2021
  }
2022
  
2023
  
2024
  /**
2025
   * the main routine used to test the DBWriter utility.
2026
   * <p>
2027
   * Usage: java DocumentImpl <-f filename -a action -d docid>
2028
   *
2029
   * @param filename the filename to be loaded into the database
2030
   * @param action the action to perform (READ, INSERT, UPDATE, DELETE)
2031
   * @param docid the id of the document to process
2032
   */
2033
  static public void main(String[] args) {
2034
     
2035
    try {
2036
      String filename    = null;
2037
      String dtdfilename = null;
2038
      String action      = null;
2039
      String docid       = null;
2040
      boolean showRuntime = false;
2041
      boolean useOldReadAlgorithm = false;
2042

    
2043
      // Parse the command line arguments
2044
      for ( int i=0 ; i < args.length; ++i ) {
2045
        if ( args[i].equals( "-f" ) ) {
2046
          filename =  args[++i];
2047
        } else if ( args[i].equals( "-r" ) ) {
2048
          dtdfilename =  args[++i];
2049
        } else if ( args[i].equals( "-a" ) ) {
2050
          action =  args[++i];
2051
        } else if ( args[i].equals( "-d" ) ) {
2052
          docid =  args[++i];
2053
        } else if ( args[i].equals( "-t" ) ) {
2054
          showRuntime = true;
2055
        } else if ( args[i].equals( "-old" ) ) {
2056
          useOldReadAlgorithm = true;
2057
        } else {
2058
          System.err.println
2059
            ( "   args[" +i+ "] '" +args[i]+ "' ignored." );
2060
        }
2061
      }
2062
      
2063
      // Check if the required arguments are provided
2064
      boolean argsAreValid = false;
2065
      if (action != null) {
2066
        if (action.equals("INSERT")) {
2067
          if (filename != null) {
2068
            argsAreValid = true;
2069
          } 
2070
        } else if (action.equals("UPDATE")) {
2071
          if ((filename != null) && (docid != null)) {
2072
            argsAreValid = true;
2073
          } 
2074
        } else if (action.equals("DELETE")) {
2075
          if (docid != null) {
2076
            argsAreValid = true;
2077
          } 
2078
        } else if (action.equals("READ")) {
2079
          if (docid != null) {
2080
            argsAreValid = true;
2081
          } 
2082
        } 
2083
      } 
2084

    
2085
      // Print usage message if the arguments are not valid
2086
      if (!argsAreValid) {
2087
        System.err.println("Wrong number of arguments!!!");
2088
        System.err.println(
2089
          "USAGE: java DocumentImpl [-t] <-a INSERT> [-d docid] <-f filename> "+
2090
          "[-r dtdfilename]");
2091
        System.err.println(
2092
          "   OR: java DocumentImpl [-t] <-a UPDATE -d docid -f filename> " +
2093
          "[-r dtdfilename]");
2094
        System.err.println(
2095
          "   OR: java DocumentImpl [-t] <-a DELETE -d docid>");
2096
        System.err.println(
2097
          "   OR: java DocumentImpl [-t] [-old] <-a READ -d docid>");
2098
        return;
2099
      }
2100
      
2101
      // Time the request if asked for
2102
      double startTime = System.currentTimeMillis();
2103
      
2104
      // Open a connection to the database
2105
      MetaCatUtil util = new MetaCatUtil();
2106
      Connection dbconn = util.openDBConnection();
2107

    
2108
      double connTime = System.currentTimeMillis();
2109
      // Execute the action requested (READ, INSERT, UPDATE, DELETE)
2110
      if (action.equals("READ")) {
2111
          DocumentImpl xmldoc = new DocumentImpl( dbconn, docid );
2112
          if (useOldReadAlgorithm) {
2113
            System.out.println(xmldoc.readUsingSlowAlgorithm());
2114
          } else {
2115
            xmldoc.toXml(new PrintWriter(System.out));
2116
          }
2117
      } else if (action.equals("DELETE")) {
2118
        DocumentImpl.delete(dbconn, docid, null, null);
2119
        System.out.println("Document deleted: " + docid);
2120
      } else {
2121
        String newdocid = DocumentImpl.write(dbconn, filename, null,
2122
                                             dtdfilename, action, docid,
2123
                                             null, null);
2124
        if ((docid != null) && (!docid.equals(newdocid))) {
2125
          if (action.equals("INSERT")) {
2126
            System.out.println("New document ID generated!!! ");
2127
          } else if (action.equals("UPDATE")) {
2128
            System.out.println("ERROR: Couldn't update document!!! ");
2129
          }
2130
        } else if ((docid == null) && (action.equals("UPDATE"))) {
2131
          System.out.println("ERROR: Couldn't update document!!! ");
2132
        }
2133
        System.out.println("Document processing finished for: " + filename
2134
              + " (" + newdocid + ")");
2135
      }
2136

    
2137
      double stopTime = System.currentTimeMillis();
2138
      double dbOpenTime = (connTime - startTime)/1000;
2139
      double insertTime = (stopTime - connTime)/1000;
2140
      double executionTime = (stopTime - startTime)/1000;
2141
      if (showRuntime) {
2142
        System.out.println("\n\nTotal Execution time was: " + 
2143
                           executionTime + " seconds.");
2144
        System.out.println("Time to open DB connection was: " + dbOpenTime + 
2145
                           " seconds.");
2146
        System.out.println("Time to insert document was: " + insertTime +
2147
                           " seconds.");
2148
      }
2149
      dbconn.close();
2150
    } catch (McdbException me) {
2151
      me.toXml(new PrintWriter(System.err));
2152
    } catch (AccessionNumberException ane) {
2153
      System.out.println(ane.getMessage());
2154
    } catch (Exception e) {
2155
      System.err.println("EXCEPTION HANDLING REQUIRED");
2156
      System.err.println(e.getMessage());
2157
      e.printStackTrace(System.err);
2158
    }
2159
  }
2160
}
(24-24/41)