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: jones $'
10
 *     '$Date: 2004-09-21 15:36:30 -0700 (Tue, 21 Sep 2004) $'
11
 * '$Revision: 2315 $'
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.sql.Statement;
45
import java.util.Enumeration;
46
import java.util.Hashtable;
47
import java.util.HashMap;
48
import java.util.Iterator;
49
import java.util.Stack;
50
import java.util.TreeSet;
51
import java.util.Vector;
52

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

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

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

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

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

    
145
            // Look up the document information
146
            getDocumentInfo(docid);
147

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
563
        // Get server code again
564
        serverCode = getServerCode(docHomeServer);
565

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
750
    public String getUserowner()
751
    {
752
        return userowner;
753
    }
754

    
755
    public String getUserupdated()
756
    {
757
        return userupdated;
758
    }
759

    
760
    public int getServerlocation()
761
    {
762
        return serverlocation;
763
    }
764

    
765
    public String getDocHomeServer()
766
    {
767
        return docHomeServer;
768
    }
769

    
770
    public String getPublicaccess()
771
    {
772
        return publicaccess;
773
    }
774

    
775
    public int getRev()
776
    {
777
        return rev;
778
    }
779

    
780
    public String getValidateType()
781
    {
782
        return validateType;
783
    }
784

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

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

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

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

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

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

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

    
852
        return (doc.toString());
853
    }
854

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

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

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

    
892
        MetaCatUtil util = new MetaCatUtil();
893

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

    
911
        // Step through all of the node records we were given
912

    
913
        Iterator it = nodeRecordLists.iterator();
914

    
915
        while (it.hasNext()) {
916

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1128
                    //reset these variable
1129
                    dbDocName = null;
1130
                    dbPublicID = null;
1131
                    dbSystemID = null;
1132
                }
1133

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

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

    
1156
    /**
1157
     * Build the index records for this document.  For each node, all absolute
1158
     * and relative paths to the root of the document are created and inserted
1159
     * into the xml_index table.  This requires that the DocumentImpl instance 
1160
     * exists, so first call the constructor that reads the document from the 
1161
     * database.
1162
     *
1163
     * @throws McdbException on error getting the node records for the document
1164
     */
1165
    public void buildIndex() throws McdbException
1166
    {
1167
        MetaCatUtil util = new MetaCatUtil();
1168
        TreeSet nodeRecordLists = getNodeRecordList(rootnodeid);
1169
        Stack openElements = new Stack();
1170
        boolean atRootElement = true;
1171
        long rootNodeId = -1;
1172

    
1173
        // Build a map of the same records that are present in the
1174
        // TreeSet so that any node can be easily accessed by nodeId
1175
        HashMap nodeRecordMap = new HashMap();
1176
        Iterator it = nodeRecordLists.iterator();
1177
        while (it.hasNext()) {
1178
            NodeRecord currentNode = (NodeRecord) it.next();
1179
            Long nodeId = new Long(currentNode.getNodeId());
1180
            nodeRecordMap.put(nodeId, currentNode);
1181
        }
1182
        
1183
        // Opening separate db connection for deleting and writing 
1184
        // XML Index -- be sure that it is all in one db transaction
1185
        int serialNumber = -1;
1186
        DBConnection dbConn = null;
1187
        try {
1188
            dbConn = DBConnectionPool.getDBConnection(
1189
                "DocumentImpl.buildIndex");
1190
            serialNumber = dbConn.getCheckOutSerialNumber();
1191
            dbConn.setAutoCommit(false);
1192
            //make sure record is done
1193
            //checkDocumentTable();
1194
            
1195
            // Delete the previous index entries for this document
1196
            deleteNodeIndex(dbConn);
1197
            
1198
            // Step through all of the node records we were given
1199
            // and build the new index and update the database
1200
            it = nodeRecordLists.iterator();
1201
            while (it.hasNext()) {
1202
                NodeRecord currentNode = (NodeRecord) it.next();
1203
                HashMap pathList = new HashMap();
1204
                if (currentNode.nodetype.equals("ELEMENT") ||
1205
                    currentNode.nodetype.equals("ATTRIBUTE") ) {
1206

    
1207
                    if (atRootElement) {
1208
                        rootNodeId = currentNode.getNodeId();
1209
                        atRootElement = false;
1210
                    }
1211
                    traverseParents(nodeRecordMap, rootNodeId, 
1212
                            currentNode.getNodeId(),
1213
                            currentNode.getNodeId(), "", pathList);
1214
                    updateNodeIndex(dbConn, pathList);
1215
                }
1216
            }
1217
            dbConn.commit();
1218
        } catch (SQLException e) {
1219
            MetaCatUtil.debugMessage(
1220
                "SQL Exception while inserting path index in " +
1221
                "DocumentImpl.buildIndex for document " + docid, 10);
1222
      		MetaCatUtil.debugMessage(e.getMessage(), 10);
1223
            e.printStackTrace();
1224
            try {
1225
                dbConn.rollback();
1226
            } catch (SQLException sqle) {
1227
            	MetaCatUtil.debugMessage(
1228
					"Error while rolling back commit in DocumentImpl.buildIndex"
1229
                    + "\n" + sqle.getMessage(), 10);
1230
            }
1231
        } finally {
1232
			DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1233
        }
1234
    }
1235

    
1236
    /**
1237
     * Recurse up the parent node hierarchy and add each node to the
1238
     * hashmap of paths to be indexed.
1239
     *
1240
     * @param records the set of records hashed by nodeId
1241
     * @param rootNodeId the id of the root element of the document
1242
     * @param leafNodeId the id of the leafNode being processed
1243
     * @param id the id of the current node to be processed
1244
     * @param children the string representation of all child nodes of this id
1245
     * @param pathList the hash to which paths are added
1246
     */
1247
    private void traverseParents(HashMap records, long rootNodeId, 
1248
            long leafNodeId, long id, 
1249
            String children, HashMap pathList) {
1250
        Long nodeId = new Long(id);
1251
        NodeRecord current = (NodeRecord)records.get(nodeId);
1252
        long parentId = current.getParentNodeId();
1253
        String currentName = current.getNodeName();
1254
        if (current.nodetype.equals("ELEMENT") ||
1255
            current.nodetype.equals("ATTRIBUTE") ) {
1256

    
1257
            if (children.equals("")) {
1258
                if (current.nodetype.equals("ATTRIBUTE")) {
1259
                    currentName = "@" + currentName;
1260
                }
1261
                MetaCatUtil.debugMessage("A: " + currentName +"\n", 60);
1262
                pathList.put(currentName, new PathIndexEntry(
1263
                    leafNodeId, currentName, docid, doctype, parentId));
1264
            }
1265
            currentName = "/" + currentName;
1266
            currentName = currentName + children;
1267
            if (parentId != 0) {
1268
                traverseParents(records, rootNodeId, leafNodeId,
1269
                    parentId, currentName, pathList);
1270
            }
1271
            String path = current.getNodeName() + children;
1272
            if (!children.equals("")) {
1273
                MetaCatUtil.debugMessage("B: " + path +"\n", 60);
1274
                pathList.put(path, new PathIndexEntry(leafNodeId, path, docid, 
1275
                    doctype, parentId));
1276
            }
1277
            if (id == rootNodeId) {
1278
                String fullPath = '/' + path;
1279
                MetaCatUtil.debugMessage("C: " + fullPath +"\n", 60);
1280
                pathList.put(fullPath, new PathIndexEntry(leafNodeId, fullPath,
1281
                    docid, doctype, parentId));
1282
            }
1283
        }
1284
    }
1285

    
1286
    /**
1287
     * Delete the paths from the xml_index table on the database in preparation 
1288
     * of a subsequent update.
1289
     *
1290
     * @param conn the database connection to use, keeping a single transaction
1291
     * @throws SQLException if there is an error deleting from the db
1292
     */
1293
    private void deleteNodeIndex(DBConnection conn) throws SQLException
1294
    {
1295
        String familyId = MetaCatUtil.getDocIdFromString(docid);
1296
        String sql = "DELETE FROM xml_index WHERE docid LIKE ?";
1297
        MetaCatUtil.debugMessage(sql, 55);
1298
        MetaCatUtil.debugMessage("SQL is: " + sql, 60);
1299
        
1300
        PreparedStatement pstmt = conn.prepareStatement(sql);
1301

    
1302
        // Increase usage count for the connection
1303
        conn.increaseUsageCount(1);
1304
        
1305
        // Execute the delete and close the statement
1306
        pstmt.setString(1, familyId);
1307
        int rows = pstmt.executeUpdate();
1308
        pstmt.close();
1309
        MetaCatUtil.debugMessage("Deleted " + rows + " rows from xml_index " +
1310
            "for document " + docid, 55);
1311
    }
1312
    
1313
    /**
1314
	 * Insert the paths from the pathList into the xml_index table on the
1315
     * database.
1316
     *
1317
     * @param conn the database connection to use, keeping a single transaction
1318
     * @param pathList the hash of paths to insert
1319
     * @throws SQLException if there is an error inserting into the db
1320
     */
1321
    private void updateNodeIndex(DBConnection conn, HashMap pathList) 
1322
    	throws SQLException
1323
    {
1324
        // Create an insert statement to reuse for all of the path
1325
        // insertions
1326
        PreparedStatement pstmt = conn.prepareStatement(
1327
                "INSERT INTO xml_index (nodeid, path, docid, doctype, " +
1328
                "parentnodeid) " + "VALUES (?, ?, ?, ?, ?)");
1329
        // Increase usage count for the connection
1330
        conn.increaseUsageCount(1);
1331
        String familyId = MetaCatUtil.getDocIdFromString(docid);
1332
        pstmt.setString(3, familyId);
1333
        pstmt.setString(4, doctype);
1334
        
1335
        // Step through the hashtable and insert each of the path values
1336
        Iterator it = pathList.values().iterator();
1337
        while (it.hasNext()) {
1338
            PathIndexEntry entry = (PathIndexEntry)it.next();
1339
            MetaCatUtil.debugMessage("Inserting: " + entry.nodeId +
1340
                " (" + entry.parentId + "): " + entry.path, 60);
1341
            pstmt.setLong(1, entry.nodeId);
1342
            pstmt.setString(2, entry.path);
1343
            pstmt.setLong(5, entry.parentId);
1344
            pstmt.executeUpdate();
1345
        }
1346
        // Close the database statement
1347
        pstmt.close();
1348
    }
1349
    
1350
    private boolean isRevisionOnly(DocumentIdentifier docid) throws Exception
1351
    {
1352
        //System.out.println("inRevisionOnly");
1353
        DBConnection dbconn = null;
1354
        int serialNumber = -1;
1355
        PreparedStatement pstmt = null;
1356
        String rev = docid.getRev();
1357
        String newid = docid.getIdentifier();
1358
        try {
1359
            dbconn = DBConnectionPool
1360
                    .getDBConnection("DocumentImpl.isRevisionOnly");
1361
            serialNumber = dbconn.getCheckOutSerialNumber();
1362
            pstmt = dbconn.prepareStatement("select rev from xml_documents "
1363
                    + "where docid like '" + newid + "'");
1364
            pstmt.execute();
1365
            ResultSet rs = pstmt.getResultSet();
1366
            boolean tablehasrows = rs.next();
1367
            if (rev.equals("newest") || rev.equals("all")) { return false; }
1368

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

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

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

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

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

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

    
1450
            pstmt = dbconn.prepareStatement(sql.toString());
1451

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1622
        if (!nodeRecordList.isEmpty()) {
1623

    
1624
            return nodeRecordList;
1625
        } else {
1626

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

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

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

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

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

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

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

    
1701
        return nodeRecordList;
1702

    
1703
    }
1704

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

    
1711
        try {
1712
            PreparedStatement pstmt = null;
1713

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

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

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

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

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

    
1782
                    pstmt.execute();
1783
                    pstmt.close();
1784
                }
1785

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

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

    
1819
            // Do the insertion
1820
            pstmt.execute();
1821

    
1822
            pstmt.close();
1823

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

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

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

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

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

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

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

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

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

    
1990
            }
1991

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

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

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

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

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

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

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

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

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

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

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

    
2151
        // insert into xml_nodes table
2152
        XMLReader parser = null;
2153
        try {
2154

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

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

    
2189
        return (accnum);
2190
    }
2191

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

    
2236
            }
2237

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

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

    
2263
    }
2264

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

    
2310
    /**
2311
     * Delete an XML file from the database (actually, just make it a revision
2312
     * in the xml_revisions table)
2313
     *
2314
     * @param docid
2315
     *            the ID of the document to be deleted from the database
2316
     */
2317
    public static void delete(String accnum, String user, String[] groups, String notifyServer)
2318
            throws Exception
2319
    {
2320

    
2321
        DBConnection conn = null;
2322
        int serialNumber = -1;
2323
        PreparedStatement pstmt = null;
2324
        boolean isXML   = true;
2325
        try {
2326
            //check out DBConnection
2327
            conn = DBConnectionPool.getDBConnection("DocumentImpl.delete");
2328
            serialNumber = conn.getCheckOutSerialNumber();
2329

    
2330
            // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV
2331
            // IN IT
2332
            //AccessionNumber ac = new AccessionNumber(accnum, "DELETE");
2333
            String docid = MetaCatUtil.getDocIdFromAccessionNumber(accnum);
2334
            //String rev = ac.getRev();
2335

    
2336
            // get the type of deleting docid, this will be used in forcereplication
2337
            String type = getDocTypeFromDB(conn, docid);
2338
            if (type != null && type.trim().equals("BIN"))
2339
            {
2340
              isXML = false;
2341
            }
2342

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

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

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

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

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

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

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

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

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

    
2418
            try {
2419
                // close preparedStatement
2420
                if (pstmt != null) {
2421
                    pstmt.close();
2422
                }
2423
            }
2424
            finally {
2425
                //check in DBonnection
2426
                DBConnectionPool.returnDBConnection(conn, serialNumber);
2427
            }
2428
        }
2429
       // add force delete replcation document here.
2430
       ForceReplicationHandler frh = new ForceReplicationHandler(
2431
                        accnum, ForceReplicationHandler.DELETE, isXML, notifyServer);
2432
    }
2433

    
2434
    private static String getDocTypeFromDB(DBConnection conn, String docidWithoutRev)
2435
                                 throws SQLException
2436
    {
2437
      String type = null;
2438
      String sql = "SELECT DOCTYPE FROM xml_documents WHERE docid LIKE " + "'" +
2439
                    docidWithoutRev +"'";
2440
      Statement stmt = null;
2441
      stmt = conn.createStatement();
2442
      ResultSet result = stmt.executeQuery(sql);
2443
      boolean hasResult = result.next();
2444
      if (hasResult)
2445
      {
2446
        type = result.getString(1);
2447
      }
2448
      MetaCatUtil.debugMessage("The type of deleting docid " + docidWithoutRev +
2449
                               " is " + type, 2);
2450
      return type;
2451
    }
2452

    
2453
    /**
2454
     * Check for "WRITE" permission on @docid for @user and/or @groups
2455
     * from DB connection
2456
     */
2457
    private static boolean hasWritePermission(String user, String[] groups,
2458
            String docid) throws SQLException, Exception
2459
    {
2460
        // Check for WRITE permission on @docid for @user and/or @groups
2461
        PermissionController controller = new PermissionController(docid);
2462
        return controller.hasPermission(user, groups,
2463
                AccessControlInterface.WRITESTRING);
2464
    }
2465

    
2466
    /**
2467
     * Check for "READ" permission base on docid, user and group
2468
     *
2469
     * @param docid, the document
2470
     * @param user, user name
2471
     * @param groups, user's group
2472
     */
2473
    public static boolean hasReadPermission(String user, String[] groups,
2474
            String docId) throws SQLException, Exception
2475
    {
2476
        // Check for READ permission on @docid for @user and/or @groups
2477
        PermissionController controller = new PermissionController(docId);
2478
        return controller.hasPermission(user, groups,
2479
                AccessControlInterface.READSTRING);
2480
    }
2481

    
2482
    /**
2483
     * Check for "WRITE" permission on @docid for @user and/or @groups
2484
     * from DB connection
2485
     */
2486
    private static boolean hasAllPermission(String user, String[] groups,
2487
            String docid) throws SQLException, Exception
2488
    {
2489
        // Check for WRITE permission on @docid for @user and/or @groups
2490
        PermissionController controller = new PermissionController(docid);
2491
        return controller.hasPermission(user, groups,
2492
                AccessControlInterface.ALLSTRING);
2493
    }
2494

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

    
2570
                if (ruleBase != null && ruleBase.equals(SCHEMA)
2571
                        && needValidation) {
2572
                    MetaCatUtil.debugMessage("General schema parser", 20);
2573
                    // turn on schema validation feature
2574
                    parser.setFeature(VALIDATIONFEATURE, true);
2575
                    parser.setFeature(NAMESPACEFEATURE, true);
2576
                    //parser.setFeature(NAMESPACEPREFIXESFEATURE, true);
2577
                    parser.setFeature(SCHEMAVALIDATIONFEATURE, true);
2578
                    // From DB to find the register external schema location
2579
                    String externalSchemaLocation = null;
2580
                    SchemaLocationResolver resolver =
2581
                        new SchemaLocationResolver();
2582
                    externalSchemaLocation = resolver
2583
                            .getNameSpaceAndLocationString();
2584
                    // Set external schemalocation.
2585
                    if (externalSchemaLocation != null
2586
                            && !(externalSchemaLocation.trim()).equals("")) {
2587
                        parser.setProperty(EXTERNALSCHEMALOCATIONPROPERTY,
2588
                                externalSchemaLocation);
2589
                    }
2590

    
2591
                } else if (ruleBase != null && ruleBase.equals(DTD)
2592
                        && needValidation) {
2593
                    MetaCatUtil.debugMessage("dtd parser", 20);
2594
                    // turn on dtd validaton feature
2595
                    parser.setFeature(VALIDATIONFEATURE, true);
2596
                    eresolver = new DBEntityResolver(dbconn,
2597
                            (DBSAXHandler) chandler, dtd);
2598
                    dtdhandler = new DBDTDHandler(dbconn);
2599
                    parser.setEntityResolver((EntityResolver) eresolver);
2600
                    parser.setDTDHandler((DTDHandler) dtdhandler);
2601
                } else {
2602
                    MetaCatUtil.debugMessage("other parser", 20);
2603
                    // non validation
2604
                    parser.setFeature(VALIDATIONFEATURE, false);
2605
                    eresolver = new DBEntityResolver(dbconn,
2606
                            (DBSAXHandler) chandler, dtd);
2607
                    dtdhandler = new DBDTDHandler(dbconn);
2608
                    parser.setEntityResolver((EntityResolver) eresolver);
2609
                    parser.setDTDHandler((DTDHandler) dtdhandler);
2610
                }
2611
            }//else
2612
        } catch (Exception e) {
2613
            throw e;
2614
        }
2615
        return parser;
2616
    }
2617

    
2618
    /**
2619
     * Save a document entry in the xml_revisions table Connection use as a
2620
     * paramter is in order to rollback feature
2621
     */
2622
    private static void archiveDocRevision(DBConnection dbconn, String docid,
2623
            String user)
2624
    {
2625
        String sysdate = dbAdapter.getDateTimeFunction();
2626
        //DBConnection conn = null;
2627
        //int serialNumber = -1;
2628
        PreparedStatement pstmt = null;
2629

    
2630
        // create a record in xml_revisions table
2631
        // for that document as selected from xml_documents
2632

    
2633
        try {
2634
            //check out DBConnection
2635
            /*
2636
             * conn=DBConnectionPool.
2637
             * getDBConnection("DocumentImpl.archiveDocRevision");
2638
             * serialNumber=conn.getCheckOutSerialNumber();
2639
             */
2640
            pstmt = dbconn.prepareStatement("INSERT INTO xml_revisions "
2641
                    + "(docid, rootnodeid, docname, doctype, "
2642
                    + "user_owner, user_updated, date_created, date_updated, "
2643
                    + "server_location, rev, public_access, catalog_id) "
2644
                    + "SELECT ?, rootnodeid, docname, doctype, "
2645
                    + "user_owner, ?, " + sysdate + ", " + sysdate + ", "
2646
                    + "server_location, rev, public_access, catalog_id "
2647
                    + "FROM xml_documents " + "WHERE docid = ?");
2648
            // Increase dbconnection usage count
2649
            dbconn.increaseUsageCount(1);
2650
            // Bind the values to the query and execute it
2651
            pstmt.setString(1, docid);
2652
            pstmt.setString(2, user);
2653
            pstmt.setString(3, docid);
2654
            pstmt.execute();
2655
            pstmt.close();
2656
        } catch (SQLException e) {
2657
            MetaCatUtil.debugMessage(
2658
                    "Error in DocumentImpl.archiveDocRevision : "
2659
                            + e.getMessage(), 30);
2660
        } finally {
2661
            try {
2662
                pstmt.close();
2663
            } catch (SQLException ee) {
2664
                MetaCatUtil.debugMessage(
2665
                        "Error in DocumnetImpl.archiveDocRevision: "
2666
                                + ee.getMessage(), 50);
2667
            }
2668
        }
2669
    }
2670

    
2671
    /** Save a document entry in the xml_revisions table */
2672
    private static void archiveDocRevision(String docid, String user)
2673
    {
2674
        String sysdate = dbAdapter.getDateTimeFunction();
2675
        DBConnection conn = null;
2676
        int serialNumber = -1;
2677
        PreparedStatement pstmt = null;
2678

    
2679
        // create a record in xml_revisions table
2680
        // for that document as selected from xml_documents
2681

    
2682
        try {
2683
            //check out DBConnection
2684
            conn = DBConnectionPool
2685
                    .getDBConnection("DocumentImpl.archiveDocRevision");
2686
            serialNumber = conn.getCheckOutSerialNumber();
2687
            pstmt = conn.prepareStatement("INSERT INTO xml_revisions "
2688
                    + "(docid, rootnodeid, docname, doctype, "
2689
                    + "user_owner, user_updated, date_created, date_updated, "
2690
                    + "server_location, rev, public_access, catalog_id) "
2691
                    + "SELECT ?, rootnodeid, docname, doctype, "
2692
                    + "user_owner, ?, " + sysdate + ", " + sysdate + ", "
2693
                    + "server_location, rev, public_access, catalog_id "
2694
                    + "FROM xml_documents " + "WHERE docid = ?");
2695
            // Bind the values to the query and execute it
2696
            pstmt.setString(1, docid);
2697
            pstmt.setString(2, user);
2698
            pstmt.setString(3, docid);
2699
            pstmt.execute();
2700
            pstmt.close();
2701
        } catch (SQLException e) {
2702
            MetaCatUtil.debugMessage(
2703
                    "Error in DocumentImpl.archiveDocRevision : "
2704
                            + e.getMessage(), 30);
2705
        } finally {
2706
            try {
2707
                pstmt.close();
2708
            } catch (SQLException ee) {
2709
                MetaCatUtil.debugMessage(
2710
                        "Error in DocumnetImpl.archiveDocRevision: "
2711
                                + ee.getMessage(), 50);
2712
            } finally {
2713
                //check in DBConnection
2714
                DBConnectionPool.returnDBConnection(conn, serialNumber);
2715
            }
2716
        }
2717
    }
2718

    
2719
    /**
2720
     * delete a entry in xml_table for given docid
2721
     *
2722
     * @param docId,
2723
     *            the id of the document need to be delete
2724
     */
2725
    private static void deleteXMLDocuments(String docId) throws SQLException
2726
    {
2727
        DBConnection conn = null;
2728
        int serialNumber = -1;
2729
        PreparedStatement pStmt = null;
2730
        try {
2731
            //check out DBConnection
2732
            conn = DBConnectionPool
2733
                    .getDBConnection("DocumentImpl.deleteXMLDocuments");
2734
            serialNumber = conn.getCheckOutSerialNumber();
2735
            //delete a record
2736
            pStmt = conn.prepareStatement(
2737
                    "DELETE FROM xml_documents WHERE docid = '" + docId + "'");
2738
            pStmt.execute();
2739
        } finally {
2740
            try {
2741
                pStmt.close();
2742
            } catch (SQLException e) {
2743
                MetaCatUtil.debugMessage(
2744
                        "error in DocumentImpl.deleteXMLDocuments: "
2745
                                + e.getMessage(), 50);
2746
            } finally {
2747
                //return back DBconnection
2748
                DBConnectionPool.returnDBConnection(conn, serialNumber);
2749
            }
2750
        }
2751
    }
2752

    
2753
    /**
2754
     * Get last revision number from database for a docid If couldn't find an
2755
     * entry, -1 will return The return value is integer because we want compare
2756
     * it to there new one
2757
     *
2758
     * @param docid
2759
     *            <sitecode>. <uniqueid>part of Accession Number
2760
     */
2761
    public static int getLatestRevisionNumber(String docId) throws SQLException
2762
    {
2763
        int rev = 1;
2764
        PreparedStatement pStmt = null;
2765
        DBConnection dbConn = null;
2766
        int serialNumber = -1;
2767
        // get rid of rev
2768
        docId = MetaCatUtil.getDocIdFromString(docId);
2769
        try {
2770
            //check out DBConnection
2771
            dbConn = DBConnectionPool
2772
                    .getDBConnection("DocumentImpl.getLatestRevisionNumber");
2773
            serialNumber = dbConn.getCheckOutSerialNumber();
2774

    
2775
            pStmt = dbConn
2776
                    .prepareStatement("SELECT rev FROM xml_documents WHERE docid='"
2777
                            + docId + "'");
2778
            pStmt.execute();
2779

    
2780
            ResultSet rs = pStmt.getResultSet();
2781
            boolean hasRow = rs.next();
2782
            if (hasRow) {
2783
                rev = rs.getInt(1);
2784
                pStmt.close();
2785
            } else {
2786
                rev = -1;
2787
                pStmt.close();
2788
            }
2789
        }//try
2790
        finally {
2791
            try {
2792
                pStmt.close();
2793
            } catch (Exception ee) {
2794
                MetaCatUtil.debugMessage("Error in DocumentImpl."
2795
                        + "getLatestRevisionNumber: " + ee.getMessage(), 50);
2796
            } finally {
2797
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2798
            }
2799
        }//finally
2800

    
2801
        return rev;
2802
    }//getLatestRevisionNumber
2803

    
2804
    /**
2805
     * Get server location form database for a accNum
2806
     *
2807
     * @param accum
2808
     *            <sitecode>. <uniqueid>. <rev>
2809
     */
2810
    private static int getServerLocationNumber(String accNum)
2811
            throws SQLException
2812
    {
2813
        //get rid of revNum part
2814
        String docId = MetaCatUtil.getDocIdFromString(accNum);
2815
        PreparedStatement pStmt = null;
2816
        int serverLocation = 1;
2817
        DBConnection conn = null;
2818
        int serialNumber = -1;
2819

    
2820
        try {
2821
            //check out DBConnection
2822
            conn = DBConnectionPool
2823
                    .getDBConnection("DocumentImpl.getServerLocationNumber");
2824
            serialNumber = conn.getCheckOutSerialNumber();
2825

    
2826
            pStmt = conn
2827
                    .prepareStatement("SELECT server_location FROM xml_documents WHERE docid='"
2828
                            + docId + "'");
2829
            pStmt.execute();
2830

    
2831
            ResultSet rs = pStmt.getResultSet();
2832
            boolean hasRow = rs.next();
2833
            //if there is entry in xml_documents, get the serverlocation
2834
            if (hasRow) {
2835
                serverLocation = rs.getInt(1);
2836
                pStmt.close();
2837
            } else {
2838
                //if htere is no entry in xml_documents, we consider it is new
2839
                // document
2840
                //the server location is local host and value is 1
2841
                serverLocation = 1;
2842
                pStmt.close();
2843
            }
2844
        }//try
2845
        finally {
2846
            try {
2847
                pStmt.close();
2848
            }//try
2849
            catch (Exception ee) {
2850
                MetaCatUtil.debugMessage(
2851
                        "Error in DocumentImpl.getServerLocationNu(): "
2852
                                + ee.getMessage(), 50);
2853
            }//catch
2854
            finally {
2855
                DBConnectionPool.returnDBConnection(conn, serialNumber);
2856
            }//finally
2857
        }//finally
2858

    
2859
        return serverLocation;
2860
    }
2861

    
2862
    /**
2863
     * Given a server name, return its servercode in xml_replication table. If
2864
     * no server is found, -1 will return
2865
     *
2866
     * @param serverName,
2867
     */
2868
    private static int getServerCode(String serverName)
2869
    {
2870
        PreparedStatement pStmt = null;
2871
        int serverLocation = -2;
2872
        DBConnection dbConn = null;
2873
        int serialNumber = -1;
2874
        //MetaCatUtil util = new MetaCatUtil();
2875

    
2876
        //we should consider about local host too
2877
        if (serverName.equals(MetaCatUtil.getLocalReplicationServerName())) {
2878
            serverLocation = 1;
2879
            return serverLocation;
2880
        }
2881

    
2882
        try {
2883
            //check xml_replication table
2884
            //dbConn=util.openDBConnection();
2885
            //check out DBConnection
2886
            dbConn = DBConnectionPool
2887
                    .getDBConnection("DocumentImpl.getServerCode");
2888
            serialNumber = dbConn.getCheckOutSerialNumber();
2889
            pStmt = dbConn
2890
                    .prepareStatement("SELECT serverid FROM xml_replication WHERE server='"
2891
                            + serverName + "'");
2892
            pStmt.execute();
2893

    
2894
            ResultSet rs = pStmt.getResultSet();
2895
            boolean hasRow = rs.next();
2896
            //if there is entry in xml_replication, get the serverid
2897
            if (hasRow) {
2898
                serverLocation = rs.getInt(1);
2899
                pStmt.close();
2900
            } else {
2901
                // if htere is no entry in xml_replication, -1 will return
2902
                serverLocation = -1;
2903
                pStmt.close();
2904
            }
2905
        } catch (Exception e) {
2906
            MetaCatUtil.debugMessage("Error in DocumentImpl.getServerCode(): "
2907
                    + e.getMessage(), 30);
2908
        } finally {
2909
            try {
2910
                pStmt.close();
2911
            } catch (Exception ee) {
2912
                MetaCatUtil.debugMessage(
2913
                        "Error in DocumentImpl.getServerCode(): "
2914
                                + ee.getMessage(), 50);
2915
            } finally {
2916
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2917
            }
2918
        }
2919

    
2920
        return serverLocation;
2921
    }
2922

    
2923
    /**
2924
     * Insert a server into xml_replcation table
2925
     *
2926
     * @param server,
2927
     *            the name of server
2928
     */
2929
    private static synchronized void insertServerIntoReplicationTable(
2930
            String server)
2931
    {
2932
        PreparedStatement pStmt = null;
2933
        DBConnection dbConn = null;
2934
        int serialNumber = -1;
2935

    
2936
        // Initial value for the server
2937
        int replicate = 0;
2938
        int dataReplicate = 0;
2939
        int hub = 0;
2940

    
2941
        try {
2942
            // Get DBConnection
2943
            dbConn = DBConnectionPool
2944
                    .getDBConnection("DocumentImpl.insertServIntoReplicationTable");
2945
            serialNumber = dbConn.getCheckOutSerialNumber();
2946

    
2947
            // Compare the server to dabase
2948
            pStmt = dbConn
2949
                    .prepareStatement("SELECT serverid FROM xml_replication WHERE server='"
2950
                            + server + "'");
2951
            pStmt.execute();
2952
            ResultSet rs = pStmt.getResultSet();
2953
            boolean hasRow = rs.next();
2954
            // Close preparedstatement and result set
2955
            pStmt.close();
2956
            rs.close();
2957

    
2958
            // If the server is not in the table, and server is not local host,
2959
            // insert it
2960
            if (!hasRow
2961
                    && !server.equals(MetaCatUtil
2962
                            .getLocalReplicationServerName())) {
2963
                // Set auto commit false
2964
                dbConn.setAutoCommit(false);
2965
                /*
2966
                 * pStmt = dbConn.prepareStatement("INSERT INTO xml_replication " +
2967
                 * "(server, last_checked, replicate, datareplicate, hub) " +
2968
                 * "VALUES ('" + server + "', to_date(" + "'01/01/00',
2969
                 * 'MM/DD/YY'), '" + replicate +"', '"+dataReplicate+"','"+ hub +
2970
                 * "')");
2971
                 */
2972
                pStmt = dbConn
2973
                        .prepareStatement("INSERT INTO xml_replication "
2974
                                + "(server, last_checked, replicate, datareplicate, hub) "
2975
                                + "VALUES ('" + server + "', "
2976
                                + dbAdapter.toDate("01/01/1980", "MM/DD/YYYY")
2977
                                + ", '" + replicate + "', '" + dataReplicate
2978
                                + "','" + hub + "')");
2979

    
2980
                pStmt.execute();
2981
                dbConn.commit();
2982
                // Increase usage number
2983
                dbConn.increaseUsageCount(1);
2984
                pStmt.close();
2985

    
2986
            }
2987
        }//try
2988
        catch (Exception e) {
2989
            MetaCatUtil.debugMessage(
2990
                    "Error in DocumentImpl.insertServerIntoRepli(): "
2991
                            + e.getMessage(), 30);
2992
        }//catch
2993
        finally {
2994

    
2995
            try {
2996
                // Set auto commit true
2997
                dbConn.setAutoCommit(true);
2998
                pStmt.close();
2999

    
3000
            }//try
3001
            catch (Exception ee) {
3002
                MetaCatUtil.debugMessage(
3003
                        "Error in DocumentImpl.insetServerIntoRepl(): "
3004
                                + ee.getMessage(), 50);
3005
            }//catch
3006
            finally {
3007
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
3008
            }
3009

    
3010
        }//finally
3011

    
3012
    }
3013

    
3014
    /**
3015
     * the main routine used to test the DBWriter utility.
3016
     * <p>
3017
     * Usage: java DocumentImpl <-f filename -a action -d docid>
3018
     *
3019
     * @param filename
3020
     *            the filename to be loaded into the database
3021
     * @param action
3022
     *            the action to perform (READ, INSERT, UPDATE, DELETE)
3023
     * @param docid
3024
     *            the id of the document to process
3025
     */
3026
    static public void main(String[] args)
3027
    {
3028
        DBConnection dbconn = null;
3029
        int serialNumber = -1;
3030
        try {
3031
            String filename = null;
3032
            String dtdfilename = null;
3033
            String action = null;
3034
            String docid = null;
3035
            boolean showRuntime = false;
3036
            boolean useOldReadAlgorithm = false;
3037

    
3038
            // Parse the command line arguments
3039
            for (int i = 0; i < args.length; ++i) {
3040
                if (args[i].equals("-f")) {
3041
                    filename = args[++i];
3042
                } else if (args[i].equals("-r")) {
3043
                    dtdfilename = args[++i];
3044
                } else if (args[i].equals("-a")) {
3045
                    action = args[++i];
3046
                } else if (args[i].equals("-d")) {
3047
                    docid = args[++i];
3048
                } else if (args[i].equals("-t")) {
3049
                    showRuntime = true;
3050
                } else if (args[i].equals("-old")) {
3051
                    useOldReadAlgorithm = true;
3052
                } else {
3053
                    System.err.println("   args[" + i + "] '" + args[i]
3054
                            + "' ignored.");
3055
                }
3056
            }
3057

    
3058
            // Check if the required arguments are provided
3059
            boolean argsAreValid = false;
3060
            if (action != null) {
3061
                if (action.equals("INSERT")) {
3062
                    if (filename != null) {
3063
                        argsAreValid = true;
3064
                    }
3065
                } else if (action.equals("UPDATE")) {
3066
                    if ((filename != null) && (docid != null)) {
3067
                        argsAreValid = true;
3068
                    }
3069
                } else if (action.equals("DELETE")) {
3070
                    if (docid != null) {
3071
                        argsAreValid = true;
3072
                    }
3073
                } else if (action.equals("READ")) {
3074
                    if (docid != null) {
3075
                        argsAreValid = true;
3076
                    }
3077
                }
3078
            }
3079

    
3080
            // Print usage message if the arguments are not valid
3081
            if (!argsAreValid) {
3082
                System.err.println("Wrong number of arguments!!!");
3083
                System.err
3084
                        .println("USAGE: java DocumentImpl [-t] <-a INSERT> [-d docid] <-f filename> "
3085
                                + "[-r dtdfilename]");
3086
                System.err
3087
                        .println("   OR: java DocumentImpl [-t] <-a UPDATE -d docid -f filename> "
3088
                                + "[-r dtdfilename]");
3089
                System.err
3090
                        .println("   OR: java DocumentImpl [-t] <-a DELETE -d docid>");
3091
                System.err
3092
                        .println("   OR: java DocumentImpl [-t] [-old] <-a READ -d docid>");
3093
                return;
3094
            }
3095

    
3096
            // Time the request if asked for
3097
            double startTime = System.currentTimeMillis();
3098

    
3099
            // Open a connection to the database
3100
            MetaCatUtil util = new MetaCatUtil();
3101

    
3102
            dbconn = DBConnectionPool.getDBConnection("DocumentImpl.main");
3103
            serialNumber = dbconn.getCheckOutSerialNumber();
3104

    
3105
            double connTime = System.currentTimeMillis();
3106
            // Execute the action requested (READ, INSERT, UPDATE, DELETE)
3107
            if (action.equals("READ")) {
3108
                DocumentImpl xmldoc = new DocumentImpl(docid);
3109
                if (useOldReadAlgorithm) {
3110
                    System.out.println(xmldoc.readUsingSlowAlgorithm());
3111
                } else {
3112
                    xmldoc.toXml(new PrintWriter(System.out), null, null, true);
3113
                }
3114
            } else if (action.equals("DELETE")) {
3115
                DocumentImpl.delete(docid, null, null,null);
3116
                System.out.println("Document deleted: " + docid);
3117
            } else {
3118
                /*
3119
                 * String newdocid = DocumentImpl.write(dbconn, filename, null,
3120
                 * dtdfilename, action, docid, null, null); if ((docid != null) &&
3121
                 * (!docid.equals(newdocid))) { if (action.equals("INSERT")) {
3122
                 * System.out.println("New document ID generated!!! "); } else
3123
                 * if (action.equals("UPDATE")) { System.out.println("ERROR:
3124
                 * Couldn't update document!!! "); } } else if ((docid == null) &&
3125
                 * (action.equals("UPDATE"))) { System.out.println("ERROR:
3126
                 * Couldn't update document!!! "); }
3127
                 * System.out.println("Document processing finished for: " +
3128
                 * filename + " (" + newdocid + ")");
3129
                 */
3130
            }
3131

    
3132
            double stopTime = System.currentTimeMillis();
3133
            double dbOpenTime = (connTime - startTime) / 1000;
3134
            double insertTime = (stopTime - connTime) / 1000;
3135
            double executionTime = (stopTime - startTime) / 1000;
3136
            if (showRuntime) {
3137
                System.out.println("\n\nTotal Execution time was: "
3138
                        + executionTime + " seconds.");
3139
                System.out.println("Time to open DB connection was: "
3140
                        + dbOpenTime + " seconds.");
3141
                System.out.println("Time to insert document was: " + insertTime
3142
                        + " seconds.");
3143
            }
3144
            dbconn.close();
3145
        } catch (McdbException me) {
3146
            me.toXml(new PrintWriter(System.err));
3147
        } catch (AccessionNumberException ane) {
3148
            System.out.println(ane.getMessage());
3149
        } catch (Exception e) {
3150
            System.err.println("EXCEPTION HANDLING REQUIRED");
3151
            System.err.println(e.getMessage());
3152
            e.printStackTrace(System.err);
3153
        } finally {
3154
            // Return db connection
3155
            DBConnectionPool.returnDBConnection(dbconn, serialNumber);
3156
        }
3157
    }
3158
}
(31-31/63)