Project

General

Profile

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

    
28
package edu.ucsb.nceas.metacat;
29

    
30
import java.io.BufferedInputStream;
31
import java.io.BufferedOutputStream;
32
import java.io.File;
33
import java.io.FileOutputStream;
34
import java.io.IOException;
35
import java.io.InputStream;
36
import java.io.PrintWriter;
37
import java.io.Reader;
38
import java.io.StringWriter;
39
import java.io.Writer;
40
import java.net.URL;
41
import java.sql.PreparedStatement;
42
import java.sql.ResultSet;
43
import java.sql.SQLException;
44
import java.util.Enumeration;
45
import java.util.Hashtable;
46
import java.util.HashMap;
47
import java.util.Iterator;
48
import java.util.Stack;
49
import java.util.TreeSet;
50
import java.util.Vector;
51

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

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

    
62
/**
63
 * A class that represents an XML document. It can be created with a simple
64
 * document identifier from a database connection. It also will write an XML
65
 * text document to a database connection using SAX.
66
 */
67
public class DocumentImpl
68
{
69
    /* Constants */
70
    public static final String SCHEMA = "Schema";
71
    public static final String DTD = "DTD";
72
    public static final String EML200 = "eml200";
73
    public static final String EML210 = "eml210";
74
    public static final String EXTERNALSCHEMALOCATIONPROPERTY = "http://apache.org/xml/properties/schema/external-schemaLocation";
75

    
76
    /*
77
     * public static final String EXTERNALSCHEMALOCATION =
78
     * "eml://ecoinformatics.org/eml-2.0.0
79
     * http://dev.nceas.ucsb.edu/tao/schema/eml.xsd"+ "
80
     * http://www.xml-cml.org/schema/stmml
81
     * http://dev.nceas.ucsb.edu/tao/schema/stmml.xsd";
82
     */
83
    public static final String DECLARATIONHANDLERPROPERTY = "http://xml.org/sax/properties/declaration-handler";
84
    public static final String LEXICALPROPERTY = "http://xml.org/sax/properties/lexical-handler";
85
    public static final String VALIDATIONFEATURE = "http://xml.org/sax/features/validation";
86
    public static final String SCHEMAVALIDATIONFEATURE = "http://apache.org/xml/features/validation/schema";
87
    public static final String NAMESPACEFEATURE = "http://xml.org/sax/features/namespaces";
88
    public static final String NAMESPACEPREFIXESFEATURE = "http://xml.org/sax/features/namespace-prefixes";
89
    public static final String EML2_1_0NAMESPACE = MetaCatUtil
90
            .getOption("eml2_1_0namespace");
91
    // "eml://ecoinformatics.org/eml-2.1.0";
92
    public static final String EML2_0_1NAMESPACE = MetaCatUtil
93
            .getOption("eml2_0_1namespace");
94
    // "eml://ecoinformatics.org/eml-2.0.1";
95
    public static final String EML2_0_0NAMESPACE = MetaCatUtil
96
            .getOption("eml2_0_0namespace");
97
    // "eml://ecoinformatics.org/eml-2.0.0";
98
    public static final String DOCNAME = "docname";
99
    public static final String PUBLICID = "publicid";
100
    public static final String SYSTEMID = "systemid";
101
    static final int ALL = 1;
102
    static final int WRITE = 2;
103
    static final int READ = 4;
104
    private static final AbstractDatabase dbAdapter = MetaCatUtil.dbAdapter;
105
    private DBConnection connection = null;
106
    private String docid = null;
107
    private String updatedVersion = null;
108
    private String docname = null;
109
    private String doctype = null;
110
    private String validateType = null; //base on dtd or schema
111
    private String createdate = null;
112
    private String updatedate = null;
113
    private String system_id = null;
114
    private String userowner = null;
115
    private String userupdated = null;
116
    private int rev;
117
    private int serverlocation;
118
    private String docHomeServer;
119
    private String publicaccess;
120
    private long rootnodeid;
121
    private ElementNode rootNode = null;
122
    private TreeSet nodeRecordList = null;
123

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

    
143
            // Look up the document information
144
            getDocumentInfo(docid);
145

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

    
155
        } catch (McdbException ex) {
156
            throw ex;
157
        } catch (Throwable t) {
158
            throw new McdbException("Error reading document: " + docid);
159
        }
160
    }
161

    
162
    /**
163
     * Constructor, creates document from database connection, used for reading
164
     * the document
165
     *
166
     * @param conn
167
     *            the database connection from which to read the document
168
     * @param docid
169
     *            the identifier of the document to be created
170
     */
171
    public DocumentImpl(String docid) throws McdbException
172
    {
173
        this(docid, true);
174
    }
175

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

    
229
    /**
230
     * This method will be call in handleUploadRequest in MetacatServlet class
231
     */
232
    public static void registerDocument(String docname, String doctype,
233
            String accnum, String user, String[] groupnames) throws SQLException,
234
            AccessionNumberException, Exception
235
    {
236
        try {
237
            // get server location for this doc
238
            int serverLocation = getServerLocationNumber(accnum);
239
            registerDocument(docname, doctype, accnum, user, groupnames,
240
                             serverLocation);
241
        } catch (Exception e) {
242
            throw e;
243
        }
244
    }
245

    
246
    /**
247
     * Register a document that resides on the filesystem with the database.
248
     * (ie, just an entry in xml_documents, nothing in xml_nodes). Creates a
249
     * reference to a filesystem document (used for non-xml data files). This
250
     * class only be called in MetaCatServerlet.
251
     *
252
     * @param conn
253
     *            the JDBC Connection to which all information is written
254
     * @param docname -
255
     *            the name of DTD, i.e. the name immediately following the
256
     *            DOCTYPE keyword ( should be the root element name ) or the
257
     *            root element name if no DOCTYPE declaration provided (Oracle's
258
     *            and IBM parsers are not aware if it is not the root element
259
     *            name)
260
     * @param doctype -
261
     *            Public ID of the DTD, i.e. the name immediately following the
262
     *            PUBLIC keyword in DOCTYPE declaration or the docname if no
263
     *            Public ID provided or null if no DOCTYPE declaration provided
264
     * @param accnum
265
     *            the accession number to use for the INSERT OR UPDATE, which
266
     *            includes a revision number for this revision of the document
267
     *            (e.g., knb.1.1)
268
     * @param user
269
     *            the user that owns the document
270
     * @param groupnames
271
     *            the groups that owns the document
272
     * @param serverCode
273
     *            the serverid from xml_replication on which this document
274
     *            resides.
275
     */
276
    public static void registerDocument(String docname, String doctype,
277
            String accnum, String user, String[] groups, int serverCode)
278
            throws SQLException, AccessionNumberException, Exception
279
    {
280

    
281
        DBConnection dbconn = null;
282
        int serialNumber = -1;
283
        PreparedStatement pstmt = null;
284
        //MetaCatUtil util = new MetaCatUtil();
285
        AccessionNumber ac;
286
        String action = null;
287
        try {
288
            //dbconn = util.openDBConnection();
289
            //check out DBConnection
290
            dbconn = DBConnectionPool
291
                    .getDBConnection("DocumentImpl.registerDocument");
292
            serialNumber = dbconn.getCheckOutSerialNumber();
293
            String docIdWithoutRev = MetaCatUtil.getDocIdFromString(accnum);
294
            int userSpecifyRev = MetaCatUtil.getVersionFromString(accnum);
295
            int revInDataBase = getLatestRevisionNumber(docIdWithoutRev);
296
            //revIndataBase=-1, there is no record in xml_documents table
297
            //the data file is a new one, inert it into table
298
            //user specified rev should be great than 0
299
            if (revInDataBase == -1 && userSpecifyRev > 0) {
300
                ac = new AccessionNumber(accnum, "insert");
301
                action = "insert";
302
            }
303
            //rev is greater the last revsion number and revInDataBase isn't -1
304
            // it is a updated data file
305
            else if (userSpecifyRev > revInDataBase && revInDataBase > 0) {
306

    
307
                if (!hasWritePermission(user, groups, accnum)) { throw new Exception(
308
                   "User " + user
309
                   + " does not have permission to update the document"
310
                   + accnum); }
311

    
312
                //archive the old entry
313
                archiveDocRevision(docIdWithoutRev, user);
314
                //delete the old entry in xml_documents
315
                //deleteXMLDocuments(docIdWithoutRev);
316
                ac = new AccessionNumber(accnum, "update");
317
                action = "update";
318
            }
319
            //other situation
320
            else {
321

    
322
                throw new Exception("Revision number couldn't be "
323
                        + userSpecifyRev);
324
            }
325
            String docid = ac.getDocid();
326
            String rev = ac.getRev();
327
            /*
328
             * SimpleDateFormat formatter = new SimpleDateFormat ("MM/dd/yy
329
             * HH:mm:ss"); Date localtime = new Date(); String dateString =
330
             * formatter.format(localtime); String
331
             * sqlDateString=dbAdapter.toDate(dateString, "MM/DD/YY
332
             * HH24:MI:SS");
333
             */
334
            String sqlDateString = dbAdapter.getDateTimeFunction();
335

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

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

    
442
                //archive the old entry
443
                archiveDocRevision(docIdWithoutRev, user);
444
                //delete the old entry in xml_documents
445
                //deleteXMLDocuments(docIdWithoutRev);
446
                ac = new AccessionNumber(accnum, "update");
447
                action = "update";
448
            }
449
            // local server has newer version, then notify the remote server
450
            else if (userSpecifyRev < revInDataBase && revInDataBase > 0) {
451
                throw new Exception("Local server: "
452
                        + MetaCatUtil.getOption("server")
453
                        + " has newer revision of doc: " + docIdWithoutRev
454
                        + "." + revInDataBase + ". Please notify it.");
455
            }
456
            //other situation
457
            else {
458

    
459
                throw new Exception("Revision number couldn't be "
460
                        + userSpecifyRev);
461
            }
462
            String docid = ac.getDocid();
463
            String rev = ac.getRev();
464
            /*
465
             * SimpleDateFormat formatter = new SimpleDateFormat ("MM/dd/yy
466
             * HH:mm:ss"); Date localtime = new Date(); String dateString =
467
             * formatter.format(localtime); String
468
             * sqlDateString=dbAdapter.toDate(dateString, "MM/DD/YY
469
             * HH24:MI:SS");
470
             */
471
            String sqlDateString = dbAdapter.getDateTimeFunction();
472

    
473
            StringBuffer sql = new StringBuffer();
474
            if (action != null && action.equals("insert")) {
475
                sql.append("insert into xml_documents (docid, docname, " +
476
                           "doctype, ");
477
                sql.append("user_owner, user_updated, server_location, " +
478
                           "rev,date_created");
479
                sql.append(", date_updated, public_access) values ('");
480
                sql.append(docid).append("','");
481
                sql.append(docname).append("','");
482
                sql.append(doctype).append("','");
483
                sql.append(user).append("','");
484
                sql.append(user).append("','");
485
                sql.append(serverCode).append("','");
486
                sql.append(rev).append("',");
487
                sql.append(sqlDateString).append(",");
488
                sql.append(sqlDateString).append(",");
489
                sql.append("'0')");
490
            } else if (action != null && action.equals("update")) {
491
                sql.append("update xml_documents set docname ='");
492
                sql.append(docname).append("', ");
493
                sql.append("user_updated='");
494
                sql.append(user).append("', ");
495
                sql.append("server_location='");
496
                sql.append(serverCode).append("',");
497
                sql.append("rev='");
498
                sql.append(rev).append("',");
499
                sql.append("date_updated=");
500
                sql.append(sqlDateString);
501
                sql.append(" where docid='");
502
                sql.append(docid).append("'");
503
            }
504
            // Set auto commit fasle
505
            dbconn.setAutoCommit(false);
506
            pstmt = dbconn.prepareStatement(sql.toString());
507

    
508
            pstmt.execute();
509
            // Commit the insert
510
            dbconn.commit();
511
            pstmt.close();
512
            //dbconn.close();
513
        } finally {
514
            // Set DBConnection auto commit true
515
            dbconn.setAutoCommit(true);
516
            pstmt.close();
517
            DBConnectionPool.returnDBConnection(dbconn, serialNumber);
518
        }
519
    }
520

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

    
551
        if (filePath == null || filePath.equals("")) { throw new Exception(
552
                "Please specify the directory where file will be store"); }
553
        if (accnum == null || accnum.equals("")) { throw new Exception(
554
                "Please specify the stored file name"); }
555

    
556
        // If server is not int the xml replication talbe, insert it into
557
        // xml_replication table
558
        //serverList.addToServerListIfItIsNot(docHomeServer);
559
        insertServerIntoReplicationTable(docHomeServer);
560

    
561
        // Get server code again
562
        serverCode = getServerCode(docHomeServer);
563

    
564
        //register data file into xml_documents table
565
        registerDocumentInReplication(docname, doctype, accnum, user,
566
                serverCode);
567
        //write inputstream into file system.
568
        File dataDirectory = new File(filePath);
569
        File newFile = new File(dataDirectory, accnum);
570

    
571
        // create a buffered byte output stream
572
        // that uses a default-sized output buffer
573
        FileOutputStream fos = new FileOutputStream(newFile);
574
        BufferedOutputStream outPut = new BufferedOutputStream(fos);
575

    
576
        BufferedInputStream bis = null;
577
        bis = new BufferedInputStream(input);
578
        byte[] buf = new byte[4 * 1024]; // 4K buffer
579
        int b = bis.read(buf);
580

    
581
        while (b != -1) {
582
            outPut.write(buf, 0, b);
583
            b = bis.read(buf);
584
        }
585
        bis.close();
586
        outPut.close();
587
        fos.close();
588

    
589
        // Force replicate data file
590
        ForceReplicationHandler forceReplication = new ForceReplicationHandler(
591
                accnum, false, notificationServer);
592
    }
593

    
594
    /**
595
     * Get a lock for a given document.
596
     */
597
    public static boolean getDataFileLockGrant(String accnum) throws Exception
598
    {
599
        try {
600
            int serverLocation = getServerLocationNumber(accnum);
601
            return getDataFileLockGrant(accnum, serverLocation);
602
        } catch (Exception e) {
603
            throw e;
604
        }
605
    }
606

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

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

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

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

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

    
692
    /**
693
     * get the document name
694
     */
695
    public String getDocname()
696
    {
697
        return docname;
698
    }
699

    
700
    /**
701
     * get the document type (which is the PublicID)
702
     */
703
    public String getDoctype()
704
    {
705
        return doctype;
706
    }
707

    
708
    /**
709
     * get the system identifier
710
     */
711
    public String getSystemID()
712
    {
713
        return system_id;
714
    }
715

    
716
    /**
717
     * get the root node identifier
718
     */
719
    public long getRootNodeID()
720
    {
721
        return rootnodeid;
722
    }
723

    
724
    /**
725
     * get the creation date
726
     */
727
    public String getCreateDate()
728
    {
729
        return createdate;
730
    }
731

    
732
    /**
733
     * get the update date
734
     */
735
    public String getUpdateDate()
736
    {
737
        return updatedate;
738
    }
739

    
740
    /**
741
     * Get the document identifier (docid)
742
     */
743
    public String getDocID()
744
    {
745
        return docid;
746
    }
747

    
748
    public String getUserowner()
749
    {
750
        return userowner;
751
    }
752

    
753
    public String getUserupdated()
754
    {
755
        return userupdated;
756
    }
757

    
758
    public int getServerlocation()
759
    {
760
        return serverlocation;
761
    }
762

    
763
    public String getDocHomeServer()
764
    {
765
        return docHomeServer;
766
    }
767

    
768
    public String getPublicaccess()
769
    {
770
        return publicaccess;
771
    }
772

    
773
    public int getRev()
774
    {
775
        return rev;
776
    }
777

    
778
    public String getValidateType()
779
    {
780
        return validateType;
781
    }
782

    
783
    /**
784
     * Print a string representation of the XML document
785
     */
786
    public String toString(String user, String[] groups, boolean withInlinedata)
787
    {
788
        StringWriter docwriter = new StringWriter();
789
        try {
790
            this.toXml(docwriter, user, groups, withInlinedata);
791
        } catch (McdbException mcdbe) {
792
            return null;
793
        }
794
        String document = docwriter.toString();
795
        return document;
796
    }
797

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

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

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

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

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

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

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

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

    
873
        if (doctype != null
874
                && (doctype.equals(EML2_0_0NAMESPACE)
875
                        || doctype.equals(EML2_0_1NAMESPACE) || doctype
876
                        .equals(EML2_1_0NAMESPACE))) {
877
            proccessEml2 = true;
878
        }
879
        // flag for process inline data
880
        boolean prcocessInlineData = false;
881

    
882
        TreeSet nodeRecordLists = null;
883
        PrintWriter out = null;
884
        if (pw instanceof PrintWriter) {
885
            out = (PrintWriter) pw;
886
        } else {
887
            out = new PrintWriter(pw);
888
        }
889

    
890
        MetaCatUtil util = new MetaCatUtil();
891

    
892
        // Here add code to handle subtree access control
893
        /*
894
         * PermissionController control = new PermissionController(docid);
895
         * Hashtable unaccessableSubTree =control.hasUnaccessableSubTree(user,
896
         * groups, AccessControlInterface.READSTRING);
897
         *
898
         * if (!unaccessableSubTree.isEmpty()) {
899
         *
900
         * nodeRecordLists = getPartNodeRecordList(rootnodeid,
901
         * unaccessableSubTree);
902
         *  } else { nodeRecordLists = getNodeRecordList(rootnodeid); }
903
         */
904
        nodeRecordLists = getNodeRecordList(rootnodeid);
905
        Stack openElements = new Stack();
906
        boolean atRootElement = true;
907
        boolean previousNodeWasElement = false;
908

    
909
        // Step through all of the node records we were given
910

    
911
        Iterator it = nodeRecordLists.iterator();
912

    
913
        while (it.hasNext()) {
914

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

    
958
            // Handle the DOCUMENT node
959
            if (currentNode.nodetype.equals("DOCUMENT")) {
960
                out.print("<?xml version=\"1.0\"?>");
961

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

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

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

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

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

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

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

    
1022
                // Handle the TEXT nodes
1023
            } else if (currentNode.nodetype.equals("TEXT")) {
1024
                if (previousNodeWasElement) {
1025
                    out.print(">");
1026
                }
1027
                if (!prcocessInlineData) {
1028
                    // if it is not inline data just out put data
1029
                    out.print(currentNode.nodedata);
1030
                } else {
1031
                    // if it is inline data first to get the inline data
1032
                    // internal id
1033
                    String fileName = currentNode.nodedata;
1034
                    String accessfileName = MetaCatUtil
1035
                            .getDocIdWithoutRevFromInlineDataID(fileName);
1036
                    // check if user has read permision for this inline data
1037
                    boolean readInlinedata = false;
1038
                    try {
1039
                        Hashtable unReadableInlineDataList =
1040
                            PermissionController
1041
                                .getUnReadableInlineDataIdList(accessfileName,
1042
                                        user, groups, true);
1043
                        if (!unReadableInlineDataList.containsValue(fileName)) {
1044
                            readInlinedata = true;
1045
                        }
1046
                    } catch (Exception e) {
1047
                        throw new McdbException(e.getMessage());
1048
                    }
1049

    
1050
                    if (readInlinedata) {
1051
                        //user want to see it, pull out from
1052
                        // file system and output it
1053
                        // for inline data, the data base only store the file
1054
                        // name, so we
1055
                        // can combine the file name and inline data file path,
1056
                        // to get it
1057

    
1058
                        Reader reader = Eml200SAXHandler
1059
                                .readInlineDataFromFileSystem(fileName);
1060
                        char[] characterArray = new char[4 * 1024];
1061
                        try {
1062
                            int length = reader.read(characterArray);
1063
                            while (length != -1) {
1064
                                out
1065
                                        .print(new String(characterArray, 0,
1066
                                                length));
1067
                                out.flush();
1068
                                length = reader.read(characterArray);
1069
                            }
1070
                            reader.close();
1071
                        } catch (IOException e) {
1072
                            throw new McdbException(e.getMessage());
1073
                        }
1074
                    }//if can read inline data
1075
                    else {
1076
                        // if user can't read it, we only send it back a empty
1077
                        // string
1078
                        // in inline element.
1079
                        out.print("");
1080
                    }// else can't read inlinedata
1081
                    // reset proccess inline data false
1082
                    prcocessInlineData = false;
1083
                }// in inlinedata part
1084
                previousNodeWasElement = false;
1085
                // Handle the COMMENT nodes
1086
            } else if (currentNode.nodetype.equals("COMMENT")) {
1087
                if (previousNodeWasElement) {
1088
                    out.print(">");
1089
                }
1090
                out.print("<!--" + currentNode.nodedata + "-->");
1091
                previousNodeWasElement = false;
1092

    
1093
                // Handle the PI nodes
1094
            } else if (currentNode.nodetype.equals("PI")) {
1095
                if (previousNodeWasElement) {
1096
                    out.print(">");
1097
                }
1098
                out.print("<?" + currentNode.nodename + " "
1099
                        + currentNode.nodedata + "?>");
1100
                previousNodeWasElement = false;
1101
                // Handle the DTD nodes (docname, publicid, systemid)
1102
            } else if (currentNode.nodetype.equals(DTD)) {
1103
                storedDTD = true;
1104
                if (currentNode.getNodeName().equals(DOCNAME)) {
1105
                    dbDocName = currentNode.getNodeData();
1106
                }
1107
                if (currentNode.getNodeName().equals(PUBLICID)) {
1108
                    dbPublicID = currentNode.getNodeData();
1109
                }
1110
                if (currentNode.getNodeName().equals(SYSTEMID)) {
1111
                    dbSystemID = currentNode.getNodeData();
1112
                    // send out <!doctype .../>
1113
                    if (dbDocName != null) {
1114
                        if ((dbPublicID != null) && (dbSystemID != null)) {
1115

    
1116
                            out
1117
                                    .print("<!DOCTYPE " + dbDocName
1118
                                            + " PUBLIC \"" + dbPublicID
1119
                                            + "\" \"" + dbSystemID + "\">");
1120
                        } else {
1121

    
1122
                            out.print("<!DOCTYPE " + dbDocName + ">");
1123
                        }
1124
                    }
1125

    
1126
                    //reset these variable
1127
                    dbDocName = null;
1128
                    dbPublicID = null;
1129
                    dbSystemID = null;
1130
                }
1131

    
1132
                // Handle any other node type (do nothing)
1133
            } else {
1134
                // Any other types of nodes are not handled.
1135
                // Probably should throw an exception here to indicate this
1136
            }
1137
            out.flush();
1138
        }
1139

    
1140
        // Print the final end tag for the root element
1141
        while (!openElements.empty()) {
1142
            NodeRecord currentElement = (NodeRecord) openElements.pop();
1143
            util.debugMessage("\n POPPED: " + currentElement.nodename, 50);
1144
            if (currentElement.nodeprefix != null) {
1145
                out.print("</" + currentElement.nodeprefix + ":"
1146
                        + currentElement.nodename + ">");
1147
            } else {
1148
                out.print("</" + currentElement.nodename + ">");
1149
            }
1150
        }
1151
        out.flush();
1152
    }
1153

    
1154
    /**
1155
     * Build the index record for this document.  This requires that the
1156
     * DocumentImpl instance exists, so first call the constructor that reads
1157
     * the document from the database.
1158
     */
1159
    public void buildIndex() throws McdbException
1160
    {
1161
        MetaCatUtil util = new MetaCatUtil();
1162
        TreeSet nodeRecordLists = getNodeRecordList(rootnodeid);
1163
        Stack openElements = new Stack();
1164
        boolean atRootElement = true;
1165
        boolean previousNodeWasElement = false;
1166

    
1167
        // Build a map of the same records that are present in the
1168
        // TreeSet so that any node can be easily accessed
1169
        HashMap nodeRecordMap = new HashMap();
1170
        Iterator it = nodeRecordLists.iterator();
1171
        while (it.hasNext()) {
1172
            NodeRecord currentNode = (NodeRecord) it.next();
1173
            Long nodeId = new Long(currentNode.getNodeId());
1174
            nodeRecordMap.put(nodeId, currentNode);
1175
        }
1176

    
1177
        // Step through all of the node records we were given
1178
        it = nodeRecordLists.iterator();
1179
        while (it.hasNext()) {
1180
            NodeRecord currentNode = (NodeRecord) it.next();
1181
            if (currentNode.nodetype.equals("ELEMENT") ||
1182
                currentNode.nodetype.equals("ATTRIBUTE") ) {
1183

    
1184
                System.err.println("Starting Node: " +
1185
                    currentNode.getNodeId() + " (" +
1186
                    currentNode.getParentNodeId() + "): " +
1187
                    currentNode.getNodeName() + " (" +
1188
                    currentNode.getNodeType() + ")" +
1189
                    "\n");
1190
                traverseParents(nodeRecordMap, currentNode.getNodeId(), "");
1191
            }
1192
            /*
1193
            util.debugMessage("[Got Node ID: " + currentNode.nodeid + " ("
1194
                    + currentNode.parentnodeid + ", " + currentNode.nodeindex
1195
                    + ", " + currentNode.nodetype + ", " + currentNode.nodename
1196
                    + ", " + currentNode.nodedata + ")]", 40);
1197
            */
1198
            // Print the end tag for the previous node if needed
1199
            //
1200
            // This is determined by inspecting the parent nodeid for the
1201
            // currentNode. If it is the same as the nodeid of the last element
1202
            // that was pushed onto the stack, then we are still in that
1203
            // previous
1204
            // parent element, and we do nothing. However, if it differs, then
1205
            // we
1206
            // have returned to a level above the previous parent, so we go into
1207
            // a loop and pop off nodes and print out their end tags until we
1208
            // get
1209
            // the node on the stack to match the currentNode parentnodeid
1210
            //
1211
            // So, this of course means that we rely on the list of elements
1212
            // having been sorted in a depth first traversal of the nodes, which
1213
            // is handled by the NodeComparator class used by the TreeSet
1214
            if (!atRootElement) {
1215
                NodeRecord currentElement = (NodeRecord) openElements.peek();
1216
                if (currentNode.parentnodeid != currentElement.nodeid) {
1217
                    while (currentNode.parentnodeid != currentElement.nodeid) {
1218
                        currentElement = (NodeRecord) openElements.pop();
1219
                        util.debugMessage("\n POPPED2: "
1220
                                + currentElement.nodename, 60);
1221
                        if (previousNodeWasElement) {
1222
                            //out.print(">");
1223
                            previousNodeWasElement = false;
1224
                        }
1225
                        if (currentElement.nodeprefix != null) {
1226
                            //out.print("</" + currentElement.nodeprefix + ":"
1227
                                    //+ currentElement.nodename + ">");
1228
                        } else {
1229
                            //System.err.print("/");
1230
                            //out.print("</" + currentElement.nodename + ">");
1231
                        }
1232
                        currentElement = (NodeRecord) openElements.peek();
1233
                    }
1234
                }
1235
            }
1236

    
1237
            // Handle the DOCUMENT node
1238
            if (currentNode.nodetype.equals("DOCUMENT")) {
1239
                // Do nothing
1240
            // Handle the ELEMENT nodes
1241
            } else if (currentNode.nodetype.equals("ELEMENT")) {
1242
                if (atRootElement) {
1243
                    atRootElement = false;
1244
                } else {
1245
                    if (previousNodeWasElement) {
1246
                        //out.print(">");
1247
                    }
1248
                }
1249

    
1250
                openElements.push(currentNode);
1251
                util.debugMessage("\n PUSHED2: " + currentNode.nodename, 60);
1252
                previousNodeWasElement = true;
1253
                if (currentNode.nodeprefix != null) {
1254
                    //out.print("<" + currentNode.nodeprefix + ":"
1255
                            //+ currentNode.nodename);
1256
                } else {
1257
                    //out.print("<" + currentNode.nodename);
1258
                    //System.err.print(currentNode.nodename + "\n");
1259
                    //System.err.print("/");
1260
                    //System.err.print(currentNode.nodename + "\n");
1261
                }
1262

    
1263
            // Handle the ATTRIBUTE nodes
1264
            } else if (currentNode.nodetype.equals("ATTRIBUTE")) {
1265
                if (currentNode.nodeprefix != null) {
1266
                    //out.print(" " + currentNode.nodeprefix + ":"
1267
                            //+ currentNode.nodename + "=\""
1268
                            //+ currentNode.nodedata + "\"");
1269
                } else {
1270
                    //out.print(" " + currentNode.nodename + "=\""
1271
                            //+ currentNode.nodedata + "\"");
1272
                    //System.err.print(currentNode.nodename);
1273
                }
1274

    
1275
            // Handle the NAMESPACE nodes
1276
            } else if (currentNode.nodetype.equals("NAMESPACE")) {
1277
                // Do nothing
1278

    
1279
            // Handle the TEXT nodes
1280
            } else if (currentNode.nodetype.equals("TEXT")) {
1281
                if (previousNodeWasElement) {
1282
                    //out.print(">");
1283
                }
1284
                previousNodeWasElement = false;
1285
            // Handle the COMMENT nodes
1286
            } else if (currentNode.nodetype.equals("COMMENT")) {
1287
                if (previousNodeWasElement) {
1288
                    //out.print(">");
1289
                }
1290
                previousNodeWasElement = false;
1291

    
1292
            // Handle the PI nodes
1293
            } else if (currentNode.nodetype.equals("PI")) {
1294
                if (previousNodeWasElement) {
1295
                    //out.print(">");
1296
                }
1297
                previousNodeWasElement = false;
1298
            // Handle the DTD nodes (docname, publicid, systemid)
1299
            } else if (currentNode.nodetype.equals(DTD)) {
1300
                // Do nothing
1301
            // Handle any other node type (do nothing)
1302
            } else {
1303
                // Any other types of nodes are not handled.
1304
                // Probably should throw an exception here to indicate this
1305
            }
1306
            //out.flush();
1307
        }
1308

    
1309
        // Print the final end tag for the root element
1310
        while (!openElements.empty()) {
1311
            NodeRecord currentElement = (NodeRecord) openElements.pop();
1312
            util.debugMessage("\n POPPED2: " + currentElement.nodename, 60);
1313
            if (currentElement.nodeprefix != null) {
1314
                //out.print("</" + currentElement.nodeprefix + ":"
1315
                        //+ currentElement.nodename + ">");
1316
            } else {
1317
                //out.print("</" + currentElement.nodename + ">");
1318
            }
1319
        }
1320
        //out.flush();
1321
    }
1322

    
1323
    /**
1324
     * Recurse up the parent node hierarchy and add each node to the
1325
     * hashmap of paths to be indexed.
1326
     *
1327
     * @param records the set of records hashed by nodeId
1328
     * @param id the id of the current node to be processed
1329
     * @param children the string representation of all child nodes of this id
1330
     */
1331
    private void traverseParents(HashMap records, long id, String children) {
1332
        NodeRecord current = (NodeRecord)records.get(new Long(id));
1333
        String currentName = current.getNodeName();
1334
        if (current.nodetype.equals("ELEMENT") ||
1335
            current.nodetype.equals("ATTRIBUTE") ) {
1336

    
1337
            System.err.print(currentName +"\n");
1338
            currentName = "/" + currentName;
1339
            System.err.print(currentName +"\n");
1340
            long parentId = current.getParentNodeId();
1341
            currentName = currentName + children;
1342
            if (parentId != 0) {
1343
                traverseParents(records, parentId, currentName);
1344
            }
1345
            if (!children.equals("")) {
1346
                System.err.print(current.getNodeName() + children +"\n");
1347
                System.err.print('/' + current.getNodeName() + children +"\n");
1348
            }
1349
        }
1350
    }
1351

    
1352
    private boolean isRevisionOnly(DocumentIdentifier docid) throws Exception
1353
    {
1354
        //System.out.println("inRevisionOnly");
1355
        DBConnection dbconn = null;
1356
        int serialNumber = -1;
1357
        PreparedStatement pstmt = null;
1358
        String rev = docid.getRev();
1359
        String newid = docid.getIdentifier();
1360
        try {
1361
            dbconn = DBConnectionPool
1362
                    .getDBConnection("DocumentImpl.isRevisionOnly");
1363
            serialNumber = dbconn.getCheckOutSerialNumber();
1364
            pstmt = dbconn.prepareStatement("select rev from xml_documents "
1365
                    + "where docid like '" + newid + "'");
1366
            pstmt.execute();
1367
            ResultSet rs = pstmt.getResultSet();
1368
            boolean tablehasrows = rs.next();
1369
            if (rev.equals("newest") || rev.equals("all")) { return false; }
1370

    
1371
            if (tablehasrows) {
1372
                int r = rs.getInt(1);
1373
                pstmt.close();
1374
                if (new Integer(rev).intValue() == r) { //the current revision
1375
                                                        // in in xml_documents
1376
                    //System.out.println("returning false");
1377
                    return false;
1378
                } else if (new Integer(rev).intValue() < r) { //the current
1379
                                                              // revision is in
1380
                                                              // xml_revisions.
1381
                    //System.out.println("returning true");
1382
                    return true;
1383
                } else if (new Integer(rev).intValue() > r) { //error, rev
1384
                                                              // cannot be
1385
                                                              // greater than r
1386
                throw new Exception(
1387
                        "requested revision cannot be greater than "
1388
                                + "the latest revision number."); }
1389
            }
1390
            // Get miss docid and rev, throw to McdDocNotFoundException
1391
            String missDocId = MetaCatUtil.getDocIdFromString(docid.toString());
1392
            String missRevision = MetaCatUtil.getRevisionStringFromString(docid
1393
                    .toString());
1394
            throw new McdbDocNotFoundException("the requested docid '"
1395
                    + docid.toString() + "' does not exist", missDocId,
1396
                    missRevision);
1397
        }//try
1398
        finally {
1399
            pstmt.close();
1400
            DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1401
        }//finally
1402
    }
1403

    
1404
    private void getDocumentInfo(String docid) throws McdbException,
1405
            AccessionNumberException, Exception
1406
    {
1407
        getDocumentInfo(new DocumentIdentifier(docid));
1408
    }
1409

    
1410
    /**
1411
     * Look up the document type information from the database
1412
     *
1413
     * @param docid
1414
     *            the id of the document to look up
1415
     */
1416
    private void getDocumentInfo(DocumentIdentifier docid)
1417
            throws McdbException, Exception
1418
    {
1419
        DBConnection dbconn = null;
1420
        int serialNumber = -1;
1421
        PreparedStatement pstmt = null;
1422
        String table = "xml_documents";
1423

    
1424
        try {
1425
            if (isRevisionOnly(docid)) { //pull the document from xml_revisions
1426
                                         // instead of from xml_documents;
1427
                table = "xml_revisions";
1428
            }
1429
        }
1430
        // catch a McdbDocNotFoundException throw it
1431
        catch (McdbDocNotFoundException notFound) {
1432
            throw notFound;
1433
        } catch (Exception e) {
1434

    
1435
            MetaCatUtil.debugMessage("error in DocumentImpl.getDocumentInfo: "
1436
                    + e.getMessage(), 30);
1437
            throw e;
1438
        }
1439

    
1440
        try {
1441
            dbconn = DBConnectionPool
1442
                    .getDBConnection("DocumentImpl.getDocumentInfo");
1443
            serialNumber = dbconn.getCheckOutSerialNumber();
1444
            StringBuffer sql = new StringBuffer();
1445
            sql.append("SELECT docname, doctype, rootnodeid, ");
1446
            sql.append("date_created, date_updated, user_owner, user_updated,");
1447
            sql.append(" server_location, public_access, rev");
1448
            sql.append(" FROM ").append(table);
1449
            sql.append(" WHERE docid LIKE '").append(docid.getIdentifier());
1450
            sql.append("' and rev like '").append(docid.getRev()).append("'");
1451

    
1452
            pstmt = dbconn.prepareStatement(sql.toString());
1453

    
1454
            pstmt.execute();
1455
            ResultSet rs = pstmt.getResultSet();
1456
            boolean tableHasRows = rs.next();
1457
            if (tableHasRows) {
1458
                this.docname = rs.getString(1);
1459
                this.doctype = rs.getString(2);
1460
                this.rootnodeid = rs.getLong(3);
1461
                this.createdate = rs.getString(4);
1462
                this.updatedate = rs.getString(5);
1463
                this.userowner = rs.getString(6);
1464
                this.userupdated = rs.getString(7);
1465
                this.serverlocation = rs.getInt(8);
1466
                this.publicaccess = rs.getString(9);
1467
                this.rev = rs.getInt(10);
1468
            }
1469
            pstmt.close();
1470

    
1471
            //get doc home server name
1472
            pstmt = dbconn.prepareStatement("select server "
1473
                    + "from xml_replication where serverid = ?");
1474
            //because connection use twice here, so we need to increase one
1475
            dbconn.increaseUsageCount(1);
1476
            pstmt.setInt(1, serverlocation);
1477
            pstmt.execute();
1478
            rs = pstmt.getResultSet();
1479
            tableHasRows = rs.next();
1480
            if (tableHasRows) {
1481

    
1482
                String server = rs.getString(1);
1483
                //get homeserver name
1484
                if (!server.equals("localhost")) {
1485
                    this.docHomeServer = server;
1486
                } else {
1487
                    this.docHomeServer = MetaCatUtil
1488
                            .getLocalReplicationServerName();
1489
                }
1490
                MetaCatUtil.debugMessage("server: " + docHomeServer, 50);
1491

    
1492
            }
1493
            pstmt.close();
1494
            if (this.doctype != null) {
1495
                pstmt = dbconn.prepareStatement("SELECT system_id, entry_type "
1496
                        + "FROM xml_catalog " + "WHERE public_id = ?");
1497
                //should increase usage count again
1498
                dbconn.increaseUsageCount(1);
1499
                // Bind the values to the query
1500
                pstmt.setString(1, doctype);
1501

    
1502
                pstmt.execute();
1503
                rs = pstmt.getResultSet();
1504
                tableHasRows = rs.next();
1505
                if (tableHasRows) {
1506
                    this.system_id = rs.getString(1);
1507
                    this.validateType = rs.getString(2);
1508

    
1509
                }
1510
                pstmt.close();
1511
            }
1512
        } catch (SQLException e) {
1513
            System.out.println("error in DocumentImpl.getDocumentInfo: "
1514
                    + e.getMessage());
1515
            e.printStackTrace(System.out);
1516
            throw new McdbException("Error accessing database connection in "
1517
                    + "DocumentImpl.getDocumentInfo: ", e);
1518
        } finally {
1519
            try {
1520
                pstmt.close();
1521
            } catch (SQLException ee) {
1522
                MetaCatUtil.debugMessage(
1523
                        "error in DocumentImple.getDocumentInfo: "
1524
                                + ee.getMessage(), 30);
1525
            } finally {
1526
                DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1527
            }
1528
        }
1529

    
1530
        if (this.docname == null) {
1531
            throw new McdbDocNotFoundException(
1532
                "Document not found: " + docid, docid.getIdentifier(), docid
1533
                        .getRev());
1534
        }
1535
    }
1536

    
1537
    /**
1538
     * Look up the node data from the database, but some node would be shown
1539
     * because of access control
1540
     *
1541
     * @param rootnodeid
1542
     *            the id of the root node of the node tree to look up
1543
     * @param accessControl
1544
     *            the hashtable has control info
1545
     */
1546
    private TreeSet getPartNodeRecordList(long rootnodeid,
1547
            Hashtable accessControl) throws McdbException
1548
    {
1549
        PreparedStatement pstmt = null;
1550
        DBConnection dbconn = null;
1551
        int serialNumber = -1;
1552
        TreeSet nodeRecordList = new TreeSet(new NodeComparator());
1553
        long nodeid = 0;
1554
        long parentnodeid = 0;
1555
        long nodeindex = 0;
1556
        String nodetype = null;
1557
        String nodename = null;
1558
        String nodeprefix = null;
1559
        String nodedata = null;
1560
        String quotechar = dbAdapter.getStringDelimiter();
1561
        String sql = "SELECT nodeid,parentnodeid,nodeindex, "
1562
                + "nodetype,nodename,nodeprefix,nodedata "
1563
                + "FROM xml_nodes WHERE rootnodeid = ?";
1564

    
1565
        // go through the access control for some nodes
1566
        Enumeration en = accessControl.elements();
1567
        while (en.hasMoreElements()) {
1568
            SubTree tree = (SubTree) en.nextElement();
1569
            long startId = tree.getStartNodeId();
1570
            long endId = tree.getEndNodeId();
1571
            sql = sql + " AND(nodeid < " + startId + " OR nodeid > " + endId
1572
                    + ")";
1573

    
1574
        }
1575
        MetaCatUtil.debugMessage("The final query to select part node tree: "
1576
                + sql, 25);
1577

    
1578
        try {
1579
            dbconn = DBConnectionPool
1580
                    .getDBConnection("DocumentImpl.getPartNodeRecordList");
1581
            serialNumber = dbconn.getCheckOutSerialNumber();
1582
            pstmt = dbconn.prepareStatement(sql);
1583

    
1584
            // Bind the values to the query
1585
            pstmt.setLong(1, rootnodeid);
1586
            pstmt.execute();
1587
            ResultSet rs = pstmt.getResultSet();
1588
            boolean tableHasRows = rs.next();
1589
            while (tableHasRows) {
1590
                nodeid = rs.getLong(1);
1591
                parentnodeid = rs.getLong(2);
1592
                nodeindex = rs.getLong(3);
1593
                nodetype = rs.getString(4);
1594
                nodename = rs.getString(5);
1595
                nodeprefix = rs.getString(6);
1596
                nodedata = rs.getString(7);
1597
                nodedata = MetaCatUtil.normalize(nodedata);
1598
                // add the data to the node record list hashtable
1599
                NodeRecord currentRecord = new NodeRecord(nodeid, parentnodeid,
1600
                        nodeindex, nodetype, nodename, nodeprefix, nodedata);
1601
                nodeRecordList.add(currentRecord);
1602

    
1603
                // Advance to the next node
1604
                tableHasRows = rs.next();
1605
            }
1606
            pstmt.close();
1607

    
1608
        } catch (SQLException e) {
1609
            throw new McdbException(
1610
                    "Error in DocumentImpl.getPartNodeRecordList "
1611
                            + e.getMessage());
1612
        } finally {
1613
            try {
1614
                pstmt.close();
1615
            } catch (SQLException ee) {
1616
                MetaCatUtil.debugMessage(
1617
                        "error in DocumentImpl.getPartNodeRecordList: "
1618
                                + ee.getMessage(), 30);
1619
            } finally {
1620
                DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1621
            }
1622
        }
1623

    
1624
        if (!nodeRecordList.isEmpty()) {
1625

    
1626
            return nodeRecordList;
1627
        } else {
1628

    
1629
            throw new McdbException("Error getting node data: " + docid);
1630
        }
1631
    }
1632

    
1633
    /**
1634
     * Look up the node data from the database
1635
     *
1636
     * @param rootnodeid
1637
     *            the id of the root node of the node tree to look up
1638
     */
1639
    private TreeSet getNodeRecordList(long rootnodeid) throws McdbException
1640
    {
1641
        PreparedStatement pstmt = null;
1642
        DBConnection dbconn = null;
1643
        int serialNumber = -1;
1644
        TreeSet nodeRecordList = new TreeSet(new NodeComparator());
1645
        long nodeid = 0;
1646
        long parentnodeid = 0;
1647
        long nodeindex = 0;
1648
        String nodetype = null;
1649
        String nodename = null;
1650
        String nodeprefix = null;
1651
        String nodedata = null;
1652
        String quotechar = dbAdapter.getStringDelimiter();
1653

    
1654
        try {
1655
            dbconn = DBConnectionPool
1656
                    .getDBConnection("DocumentImpl.getNodeRecordList");
1657
            serialNumber = dbconn.getCheckOutSerialNumber();
1658
            pstmt = dbconn
1659
                    .prepareStatement("SELECT nodeid,parentnodeid,nodeindex, "
1660
                            + "nodetype,nodename,nodeprefix,nodedata "
1661
                            + "FROM xml_nodes WHERE rootnodeid = ?");
1662

    
1663
            // Bind the values to the query
1664
            pstmt.setLong(1, rootnodeid);
1665

    
1666
            pstmt.execute();
1667
            ResultSet rs = pstmt.getResultSet();
1668
            boolean tableHasRows = rs.next();
1669
            while (tableHasRows) {
1670
                nodeid = rs.getLong(1);
1671
                parentnodeid = rs.getLong(2);
1672
                nodeindex = rs.getLong(3);
1673
                nodetype = rs.getString(4);
1674
                nodename = rs.getString(5);
1675
                nodeprefix = rs.getString(6);
1676
                nodedata = rs.getString(7);
1677
                nodedata = MetaCatUtil.normalize(nodedata);
1678
                // add the data to the node record list hashtable
1679
                NodeRecord currentRecord = new NodeRecord(nodeid, parentnodeid,
1680
                        nodeindex, nodetype, nodename, nodeprefix, nodedata);
1681
                nodeRecordList.add(currentRecord);
1682

    
1683
                // Advance to the next node
1684
                tableHasRows = rs.next();
1685
            }
1686
            pstmt.close();
1687

    
1688
        } catch (SQLException e) {
1689
            throw new McdbException("Error in DocumentImpl.getNodeRecordList "
1690
                    + e.getMessage());
1691
        } finally {
1692
            try {
1693
                pstmt.close();
1694
            } catch (SQLException ee) {
1695
                MetaCatUtil.debugMessage(
1696
                        "error in DocumentImpl.getNodeRecordList: "
1697
                                + ee.getMessage(), 30);
1698
            } finally {
1699
                DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1700
            }
1701
        }
1702

    
1703
        return nodeRecordList;
1704

    
1705
    }
1706

    
1707
    /** creates SQL code and inserts new document into DB connection */
1708
    private void writeDocumentToDB(String action, String user, String pub,
1709
            String catalogid, int serverCode) throws SQLException, Exception
1710
    {
1711
        String sysdate = dbAdapter.getDateTimeFunction();
1712

    
1713
        try {
1714
            PreparedStatement pstmt = null;
1715

    
1716
            if (action.equals("INSERT")) {
1717
                //AccessionNumber ac = new AccessionNumber();
1718
                //this.docid = ac.generate(docid, "INSERT");
1719

    
1720
                pstmt = connection
1721
                        .prepareStatement("INSERT INTO xml_documents "
1722
                        + "(docid, rootnodeid, docname, doctype, user_owner, "
1723
                        + "user_updated, date_created, date_updated, "
1724
                        + "public_access, catalog_id, server_location, rev) "
1725
                        + "VALUES (?, ?, ?, ?, ?, ?, " + sysdate + ", "
1726
                        + sysdate + ", ?, ?, ?, ?)");
1727
                // Increase dbconnection usage count
1728
                connection.increaseUsageCount(1);
1729

    
1730
                //note that the server_location is set to 1.
1731
                //this means that "localhost" in the xml_replication table must
1732
                //always be the first entry!!!!!
1733

    
1734
                // Bind the values to the query
1735
                pstmt.setString(1, this.docid);
1736
                pstmt.setLong(2, rootnodeid);
1737
                pstmt.setString(3, docname);
1738
                pstmt.setString(4, doctype);
1739
                pstmt.setString(5, user);
1740
                pstmt.setString(6, user);
1741
                //public access is usefulless, so set it to null
1742
                pstmt.setString(7, null);
1743
                /*
1744
                 * if ( pub == null ) { pstmt.setString(7, null); } else if (
1745
                 * pub.toUpperCase().equals("YES") || pub.equals("1") ) {
1746
                 * pstmt.setInt(7, 1); } else if (
1747
                 * pub.toUpperCase().equals("NO") || pub.equals("0") ) {
1748
                 * pstmt.setInt(7, 0); }
1749
                 */
1750
                pstmt.setString(8, catalogid);
1751
                pstmt.setInt(9, serverCode);
1752
                pstmt.setInt(10, Integer.parseInt(updatedVersion));
1753
            } else if (action.equals("UPDATE")) {
1754

    
1755
                // Save the old document publicaccessentry in a backup table
1756
                DocumentImpl.archiveDocRevision(connection, docid, user);
1757
                MetaCatUtil.debugMessage("after archiveDoc", 40);
1758
                DocumentImpl thisdoc = new DocumentImpl(docid, false);
1759
                int thisrev = thisdoc.getRev();
1760
                MetaCatUtil.debugMessage("this revsion is: " + thisrev, 40);
1761
                //if the updated vesion is not greater than current one,
1762
                //throw it into a exception
1763
                if (Integer.parseInt(updatedVersion) <= thisrev) {
1764
                    throw new Exception("Next revision number couldn't be less"
1765
                            + " than or equal " + thisrev);
1766
                } else {
1767
                    //set the user specified revision
1768
                    thisrev = Integer.parseInt(updatedVersion);
1769
                }
1770
                MetaCatUtil.debugMessage("final revsion is: " + thisrev, 40);
1771
                boolean useXMLIndex = (new Boolean(MetaCatUtil
1772
                        .getOption("usexmlindex"))).booleanValue();
1773
                if (useXMLIndex) {
1774
                    MetaCatUtil.debugMessage("before delete", 40);
1775
                    // Delete index for the old version of docid
1776
                    // The new index is inserting on the next calls to DBSAXNode
1777
                    pstmt = connection
1778
                            .prepareStatement("DELETE FROM xml_index WHERE docid='"
1779
                                    + this.docid + "'");
1780
                    MetaCatUtil.debugMessage("after delete", 40);
1781
                    // Increase dbconnection usage count
1782
                    connection.increaseUsageCount(1);
1783

    
1784
                    pstmt.execute();
1785
                    pstmt.close();
1786
                }
1787

    
1788
                // Update the new document to reflect the new node tree
1789
                pstmt = connection
1790
                        .prepareStatement("UPDATE xml_documents "
1791
                        + "SET rootnodeid = ?, docname = ?, doctype = ?, "
1792
                        + "user_updated = ?, date_updated = "
1793
                        + sysdate
1794
                        + ", "
1795
                        + "server_location = ?, rev = ?, public_access = ?, "
1796
                        + "catalog_id = ? "
1797
                        + "WHERE docid = ?");
1798
                // Increase dbconnection usage count
1799
                connection.increaseUsageCount(1);
1800
                // Bind the values to the query
1801
                pstmt.setLong(1, rootnodeid);
1802
                pstmt.setString(2, docname);
1803
                pstmt.setString(3, doctype);
1804
                pstmt.setString(4, user);
1805
                pstmt.setInt(5, serverCode);
1806
                pstmt.setInt(6, thisrev);
1807
                pstmt.setString(7, null);
1808
                /*
1809
                 * if ( pub == null ) { pstmt.setString(7, null); } else if (
1810
                 * pub.toUpperCase().equals("YES") || pub.equals("1") ) { pstmt
1811
                 * .setInt(7, 1); } else if ( pub.toUpperCase().equals("NO") ||
1812
                 * pub.equals("0") ) { pstmt.setInt(7, 0); }
1813
                 */
1814
                pstmt.setString(8, catalogid);
1815
                pstmt.setString(9, this.docid);
1816

    
1817
            } else {
1818
                System.err.println("Action not supported: " + action);
1819
            }
1820

    
1821
            // Do the insertion
1822
            pstmt.execute();
1823

    
1824
            pstmt.close();
1825

    
1826
        } catch (SQLException sqle) {
1827
            throw sqle;
1828
        } catch (Exception e) {
1829
            throw e;
1830
        }
1831
    }
1832

    
1833
    /**
1834
     * Write an XML file to the database, given a filename
1835
     *
1836
     * @param conn
1837
     *            the JDBC connection to the database
1838
     * @param filename
1839
     *            the filename to be loaded into the database
1840
     * @param pub
1841
     *            flag for public "read" access on document
1842
     * @param dtdfilename
1843
     *            the dtd to be uploaded on server's file system
1844
     * @param action
1845
     *            the action to be performed (INSERT OR UPDATE)
1846
     * @param docid
1847
     *            the docid to use for the INSERT OR UPDATE
1848
     * @param user
1849
     *            the user that owns the document
1850
     * @param groups
1851
     *            the groups to which user belongs
1852
     */
1853
    /*
1854
     * public static String write(DBConnection conn,String filename, String pub,
1855
     * String dtdfilename, String action, String docid, String user, String[]
1856
     * groups ) throws Exception {
1857
     *
1858
     * Reader dtd = null; if ( dtdfilename != null ) { dtd = new FileReader(new
1859
     * File(dtdfilename).toString()); } return write ( conn, new FileReader(new
1860
     * File(filename).toString()), pub, dtd, action, docid, user, groups,
1861
     * false); }
1862
     */
1863

    
1864
    public static String write(DBConnection conn, Reader xml, String pub,
1865
            Reader dtd, String action, String docid, String user,
1866
            String[] groups, String ruleBase, boolean needValidation)
1867
            throws Exception
1868
    {
1869
        //this method will be called in handleUpdateOrInsert method
1870
        //in MetacatServlet class and now is wrapper into documentImple
1871
        // get server location for this doc
1872
        int serverLocation = getServerLocationNumber(docid);
1873
        return write(conn, xml, pub, dtd, action, docid, user, groups,
1874
                serverLocation, false, ruleBase, needValidation);
1875
    }
1876

    
1877
    /**
1878
     * Write an XML file to the database, given a Reader
1879
     *
1880
     * @param conn
1881
     *            the JDBC connection to the database
1882
     * @param xml
1883
     *            the xml stream to be loaded into the database
1884
     * @param pub
1885
     *            flag for public "read" access on xml document
1886
     * @param dtd
1887
     *            the dtd to be uploaded on server's file system
1888
     * @param action
1889
     *            the action to be performed (INSERT or UPDATE)
1890
     * @param accnum
1891
     *            the docid + rev# to use on INSERT or UPDATE
1892
     * @param user
1893
     *            the user that owns the document
1894
     * @param groups
1895
     *            the groups to which user belongs
1896
     * @param serverCode
1897
     *            the serverid from xml_replication on which this document
1898
     *            resides.
1899
     * @param override
1900
     *            flag to stop insert replication checking. if override = true
1901
     *            then a document not belonging to the local server will not be
1902
     *            checked upon update for a file lock. if override = false then
1903
     *            a document not from this server, upon update will be locked
1904
     *            and version checked.
1905
     */
1906

    
1907
    public static String write(DBConnection conn, Reader xml, String pub,
1908
            Reader dtd, String action, String accnum, String user,
1909
            String[] groups, int serverCode, boolean override, String ruleBase,
1910
            boolean needValidation) throws Exception
1911
    {
1912
        // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
1913
        //MetaCatUtil util = new MetaCatUtil();
1914
        MetaCatUtil.debugMessage("conn usage count before writting: "
1915
                + conn.getUsageCount(), 50);
1916
        AccessionNumber ac = new AccessionNumber(accnum, action);
1917
        String docid = ac.getDocid();
1918
        String rev = ac.getRev();
1919
        MetaCatUtil.debugMessage("action: " + action + " servercode: "
1920
                + serverCode + " override: " + override, 10);
1921

    
1922
        if ((serverCode != 1 && action.equals("UPDATE")) && !override) {
1923
            // if this document being written is not a resident of this server
1924
            // then we need to try to get a lock from it's resident server. If
1925
            // the resident server will not give a lock then we send the user
1926
            // a  message saying that he/she needs to download a new copy of
1927
            // the file and merge the differences manually.
1928
            int istreamInt;
1929
            char istreamChar;
1930

    
1931
            // check for 'write' permission for 'user' to update this document
1932
            if (!hasWritePermission(user, groups, accnum)) {
1933
                throw new Exception(
1934
                    "User " + user
1935
                    + " does not have permission to update XML Document #"
1936
                    + accnum);
1937
            }
1938

    
1939
            DocumentIdentifier id = new DocumentIdentifier(accnum);
1940
            String updaterev = id.getRev();
1941
            String server = MetacatReplication
1942
                    .getServerNameForServerCode(serverCode);
1943
            MetacatReplication.replLog("attempting to lock " + accnum);
1944
            URL u = new URL("https://" + server + "?server="
1945
                    + MetaCatUtil.getLocalReplicationServerName()
1946
                    + "&action=getlock&updaterev=" + updaterev + "&docid="
1947
                    + docid);
1948
            //System.out.println("sending message: " + u.toString());
1949
            String serverResStr = MetacatReplication.getURLContent(u);
1950
            String openingtag = serverResStr.substring(0, serverResStr
1951
                    .indexOf(">") + 1);
1952
            if (openingtag.equals("<lockgranted>")) {//the lock was granted go
1953
                                                     // ahead with the insert
1954
                XMLReader parser = null;
1955
                try {
1956
                    //System.out.println("In lockgranted");
1957
                    MetacatReplication.replLog("lock granted for " + accnum
1958
                            + " from " + server);
1959
                    /*
1960
                     * XMLReader parser = initializeParser(conn, action, docid,
1961
                     * updaterev, validate, user, groups, pub, serverCode, dtd);
1962
                     */
1963
                    parser = initializeParser(conn, action, docid, updaterev,
1964
                            user, groups, pub, serverCode, dtd, ruleBase,
1965
                            needValidation);
1966
                    conn.setAutoCommit(false);
1967
                    parser.parse(new InputSource(xml));
1968
                    conn.commit();
1969
                    conn.setAutoCommit(true);
1970
                } catch (Exception e) {
1971
                    conn.rollback();
1972
                    conn.setAutoCommit(true);
1973
                    //if it is a eml2 document, we need delete online data
1974
                    if (parser != null) {
1975
                        ContentHandler handler = parser.getContentHandler();
1976
                        if (handler instanceof Eml200SAXHandler) {
1977
                            Eml200SAXHandler eml = (Eml200SAXHandler) handler;
1978
                            eml.deleteInlineFiles();
1979
                        }
1980
                    }
1981
                    throw e;
1982
                }
1983
                // run write into access db base one relation table and access
1984
                // object
1985
                runRelationAndAccessHandler(accnum, user, groups, serverCode);
1986

    
1987
                // Force replication the docid
1988
                ForceReplicationHandler frh = new ForceReplicationHandler(
1989
                        accnum, true, null);
1990
                return (accnum);
1991

    
1992
            }
1993

    
1994
            else if (openingtag.equals("<filelocked>")) {
1995
                // the file is currently locked by another user notify our
1996
                // user to wait a few minutes, check out a new copy and try
1997
                // again.
1998
                MetacatReplication.replLog("lock denied for " + accnum + " on "
1999
                        + server + " reason: file already locked");
2000
                throw new Exception(
2001
                        "The file specified is already locked by another "
2002
                                + "user.  Please wait 30 seconds, checkout the "
2003
                                + "newer document, merge your changes and try "
2004
                                + "again.");
2005
            } else if (openingtag.equals("<outdatedfile>")) {
2006
                // our file is outdated. notify our user to check out a new
2007
                // copy of the file and merge his version with the new version.
2008
                //System.out.println("outdated file");
2009
                MetacatReplication.replLog("lock denied for " + accnum + " on "
2010
                        + server + " reason: local file outdated");
2011
                throw new Exception(
2012
                        "The file you are trying to update is an outdated"
2013
                        + " version.  Please checkout the newest document, "
2014
                        + "merge your changes and try again.");
2015
            }
2016
        }
2017

    
2018
        if (action.equals("UPDATE")) {
2019
            // check for 'write' permission for 'user' to update this document
2020
            if (!hasWritePermission(user, groups, accnum)) {
2021
                throw new Exception(
2022
                    "User " + user
2023
                    + " does not have permission to update XML Document #"
2024
                    + accnum); }
2025
        }
2026
        XMLReader parser = null;
2027
        try {
2028
            parser = initializeParser(conn, action, docid, rev, user, groups,
2029
                    pub, serverCode, dtd, ruleBase, needValidation);
2030

    
2031
            conn.setAutoCommit(false);
2032
            parser.parse(new InputSource(xml));
2033
            conn.commit();
2034
            conn.setAutoCommit(true);
2035
        } catch (Exception e) {
2036
            conn.rollback();
2037
            conn.setAutoCommit(true);
2038
            //if it is a eml2 document, we need delete online data
2039
            if (parser != null) {
2040
                ContentHandler handler = parser.getContentHandler();
2041
                if (handler instanceof Eml200SAXHandler) {
2042
                    Eml200SAXHandler eml = (Eml200SAXHandler) handler;
2043
                    eml.deleteInlineFiles();
2044
                }
2045
            }
2046
            throw e;
2047
        }
2048

    
2049
        // run access db base on relation table and access object
2050
        runRelationAndAccessHandler(accnum, user, groups, serverCode);
2051

    
2052
        // Force replicate out the new document to each server in our server
2053
        // list. Start the thread to replicate this new document out to the
2054
        // other servers true mean it is xml document null is because no
2055
        // metacat notify the force replication.
2056
        ForceReplicationHandler frh = new ForceReplicationHandler(accnum,
2057
                action, true, null);
2058

    
2059
        MetaCatUtil.debugMessage("Conn Usage count after writting: "
2060
                + conn.getUsageCount(), 50);
2061
        return (accnum);
2062
    }
2063

    
2064
    /**
2065
     * Write an XML file to the database during replication
2066
     *
2067
     * @param conn
2068
     *            the JDBC connection to the database
2069
     * @param xml
2070
     *            the xml stream to be loaded into the database
2071
     * @param pub
2072
     *            flag for public "read" access on xml document
2073
     * @param dtd
2074
     *            the dtd to be uploaded on server's file system
2075
     * @param action
2076
     *            the action to be performed (INSERT or UPDATE)
2077
     * @param accnum
2078
     *            the docid + rev# to use on INSERT or UPDATE
2079
     * @param user
2080
     *            the user that owns the document
2081
     * @param groups
2082
     *            the groups to which user belongs
2083
     * @param homeServer
2084
     *            the name of server which the document origanlly create
2085
     * @param validate,
2086
     *            if the xml document is valid or not
2087
     * @param notifyServer,
2088
     *            the server which notify local server the force replication
2089
     *            command
2090
     */
2091
    public static String writeReplication(DBConnection conn, Reader xml,
2092
            String pub, Reader dtd, String action, String accnum, String user,
2093
            String[] groups, String homeServer, String notifyServer,
2094
            String ruleBase, boolean needValidation) throws Exception
2095
    {
2096
        MetaCatUtil.debugMessage("user in replication" + user, 30);
2097
        // Docid without revision
2098
        String docid = MetaCatUtil.getDocIdFromAccessionNumber(accnum);
2099
        // Revision specified by user (int)
2100
        int userSpecifyRev = MetaCatUtil.getRevisionFromAccessionNumber(accnum);
2101
        MetaCatUtil.debugMessage("The user specifyRev: " + userSpecifyRev, 30);
2102
        // Revision for this docid in current database
2103
        int revInDataBase = getLatestRevisionNumber(docid);
2104
        MetaCatUtil.debugMessage("The rev in data base: " + revInDataBase, 30);
2105
        // String to store the revision
2106
        String rev = null;
2107

    
2108
        //revIndataBase=-1, there is no record in xml_documents table
2109
        //the document is a new one for local server, inert it into table
2110
        //user specified rev should be great than 0
2111
        if (revInDataBase == -1 && userSpecifyRev >= 0) {
2112
            // rev equals user specified
2113
            rev = (new Integer(userSpecifyRev)).toString();
2114
            // action should be INSERT
2115
            action = "INSERT";
2116
        }
2117
        //rev is greater the last revsion number and revInDataBase isn't -1
2118
        // it is a updated file
2119
        else if (userSpecifyRev > revInDataBase && revInDataBase >= 0) {
2120
            // rev equals user specified
2121
            rev = (new Integer(userSpecifyRev)).toString();
2122
            // action should be update
2123
            action = "UPDATE";
2124
        }
2125
        // local server has newer version, then notify the remote server
2126
        else if (userSpecifyRev < revInDataBase && revInDataBase > 0) {
2127
            throw new Exception("Local server: "
2128
                    + MetaCatUtil.getOption("server")
2129
                    + " has newer revision of doc: " + docid + "."
2130
                    + revInDataBase + ". Please notify it.");
2131
        }
2132
        //other situation
2133
        else {
2134

    
2135
            throw new Exception("The docid" + docid
2136
                    + "'s revision number couldn't be " + userSpecifyRev);
2137
        }
2138
        // Variable to store homeserver code
2139
        int serverCode = -2;
2140

    
2141
        // If server is not int the xml replication talbe, insert it into
2142
        // xml_replication table
2143
        //serverList.addToServerListIfItIsNot(homeServer);
2144
        insertServerIntoReplicationTable(homeServer);
2145
        // Get server code again
2146
        serverCode = getServerCode(homeServer);
2147

    
2148
        MetaCatUtil
2149
                .debugMessage("Document " + docid + "." + rev + " " + action
2150
                        + " into local" + " metacat with servercode: "
2151
                        + serverCode, 10);
2152

    
2153
        // insert into xml_nodes table
2154
        XMLReader parser = null;
2155
        try {
2156

    
2157
            parser = initializeParser(conn, action, docid, rev, user, groups,
2158
                    pub, serverCode, dtd, ruleBase, needValidation);
2159
            conn.setAutoCommit(false);
2160
            parser.parse(new InputSource(xml));
2161
            conn.commit();
2162
            conn.setAutoCommit(true);
2163
        } catch (Exception e) {
2164
            conn.rollback();
2165
            conn.setAutoCommit(true);
2166
            if (parser != null) {
2167
                ContentHandler handler = parser.getContentHandler();
2168
                if (handler instanceof Eml200SAXHandler) {
2169
                    Eml200SAXHandler eml = (Eml200SAXHandler) handler;
2170
                    eml.deleteInlineFiles();
2171
                }
2172
            }
2173
            throw e;
2174
        }
2175

    
2176
        // run write into access db base on relation table and access rule
2177
        try {
2178
            runRelationAndAccessHandler(accnum, user, groups, serverCode);
2179
        } catch (Exception ee) {
2180
            MetacatReplication.replErrorLog("Failed to " + "create access "
2181
                    + "rule for package: " + accnum + " because "
2182
                    + ee.getMessage());
2183
            MetaCatUtil.debugMessage("Failed to  " + "create access "
2184
                    + "rule for package: " + accnum + " because "
2185
                    + ee.getMessage(), 30);
2186
        }
2187
        //Force replication to other server
2188
        ForceReplicationHandler forceReplication = new ForceReplicationHandler(
2189
                accnum, action, true, notifyServer);
2190

    
2191
        return (accnum);
2192
    }
2193

    
2194
    /* Running write record to xml_relation and xml_access */
2195
    private static void runRelationAndAccessHandler(String accnumber,
2196
            String userName, String[] group, int servercode) throws Exception
2197
    {
2198
        DBConnection dbconn = null;
2199
        int serialNumber = -1;
2200
        PreparedStatement pstmt = null;
2201
        String documenttype = getDocTypeFromDBForCurrentDocument(accnumber);
2202
        try {
2203
            String packagedoctype = MetaCatUtil.getOption("packagedoctype");
2204
            Vector packagedoctypes = new Vector();
2205
            packagedoctypes = MetaCatUtil.getOptionList(packagedoctype);
2206
            String docIdWithoutRev = MetaCatUtil.getDocIdFromString(accnumber);
2207
            if (documenttype != null &&
2208
                    packagedoctypes.contains(documenttype)) {
2209
                dbconn = DBConnectionPool.getDBConnection(
2210
                        "DocumentImpl.runRelationAndAccessHandeler");
2211
                serialNumber = dbconn.getCheckOutSerialNumber();
2212
                dbconn.setAutoCommit(false);
2213
                // from the relations get the access file id for that package
2214
                String aclid = RelationHandler.getAccessFileID(docIdWithoutRev);
2215
                // if there are access file, write ACL for that package
2216
                if (aclid != null) {
2217
                    runAccessControlList(dbconn, aclid, userName, group,
2218
                            servercode);
2219
                }
2220
                dbconn.commit();
2221
                dbconn.setAutoCommit(true);
2222
            }
2223
            // if it is an access file
2224
            else if (documenttype != null
2225
                    && MetaCatUtil.getOptionList(
2226
                            MetaCatUtil.getOption("accessdoctype")).contains(
2227
                            documenttype)) {
2228
                dbconn = DBConnectionPool.getDBConnection(
2229
                        "DocumentImpl.runRelationAndAccessHandeler");
2230
                serialNumber = dbconn.getCheckOutSerialNumber();
2231
                dbconn.setAutoCommit(false);
2232
                // write ACL for the package
2233
                runAccessControlList(dbconn, docIdWithoutRev, userName, group,
2234
                        servercode);
2235
                dbconn.commit();
2236
                dbconn.setAutoCommit(true);
2237

    
2238
            }
2239

    
2240
        } catch (Exception e) {
2241
            if (dbconn != null) {
2242
                dbconn.rollback();
2243
                dbconn.setAutoCommit(true);
2244
            }
2245
            MetaCatUtil.debugMessage(
2246
                    "Error in DocumentImple.runRelationAndAccessHandler "
2247
                            + e.getMessage(), 30);
2248
            throw e;
2249
        } finally {
2250
            if (dbconn != null) {
2251
                DBConnectionPool.returnDBConnection(dbconn, serialNumber);
2252
            }
2253
        }
2254
    }
2255

    
2256
    // It runs in xmlIndex thread. It writes ACL for a package.
2257
    private static void runAccessControlList(DBConnection conn, String aclid,
2258
            String users, String[] group, int servercode) throws Exception
2259
    {
2260
        // read the access file from xml_nodes
2261
        // parse the access file and store the access info into xml_access
2262
        AccessControlList aclobj = new AccessControlList(conn, aclid, users,
2263
                group, servercode);
2264

    
2265
    }
2266

    
2267
    /* Method get document type from db */
2268
    private static String getDocTypeFromDBForCurrentDocument(String accnumber)
2269
            throws SQLException
2270
    {
2271
        String docoumentType = null;
2272
        String docid = null;
2273
        PreparedStatement pstate = null;
2274
        ResultSet rs = null;
2275
        String sql = "SELECT doctype FROM xml_documents where docid = ?";
2276
        DBConnection dbConnection = null;
2277
        int serialNumber = -1;
2278
        try {
2279
            //get rid of revision number
2280
            docid = MetaCatUtil.getDocIdFromString(accnumber);
2281
            dbConnection = DBConnectionPool.getDBConnection(
2282
                    "DocumentImpl.getDocTypeFromDBForCurrentDoc");
2283
            serialNumber = dbConnection.getCheckOutSerialNumber();
2284
            pstate = dbConnection.prepareStatement(sql);
2285
            //bind variable
2286
            pstate.setString(1, docid);
2287
            //excute query
2288
            pstate.execute();
2289
            //handle resultset
2290
            rs = pstate.getResultSet();
2291
            if (rs.next()) {
2292
                docoumentType = rs.getString(1);
2293
            }
2294
            rs.close();
2295
            pstate.close();
2296
        }//try
2297
        catch (SQLException e) {
2298
            MetaCatUtil.debugMessage("error in DocumentImpl."
2299
                    + "getDocTypeFromDBForCurrentDocument " + e.getMessage(),
2300
                    30);
2301
            throw e;
2302
        }//catch
2303
        finally {
2304
            pstate.close();
2305
            DBConnectionPool.returnDBConnection(dbConnection, serialNumber);
2306
        }//
2307
        MetaCatUtil.debugMessage("The current doctype from db is: "
2308
                + docoumentType, 35);
2309
        return docoumentType;
2310
    }
2311

    
2312
    /**
2313
     * Delete an XML file from the database (actually, just make it a revision
2314
     * in the xml_revisions table)
2315
     *
2316
     * @param docid
2317
     *            the ID of the document to be deleted from the database
2318
     */
2319
    public static void delete(String accnum, String user, String[] groups)
2320
            throws Exception
2321
    {
2322
        // OLD
2323
        //DocumentIdentifier id = new DocumentIdentifier(accnum);
2324
        //String docid = id.getIdentifier();
2325
        //String rev = id.getRev();
2326

    
2327
        // OLD
2328
        // Determine if the docid,rev are OK for DELETE
2329
        //AccessionNumber ac = new AccessionNumber(conn);
2330
        //docid = ac.generate(docid, rev, "DELETE");
2331
        DBConnection conn = null;
2332
        int serialNumber = -1;
2333
        PreparedStatement pstmt = null;
2334
        try {
2335
            //check out DBConnection
2336
            conn = DBConnectionPool.getDBConnection("DocumentImpl.delete");
2337
            serialNumber = conn.getCheckOutSerialNumber();
2338

    
2339
            // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV
2340
            // IN IT
2341
            AccessionNumber ac = new AccessionNumber(accnum, "DELETE");
2342
            String docid = ac.getDocid();
2343
            String rev = ac.getRev();
2344

    
2345
            MetaCatUtil.debugMessage("Start deleting doc " + docid + "...", 20);
2346
            // check for 'write' permission for 'user' to delete this document
2347
            if (!hasAllPermission(user, groups, accnum)) { throw new Exception(
2348
                    "User " + user
2349
                    + " does not have permission to delete XML Document #"
2350
                    + accnum); }
2351

    
2352
            conn.setAutoCommit(false);
2353
            // Copy the record to the xml_revisions table
2354
            DocumentImpl.archiveDocRevision(conn, docid, user);
2355

    
2356
            // Now delete it from the xml_index table
2357
            boolean useXMLIndex = (new Boolean(MetaCatUtil
2358
                    .getOption("usexmlindex"))).booleanValue();
2359
            //if (useXMLIndex) {
2360
            pstmt = conn
2361
                    .prepareStatement("DELETE FROM xml_index WHERE docid = ?");
2362
            pstmt.setString(1, docid);
2363
            pstmt.execute();
2364
            pstmt.close();
2365
            conn.increaseUsageCount(1);
2366
            //}
2367

    
2368
            //stmt.execute("DELETE FROM xml_access WHERE docid = '" + docid +
2369
            // "'");
2370
            // Now delete it from xml_access table
2371
            pstmt = conn.prepareStatement(
2372
                    "DELETE FROM xml_access WHERE accessfileid = ?");
2373
            pstmt.setString(1, docid);
2374
            pstmt.execute();
2375
            pstmt.close();
2376
            conn.increaseUsageCount(1);
2377

    
2378
            pstmt = conn.prepareStatement(
2379
                    "DELETE FROM xml_access WHERE docid = ?");
2380
            pstmt.setString(1, docid);
2381
            pstmt.execute();
2382
            pstmt.close();
2383
            conn.increaseUsageCount(1);
2384

    
2385
            // Delete it from relation table
2386
            pstmt = conn.prepareStatement(
2387
                    "DELETE FROM xml_relation WHERE docid = ?");
2388
            //increase usage count
2389
            conn.increaseUsageCount(1);
2390
            pstmt.setString(1, docid);
2391
            pstmt.execute();
2392
            pstmt.close();
2393

    
2394
            // Delete it from xml_accesssubtree table
2395
            pstmt = conn.prepareStatement(
2396
                    "DELETE FROM xml_accesssubtree WHERE docid = ?");
2397
            //increase usage count
2398
            conn.increaseUsageCount(1);
2399
            pstmt.setString(1, docid);
2400
            pstmt.execute();
2401
            pstmt.close();
2402

    
2403
            // Delete it from xml_documents table
2404
            pstmt = conn.prepareStatement(
2405
                    "DELETE FROM xml_documents WHERE docid = ?");
2406
            pstmt.setString(1, docid);
2407
            pstmt.execute();
2408
            pstmt.close();
2409
            //Usaga count increase 1
2410
            conn.increaseUsageCount(1);
2411

    
2412
            conn.commit();
2413
            conn.setAutoCommit(true);
2414
        } catch (Exception e) {
2415
            MetaCatUtil.debugMessage("error in DocumentImpl.delete: "
2416
                    + e.getMessage(), 30);
2417
            throw e;
2418
        } finally {
2419

    
2420
            try {
2421
                // close preparedStatement
2422
                if (pstmt != null) {
2423
                    pstmt.close();
2424
                }
2425
            }
2426
            finally {
2427
                //check in DBonnection
2428
                DBConnectionPool.returnDBConnection(conn, serialNumber);
2429
            }
2430
        }
2431
        //IF this is a package document:
2432
        //delete all of the relations that this document created.
2433
        //if the deleted document is a package document its relations should
2434
        //no longer be active if it has been deleted from the system.
2435
    }
2436

    
2437
    /**
2438
     * Check for "WRITE" permission on @docid for @user and/or @groups
2439
     * from DB connection
2440
     */
2441
    private static boolean hasWritePermission(String user, String[] groups,
2442
            String docid) throws SQLException, Exception
2443
    {
2444
        // Check for WRITE permission on @docid for @user and/or @groups
2445
        PermissionController controller = new PermissionController(docid);
2446
        return controller.hasPermission(user, groups,
2447
                AccessControlInterface.WRITESTRING);
2448
    }
2449

    
2450
    /**
2451
     * Check for "READ" permission base on docid, user and group
2452
     *
2453
     * @param docid, the document
2454
     * @param user, user name
2455
     * @param groups, user's group
2456
     */
2457
    public static boolean hasReadPermission(String user, String[] groups,
2458
            String docId) throws SQLException, Exception
2459
    {
2460
        // Check for READ permission on @docid for @user and/or @groups
2461
        PermissionController controller = new PermissionController(docId);
2462
        return controller.hasPermission(user, groups,
2463
                AccessControlInterface.READSTRING);
2464
    }
2465

    
2466
    /**
2467
     * Check for "WRITE" permission on @docid for @user and/or @groups
2468
     * from DB connection
2469
     */
2470
    private static boolean hasAllPermission(String user, String[] groups,
2471
            String docid) throws SQLException, Exception
2472
    {
2473
        // Check for WRITE permission on @docid for @user and/or @groups
2474
        PermissionController controller = new PermissionController(docid);
2475
        return controller.hasPermission(user, groups,
2476
                AccessControlInterface.ALLSTRING);
2477
    }
2478

    
2479
    /**
2480
     * Set up the parser handlers for writing the document to the database
2481
     */
2482
    private static XMLReader initializeParser(DBConnection dbconn,
2483
            String action, String docid, String rev, String user,
2484
            String[] groups, String pub, int serverCode, Reader dtd,
2485
            String ruleBase, boolean needValidation) throws Exception
2486
    {
2487
        XMLReader parser = null;
2488
        try {
2489
            // handler
2490
            ContentHandler chandler;
2491
            EntityResolver eresolver;
2492
            DTDHandler dtdhandler;
2493
            // Get an instance of the parser
2494
            String parserName = MetaCatUtil.getOption("saxparser");
2495
            parser = XMLReaderFactory.createXMLReader(parserName);
2496
            if (ruleBase != null && ruleBase.equals(EML200)) {
2497
                MetaCatUtil.debugMessage("eml 2.0.0 parser", 20);
2498
                chandler = new Eml200SAXHandler(dbconn, action, docid, rev,
2499
                        user, groups, pub, serverCode);
2500
                parser.setContentHandler((ContentHandler) chandler);
2501
                parser.setErrorHandler((ErrorHandler) chandler);
2502
                parser.setProperty(DECLARATIONHANDLERPROPERTY, chandler);
2503
                parser.setProperty(LEXICALPROPERTY, chandler);
2504
                // turn on schema validation feature
2505
                parser.setFeature(VALIDATIONFEATURE, true);
2506
                parser.setFeature(NAMESPACEFEATURE, true);
2507
                //parser.setFeature(NAMESPACEPREFIXESFEATURE, true);
2508
                parser.setFeature(SCHEMAVALIDATIONFEATURE, true);
2509
                // From DB to find the register external schema location
2510
                String externalSchemaLocation = null;
2511
                SchemaLocationResolver resolver = new SchemaLocationResolver();
2512
                externalSchemaLocation = resolver
2513
                        .getNameSpaceAndLocationString();
2514
                // Set external schemalocation.
2515
                if (externalSchemaLocation != null
2516
                        && !(externalSchemaLocation.trim()).equals("")) {
2517
                    parser.setProperty(EXTERNALSCHEMALOCATIONPROPERTY,
2518
                            externalSchemaLocation);
2519
                }
2520
            } else if (ruleBase != null && ruleBase.equals(EML210)) {
2521
                MetaCatUtil.debugMessage("eml 2.1.0 parser", 20);
2522
                chandler = new Eml210SAXHandler(dbconn, action, docid, rev,
2523
                        user, groups, pub, serverCode);
2524
                parser.setContentHandler((ContentHandler) chandler);
2525
                parser.setErrorHandler((ErrorHandler) chandler);
2526
                parser.setProperty(DECLARATIONHANDLERPROPERTY, chandler);
2527
                parser.setProperty(LEXICALPROPERTY, chandler);
2528
                // turn on schema validation feature
2529
                parser.setFeature(VALIDATIONFEATURE, true);
2530
                parser.setFeature(NAMESPACEFEATURE, true);
2531
                //parser.setFeature(NAMESPACEPREFIXESFEATURE, true);
2532
                parser.setFeature(SCHEMAVALIDATIONFEATURE, true);
2533
                // From DB to find the register external schema location
2534
                String externalSchemaLocation = null;
2535
                SchemaLocationResolver resolver = new SchemaLocationResolver();
2536
                externalSchemaLocation = resolver
2537
                        .getNameSpaceAndLocationString();
2538
                // Set external schemalocation.
2539
                if (externalSchemaLocation != null
2540
                        && !(externalSchemaLocation.trim()).equals("")) {
2541
                    parser.setProperty(EXTERNALSCHEMALOCATIONPROPERTY,
2542
                            externalSchemaLocation);
2543
                }
2544
            } else {
2545
                //create a DBSAXHandler object which has the revision
2546
                // specification
2547
                chandler = new DBSAXHandler(dbconn, action, docid, rev, user,
2548
                        groups, pub, serverCode);
2549
                parser.setContentHandler((ContentHandler) chandler);
2550
                parser.setErrorHandler((ErrorHandler) chandler);
2551
                parser.setProperty(DECLARATIONHANDLERPROPERTY, chandler);
2552
                parser.setProperty(LEXICALPROPERTY, chandler);
2553

    
2554
                if (ruleBase != null && ruleBase.equals(SCHEMA)
2555
                        && needValidation) {
2556
                    MetaCatUtil.debugMessage("General schema parser", 20);
2557
                    // turn on schema validation feature
2558
                    parser.setFeature(VALIDATIONFEATURE, true);
2559
                    parser.setFeature(NAMESPACEFEATURE, true);
2560
                    //parser.setFeature(NAMESPACEPREFIXESFEATURE, true);
2561
                    parser.setFeature(SCHEMAVALIDATIONFEATURE, true);
2562
                    // From DB to find the register external schema location
2563
                    String externalSchemaLocation = null;
2564
                    SchemaLocationResolver resolver =
2565
                        new SchemaLocationResolver();
2566
                    externalSchemaLocation = resolver
2567
                            .getNameSpaceAndLocationString();
2568
                    // Set external schemalocation.
2569
                    if (externalSchemaLocation != null
2570
                            && !(externalSchemaLocation.trim()).equals("")) {
2571
                        parser.setProperty(EXTERNALSCHEMALOCATIONPROPERTY,
2572
                                externalSchemaLocation);
2573
                    }
2574

    
2575
                } else if (ruleBase != null && ruleBase.equals(DTD)
2576
                        && needValidation) {
2577
                    MetaCatUtil.debugMessage("dtd parser", 20);
2578
                    // turn on dtd validaton feature
2579
                    parser.setFeature(VALIDATIONFEATURE, true);
2580
                    eresolver = new DBEntityResolver(dbconn,
2581
                            (DBSAXHandler) chandler, dtd);
2582
                    dtdhandler = new DBDTDHandler(dbconn);
2583
                    parser.setEntityResolver((EntityResolver) eresolver);
2584
                    parser.setDTDHandler((DTDHandler) dtdhandler);
2585
                } else {
2586
                    MetaCatUtil.debugMessage("other parser", 20);
2587
                    // non validation
2588
                    parser.setFeature(VALIDATIONFEATURE, false);
2589
                    eresolver = new DBEntityResolver(dbconn,
2590
                            (DBSAXHandler) chandler, dtd);
2591
                    dtdhandler = new DBDTDHandler(dbconn);
2592
                    parser.setEntityResolver((EntityResolver) eresolver);
2593
                    parser.setDTDHandler((DTDHandler) dtdhandler);
2594
                }
2595
            }//else
2596
        } catch (Exception e) {
2597
            throw e;
2598
        }
2599
        return parser;
2600
    }
2601

    
2602
    /**
2603
     * Save a document entry in the xml_revisions table Connection use as a
2604
     * paramter is in order to rollback feature
2605
     */
2606
    private static void archiveDocRevision(DBConnection dbconn, String docid,
2607
            String user)
2608
    {
2609
        String sysdate = dbAdapter.getDateTimeFunction();
2610
        //DBConnection conn = null;
2611
        //int serialNumber = -1;
2612
        PreparedStatement pstmt = null;
2613

    
2614
        // create a record in xml_revisions table
2615
        // for that document as selected from xml_documents
2616

    
2617
        try {
2618
            //check out DBConnection
2619
            /*
2620
             * conn=DBConnectionPool.
2621
             * getDBConnection("DocumentImpl.archiveDocRevision");
2622
             * serialNumber=conn.getCheckOutSerialNumber();
2623
             */
2624
            pstmt = dbconn.prepareStatement("INSERT INTO xml_revisions "
2625
                    + "(docid, rootnodeid, docname, doctype, "
2626
                    + "user_owner, user_updated, date_created, date_updated, "
2627
                    + "server_location, rev, public_access, catalog_id) "
2628
                    + "SELECT ?, rootnodeid, docname, doctype, "
2629
                    + "user_owner, ?, " + sysdate + ", " + sysdate + ", "
2630
                    + "server_location, rev, public_access, catalog_id "
2631
                    + "FROM xml_documents " + "WHERE docid = ?");
2632
            // Increase dbconnection usage count
2633
            dbconn.increaseUsageCount(1);
2634
            // Bind the values to the query and execute it
2635
            pstmt.setString(1, docid);
2636
            pstmt.setString(2, user);
2637
            pstmt.setString(3, docid);
2638
            pstmt.execute();
2639
            pstmt.close();
2640
        } catch (SQLException e) {
2641
            MetaCatUtil.debugMessage(
2642
                    "Error in DocumentImpl.archiveDocRevision : "
2643
                            + e.getMessage(), 30);
2644
        } finally {
2645
            try {
2646
                pstmt.close();
2647
            } catch (SQLException ee) {
2648
                MetaCatUtil.debugMessage(
2649
                        "Error in DocumnetImpl.archiveDocRevision: "
2650
                                + ee.getMessage(), 50);
2651
            }
2652
        }
2653
    }
2654

    
2655
    /** Save a document entry in the xml_revisions table */
2656
    private static void archiveDocRevision(String docid, String user)
2657
    {
2658
        String sysdate = dbAdapter.getDateTimeFunction();
2659
        DBConnection conn = null;
2660
        int serialNumber = -1;
2661
        PreparedStatement pstmt = null;
2662

    
2663
        // create a record in xml_revisions table
2664
        // for that document as selected from xml_documents
2665

    
2666
        try {
2667
            //check out DBConnection
2668
            conn = DBConnectionPool
2669
                    .getDBConnection("DocumentImpl.archiveDocRevision");
2670
            serialNumber = conn.getCheckOutSerialNumber();
2671
            pstmt = conn.prepareStatement("INSERT INTO xml_revisions "
2672
                    + "(docid, rootnodeid, docname, doctype, "
2673
                    + "user_owner, user_updated, date_created, date_updated, "
2674
                    + "server_location, rev, public_access, catalog_id) "
2675
                    + "SELECT ?, rootnodeid, docname, doctype, "
2676
                    + "user_owner, ?, " + sysdate + ", " + sysdate + ", "
2677
                    + "server_location, rev, public_access, catalog_id "
2678
                    + "FROM xml_documents " + "WHERE docid = ?");
2679
            // Bind the values to the query and execute it
2680
            pstmt.setString(1, docid);
2681
            pstmt.setString(2, user);
2682
            pstmt.setString(3, docid);
2683
            pstmt.execute();
2684
            pstmt.close();
2685
        } catch (SQLException e) {
2686
            MetaCatUtil.debugMessage(
2687
                    "Error in DocumentImpl.archiveDocRevision : "
2688
                            + e.getMessage(), 30);
2689
        } finally {
2690
            try {
2691
                pstmt.close();
2692
            } catch (SQLException ee) {
2693
                MetaCatUtil.debugMessage(
2694
                        "Error in DocumnetImpl.archiveDocRevision: "
2695
                                + ee.getMessage(), 50);
2696
            } finally {
2697
                //check in DBConnection
2698
                DBConnectionPool.returnDBConnection(conn, serialNumber);
2699
            }
2700
        }
2701
    }
2702

    
2703
    /**
2704
     * delete a entry in xml_table for given docid
2705
     *
2706
     * @param docId,
2707
     *            the id of the document need to be delete
2708
     */
2709
    private static void deleteXMLDocuments(String docId) throws SQLException
2710
    {
2711
        DBConnection conn = null;
2712
        int serialNumber = -1;
2713
        PreparedStatement pStmt = null;
2714
        try {
2715
            //check out DBConnection
2716
            conn = DBConnectionPool
2717
                    .getDBConnection("DocumentImpl.deleteXMLDocuments");
2718
            serialNumber = conn.getCheckOutSerialNumber();
2719
            //delete a record
2720
            pStmt = conn.prepareStatement(
2721
                    "DELETE FROM xml_documents WHERE docid = '" + docId + "'");
2722
            pStmt.execute();
2723
        } finally {
2724
            try {
2725
                pStmt.close();
2726
            } catch (SQLException e) {
2727
                MetaCatUtil.debugMessage(
2728
                        "error in DocumentImpl.deleteXMLDocuments: "
2729
                                + e.getMessage(), 50);
2730
            } finally {
2731
                //return back DBconnection
2732
                DBConnectionPool.returnDBConnection(conn, serialNumber);
2733
            }
2734
        }
2735
    }
2736

    
2737
    /**
2738
     * Get last revision number from database for a docid If couldn't find an
2739
     * entry, -1 will return The return value is integer because we want compare
2740
     * it to there new one
2741
     *
2742
     * @param docid
2743
     *            <sitecode>. <uniqueid>part of Accession Number
2744
     */
2745
    public static int getLatestRevisionNumber(String docId) throws SQLException
2746
    {
2747
        int rev = 1;
2748
        PreparedStatement pStmt = null;
2749
        DBConnection dbConn = null;
2750
        int serialNumber = -1;
2751
        // get rid of rev
2752
        docId = MetaCatUtil.getDocIdFromString(docId);
2753
        try {
2754
            //check out DBConnection
2755
            dbConn = DBConnectionPool
2756
                    .getDBConnection("DocumentImpl.getLatestRevisionNumber");
2757
            serialNumber = dbConn.getCheckOutSerialNumber();
2758

    
2759
            pStmt = dbConn
2760
                    .prepareStatement("SELECT rev FROM xml_documents WHERE docid='"
2761
                            + docId + "'");
2762
            pStmt.execute();
2763

    
2764
            ResultSet rs = pStmt.getResultSet();
2765
            boolean hasRow = rs.next();
2766
            if (hasRow) {
2767
                rev = rs.getInt(1);
2768
                pStmt.close();
2769
            } else {
2770
                rev = -1;
2771
                pStmt.close();
2772
            }
2773
        }//try
2774
        finally {
2775
            try {
2776
                pStmt.close();
2777
            } catch (Exception ee) {
2778
                MetaCatUtil.debugMessage("Error in DocumentImpl."
2779
                        + "getLatestRevisionNumber: " + ee.getMessage(), 50);
2780
            } finally {
2781
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2782
            }
2783
        }//finally
2784

    
2785
        return rev;
2786
    }//getLatestRevisionNumber
2787

    
2788
    /**
2789
     * Get server location form database for a accNum
2790
     *
2791
     * @param accum
2792
     *            <sitecode>. <uniqueid>. <rev>
2793
     */
2794
    private static int getServerLocationNumber(String accNum)
2795
            throws SQLException
2796
    {
2797
        //get rid of revNum part
2798
        String docId = MetaCatUtil.getDocIdFromString(accNum);
2799
        PreparedStatement pStmt = null;
2800
        int serverLocation = 1;
2801
        DBConnection conn = null;
2802
        int serialNumber = -1;
2803

    
2804
        try {
2805
            //check out DBConnection
2806
            conn = DBConnectionPool
2807
                    .getDBConnection("DocumentImpl.getServerLocationNumber");
2808
            serialNumber = conn.getCheckOutSerialNumber();
2809

    
2810
            pStmt = conn
2811
                    .prepareStatement("SELECT server_location FROM xml_documents WHERE docid='"
2812
                            + docId + "'");
2813
            pStmt.execute();
2814

    
2815
            ResultSet rs = pStmt.getResultSet();
2816
            boolean hasRow = rs.next();
2817
            //if there is entry in xml_documents, get the serverlocation
2818
            if (hasRow) {
2819
                serverLocation = rs.getInt(1);
2820
                pStmt.close();
2821
            } else {
2822
                //if htere is no entry in xml_documents, we consider it is new
2823
                // document
2824
                //the server location is local host and value is 1
2825
                serverLocation = 1;
2826
                pStmt.close();
2827
            }
2828
        }//try
2829
        finally {
2830
            try {
2831
                pStmt.close();
2832
            }//try
2833
            catch (Exception ee) {
2834
                MetaCatUtil.debugMessage(
2835
                        "Error in DocumentImpl.getServerLocationNu(): "
2836
                                + ee.getMessage(), 50);
2837
            }//catch
2838
            finally {
2839
                DBConnectionPool.returnDBConnection(conn, serialNumber);
2840
            }//finally
2841
        }//finally
2842

    
2843
        return serverLocation;
2844
    }
2845

    
2846
    /**
2847
     * Given a server name, return its servercode in xml_replication table. If
2848
     * no server is found, -1 will return
2849
     *
2850
     * @param serverName,
2851
     */
2852
    private static int getServerCode(String serverName)
2853
    {
2854
        PreparedStatement pStmt = null;
2855
        int serverLocation = -2;
2856
        DBConnection dbConn = null;
2857
        int serialNumber = -1;
2858
        //MetaCatUtil util = new MetaCatUtil();
2859

    
2860
        //we should consider about local host too
2861
        if (serverName.equals(MetaCatUtil.getLocalReplicationServerName())) {
2862
            serverLocation = 1;
2863
            return serverLocation;
2864
        }
2865

    
2866
        try {
2867
            //check xml_replication table
2868
            //dbConn=util.openDBConnection();
2869
            //check out DBConnection
2870
            dbConn = DBConnectionPool
2871
                    .getDBConnection("DocumentImpl.getServerCode");
2872
            serialNumber = dbConn.getCheckOutSerialNumber();
2873
            pStmt = dbConn
2874
                    .prepareStatement("SELECT serverid FROM xml_replication WHERE server='"
2875
                            + serverName + "'");
2876
            pStmt.execute();
2877

    
2878
            ResultSet rs = pStmt.getResultSet();
2879
            boolean hasRow = rs.next();
2880
            //if there is entry in xml_replication, get the serverid
2881
            if (hasRow) {
2882
                serverLocation = rs.getInt(1);
2883
                pStmt.close();
2884
            } else {
2885
                // if htere is no entry in xml_replication, -1 will return
2886
                serverLocation = -1;
2887
                pStmt.close();
2888
            }
2889
        } catch (Exception e) {
2890
            MetaCatUtil.debugMessage("Error in DocumentImpl.getServerCode(): "
2891
                    + e.getMessage(), 30);
2892
        } finally {
2893
            try {
2894
                pStmt.close();
2895
            } catch (Exception ee) {
2896
                MetaCatUtil.debugMessage(
2897
                        "Error in DocumentImpl.getServerCode(): "
2898
                                + ee.getMessage(), 50);
2899
            } finally {
2900
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2901
            }
2902
        }
2903

    
2904
        return serverLocation;
2905
    }
2906

    
2907
    /**
2908
     * Insert a server into xml_replcation table
2909
     *
2910
     * @param server,
2911
     *            the name of server
2912
     */
2913
    private static synchronized void insertServerIntoReplicationTable(
2914
            String server)
2915
    {
2916
        PreparedStatement pStmt = null;
2917
        DBConnection dbConn = null;
2918
        int serialNumber = -1;
2919

    
2920
        // Initial value for the server
2921
        int replicate = 0;
2922
        int dataReplicate = 0;
2923
        int hub = 0;
2924

    
2925
        try {
2926
            // Get DBConnection
2927
            dbConn = DBConnectionPool
2928
                    .getDBConnection("DocumentImpl.insertServIntoReplicationTable");
2929
            serialNumber = dbConn.getCheckOutSerialNumber();
2930

    
2931
            // Compare the server to dabase
2932
            pStmt = dbConn
2933
                    .prepareStatement("SELECT serverid FROM xml_replication WHERE server='"
2934
                            + server + "'");
2935
            pStmt.execute();
2936
            ResultSet rs = pStmt.getResultSet();
2937
            boolean hasRow = rs.next();
2938
            // Close preparedstatement and result set
2939
            pStmt.close();
2940
            rs.close();
2941

    
2942
            // If the server is not in the table, and server is not local host,
2943
            // insert it
2944
            if (!hasRow
2945
                    && !server.equals(MetaCatUtil
2946
                            .getLocalReplicationServerName())) {
2947
                // Set auto commit false
2948
                dbConn.setAutoCommit(false);
2949
                /*
2950
                 * pStmt = dbConn.prepareStatement("INSERT INTO xml_replication " +
2951
                 * "(server, last_checked, replicate, datareplicate, hub) " +
2952
                 * "VALUES ('" + server + "', to_date(" + "'01/01/00',
2953
                 * 'MM/DD/YY'), '" + replicate +"', '"+dataReplicate+"','"+ hub +
2954
                 * "')");
2955
                 */
2956
                pStmt = dbConn
2957
                        .prepareStatement("INSERT INTO xml_replication "
2958
                                + "(server, last_checked, replicate, datareplicate, hub) "
2959
                                + "VALUES ('" + server + "', "
2960
                                + dbAdapter.toDate("01/01/1980", "MM/DD/YYYY")
2961
                                + ", '" + replicate + "', '" + dataReplicate
2962
                                + "','" + hub + "')");
2963

    
2964
                pStmt.execute();
2965
                dbConn.commit();
2966
                // Increase usage number
2967
                dbConn.increaseUsageCount(1);
2968
                pStmt.close();
2969

    
2970
            }
2971
        }//try
2972
        catch (Exception e) {
2973
            MetaCatUtil.debugMessage(
2974
                    "Error in DocumentImpl.insertServerIntoRepli(): "
2975
                            + e.getMessage(), 30);
2976
        }//catch
2977
        finally {
2978

    
2979
            try {
2980
                // Set auto commit true
2981
                dbConn.setAutoCommit(true);
2982
                pStmt.close();
2983

    
2984
            }//try
2985
            catch (Exception ee) {
2986
                MetaCatUtil.debugMessage(
2987
                        "Error in DocumentImpl.insetServerIntoRepl(): "
2988
                                + ee.getMessage(), 50);
2989
            }//catch
2990
            finally {
2991
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2992
            }
2993

    
2994
        }//finally
2995

    
2996
    }
2997

    
2998
    /**
2999
     * the main routine used to test the DBWriter utility.
3000
     * <p>
3001
     * Usage: java DocumentImpl <-f filename -a action -d docid>
3002
     *
3003
     * @param filename
3004
     *            the filename to be loaded into the database
3005
     * @param action
3006
     *            the action to perform (READ, INSERT, UPDATE, DELETE)
3007
     * @param docid
3008
     *            the id of the document to process
3009
     */
3010
    static public void main(String[] args)
3011
    {
3012
        DBConnection dbconn = null;
3013
        int serialNumber = -1;
3014
        try {
3015
            String filename = null;
3016
            String dtdfilename = null;
3017
            String action = null;
3018
            String docid = null;
3019
            boolean showRuntime = false;
3020
            boolean useOldReadAlgorithm = false;
3021

    
3022
            // Parse the command line arguments
3023
            for (int i = 0; i < args.length; ++i) {
3024
                if (args[i].equals("-f")) {
3025
                    filename = args[++i];
3026
                } else if (args[i].equals("-r")) {
3027
                    dtdfilename = args[++i];
3028
                } else if (args[i].equals("-a")) {
3029
                    action = args[++i];
3030
                } else if (args[i].equals("-d")) {
3031
                    docid = args[++i];
3032
                } else if (args[i].equals("-t")) {
3033
                    showRuntime = true;
3034
                } else if (args[i].equals("-old")) {
3035
                    useOldReadAlgorithm = true;
3036
                } else {
3037
                    System.err.println("   args[" + i + "] '" + args[i]
3038
                            + "' ignored.");
3039
                }
3040
            }
3041

    
3042
            // Check if the required arguments are provided
3043
            boolean argsAreValid = false;
3044
            if (action != null) {
3045
                if (action.equals("INSERT")) {
3046
                    if (filename != null) {
3047
                        argsAreValid = true;
3048
                    }
3049
                } else if (action.equals("UPDATE")) {
3050
                    if ((filename != null) && (docid != null)) {
3051
                        argsAreValid = true;
3052
                    }
3053
                } else if (action.equals("DELETE")) {
3054
                    if (docid != null) {
3055
                        argsAreValid = true;
3056
                    }
3057
                } else if (action.equals("READ")) {
3058
                    if (docid != null) {
3059
                        argsAreValid = true;
3060
                    }
3061
                }
3062
            }
3063

    
3064
            // Print usage message if the arguments are not valid
3065
            if (!argsAreValid) {
3066
                System.err.println("Wrong number of arguments!!!");
3067
                System.err
3068
                        .println("USAGE: java DocumentImpl [-t] <-a INSERT> [-d docid] <-f filename> "
3069
                                + "[-r dtdfilename]");
3070
                System.err
3071
                        .println("   OR: java DocumentImpl [-t] <-a UPDATE -d docid -f filename> "
3072
                                + "[-r dtdfilename]");
3073
                System.err
3074
                        .println("   OR: java DocumentImpl [-t] <-a DELETE -d docid>");
3075
                System.err
3076
                        .println("   OR: java DocumentImpl [-t] [-old] <-a READ -d docid>");
3077
                return;
3078
            }
3079

    
3080
            // Time the request if asked for
3081
            double startTime = System.currentTimeMillis();
3082

    
3083
            // Open a connection to the database
3084
            MetaCatUtil util = new MetaCatUtil();
3085

    
3086
            dbconn = DBConnectionPool.getDBConnection("DocumentImpl.main");
3087
            serialNumber = dbconn.getCheckOutSerialNumber();
3088

    
3089
            double connTime = System.currentTimeMillis();
3090
            // Execute the action requested (READ, INSERT, UPDATE, DELETE)
3091
            if (action.equals("READ")) {
3092
                DocumentImpl xmldoc = new DocumentImpl(docid);
3093
                if (useOldReadAlgorithm) {
3094
                    System.out.println(xmldoc.readUsingSlowAlgorithm());
3095
                } else {
3096
                    xmldoc.toXml(new PrintWriter(System.out), null, null, true);
3097
                }
3098
            } else if (action.equals("DELETE")) {
3099
                DocumentImpl.delete(docid, null, null);
3100
                System.out.println("Document deleted: " + docid);
3101
            } else {
3102
                /*
3103
                 * String newdocid = DocumentImpl.write(dbconn, filename, null,
3104
                 * dtdfilename, action, docid, null, null); if ((docid != null) &&
3105
                 * (!docid.equals(newdocid))) { if (action.equals("INSERT")) {
3106
                 * System.out.println("New document ID generated!!! "); } else
3107
                 * if (action.equals("UPDATE")) { System.out.println("ERROR:
3108
                 * Couldn't update document!!! "); } } else if ((docid == null) &&
3109
                 * (action.equals("UPDATE"))) { System.out.println("ERROR:
3110
                 * Couldn't update document!!! "); }
3111
                 * System.out.println("Document processing finished for: " +
3112
                 * filename + " (" + newdocid + ")");
3113
                 */
3114
            }
3115

    
3116
            double stopTime = System.currentTimeMillis();
3117
            double dbOpenTime = (connTime - startTime) / 1000;
3118
            double insertTime = (stopTime - connTime) / 1000;
3119
            double executionTime = (stopTime - startTime) / 1000;
3120
            if (showRuntime) {
3121
                System.out.println("\n\nTotal Execution time was: "
3122
                        + executionTime + " seconds.");
3123
                System.out.println("Time to open DB connection was: "
3124
                        + dbOpenTime + " seconds.");
3125
                System.out.println("Time to insert document was: " + insertTime
3126
                        + " seconds.");
3127
            }
3128
            dbconn.close();
3129
        } catch (McdbException me) {
3130
            me.toXml(new PrintWriter(System.err));
3131
        } catch (AccessionNumberException ane) {
3132
            System.out.println(ane.getMessage());
3133
        } catch (Exception e) {
3134
            System.err.println("EXCEPTION HANDLING REQUIRED");
3135
            System.err.println(e.getMessage());
3136
            e.printStackTrace(System.err);
3137
        } finally {
3138
            // Return db connection
3139
            DBConnectionPool.returnDBConnection(dbconn, serialNumber);
3140
        }
3141
    }
3142
}
(31-31/62)