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-08 09:25:18 -0700 (Wed, 08 May 2002) $'
11
 * '$Revision: 1059 $'
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
    dbConn = ut.getConnection();
234
    // get server location for this doc
235
    int serverLocation=getServerLocationNumber(dbConn,accnum);
236
    ut.returnConnection(dbConn);
237
    registerDocument(docname, doctype,accnum, user, serverLocation);
238
    
239
  }
240
  /**
241
   * Register a document that resides on the filesystem with the database.
242
   * (ie, just an entry in xml_documents, nothing in xml_nodes).
243
   * Creates a reference to a filesystem document (used for non-xml data files).
244
   * This class only be called in MetaCatServerlet.
245
   * @param conn the JDBC Connection to which all information is written
246
   * @param docname - the name of DTD, i.e. the name immediately following 
247
   *        the DOCTYPE keyword ( should be the root element name ) or
248
   *        the root element name if no DOCTYPE declaration provided
249
   *        (Oracle's and IBM parsers are not aware if it is not the 
250
   *        root element name)
251
   * @param doctype - Public ID of the DTD, i.e. the name immediately 
252
   *                  following the PUBLIC keyword in DOCTYPE declaration or
253
   *                  the docname if no Public ID provided or
254
   *                  null if no DOCTYPE declaration provided
255
   * @param accnum the accession number to use for the INSERT OR UPDATE, which 
256
   *               includes a revision number for this revision of the document 
257
   *               (e.g., knb.1.1)
258
   * @param user the user that owns the document
259
   * @param serverCode the serverid from xml_replication on which this document
260
   *        resides.
261
   */
262
  public static void registerDocument(
263
                     String docname, String doctype, String accnum, 
264
                     String user, int serverCode)
265
                     throws SQLException, AccessionNumberException, Exception
266
  {
267
    Connection dbconn = null;
268
    MetaCatUtil util = new MetaCatUtil();
269
    AccessionNumber ac;
270
    try {
271
      dbconn = util.openDBConnection();
272
      String docIdWithoutRev=MetaCatUtil.getDocIdFromString(accnum);
273
      int userSpecifyRev=MetaCatUtil.getVersionFromString(accnum);
274
      int revInDataBase=getLatestRevisionNumber(dbconn, docIdWithoutRev);
275
      //revIndataBase=-1, there is no record in xml_documents table
276
      //the data file is a new one, inert it into table
277
      //user specified rev should be great than 0
278
      if (revInDataBase==-1 && userSpecifyRev>0 )
279
      {
280
        ac = new AccessionNumber(dbconn, accnum, "insert");
281
      }
282
      //rev is greater the last revsion number and revInDataBase isn't -1
283
      // it is a updated data file
284
      else if (userSpecifyRev>revInDataBase && revInDataBase>0)
285
      {
286
        
287
        //archive the old entry 
288
        archiveDocRevision(dbconn, docIdWithoutRev, user);
289
        //delete the old entry in xml_documents
290
        deleteXMLDocuments(dbconn, docIdWithoutRev);
291
        ac = new AccessionNumber(dbconn, accnum, "update");
292
      }
293
      //other situation
294
      else
295
      {
296
        
297
        throw new Exception("Revision number couldn't be "
298
                    +userSpecifyRev);
299
      }
300
      String docid = ac.getDocid();
301
      String rev = ac.getRev();
302
      SimpleDateFormat formatter = new SimpleDateFormat ("yy-MM-dd HH:mm:ss");
303
      Date localtime = new Date();
304
      String dateString = formatter.format(localtime);
305
  
306
      String sqlDateString = "to_date('" + dateString + 
307
                                          "', 'YY-MM-DD HH24:MI:SS')";
308
  
309
      StringBuffer sql = new StringBuffer();
310
      sql.append("insert into xml_documents (docid, docname, doctype, ");
311
      sql.append("user_owner, user_updated, server_location, rev,date_created");
312
      sql.append(", date_updated, public_access) values ('");
313
      sql.append(docid).append("','");
314
      sql.append(docname).append("','");
315
      sql.append(doctype).append("','");
316
      sql.append(user).append("','");
317
      sql.append(user).append("','");
318
      sql.append(serverCode).append("','");
319
      sql.append(rev).append("',");
320
      sql.append(sqlDateString).append(",");
321
      sql.append(sqlDateString).append(",");
322
      sql.append("'0')");
323
      PreparedStatement pstmt = dbconn.prepareStatement(sql.toString());
324
      pstmt.execute();
325
      pstmt.close();
326
      dbconn.close();
327
    } finally {
328
      util.returnConnection(dbconn);
329
    }    
330
  }
331
  
332
    /**
333
   * Register a document that resides on the filesystem with the database.
334
   * (ie, just an entry in xml_documents, nothing in xml_nodes).
335
   * Creates a reference to a filesystem document (used for non-xml data files)
336
   * This method will be called for register data file in xml_documents in 
337
   * Replication.
338
   * This method is revised from registerDocument.
339
   *
340
   * @param conn the JDBC Connection to which all information is written
341
   * @param docname - the name of DTD, i.e. the name immediately following 
342
   *        the DOCTYPE keyword ( should be the root element name ) or
343
   *        the root element name if no DOCTYPE declaration provided
344
   *        (Oracle's and IBM parsers are not aware if it is not the 
345
   *        root element name)
346
   * @param doctype - Public ID of the DTD, i.e. the name immediately 
347
   *                  following the PUBLIC keyword in DOCTYPE declaration or
348
   *                  the docname if no Public ID provided or
349
   *                  null if no DOCTYPE declaration provided
350
   * @param accnum the accession number to use for the INSERT OR UPDATE, which 
351
   *               includes a revision number for this revision of the document 
352
   *               (e.g., knb.1.1)
353
   * @param user the user that owns the document
354
   * @param serverCode the serverid from xml_replication on which this document
355
   *        resides.
356
   */
357
  public static void registerDocumentInReplication(
358
                     String docname, String doctype, String accnum, 
359
                     String user, int serverCode)
360
                     throws SQLException, AccessionNumberException, Exception
361
  {
362
    Connection dbconn = null;
363
    MetaCatUtil util = new MetaCatUtil();
364
    AccessionNumber ac;
365
    try {
366
      dbconn = util.openDBConnection();
367
      String docIdWithoutRev=MetaCatUtil.getDocIdFromString(accnum);
368
      int userSpecifyRev=MetaCatUtil.getVersionFromString(accnum);
369
      int revInDataBase=getLatestRevisionNumber(dbconn, docIdWithoutRev);
370
      //revIndataBase=-1, there is no record in xml_documents table
371
      //the data file is a new one, inert it into table
372
      //user specified rev should be great than 0
373
      if (revInDataBase==-1 && userSpecifyRev>0 )
374
      {
375
        //ture means for replication
376
        ac = new AccessionNumber(dbconn, accnum, "insert");
377
      }
378
      //rev is greater the last revsion number and revInDataBase isn't -1
379
      // it is a updated data file
380
      else if (userSpecifyRev>revInDataBase && revInDataBase>0)
381
      {
382
        
383
        //archive the old entry 
384
        archiveDocRevision(dbconn, docIdWithoutRev, user);
385
        //delete the old entry in xml_documents
386
        deleteXMLDocuments(dbconn, docIdWithoutRev);
387
        ac = new AccessionNumber(dbconn, accnum, "update");
388
      }
389
      //other situation
390
      else
391
      {
392
        
393
        throw new Exception("Revision number couldn't be "
394
                    +userSpecifyRev);
395
      }
396
      String docid = ac.getDocid();
397
      String rev = ac.getRev();
398
      SimpleDateFormat formatter = new SimpleDateFormat ("yy-MM-dd HH:mm:ss");
399
      Date localtime = new Date();
400
      String dateString = formatter.format(localtime);
401
  
402
      String sqlDateString = "to_date('" + dateString + 
403
                                          "', 'YY-MM-DD HH24:MI:SS')";
404
  
405
      StringBuffer sql = new StringBuffer();
406
      sql.append("insert into xml_documents (docid, docname, doctype, ");
407
      sql.append("user_owner, user_updated, server_location, rev,date_created");
408
      sql.append(", date_updated, public_access) values ('");
409
      sql.append(docid).append("','");
410
      sql.append(docname).append("','");
411
      sql.append(doctype).append("','");
412
      sql.append(user).append("','");
413
      sql.append(user).append("','");
414
      sql.append(serverCode).append("','");
415
      sql.append(rev).append("',");
416
      sql.append(sqlDateString).append(",");
417
      sql.append(sqlDateString).append(",");
418
      sql.append("'0')");
419
      PreparedStatement pstmt = dbconn.prepareStatement(sql.toString());
420
      pstmt.execute();
421
      pstmt.close();
422
      dbconn.close();
423
    } finally {
424
      util.returnConnection(dbconn);
425
    }    
426
  }
427
  
428
 /**
429
   * This method will register a data file entry in xml_documents and save a
430
   * data file input Stream into file system.. It is only used in force 
431
   * replication
432
   *
433
   * @param  input, the input stream which contain the file content.
434
   * @param  , the input stream which contain the file content
435
   * @param docname - the name of DTD, for data file, it is a docid number.
436
   * @param doctype - "BIN" for data file
437
   * @param accnum the accession number to use for the INSERT OR UPDATE, which 
438
   *               includes a revision number for this revision of the document 
439
   *               (e.g., knb.1.1)
440
   * @param user the user that owns the document
441
   * @param serverCode the serverid from xml_replication on which this document
442
   *        resides.
443
   */
444
 public static void writeDataFile(InputStream input, String filePath, 
445
    String docname, String doctype, String accnum, String user, int serverCode)
446
                     throws SQLException, AccessionNumberException, Exception
447
 {
448
    if (filePath==null||filePath.equals(""))
449
    {
450
      throw new 
451
            Exception("Please specify the directory where file will be store");
452
    }
453
    if (accnum==null||accnum.equals(""))
454
    {
455
      throw new Exception("Please specify the stored file name");
456
    }
457
    //make sure user have file lock grant(local metacat means have it too)
458
    if (getDataFileLockGrant(accnum))
459
    {
460
      //register data file into xml_documents table
461
      registerDocumentInReplication(docname, doctype, accnum, user, serverCode);
462
      //write inputstream into file system.
463
      File dataDirectory = new File(filePath);
464
      File newFile = new File(dataDirectory, accnum); 
465
       
466
      // create a buffered byte output stream
467
      // that uses a default-sized output buffer
468
      FileOutputStream fos = new FileOutputStream(newFile);
469
      BufferedOutputStream outPut = new BufferedOutputStream(fos);
470

    
471
      BufferedInputStream bis = null;
472
      bis = new BufferedInputStream(input);
473
      byte[] buf = new byte[4 * 1024]; // 4K buffer
474
      int b = bis.read(buf);
475
       
476
      while (b != -1) 
477
      {
478
        outPut.write(buf, 0, b);
479
        b = bis.read(buf);
480
      }
481
      bis.close();
482
	    outPut.close();
483
	    fos.close();
484
      //force replication to other server
485
      /*during replciation, don't need force replication again.
486
      MetaCatUtil util = new MetaCatUtil();
487
      if ((util.getOption("replicationdata")).equals("on"))
488
      {
489
        Connection dbConn = util.getConnection();
490
       
491
        if (serverCode==1)
492
        {
493
          
494
          ForceReplicationHandler frh = new ForceReplicationHandler(accnum,
495
                  "insert",false,ReplicationHandler.buildServerList(dbConn));
496
          util.returnConnection(dbConn);
497
        }
498
        else
499
        {
500
          
501
          if ((util.getOption("hub")).equals("super"))
502
          {
503
            ForceReplicationHandler frh = new ForceReplicationHandler(accnum, 
504
                true, ReplicationHandler.buildServerList(dbConn));
505
            util.returnConnection(dbConn);
506
          }
507
          else
508
          {
509
            
510
            String docId=util.getDocIdFromString(accnum);
511
            ForceReplicationHandler frh = new ForceReplicationHandler(accnum, 
512
                true, ReplicationHandler.getHomeServer(docId));
513
          }
514
        }
515
      }*/
516
    }//if
517
 }
518
  
519

    
520
  
521
  public static boolean getDataFileLockGrant(String accnum) 
522
                                                  throws Exception
523
  { 
524
    Connection dbConn = null;
525
    MetaCatUtil ut= new MetaCatUtil();
526
    dbConn = ut.getConnection();
527
    int serverLocation=getServerLocationNumber(dbConn,accnum);
528
    ut.returnConnection(dbConn);
529
    return getDataFileLockGrant(accnum,serverLocation);
530
  }
531
    
532
  /**
533
   * The method will check if metacat can get data file lock grant
534
   * If server code is 1, it get.
535
   * If server code is not 1 but call replication getlock successfully,
536
   * it get
537
   * else, it didn't get
538
   * @param accnum, the ID of the document 
539
   * @param action, the action to the document
540
   * @param serverCode, the server location code
541
   */
542
  public static boolean getDataFileLockGrant(String accnum, int serverCode)
543
                                          throws Exception 
544
  {
545
    boolean flag=true;
546
    MetaCatUtil util = new MetaCatUtil();
547
    String docid = util.getDocIdFromString(accnum);
548
    int rev = util.getVersionFromString(accnum);
549
    
550
    if (serverCode == 1)
551
    {
552
      flag=true;
553
      return flag;
554
    }
555
    
556
    //if((serverCode != 1 && action.equals("UPDATE")) )
557
    if (serverCode != 1)
558
    { //if this document being written is not a resident of this server then
559
      //we need to try to get a lock from it's resident server.  If the
560
      //resident server will not give a lock then we send the user a message
561
      //saying that he/she needs to download a new copy of the file and
562
      //merge the differences manually.
563
      
564
      String server = MetacatReplication.getServer(serverCode);
565
      MetacatReplication.replLog("attempting to lock " + accnum);
566
      URL u = new URL("https://" + server + "?server="
567
           +util.getLocalReplicationServerName()+"&action=getlock&updaterev=" 
568
           +rev + "&docid=" + docid);
569
      //System.out.println("sending message: " + u.toString());
570
      String serverResStr = MetacatReplication.getURLContent(u);
571
      String openingtag =serverResStr.substring(0, serverResStr.indexOf(">")+1);
572
      if(openingtag.equals("<lockgranted>"))
573
      {
574
        //the lock was granted go ahead with the insert
575
        //System.out.println("In lockgranted");
576
        MetacatReplication.replLog("lock granted for " + accnum + " from " +
577
                                      server);
578
        flag=true;  
579
        return flag;
580
      }//if
581

    
582
      else if(openingtag.equals("<filelocked>"))
583
      {//the file is currently locked by another user
584
       //notify our user to wait a few minutes, check out a new copy and try
585
       //again.
586
        //System.out.println("file locked");
587
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
588
                                   server + " reason: file already locked");
589
        throw new Exception("The file specified is already locked by another " +
590
                            "user.  Please wait 30 seconds, checkout the " +
591
                            "newer document, merge your changes and try " +
592
                            "again.");
593
      }
594
      else if(openingtag.equals("<outdatedfile>"))
595
      {//our file is outdated.  notify our user to check out a new copy of the
596
       //file and merge his version with the new version.
597
        //System.out.println("outdated file");
598
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
599
                                    server + " reason: local file outdated");
600
        throw new Exception("The file you are trying to update is an outdated" +
601
                            " version.  Please checkout the newest document, " +
602
                            "merge your changes and try again.");
603
      }//else if
604
    }//if
605
    
606
   return flag;
607
   
608
  }//getDataFileLockGrant
609
  
610
  /**
611
   * get the document name
612
   */
613
  public String getDocname() {
614
    return docname;
615
  }
616

    
617
  /**
618
   * get the document type (which is the PublicID)
619
   */
620
  public String getDoctype() {
621
    return doctype;
622
  }
623

    
624
  /**
625
   * get the system identifier
626
   */
627
  public String getSystemID() {
628
    return system_id;
629
  }
630

    
631
  /**
632
   * get the root node identifier
633
   */
634
  public long getRootNodeID() {
635
    return rootnodeid;
636
  }
637
  
638
  /**
639
   * get the creation date
640
   */
641
  public String getCreateDate() {
642
    return createdate;
643
  }
644
  
645
  /**
646
   * get the update date
647
   */
648
  public String getUpdateDate() {
649
    return updatedate;
650
  }
651

    
652
  /** 
653
   * Get the document identifier (docid)
654
   */
655
  public String getDocID() {
656
    return docid;
657
  }
658
  
659
// DOCTITLE attr cleared from the db
660
//  /**
661
//   *get the document title
662
//   */
663
//  public String getDocTitle() {
664
//    return doctitle;
665
//  }
666
  
667
  public String getUserowner() {
668
    return userowner;
669
  }
670
  
671
  public String getUserupdated() {
672
    return userupdated;
673
  }
674
  
675
  public int getServerlocation() {
676
    return serverlocation;
677
  }
678
  
679
  public String getDocHomeServer() {
680
    return docHomeServer;
681
  }
682
  
683
 
684
 
685
  public String getPublicaccess() {
686
    return publicaccess;
687
  }
688
  
689
  public int getRev() {
690
    return rev;
691
  }
692
  
693
   /**
694
   * Print a string representation of the XML document
695
   */
696
  public String toString()
697
  {
698
    StringWriter docwriter = new StringWriter();
699
    try {
700
      this.toXml(docwriter);
701
    } catch (McdbException mcdbe) {
702
      return null;
703
    }
704
    String document = docwriter.toString();
705
    return document;
706
  }
707

    
708
  /**
709
   * Get a text representation of the XML document as a string
710
   * This older algorithm uses a recursive tree of Objects to represent the
711
   * nodes of the tree.  Each object is passed the data for the document 
712
   * and searches all of the document data to find its children nodes and
713
   * recursively build.  Thus, because each node reads the whole document,
714
   * this algorithm is extremely slow for larger documents, and the time
715
   * to completion is O(N^N) wrt the number of nodes.  See toXml() for a
716
   * better algorithm.
717
   */
718
  public String readUsingSlowAlgorithm() throws McdbException
719
  {
720
    StringBuffer doc = new StringBuffer();
721

    
722
    // First, check that we have the needed node data, and get it if not
723
    if (nodeRecordList == null) {
724
      nodeRecordList = getNodeRecordList(rootnodeid);
725
    }
726

    
727
    // Create the elements from the downloaded data in the TreeSet
728
    rootNode = new ElementNode(nodeRecordList, rootnodeid);
729

    
730
    // Append the resulting document to the StringBuffer and return it
731
    doc.append("<?xml version=\"1.0\"?>\n");
732
      
733
    if (docname != null) {
734
      if ((doctype != null) && (system_id != null)) {
735
        doc.append("<!DOCTYPE " + docname + " PUBLIC \"" + doctype + 
736
                   "\" \"" + system_id + "\">\n");
737
      } else {
738
        doc.append("<!DOCTYPE " + docname + ">\n");
739
      }
740
    }
741
    doc.append(rootNode.toString());
742
  
743
    return (doc.toString());
744
  }
745

    
746
  /**
747
   * Print a text representation of the XML document to a Writer
748
   *
749
   * @param pw the Writer to which we print the document
750
   */
751
  public void toXml(Writer pw) throws McdbException
752
  {
753
    PrintWriter out = null;
754
    if (pw instanceof PrintWriter) {
755
      out = (PrintWriter)pw;
756
    } else {
757
      out = new PrintWriter(pw);
758
    }
759

    
760
    MetaCatUtil util = new MetaCatUtil();
761
    
762
    // First, check that we have the needed node data, and get it if not
763
    if (nodeRecordList == null) {
764
      nodeRecordList = getNodeRecordList(rootnodeid);
765
    }
766

    
767
    Stack openElements = new Stack();
768
    boolean atRootElement = true;
769
    boolean previousNodeWasElement = false;
770

    
771
    // Step through all of the node records we were given
772
    Iterator it = nodeRecordList.iterator();
773
    while (it.hasNext()) {
774
      NodeRecord currentNode = (NodeRecord)it.next();
775
      //util.debugMessage("[Got Node ID: " + currentNode.nodeid +
776
                          //" (" + currentNode.parentnodeid +
777
                          //", " + currentNode.nodeindex + 
778
                          //", " + currentNode.nodetype + 
779
                          //", " + currentNode.nodename + 
780
                          //", " + currentNode.nodedata + ")]");
781
      // Print the end tag for the previous node if needed
782
      //
783
      // This is determined by inspecting the parent nodeid for the
784
      // currentNode.  If it is the same as the nodeid of the last element
785
      // that was pushed onto the stack, then we are still in that previous
786
      // parent element, and we do nothing.  However, if it differs, then we
787
      // have returned to a level above the previous parent, so we go into
788
      // a loop and pop off nodes and print out their end tags until we get
789
      // the node on the stack to match the currentNode parentnodeid
790
      //
791
      // So, this of course means that we rely on the list of elements
792
      // having been sorted in a depth first traversal of the nodes, which
793
      // is handled by the NodeComparator class used by the TreeSet
794
      if (!atRootElement) {
795
        NodeRecord currentElement = (NodeRecord)openElements.peek();
796
        if ( currentNode.parentnodeid != currentElement.nodeid ) {
797
          while ( currentNode.parentnodeid != currentElement.nodeid ) {
798
            currentElement = (NodeRecord)openElements.pop();
799
            util.debugMessage("\n POPPED: " + currentElement.nodename);
800
            if (previousNodeWasElement) {
801
              out.print(">");
802
              previousNodeWasElement = false;
803
            }  
804
            if ( currentElement.nodeprefix != null ) {
805
              out.print("</" + currentElement.nodeprefix + ":" + 
806
                        currentElement.nodename + ">" );
807
            } else {
808
              out.print("</" + currentElement.nodename + ">" );
809
            }
810
            currentElement = (NodeRecord)openElements.peek();
811
          }
812
        }
813
      }
814

    
815
      // Handle the DOCUMENT node
816
      if (currentNode.nodetype.equals("DOCUMENT")) {
817
        out.println("<?xml version=\"1.0\"?>");
818
      
819
        if (docname != null) {
820
          if ((doctype != null) && (system_id != null)) {
821
            out.println("<!DOCTYPE " + docname + " PUBLIC \"" + doctype + 
822
                       "\" \"" + system_id + "\">");
823
          } else {
824
            out.println("<!DOCTYPE " + docname + ">");
825
          }
826
        }
827

    
828
      // Handle the ELEMENT nodes
829
      } else if (currentNode.nodetype.equals("ELEMENT")) {
830
        if (atRootElement) {
831
          atRootElement = false;
832
        } else {
833
          if (previousNodeWasElement) {
834
            out.print(">");
835
          }
836
        }
837
        openElements.push(currentNode);
838
        util.debugMessage("\n PUSHED: " + currentNode.nodename);
839
        previousNodeWasElement = true;
840
        if ( currentNode.nodeprefix != null ) {
841
          out.print("<" + currentNode.nodeprefix + ":" + currentNode.nodename);
842
        } else {
843
          out.print("<" + currentNode.nodename);
844
        }
845

    
846
      // Handle the ATTRIBUTE nodes
847
      } else if (currentNode.nodetype.equals("ATTRIBUTE")) {
848
        if ( currentNode.nodeprefix != null ) {
849
          out.print(" " + currentNode.nodeprefix + ":" + currentNode.nodename +
850
                    "=\"" + currentNode.nodedata + "\"");
851
        } else {
852
          out.print(" " + currentNode.nodename + "=\"" +
853
                    currentNode.nodedata + "\"");
854
        }
855

    
856
      // Handle the NAMESPACE nodes
857
      } else if (currentNode.nodetype.equals("NAMESPACE")) {
858
        out.print(" xmlns:" + currentNode.nodename + "=\""
859
                 + currentNode.nodedata + "\"");
860

    
861
      // Handle the TEXT nodes
862
      } else if (currentNode.nodetype.equals("TEXT")) {
863
        if (previousNodeWasElement) {
864
          out.print(">");
865
        }
866
        out.print(currentNode.nodedata);
867
        previousNodeWasElement = false;
868

    
869
      // Handle the COMMENT nodes
870
      } else if (currentNode.nodetype.equals("COMMENT")) {
871
        if (previousNodeWasElement) {
872
          out.print(">");
873
        }
874
        out.print("<!--" + currentNode.nodedata + "-->");
875
        previousNodeWasElement = false;
876

    
877
      // Handle the PI nodes
878
      } else if (currentNode.nodetype.equals("PI")) {
879
        if (previousNodeWasElement) {
880
          out.print(">");
881
        }
882
        out.print("<?" + currentNode.nodename + " " +
883
                        currentNode.nodedata + "?>");
884
        previousNodeWasElement = false;
885

    
886
      // Handle any other node type (do nothing)
887
      } else {
888
        // Any other types of nodes are not handled.
889
        // Probably should throw an exception here to indicate this
890
      }
891
      out.flush();
892
    }
893

    
894
    // Print the final end tag for the root element
895
    while(!openElements.empty())
896
    {
897
      NodeRecord currentElement = (NodeRecord)openElements.pop();
898
      util.debugMessage("\n POPPED: " + currentElement.nodename);
899
      if ( currentElement.nodeprefix != null ) {
900
        out.print("</" + currentElement.nodeprefix + ":" + 
901
                  currentElement.nodename + ">" );
902
      } else {
903
        out.print("</" + currentElement.nodename + ">" );
904
      }
905
    }
906
    out.flush();
907
  }
908
  
909
  private boolean isRevisionOnly(DocumentIdentifier docid) throws Exception
910
  {
911
    //System.out.println("inRevisionOnly");
912
    PreparedStatement pstmt;
913
    String rev = docid.getRev();
914
    String newid = docid.getIdentifier();
915
    pstmt = conn.prepareStatement("select rev from xml_documents " +
916
                                  "where docid like '" + newid + "'");
917
    pstmt.execute();
918
    ResultSet rs = pstmt.getResultSet();
919
    boolean tablehasrows = rs.next();
920
    if(rev.equals("newest") || rev.equals("all"))
921
    {
922
      return false;
923
    }
924
    
925
    if(tablehasrows)
926
    {
927
      int r = rs.getInt(1);
928
      pstmt.close();
929
      if(new Integer(rev).intValue() == r)
930
      { //the current revision in in xml_documents
931
        //System.out.println("returning false");
932
        return false;
933
      }
934
      else if(new Integer(rev).intValue() < r)
935
      { //the current revision is in xml_revisions.
936
        //System.out.println("returning true");
937
        return true;
938
      }
939
      else if(new Integer(rev).intValue() > r)
940
      { //error, rev cannot be greater than r
941
        throw new Exception("requested revision cannot be greater than " +
942
                            "the latest revision number.");
943
      }
944
    }
945
    throw new Exception("the requested docid '" + docid.toString() + 
946
                        "' does not exist");
947
  }
948

    
949
  private void getDocumentInfo(String docid) throws McdbException, 
950
                                                    AccessionNumberException
951
  {
952
    getDocumentInfo(new DocumentIdentifier(docid));
953
  }
954
  
955
  /**
956
   * Look up the document type information from the database
957
   *
958
   * @param docid the id of the document to look up
959
   */
960
  private void getDocumentInfo(DocumentIdentifier docid) throws McdbException 
961
  {
962
    PreparedStatement pstmt;
963
    String table = "xml_documents";
964
        
965
    try
966
    {
967
      if(isRevisionOnly(docid))
968
      { //pull the document from xml_revisions instead of from xml_documents;
969
        table = "xml_revisions";
970
      }
971
    }
972
    catch(Exception e)
973
    {
974
      System.out.println("error in DocumentImpl.getDocumentInfo: " + 
975
                          e.getMessage());
976
    }
977
    
978
    //deal with the key words here.
979
    
980
    if(docid.getRev().equals("all"))
981
    {
982
      
983
    }
984
    
985
    try {
986
      StringBuffer sql = new StringBuffer();
987
// DOCTITLE attr cleared from the db
988
//      sql.append("SELECT docname, doctype, rootnodeid, doctitle, ");
989
      sql.append("SELECT docname, doctype, rootnodeid, ");
990
      sql.append("date_created, date_updated, user_owner, user_updated, ");
991
      sql.append("server_location, public_access, rev");
992
      sql.append(" FROM ").append(table);
993
      sql.append(" WHERE docid LIKE '").append(docid.getIdentifier());
994
      sql.append("' and rev like '").append(docid.getRev()).append("'");
995
      //System.out.println(sql.toString());
996
      pstmt =
997
        conn.prepareStatement(sql.toString());
998
      // Bind the values to the query
999
      //pstmt.setString(1, docid.getIdentifier());
1000
      //pstmt.setString(2, docid.getRev());
1001

    
1002
      pstmt.execute();
1003
      ResultSet rs = pstmt.getResultSet();
1004
      boolean tableHasRows = rs.next();
1005
      if (tableHasRows) {
1006
        this.docname        = rs.getString(1);
1007
        this.doctype        = rs.getString(2);
1008
        this.rootnodeid     = rs.getLong(3);
1009
// DOCTITLE attr cleared from the db
1010
//        this.doctitle       = rs.getString(4);
1011
        this.createdate     = rs.getString(4);
1012
        this.updatedate     = rs.getString(5);
1013
        this.userowner      = rs.getString(6);
1014
        this.userupdated    = rs.getString(7);
1015
        this.serverlocation = rs.getInt(8);
1016
        this.publicaccess   = rs.getString(9);
1017
        this.rev            = rs.getInt(10);
1018
      } 
1019
      pstmt.close();
1020
      
1021
      //get doc  home server name
1022
      
1023
      pstmt = conn.prepareStatement("select server " +
1024
                        "from xml_replication where serverid = ?");
1025
                        
1026
      
1027
      pstmt.setInt(1, serverlocation);
1028
      pstmt.execute();
1029
      rs = pstmt.getResultSet();
1030
      tableHasRows = rs.next();
1031
      if (tableHasRows)
1032
      {
1033
        
1034
          String server = rs.getString(1);
1035
          //get homeserver name
1036
          if(!server.equals("localhost"))
1037
          {
1038
            this.docHomeServer=server;
1039
          }
1040
          else
1041
          {
1042
            this.docHomeServer=MetaCatUtil.getLocalReplicationServerName();
1043
          }
1044
          MetaCatUtil.debugMessage("server: "+docHomeServer, 50);
1045
        
1046
      }
1047
      pstmt.close();
1048
      if (this.doctype != null) {
1049
        pstmt =
1050
          conn.prepareStatement("SELECT system_id " +
1051
                                  "FROM xml_catalog " +
1052
                                 "WHERE public_id = ?");
1053
        // Bind the values to the query
1054
        pstmt.setString(1, doctype);
1055
  
1056
        pstmt.execute();
1057
        rs = pstmt.getResultSet();
1058
        tableHasRows = rs.next();
1059
        if (tableHasRows) {
1060
          this.system_id  = rs.getString(1);
1061
        } 
1062
        pstmt.close();
1063
      }
1064
    } catch (SQLException e) {
1065
      System.out.println("error in DocumentImpl.getDocumentInfo: " + 
1066
                          e.getMessage());
1067
      e.printStackTrace(System.out);
1068
      throw new McdbException("Error accessing database connection in " +
1069
                              "DocumentImpl.getDocumentInfo: ", e);
1070
    }
1071

    
1072
    if (this.docname == null) {
1073
      throw new McdbDocNotFoundException("Document not found: " + docid);
1074
    }
1075
  }
1076

    
1077
  /**
1078
   * Look up the node data from the database
1079
   *
1080
   * @param rootnodeid the id of the root node of the node tree to look up
1081
   */
1082
  private TreeSet getNodeRecordList(long rootnodeid) throws McdbException 
1083
  {
1084
    PreparedStatement pstmt;
1085
    TreeSet nodeRecordList = new TreeSet(new NodeComparator());
1086
    long nodeid = 0;
1087
    long parentnodeid = 0;
1088
    long nodeindex = 0;
1089
    String nodetype = null;
1090
    String nodename = null;
1091
    String nodeprefix = null;
1092
    String nodedata = null;
1093
    String quotechar = dbAdapter.getStringDelimiter();
1094

    
1095
    try {
1096
      pstmt =
1097
      conn.prepareStatement("SELECT nodeid,parentnodeid,nodeindex, " +
1098
           "nodetype,nodename,nodeprefix,nodedata " +               
1099
           "FROM xml_nodes WHERE rootnodeid = ?");
1100

    
1101
      // Bind the values to the query
1102
      pstmt.setLong(1, rootnodeid);
1103

    
1104
      pstmt.execute();
1105
      ResultSet rs = pstmt.getResultSet();
1106
      boolean tableHasRows = rs.next();
1107
      while (tableHasRows) {
1108
        nodeid = rs.getLong(1);
1109
        parentnodeid = rs.getLong(2);
1110
        nodeindex = rs.getLong(3);
1111
        nodetype = rs.getString(4);
1112
        nodename = rs.getString(5);
1113
        nodeprefix = rs.getString(6);
1114
        nodedata = rs.getString(7);
1115
        nodedata = MetaCatUtil.normalize(nodedata);
1116
        // add the data to the node record list hashtable
1117
        NodeRecord currentRecord = new NodeRecord(nodeid,parentnodeid,nodeindex,
1118
                                      nodetype, nodename, nodeprefix, nodedata);
1119
        nodeRecordList.add(currentRecord);
1120

    
1121
        // Advance to the next node
1122
        tableHasRows = rs.next();
1123
      } 
1124
      pstmt.close();
1125

    
1126
    } catch (SQLException e) {
1127
      throw new McdbException("Error in DocumentImpl.getNodeRecordList " +
1128
                              e.getMessage());
1129
    }
1130

    
1131
    if (nodeRecordList != null) {
1132
      return nodeRecordList;
1133
    } else {
1134
      throw new McdbException("Error getting node data: " + docid);
1135
    }
1136
  }
1137
  
1138
// NOT USED ANY MORE
1139
//  /** creates SQL code and inserts new document into DB connection 
1140
//   default serverCode of 1*/
1141
//  private void writeDocumentToDB(String action, String user)
1142
//               throws SQLException, Exception
1143
//  {
1144
//    writeDocumentToDB(action, user, null, 1);
1145
//  }
1146

    
1147
 /** creates SQL code and inserts new document into DB connection */
1148
  private void writeDocumentToDB(String action, String user, String pub, 
1149
                                 String catalogid, int serverCode) 
1150
               throws SQLException, Exception {
1151
    String sysdate = dbAdapter.getDateTimeFunction();
1152

    
1153
    try {
1154
      PreparedStatement pstmt = null;
1155

    
1156
      if (action.equals("INSERT")) {
1157
        //AccessionNumber ac = new AccessionNumber();
1158
        //this.docid = ac.generate(docid, "INSERT");
1159
        pstmt = conn.prepareStatement(
1160
                "INSERT INTO xml_documents " +
1161
                "(docid, rootnodeid, docname, doctype, " + 
1162
                "user_owner, user_updated, date_created, date_updated, " + 
1163
                "public_access, catalog_id, server_location) " +
1164
                "VALUES (?, ?, ?, ?, ?, ?, " + sysdate + ", " + sysdate + 
1165
                ", ?, ?, ?)");
1166
        //note that the server_location is set to 1. 
1167
        //this means that "localhost" in the xml_replication table must
1168
        //always be the first entry!!!!!
1169
        
1170
        // Bind the values to the query
1171
        pstmt.setString(1, this.docid);
1172
        pstmt.setLong(2, rootnodeid);
1173
        pstmt.setString(3, docname);
1174
        pstmt.setString(4, doctype);
1175
        pstmt.setString(5, user);
1176
        pstmt.setString(6, user);
1177
        if ( pub == null ) {
1178
          pstmt.setString(7, null);
1179
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
1180
          pstmt.setInt(7, 1);
1181
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
1182
          pstmt.setInt(7, 0);
1183
        }
1184
        pstmt.setString(8, catalogid);
1185
        pstmt.setInt(9, serverCode);
1186
      } else if (action.equals("UPDATE")) {
1187

    
1188
        // Save the old document entry in a backup table
1189
        DocumentImpl.archiveDocRevision( conn, docid, user );
1190
        DocumentImpl thisdoc = new DocumentImpl(conn, docid);
1191
        int thisrev = thisdoc.getRev();
1192
        
1193
        //if the updated vesion is not greater than current one,
1194
        //throw it into a exception
1195
        if (Integer.parseInt(updatedVersion)<=thisrev)
1196
        {
1197
          throw new Exception("Next revision number couldn't be less"
1198
                               +" than or equal "+ thisrev);
1199
        }
1200
        else
1201
        {
1202
          //set the user specified revision 
1203
          thisrev=Integer.parseInt(updatedVersion);
1204
        }
1205
        
1206
        // Delete index for the old version of docid
1207
        // The new index is inserting on the next calls to DBSAXNode
1208
        pstmt = conn.prepareStatement(
1209
                "DELETE FROM xml_index WHERE docid='" + this.docid + "'");
1210
        pstmt.execute();
1211
        pstmt.close();
1212

    
1213
        // Update the new document to reflect the new node tree
1214
        pstmt = conn.prepareStatement(
1215
            "UPDATE xml_documents " +
1216
            "SET rootnodeid = ?, docname = ?, doctype = ?, " +
1217
            "user_updated = ?, date_updated = " + sysdate + ", " +
1218
            "server_location = ?, rev = ?, public_access = ?, catalog_id = ? " +
1219
            "WHERE docid = ?");
1220
        // Bind the values to the query
1221
        pstmt.setLong(1, rootnodeid);
1222
        pstmt.setString(2, docname);
1223
        pstmt.setString(3, doctype);
1224
        pstmt.setString(4, user);
1225
        pstmt.setInt(5, serverCode);
1226
        pstmt.setInt(6, thisrev);
1227
        if ( pub == null ) {
1228
          pstmt.setString(7, null);
1229
        } else if ( pub.toUpperCase().equals("YES") || pub.equals("1") ) {
1230
          pstmt .setInt(7, 1);
1231
        } else if ( pub.toUpperCase().equals("NO") || pub.equals("0") ) {
1232
          pstmt.setInt(7, 0);
1233
        }
1234
        pstmt.setString(8, catalogid);
1235
        pstmt.setString(9, this.docid);
1236

    
1237
      } else {
1238
        System.err.println("Action not supported: " + action);
1239
      }
1240

    
1241
      // Do the insertion
1242
      pstmt.execute();
1243
      pstmt.close();
1244

    
1245
    } catch (SQLException sqle) {
1246
      throw sqle;
1247
    } catch (Exception e) {
1248
      throw e;
1249
    }
1250
  }
1251

    
1252
  /**
1253
   * Write an XML file to the database, given a filename
1254
   *
1255
   * @param conn the JDBC connection to the database
1256
   * @param filename the filename to be loaded into the database
1257
   * @param pub flag for public "read" access on document
1258
   * @param dtdfilename the dtd to be uploaded on server's file system
1259
   * @param action the action to be performed (INSERT OR UPDATE)
1260
   * @param docid the docid to use for the INSERT OR UPDATE
1261
   * @param user the user that owns the document
1262
   * @param groups the groups to which user belongs
1263
   */
1264
  public static String write(Connection conn,String filename,
1265
                             String pub, String dtdfilename,
1266
                             String action, String docid, String user,
1267
                             String[] groups )
1268
                throws Exception {
1269
                  
1270
    Reader dtd = null;
1271
    if ( dtdfilename != null ) {
1272
      dtd = new FileReader(new File(dtdfilename).toString());
1273
    }
1274
    return write ( conn, new FileReader(new File(filename).toString()),
1275
                   pub, dtd, action, docid, user, groups, false);
1276
  }
1277

    
1278
  public static String write(Connection conn,Reader xml,String pub,Reader dtd,
1279
                             String action, String docid, String user,
1280
                             String[] groups, boolean validate)
1281
                throws Exception {
1282
    //this method will be called in handleUpdateOrInsert method 
1283
    //in MetacatServlet class
1284
    // get server location for this doc
1285
    int serverLocation=getServerLocationNumber(conn,docid);
1286
    //System.out.println("server location: "+serverLocation);
1287
    return write(conn,xml,pub,dtd,action,docid,user,groups,serverLocation,false,
1288
                 validate);
1289
  }
1290

    
1291
  public static String write(Connection conn, Reader xml, String pub,
1292
                             String action, String docid, String user,
1293
                             String[] groups )
1294
                throws Exception {
1295
    if(action.equals("UPDATE"))
1296
    {//if the document is being updated then use the servercode from the 
1297
     //originally inserted document.
1298
      DocumentImpl doc = new DocumentImpl(conn, docid);
1299
      int servercode = doc.getServerlocation();
1300
      return write(conn, xml, pub, action, docid, user, groups, servercode);
1301
    }
1302
    else
1303
    {//if the file is being inserted then the servercode is always 1
1304
      return write(conn, xml, pub, action, docid, user, groups, 1);
1305
    }
1306
  }
1307
  
1308
  public static String write( Connection conn, Reader xml,
1309
                              String action, String docid, String user,
1310
                              String[] groups, int serverCode )
1311
                throws Exception
1312
  {
1313
    return write(conn,xml,null,action,docid,user,groups,serverCode);
1314
  }
1315
  
1316
  public static String write( Connection conn, Reader xml, String pub,
1317
                              String action, String docid, String user,
1318
                              String[] groups, int serverCode) 
1319
                throws Exception
1320
  {
1321
    return write(conn,xml,pub,null,action,docid,user,groups,
1322
                 serverCode,false,false);
1323
  }
1324
  
1325
  public static String write( Connection conn, Reader xml, String pub,
1326
                              String action, String docid, String user,
1327
                              String[] groups, int serverCode, boolean override)
1328
                throws Exception
1329
  {
1330
    return write(conn,xml,pub,null,action,docid,user,groups,
1331
                 serverCode,override,false);
1332
  }
1333
  
1334
  /**
1335
   * Write an XML file to the database, given a Reader
1336
   *
1337
   * @param conn the JDBC connection to the database
1338
   * @param xml the xml stream to be loaded into the database
1339
   * @param pub flag for public "read" access on xml document
1340
   * @param dtd the dtd to be uploaded on server's file system
1341
   * @param action the action to be performed (INSERT or UPDATE)
1342
   * @param accnum the docid + rev# to use on INSERT or UPDATE
1343
   * @param user the user that owns the document
1344
   * @param groups the groups to which user belongs
1345
   * @param serverCode the serverid from xml_replication on which this document
1346
   *        resides.
1347
   * @param override flag to stop insert replication checking.
1348
   *        if override = true then a document not belonging to the local server
1349
   *        will not be checked upon update for a file lock.
1350
   *        if override = false then a document not from this server, upon 
1351
   *        update will be locked and version checked.
1352
   */
1353

    
1354
  public static String write( Connection conn,Reader xml,String pub,Reader dtd,
1355
                              String action, String accnum, String user,
1356
                              String[] groups, int serverCode, boolean override,
1357
                              boolean validate)
1358
                throws Exception
1359
  {
1360
    // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1361
    MetaCatUtil util = new MetaCatUtil();
1362
    AccessionNumber ac = new AccessionNumber(conn, accnum, action);
1363
    String docid = ac.getDocid();
1364
    String rev = ac.getRev();
1365
    MetaCatUtil.debugMessage("action: " + action + " servercode: " + 
1366
                             serverCode + " override: " + override, 10);
1367
                        
1368
    if((serverCode != 1 && action.equals("UPDATE")) && !override)
1369
    { //if this document being written is not a resident of this server then
1370
      //we need to try to get a lock from it's resident server.  If the
1371
      //resident server will not give a lock then we send the user a message
1372
      //saying that he/she needs to download a new copy of the file and
1373
      //merge the differences manually.
1374
      int istreamInt; 
1375
      char istreamChar;
1376
      DocumentIdentifier id = new DocumentIdentifier(accnum);
1377
      String updaterev = id.getRev();
1378
      String server = MetacatReplication.getServer(serverCode);
1379
      MetacatReplication.replLog("attempting to lock " + accnum);
1380
      URL u = new URL("https://" + server + "?server="
1381
           +util.getLocalReplicationServerName()+"&action=getlock&updaterev=" 
1382
           +updaterev + "&docid=" + docid);
1383
      //System.out.println("sending message: " + u.toString());
1384
      String serverResStr = MetacatReplication.getURLContent(u);
1385
      String openingtag =serverResStr.substring(0, serverResStr.indexOf(">")+1);
1386
      if(openingtag.equals("<lockgranted>"))
1387
      {//the lock was granted go ahead with the insert
1388
        try 
1389
        {
1390
          //System.out.println("In lockgranted");
1391
          MetacatReplication.replLog("lock granted for " + accnum + " from " +
1392
                                      server);
1393
          XMLReader parser = initializeParser(conn, action, docid, updaterev,
1394
                                  validate, user, groups, pub, serverCode, dtd);
1395
          conn.setAutoCommit(false);
1396
          parser.parse(new InputSource(xml)); 
1397
          conn.commit();
1398
          conn.setAutoCommit(true);
1399
        } 
1400
        catch (Exception e) 
1401
        {
1402
          conn.rollback();
1403
          conn.setAutoCommit(true);
1404
          throw e;
1405
        }
1406
                
1407
        
1408
        
1409
        //If Metacat is super hub, tell all servers in its server list to get 
1410
        //the new document, ture mean it is xml document
1411
        if ((util.getOption("hub")).equals("super"))
1412
        {
1413
          ForceReplicationHandler frh = new ForceReplicationHandler(accnum, 
1414
                true, ReplicationHandler.buildServerList(conn));
1415
        }
1416
        else
1417
        {
1418
          //after inserting the document locally, tell the document's homeserver
1419
          //to come get a copy from here.
1420
         
1421
          ForceReplicationHandler frh = new ForceReplicationHandler(accnum, 
1422
                true, ReplicationHandler.getHomeServer(docid));
1423
        }
1424
        return (accnum);
1425
      }
1426

    
1427
      else if(openingtag.equals("<filelocked>"))
1428
      {//the file is currently locked by another user
1429
       //notify our user to wait a few minutes, check out a new copy and try
1430
       //again.
1431
        //System.out.println("file locked");
1432
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1433
                                   server + " reason: file already locked");
1434
        throw new Exception("The file specified is already locked by another " +
1435
                            "user.  Please wait 30 seconds, checkout the " +
1436
                            "newer document, merge your changes and try " +
1437
                            "again.");
1438
      }
1439
      else if(openingtag.equals("<outdatedfile>"))
1440
      {//our file is outdated.  notify our user to check out a new copy of the
1441
       //file and merge his version with the new version.
1442
        //System.out.println("outdated file");
1443
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1444
                                    server + " reason: local file outdated");
1445
        throw new Exception("The file you are trying to update is an outdated" +
1446
                            " version.  Please checkout the newest document, " +
1447
                            "merge your changes and try again.");
1448
      }
1449
    }
1450
    
1451
    if ( action.equals("UPDATE") ) {
1452
      // check for 'write' permission for 'user' to update this document
1453

    
1454
      if ( !hasPermission(conn, user, groups, docid) ) {
1455
        throw new Exception("User " + user + 
1456
              " does not have permission to update XML Document #" + accnum);
1457
      }          
1458
    }
1459

    
1460
    try 
1461
    { 
1462
      
1463
      XMLReader parser = initializeParser(conn, action, docid, rev, validate,
1464
                                          user, groups, pub, serverCode, dtd);
1465
      conn.setAutoCommit(false);
1466
      parser.parse(new InputSource(xml));
1467
      conn.commit();
1468
      conn.setAutoCommit(true);
1469
    } 
1470
    catch (Exception e) 
1471
    {
1472
      conn.rollback();
1473
      conn.setAutoCommit(true);
1474
      throw e;
1475
    }
1476
    
1477
    //force replicate out the new document to each server in our server list.
1478
    if(serverCode == 1)
1479
    { 
1480
      
1481
      //start the thread to replicate this new document out to the other servers
1482
      //true mean it is xml document
1483
      ForceReplicationHandler frh = new ForceReplicationHandler
1484
                (accnum, action, true,ReplicationHandler.buildServerList(conn));
1485
      
1486
    }
1487
      
1488
    return(accnum);
1489
  }
1490

    
1491
  /**
1492
   * Write an XML file to the database during replication
1493
   *
1494
   * @param conn the JDBC connection to the database
1495
   * @param xml the xml stream to be loaded into the database
1496
   * @param pub flag for public "read" access on xml document
1497
   * @param dtd the dtd to be uploaded on server's file system
1498
   * @param action the action to be performed (INSERT or UPDATE)
1499
   * @param accnum the docid + rev# to use on INSERT or UPDATE
1500
   * @param user the user that owns the document
1501
   * @param groups the groups to which user belongs
1502
   * @param homeServer the name of server which the document origanlly create
1503
   * @param validate, if the xml document is valid or not
1504
   */
1505

    
1506
  public static String writeReplication( Connection conn,Reader xml,String pub,
1507
                Reader dtd, String action, String accnum, String user,
1508
                            String[] groups,String homeServer, boolean validate)
1509
                throws Exception
1510
  {
1511
    // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1512
    MetaCatUtil util = new MetaCatUtil();
1513
    AccessionNumber ac = new AccessionNumber(conn, accnum, action);
1514
    String docid = ac.getDocid();
1515
    String rev = ac.getRev();
1516
    int serverCode=-2;
1517
    //get server code for the home server
1518
    serverCode=getServerCode(homeServer);
1519
    //if the server is not in the xml replication table, insert it.
1520
    if (serverCode==-1)
1521
    {
1522
      insertServerIntoReplicationTable(homeServer);
1523
      //get server code again
1524
      serverCode=getServerCode(homeServer);
1525
    }
1526
      
1527
    MetaCatUtil.debugMessage("action: " + action + " servercode: " + 
1528
                             serverCode, 10);
1529
                        
1530
    if((serverCode != 1 && action.equals("UPDATE")) )
1531
    { //if this document being written is not a resident of this server then
1532
      //we need to try to get a lock from it's resident server.  If the
1533
      //resident server will not give a lock then we send the user a message
1534
      //saying that he/she needs to download a new copy of the file and
1535
      //merge the differences manually.
1536
      int istreamInt; 
1537
      char istreamChar;
1538
      DocumentIdentifier id = new DocumentIdentifier(accnum);
1539
      String updaterev = id.getRev();
1540
      String server = MetacatReplication.getServer(serverCode);
1541
      MetacatReplication.replLog("attempting to lock " + accnum);
1542
      URL u = new URL("https://" + server + "?server="
1543
           +util.getLocalReplicationServerName()+"&action=getlock&updaterev=" 
1544
           +updaterev + "&docid=" + docid);
1545
      //System.out.println("sending message: " + u.toString());
1546
      String serverResStr = MetacatReplication.getURLContent(u);
1547
      String openingtag =serverResStr.substring(0, serverResStr.indexOf(">")+1);
1548
      if(openingtag.equals("<lockgranted>"))
1549
      {//the lock was granted go ahead with the insert
1550
        try 
1551
        {
1552
          //System.out.println("In lockgranted");
1553
          MetacatReplication.replLog("lock granted for " + accnum + " from " +
1554
                                      server);
1555
          XMLReader parser = initializeParser(conn, action, docid, updaterev,
1556
                                  validate, user, groups, pub, serverCode, dtd);
1557
          conn.setAutoCommit(false);
1558
          parser.parse(new InputSource(xml)); 
1559
          conn.commit();
1560
          conn.setAutoCommit(true);
1561
        } 
1562
        catch (Exception e) 
1563
        {
1564
          conn.rollback();
1565
          conn.setAutoCommit(true);
1566
          throw e;
1567
        }
1568
        return (accnum);
1569
      }
1570

    
1571
      else if(openingtag.equals("<filelocked>"))
1572
      {//the file is currently locked by another user
1573
       //notify our user to wait a few minutes, check out a new copy and try
1574
       //again.
1575
        //System.out.println("file locked");
1576
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1577
                                   server + " reason: file already locked");
1578
        throw new Exception("The file specified is already locked by another " +
1579
                            "user.  Please wait 30 seconds, checkout the " +
1580
                            "newer document, merge your changes and try " +
1581
                            "again.");
1582
      }
1583
      else if(openingtag.equals("<outdatedfile>"))
1584
      {//our file is outdated.  notify our user to check out a new copy of the
1585
       //file and merge his version with the new version.
1586
        //System.out.println("outdated file");
1587
        MetacatReplication.replLog("lock denied for " + accnum + " on " +
1588
                                    server + " reason: local file outdated");
1589
        throw new Exception("The file you are trying to update is an outdated" +
1590
                            " version.  Please checkout the newest document, " +
1591
                            "merge your changes and try again.");
1592
      }
1593
    }
1594
    
1595
    if ( action.equals("UPDATE") ) {
1596
      // check for 'write' permission for 'user' to update this document
1597

    
1598
      if ( !hasPermission(conn, user, groups, docid) ) {
1599
        throw new Exception("User " + user + 
1600
              " does not have permission to update XML Document #" + accnum);
1601
      }          
1602
    }
1603

    
1604
    try 
1605
    { 
1606
      
1607
      XMLReader parser = initializeParser(conn, action, docid, rev, validate,
1608
                                          user, groups, pub, serverCode, dtd);
1609
      conn.setAutoCommit(false);
1610
      parser.parse(new InputSource(xml));
1611
      conn.commit();
1612
      conn.setAutoCommit(true);
1613
    } 
1614
    catch (Exception e) 
1615
    {
1616
      conn.rollback();
1617
      conn.setAutoCommit(true);
1618
      throw e;
1619
    }
1620

    
1621
    return(accnum);
1622
  }
1623

    
1624
  
1625
  /**
1626
   * Delete an XML file from the database (actually, just make it a revision
1627
   * in the xml_revisions table)
1628
   *
1629
   * @param docid the ID of the document to be deleted from the database
1630
   */
1631
  public static void delete( Connection conn, String accnum,
1632
                                 String user, String[] groups )
1633
                throws Exception 
1634
  {
1635
    // OLD
1636
    //DocumentIdentifier id = new DocumentIdentifier(accnum);
1637
    //String docid = id.getIdentifier();
1638
    //String rev = id.getRev();
1639
    
1640
    // OLD
1641
    // Determine if the docid,rev are OK for DELETE
1642
    //AccessionNumber ac = new AccessionNumber(conn);
1643
    //docid = ac.generate(docid, rev, "DELETE");
1644

    
1645
    // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1646
    AccessionNumber ac = new AccessionNumber(conn, accnum, "DELETE");
1647
    String docid = ac.getDocid();
1648
    String rev = ac.getRev();
1649
    
1650

    
1651
    // check for 'write' permission for 'user' to delete this document
1652
    if ( !hasPermission(conn, user, groups, docid) ) {
1653
      throw new Exception("User " + user + 
1654
              " does not have permission to delete XML Document #" + accnum);
1655
    }
1656

    
1657
    conn.setAutoCommit(false);
1658
    // Copy the record to the xml_revisions table
1659
    DocumentImpl.archiveDocRevision( conn, docid, user );
1660

    
1661
    // Now delete it from the xml_documents table
1662
    
1663
    Statement stmt = conn.createStatement();
1664
    stmt.execute("DELETE FROM xml_index WHERE docid = '" + docid + "'");
1665
    //stmt.execute("DELETE FROM xml_access WHERE docid = '" + docid + "'");
1666
    stmt.execute("DELETE FROM xml_access WHERE accessfileid = '" + docid + "'");
1667
    stmt.execute("DELETE FROM xml_relation WHERE docid = '" + docid + "'");
1668
    stmt.execute("DELETE FROM xml_documents WHERE docid = '" + docid + "'");
1669
    stmt.close();
1670
    conn.commit();
1671
    conn.setAutoCommit(true);
1672
    //IF this is a package document:
1673
    //delete all of the relations that this document created.
1674
    //if the deleted document is a package document its relations should 
1675
    //no longer be active if it has been deleted from the system.
1676
    
1677
  }
1678

    
1679
  /** 
1680
    * Check for "WRITE" permission on @docid for @user and/or @groups 
1681
    * from DB connection 
1682
    */
1683
  private static boolean hasPermission ( Connection conn, String user,
1684
                                  String[] groups, String docid ) 
1685
                  throws SQLException, Exception
1686
  {
1687
    // Check for WRITE permission on @docid for @user and/or @groups
1688
    AccessControlList aclobj = new AccessControlList(conn);
1689
    return aclobj.hasPermission("WRITE", user, groups, docid);
1690
  }
1691

    
1692
  /** 
1693
    * Check for "READ" permission base on docid, user and group
1694
    *@docid, the document
1695
    *@user, user name
1696
    *@group, user's group
1697
    * 
1698
    */
1699
  public boolean hasReadPermission ( Connection conn, String user,
1700
                                  String[] groups, String docId ) 
1701
                  throws SQLException, Exception
1702
  {
1703
    // Check for READ permission on @docid for @user and/or @groups
1704
    AccessControlList aclObj = new AccessControlList(conn);
1705
    return aclObj.hasPermission("READ", user, groups, docId);
1706
  }  
1707

    
1708
  /**
1709
   * Set up the parser handlers for writing the document to the database
1710
   */
1711
  private static XMLReader initializeParser(Connection conn, String action,
1712
                               String docid, String rev, boolean validate, 
1713
                                   String user, String[] groups, String pub, 
1714
                                   int serverCode, Reader dtd) 
1715
                           throws Exception 
1716
  {
1717
    XMLReader parser = null;
1718
    //
1719
    // Set up the SAX document handlers for parsing
1720
    //
1721
    try {
1722
      //create a DBSAXHandler object which has the revision specification
1723
      ContentHandler chandler = new DBSAXHandler(conn, action, docid, rev,
1724
                                                 user, groups, pub, serverCode);
1725
      EntityResolver eresolver= new DBEntityResolver(conn,
1726
                                                 (DBSAXHandler)chandler, dtd);
1727
      DTDHandler dtdhandler   = new DBDTDHandler(conn);
1728

    
1729
      // Get an instance of the parser
1730
      String parserName = MetaCatUtil.getOption("saxparser");
1731
      parser = XMLReaderFactory.createXMLReader(parserName);
1732

    
1733
      // Turn on validation
1734
      parser.setFeature("http://xml.org/sax/features/validation", validate);
1735
      // Turn off Including all external parameter entities
1736
      // (the external DTD subset also)
1737
      // Doesn't work well, probably the feature name is not correct
1738
      // parser.setFeature(
1739
      //  "http://xml.org/sax/features/external-parameter-entities", false);
1740
      
1741
      // Set Handlers in the parser
1742
      parser.setProperty("http://xml.org/sax/properties/declaration-handler",
1743
                         chandler);
1744
      parser.setProperty("http://xml.org/sax/properties/lexical-handler",
1745
                         chandler);
1746
      parser.setContentHandler((ContentHandler)chandler);
1747
      parser.setEntityResolver((EntityResolver)eresolver);
1748
      parser.setDTDHandler((DTDHandler)dtdhandler);
1749
      parser.setErrorHandler((ErrorHandler)chandler);
1750

    
1751
    } catch (Exception e) {
1752
      throw e;
1753
    }
1754

    
1755
    return parser;
1756
  }
1757

    
1758
  /** Save a document entry in the xml_revisions table */
1759
  private static void archiveDocRevision(Connection conn, String docid,
1760
                                         String user) 
1761
                                         throws SQLException {
1762
    String sysdate = dbAdapter.getDateTimeFunction();
1763
    // create a record in xml_revisions table 
1764
    // for that document as selected from xml_documents
1765
    PreparedStatement pstmt = conn.prepareStatement(
1766
      "INSERT INTO xml_revisions " +
1767
        "(docid, rootnodeid, docname, doctype, " +
1768
        "user_owner, user_updated, date_created, date_updated, " +
1769
        "server_location, rev, public_access, catalog_id) " +
1770
      "SELECT ?, rootnodeid, docname, doctype, " + 
1771
        "user_owner, ?, " + sysdate + ", " + sysdate + ", "+
1772
        "server_location, rev, public_access, catalog_id " +
1773
      "FROM xml_documents " +
1774
      "WHERE docid = ?");
1775
    // Bind the values to the query and execute it
1776
    pstmt.setString(1, docid);
1777
    pstmt.setString(2, user);
1778
    pstmt.setString(3, docid);
1779
    pstmt.execute();
1780
    pstmt.close();
1781

    
1782
  }
1783
  
1784
  /**
1785
    * delete a entry in xml_table for given docid
1786
    * @param docId, the id of the document need to be delete
1787
    */
1788
  private static void deleteXMLDocuments(Connection conn, String docId) 
1789
                                         throws SQLException 
1790
  {
1791
    //delete a record 
1792
    PreparedStatement pStmt = 
1793
             conn.prepareStatement("DELETE FROM xml_documents WHERE docid = '" 
1794
                                              + docId + "'");
1795
    pStmt.execute();
1796
    pStmt.close();
1797

    
1798
  }//deleteXMLDocuments
1799
  
1800
  /**
1801
    * Get last revision number from database for a docid
1802
    * If couldn't find an entry,  -1 will return
1803
    * The return value is integer because we want compare it to there new one
1804
    * @param docid <sitecode>.<uniqueid> part of Accession Number
1805
    */
1806
  private static int getLatestRevisionNumber(Connection conn, String docId)
1807
                                      throws SQLException
1808
  {
1809
    int rev = 1;
1810
    PreparedStatement pStmt;
1811
     
1812
    pStmt = conn.prepareStatement
1813
              ("SELECT rev FROM xml_documents WHERE docid='" + docId + "'");
1814
    pStmt.execute();
1815

    
1816
    ResultSet rs = pStmt.getResultSet();
1817
    boolean hasRow = rs.next();
1818
    if (hasRow)
1819
    {
1820
      rev = rs.getInt(1);
1821
      pStmt.close();
1822
    }
1823
    else
1824
    {
1825
      rev=-1;
1826
      pStmt.close();
1827
    }
1828
      
1829
    return rev;
1830
  }//getLatestRevisionNumber
1831
  
1832
  /**
1833
   * Get server location form database for a accNum
1834
   * 
1835
   * @param accum <sitecode>.<uniqueid>.<rev>
1836
   */
1837
  private static int getServerLocationNumber(Connection conn, String accNum)
1838
                                            throws SQLException
1839
  {
1840
    //get rid of revNum part
1841
    String docId=MetaCatUtil.getDocIdFromString(accNum);
1842
    PreparedStatement pStmt;
1843
    int serverLocation;
1844
     
1845
    pStmt = conn.prepareStatement
1846
      ("SELECT server_location FROM xml_documents WHERE docid='" + docId + "'");
1847
    pStmt.execute();
1848

    
1849
    ResultSet rs = pStmt.getResultSet();
1850
    boolean hasRow = rs.next();
1851
    //if there is entry in xml_documents, get the serverlocation
1852
    if (hasRow)
1853
    {
1854
      serverLocation = rs.getInt(1);
1855
      pStmt.close();
1856
    }
1857
    else
1858
    {
1859
      // if htere is no entry in xml_documents, we consider it is new document
1860
      // the server location is local host and value is 1
1861
      serverLocation=1;
1862
      pStmt.close();
1863
    }
1864
      
1865
    return serverLocation;
1866
  }
1867
  
1868
  /**
1869
   * Given a server name, return its servercode in xml_replication table.
1870
   * If no server is found, -1 will return
1871
   * @param serverName, 
1872
   */
1873
  private static int getServerCode(String serverName) 
1874
  {
1875
    PreparedStatement pStmt=null;
1876
    int serverLocation=-2;
1877
    Connection dbConn = null;
1878
    MetaCatUtil util = new MetaCatUtil();
1879
    
1880
    
1881
    //we should consider about local host too
1882
    if (serverName.equals(util.getLocalReplicationServerName()))
1883
    { 
1884
      serverLocation=1;
1885
      return serverLocation;
1886
    }
1887
    
1888
   
1889
    try
1890
    {
1891
      //check xml_replication table
1892
      dbConn=util.getConnection();
1893
      pStmt = dbConn.prepareStatement
1894
      ("SELECT serverid FROM xml_replication WHERE server='" + serverName +"'");
1895
      pStmt.execute();
1896

    
1897
      ResultSet rs = pStmt.getResultSet();
1898
      boolean hasRow = rs.next();
1899
      //if there is entry in xml_replication, get the serverid
1900
      if (hasRow)
1901
      {
1902
        serverLocation = rs.getInt(1);
1903
        pStmt.close();
1904
      }
1905
      else
1906
      {
1907
        // if htere is no entry in xml_replication, -1 will return
1908
        serverLocation=-1;
1909
        pStmt.close();
1910
      }
1911
    }
1912
    catch (Exception e)
1913
    {
1914
      util.debugMessage("Error in DocumentImpl.getServerCode(): "
1915
                                    +e.getMessage(), 30);
1916
    }
1917
    finally
1918
    {
1919
      try
1920
      {
1921
        util.returnConnection(dbConn);
1922
      }
1923
      catch (Exception ee)
1924
      {}
1925
    }
1926
                 
1927
      
1928
    return serverLocation;
1929
  }
1930
  
1931
  /**
1932
   * Insert a server into xml_replcation table
1933
   * @param server, the name of server 
1934
   */
1935
  private static void  insertServerIntoReplicationTable(String server)
1936
  {
1937
    PreparedStatement pStmt=null;
1938
    Connection dbConn = null;
1939
    int replicate = 1;
1940
    MetaCatUtil util = new MetaCatUtil();
1941
    try
1942
    {
1943
       dbConn=util.getConnection();
1944
       pStmt = dbConn.prepareStatement("INSERT INTO xml_replication " +
1945
                                      "(server, last_checked, replicate) " +
1946
                                      "VALUES ('" + server + "', to_date(" +
1947
                                      "'01/01/00', 'MM/DD/YY'), '" +
1948
                                      replicate + "')");
1949
        pStmt.execute();
1950
        pStmt.close();
1951
        dbConn.commit();
1952
    }
1953
    catch (Exception e)
1954
    {
1955
      util.debugMessage("Error in DocumentImpl.getServerCode(): "
1956
                                    +e.getMessage(), 30);
1957
    }
1958
    finally
1959
    {
1960
      try
1961
      {
1962
        pStmt.close();
1963
        util.returnConnection(dbConn);
1964
      }
1965
      catch (Exception ee)
1966
      {}
1967
    }
1968

    
1969
  }
1970
  
1971
  
1972
  /**
1973
   * the main routine used to test the DBWriter utility.
1974
   * <p>
1975
   * Usage: java DocumentImpl <-f filename -a action -d docid>
1976
   *
1977
   * @param filename the filename to be loaded into the database
1978
   * @param action the action to perform (READ, INSERT, UPDATE, DELETE)
1979
   * @param docid the id of the document to process
1980
   */
1981
  static public void main(String[] args) {
1982
     
1983
    try {
1984
      String filename    = null;
1985
      String dtdfilename = null;
1986
      String action      = null;
1987
      String docid       = null;
1988
      boolean showRuntime = false;
1989
      boolean useOldReadAlgorithm = false;
1990

    
1991
      // Parse the command line arguments
1992
      for ( int i=0 ; i < args.length; ++i ) {
1993
        if ( args[i].equals( "-f" ) ) {
1994
          filename =  args[++i];
1995
        } else if ( args[i].equals( "-r" ) ) {
1996
          dtdfilename =  args[++i];
1997
        } else if ( args[i].equals( "-a" ) ) {
1998
          action =  args[++i];
1999
        } else if ( args[i].equals( "-d" ) ) {
2000
          docid =  args[++i];
2001
        } else if ( args[i].equals( "-t" ) ) {
2002
          showRuntime = true;
2003
        } else if ( args[i].equals( "-old" ) ) {
2004
          useOldReadAlgorithm = true;
2005
        } else {
2006
          System.err.println
2007
            ( "   args[" +i+ "] '" +args[i]+ "' ignored." );
2008
        }
2009
      }
2010
      
2011
      // Check if the required arguments are provided
2012
      boolean argsAreValid = false;
2013
      if (action != null) {
2014
        if (action.equals("INSERT")) {
2015
          if (filename != null) {
2016
            argsAreValid = true;
2017
          } 
2018
        } else if (action.equals("UPDATE")) {
2019
          if ((filename != null) && (docid != null)) {
2020
            argsAreValid = true;
2021
          } 
2022
        } else if (action.equals("DELETE")) {
2023
          if (docid != null) {
2024
            argsAreValid = true;
2025
          } 
2026
        } else if (action.equals("READ")) {
2027
          if (docid != null) {
2028
            argsAreValid = true;
2029
          } 
2030
        } 
2031
      } 
2032

    
2033
      // Print usage message if the arguments are not valid
2034
      if (!argsAreValid) {
2035
        System.err.println("Wrong number of arguments!!!");
2036
        System.err.println(
2037
          "USAGE: java DocumentImpl [-t] <-a INSERT> [-d docid] <-f filename> "+
2038
          "[-r dtdfilename]");
2039
        System.err.println(
2040
          "   OR: java DocumentImpl [-t] <-a UPDATE -d docid -f filename> " +
2041
          "[-r dtdfilename]");
2042
        System.err.println(
2043
          "   OR: java DocumentImpl [-t] <-a DELETE -d docid>");
2044
        System.err.println(
2045
          "   OR: java DocumentImpl [-t] [-old] <-a READ -d docid>");
2046
        return;
2047
      }
2048
      
2049
      // Time the request if asked for
2050
      double startTime = System.currentTimeMillis();
2051
      
2052
      // Open a connection to the database
2053
      MetaCatUtil util = new MetaCatUtil();
2054
      Connection dbconn = util.openDBConnection();
2055

    
2056
      double connTime = System.currentTimeMillis();
2057
      // Execute the action requested (READ, INSERT, UPDATE, DELETE)
2058
      if (action.equals("READ")) {
2059
          DocumentImpl xmldoc = new DocumentImpl( dbconn, docid );
2060
          if (useOldReadAlgorithm) {
2061
            System.out.println(xmldoc.readUsingSlowAlgorithm());
2062
          } else {
2063
            xmldoc.toXml(new PrintWriter(System.out));
2064
          }
2065
      } else if (action.equals("DELETE")) {
2066
        DocumentImpl.delete(dbconn, docid, null, null);
2067
        System.out.println("Document deleted: " + docid);
2068
      } else {
2069
        String newdocid = DocumentImpl.write(dbconn, filename, null,
2070
                                             dtdfilename, action, docid,
2071
                                             null, null);
2072
        if ((docid != null) && (!docid.equals(newdocid))) {
2073
          if (action.equals("INSERT")) {
2074
            System.out.println("New document ID generated!!! ");
2075
          } else if (action.equals("UPDATE")) {
2076
            System.out.println("ERROR: Couldn't update document!!! ");
2077
          }
2078
        } else if ((docid == null) && (action.equals("UPDATE"))) {
2079
          System.out.println("ERROR: Couldn't update document!!! ");
2080
        }
2081
        System.out.println("Document processing finished for: " + filename
2082
              + " (" + newdocid + ")");
2083
      }
2084

    
2085
      double stopTime = System.currentTimeMillis();
2086
      double dbOpenTime = (connTime - startTime)/1000;
2087
      double insertTime = (stopTime - connTime)/1000;
2088
      double executionTime = (stopTime - startTime)/1000;
2089
      if (showRuntime) {
2090
        System.out.println("\n\nTotal Execution time was: " + 
2091
                           executionTime + " seconds.");
2092
        System.out.println("Time to open DB connection was: " + dbOpenTime + 
2093
                           " seconds.");
2094
        System.out.println("Time to insert document was: " + insertTime +
2095
                           " seconds.");
2096
      }
2097
      dbconn.close();
2098
    } catch (McdbException me) {
2099
      me.toXml(new PrintWriter(System.err));
2100
    } catch (AccessionNumberException ane) {
2101
      System.out.println(ane.getMessage());
2102
    } catch (Exception e) {
2103
      System.err.println("EXCEPTION HANDLING REQUIRED");
2104
      System.err.println(e.getMessage());
2105
      e.printStackTrace(System.err);
2106
    }
2107
  }
2108
}
(24-24/41)