Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that searches a relational DB for elements and
4
 *             attributes that have free text matches a query string,
5
 *             or structured query matches to a path specified node in the
6
 *             XML hierarchy.  It returns a result set consisting of the
7
 *             document ID for each document that satisfies the query
8
 *  Copyright: 2000 Regents of the University of California and the
9
 *             National Center for Ecological Analysis and Synthesis
10
 *    Authors: Matt Jones
11
 *    Release: @release@
12
 *
13
 *   '$Author: jones $'
14
 *     '$Date: 2004-03-30 10:09:02 -0800 (Tue, 30 Mar 2004) $'
15
 * '$Revision: 2075 $'
16
 *
17
 * This program is free software; you can redistribute it and/or modify
18
 * it under the terms of the GNU General Public License as published by
19
 * the Free Software Foundation; either version 2 of the License, or
20
 * (at your option) any later version.
21
 *
22
 * This program is distributed in the hope that it will be useful,
23
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25
 * GNU General Public License for more details.
26
 *
27
 * You should have received a copy of the GNU General Public License
28
 * along with this program; if not, write to the Free Software
29
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
30
 */
31

    
32
package edu.ucsb.nceas.metacat;
33

    
34
import java.io.BufferedWriter;
35
import java.io.File;
36
import java.io.FileInputStream;
37
import java.io.FileReader;
38
import java.io.FileWriter;
39
import java.io.IOException;
40
import java.io.InputStream;
41
import java.io.Reader;
42
import java.io.StringReader;
43
import java.io.StringWriter;
44
import java.sql.PreparedStatement;
45
import java.sql.ResultSet;
46
import java.sql.SQLException;
47
import java.util.Enumeration;
48
import java.util.Hashtable;
49
import java.util.StringTokenizer;
50
import java.util.Vector;
51
import java.util.zip.ZipEntry;
52
import java.util.zip.ZipOutputStream;
53

    
54
import javax.servlet.ServletOutputStream;
55

    
56
import edu.ucsb.nceas.morpho.datapackage.Triple;
57
import edu.ucsb.nceas.morpho.datapackage.TripleCollection;
58

    
59
/**
60
 * A Class that searches a relational DB for elements and attributes that have
61
 * free text matches a query string, or structured query matches to a path
62
 * specified node in the XML hierarchy. It returns a result set consisting of
63
 * the document ID for each document that satisfies the query
64
 */
65
public class DBQuery
66
{
67

    
68
    static final int ALL = 1;
69

    
70
    static final int WRITE = 2;
71

    
72
    static final int READ = 4;
73

    
74
    //private Connection conn = null;
75
    private String parserName = null;
76

    
77
    private MetaCatUtil util = new MetaCatUtil();
78

    
79
    /**
80
     * the main routine used to test the DBQuery utility.
81
     * <p>
82
     * Usage: java DBQuery <xmlfile>
83
     * 
84
     * @param xmlfile the filename of the xml file containing the query
85
     */
86
    static public void main(String[] args)
87
    {
88

    
89
        if (args.length < 1) {
90
            System.err.println("Wrong number of arguments!!!");
91
            System.err.println("USAGE: java DBQuery [-t] [-index] <xmlfile>");
92
            return;
93
        } else {
94
            try {
95

    
96
                int i = 0;
97
                boolean showRuntime = false;
98
                boolean useXMLIndex = false;
99
                if (args[i].equals("-t")) {
100
                    showRuntime = true;
101
                    i++;
102
                }
103
                if (args[i].equals("-index")) {
104
                    useXMLIndex = true;
105
                    i++;
106
                }
107
                String xmlfile = args[i];
108

    
109
                // Time the request if asked for
110
                double startTime = System.currentTimeMillis();
111

    
112
                // Open a connection to the database
113
                MetaCatUtil util = new MetaCatUtil();
114
                //Connection dbconn = util.openDBConnection();
115

    
116
                double connTime = System.currentTimeMillis();
117

    
118
                // Execute the query
119
                DBQuery queryobj = new DBQuery(MetaCatUtil
120
                        .getOption("saxparser"));
121
                FileReader xml = new FileReader(new File(xmlfile));
122
                Hashtable nodelist = null;
123
                nodelist = queryobj.findDocuments(xml, null, null, useXMLIndex);
124

    
125
                // Print the reulting document listing
126
                StringBuffer result = new StringBuffer();
127
                String document = null;
128
                String docid = null;
129
                result.append("<?xml version=\"1.0\"?>\n");
130
                result.append("<resultset>\n");
131

    
132
                if (!showRuntime) {
133
                    Enumeration doclist = nodelist.keys();
134
                    while (doclist.hasMoreElements()) {
135
                        docid = (String) doclist.nextElement();
136
                        document = (String) nodelist.get(docid);
137
                        result.append("  <document>\n    " + document
138
                                + "\n  </document>\n");
139
                    }
140

    
141
                    result.append("</resultset>\n");
142
                }
143
                // Time the request if asked for
144
                double stopTime = System.currentTimeMillis();
145
                double dbOpenTime = (connTime - startTime) / 1000;
146
                double readTime = (stopTime - connTime) / 1000;
147
                double executionTime = (stopTime - startTime) / 1000;
148
                if (showRuntime) {
149
                    System.out.print("  " + executionTime);
150
                    System.out.print("  " + dbOpenTime);
151
                    System.out.print("  " + readTime);
152
                    System.out.print("  " + nodelist.size());
153
                    System.out.println();
154
                }
155
                //System.out.println(result);
156
                //write into a file "result.txt"
157
                if (!showRuntime) {
158
                    File f = new File("./result.txt");
159
                    FileWriter fw = new FileWriter(f);
160
                    BufferedWriter out = new BufferedWriter(fw);
161
                    out.write(result.toString());
162
                    out.flush();
163
                    out.close();
164
                    fw.close();
165
                }
166

    
167
            } catch (Exception e) {
168
                System.err.println("Error in DBQuery.main");
169
                System.err.println(e.getMessage());
170
                e.printStackTrace(System.err);
171
            }
172
        }
173
    }
174

    
175
    /**
176
     * construct an instance of the DBQuery class
177
     * 
178
     * <p>
179
     * Generally, one would call the findDocuments() routine after creating an
180
     * instance to specify the search query
181
     * </p>
182
     * 
183
     * @param conn the JDBC connection that we use for the query
184
     * @param parserName the fully qualified name of a Java class implementing
185
     *            the org.xml.sax.XMLReader interface
186
     */
187
    public DBQuery(String parserName) throws IOException, SQLException,
188
            ClassNotFoundException
189
    {
190
        //this.conn = conn;
191
        this.parserName = parserName;
192
    }
193

    
194
    /**
195
     * routine to search the elements and attributes looking to match query
196
     * 
197
     * @param xmlquery the xml serialization of the query (@see pathquery.dtd)
198
     * @param user the username of the user
199
     * @param group the group of the user
200
     */
201
    public Hashtable findDocuments(Reader xmlquery, String user, String[] groups)
202
    {
203
        boolean useXMLIndex = (new Boolean(MetaCatUtil.getOption("usexmlindex")))
204
                .booleanValue();
205
        return findDocuments(xmlquery, user, groups, useXMLIndex);
206
    }
207

    
208
    /**
209
     * routine to search the elements and attributes looking to match query
210
     * 
211
     * @param xmlquery the xml serialization of the query (@see pathquery.dtd)
212
     * @param user the username of the user
213
     * @param group the group of the user
214
     * @param useXMLIndex flag whether to search using the path index
215
     */
216
    public Hashtable findDocuments(Reader xmlquery, String user,
217
            String[] groups, boolean useXMLIndex)
218
    {
219
        Hashtable result = new Hashtable();
220
        try {
221
            // Get the XML query and covert it into a SQL statment
222
            QuerySpecification qspec = new QuerySpecification(xmlquery,
223
                    parserName, MetaCatUtil.getOption("accNumSeparator"));
224
            result = findDocuments(qspec, user, groups, useXMLIndex);
225
        } catch (IOException ioe) {
226
            MetaCatUtil.debugMessage("IO error in DBQuery.findDocuments:", 30);
227
            MetaCatUtil.debugMessage(ioe.getMessage(), 30);
228
        }
229
        return result;
230
    }
231

    
232
    /**
233
     * routine to search the elements and attributes looking to match query
234
     * 
235
     * @param qspec java object of the query
236
     * @param user the username of the user
237
     * @param group the group of the user
238
     * @param useXMLIndex flag whether to search using the path index
239
     */
240
    public Hashtable findDocuments(QuerySpecification qspec, String user,
241
            String[] groups, boolean useXMLIndex)
242
    {
243
        Hashtable docListResult = new Hashtable();
244
        PreparedStatement pstmt = null;
245
        String docid = null;
246
        String docname = null;
247
        String doctype = null;
248
        String createDate = null;
249
        String updateDate = null;
250
        String fieldname = null;
251
        String fielddata = null;
252
        String relation = null;
253
        //Connection dbconn = null;
254
        //Connection dbconn2 = null;
255
        int rev = 0;
256
        StringBuffer document = null;
257
        DBConnection dbconn = null;
258
        int serialNumber = -1;
259

    
260
        try {
261

    
262
            dbconn = DBConnectionPool.getDBConnection("DBQuery.findDocuments");
263
            serialNumber = dbconn.getCheckOutSerialNumber();
264

    
265
            String query = qspec.printSQL(useXMLIndex);
266
            String ownerQuery = getOwnerQuery(user);
267
            MetaCatUtil.debugMessage("query: " + query, 30);
268
            //MetaCatUtil.debugMessage("query: "+ownerQuery, 30);
269
            // if query is not the owner query, we need to check the permission
270
            // otherwise we don't need (owner has all permission by default)
271
            if (!query.equals(ownerQuery)) {
272
                // set user name and group
273
                qspec.setUserName(user);
274
                qspec.setGroup(groups);
275
                // Get access query
276
                String accessQuery = qspec.getAccessQuery();
277
                query = query + accessQuery;
278
                MetaCatUtil.debugMessage(" final query: " + query, 30);
279
            }
280

    
281
            double startTime = System.currentTimeMillis() / 1000;
282
            pstmt = dbconn.prepareStatement(query);
283

    
284
            // Execute the SQL query using the JDBC connection
285
            pstmt.execute();
286
            ResultSet rs = pstmt.getResultSet();
287
            double queryExecuteTime = System.currentTimeMillis() / 1000;
288
            MetaCatUtil.debugMessage("Time for execute query: "
289
                    + (queryExecuteTime - startTime), 30);
290
            boolean tableHasRows = rs.next();
291
            while (tableHasRows) {
292
                docid = rs.getString(1).trim();
293
                //long checkTimeStart = System.currentTimeMillis();
294
                //boolean permit =hasPermission(user, groups, docid);
295
                //long checkTimeEnd = System.currentTimeMillis();
296
                //MetaCatUtil.debugMessage("check permission time: "+
297
                //(checkTimeEnd - checkTimeStart), 30);
298
                //if ( !permit ) {
299
                // Advance to the next record in the cursor
300
                //tableHasRows = rs.next();
301
                //continue;
302
                //}
303

    
304
                docname = rs.getString(2);
305
                doctype = rs.getString(3);
306
                createDate = rs.getString(4);
307
                updateDate = rs.getString(5);
308
                rev = rs.getInt(6);
309

    
310
                // if there are returndocs to match, backtracking can be
311
                // performed
312
                // otherwise, just return the document that was hit
313
                Vector returndocVec = qspec.getReturnDocList();
314
                if (returndocVec.size() != 0 && !returndocVec.contains(doctype)
315
                        && !qspec.isPercentageSearch()) {
316
                    MetaCatUtil.debugMessage("Back tracing now...", 20);
317
                    String sep = MetaCatUtil.getOption("accNumSeparator");
318
                    StringBuffer btBuf = new StringBuffer();
319
                    btBuf.append("select docid from xml_relation where ");
320

    
321
                    //build the doctype list for the backtracking sql
322
                    // statement
323
                    btBuf.append("packagetype in (");
324
                    for (int i = 0; i < returndocVec.size(); i++) {
325
                        btBuf.append("'").append((String) returndocVec.get(i))
326
                                .append("'");
327
                        if (i != (returndocVec.size() - 1)) {
328
                            btBuf.append(", ");
329
                        }
330
                    }
331
                    btBuf.append(") ");
332

    
333
                    btBuf.append("and (subject like '");
334
                    btBuf.append(docid).append("'");
335
                    btBuf.append("or object like '");
336
                    btBuf.append(docid).append("')");
337

    
338
                    PreparedStatement npstmt = dbconn.prepareStatement(btBuf
339
                            .toString());
340
                    //should incease usage count
341
                    dbconn.increaseUsageCount(1);
342
                    npstmt.execute();
343
                    ResultSet btrs = npstmt.getResultSet();
344
                    boolean hasBtRows = btrs.next();
345
                    while (hasBtRows) { //there was a backtrackable document
346
                                        // found
347
                        DocumentImpl xmldoc = null;
348
                        String packageDocid = btrs.getString(1);
349
                        MetaCatUtil.debugMessage("Getting document for docid: "
350
                                + packageDocid, 40);
351
                        try {
352
                            //  THIS CONSTRUCTOR BUILDS THE WHOLE XML doc not
353
                            // needed here
354
                            // xmldoc = new DocumentImpl(dbconn, packageDocid);
355
                            //  thus use the following to get the doc info only
356
                            //  xmldoc = new DocumentImpl(dbconn);
357
                            xmldoc = new DocumentImpl(packageDocid, false);
358
                            if (xmldoc == null) {
359
                                MetaCatUtil.debugMessage(
360
                                        "Document was null for: "
361
                                                + packageDocid, 50);
362
                            }
363
                        } catch (Exception e) {
364
                            System.out.println("Error getting document in "
365
                                    + "DBQuery.findDocuments: "
366
                                    + e.getMessage());
367
                        }
368

    
369
                        String docid_org = xmldoc.getDocID();
370
                        if (docid_org == null) {
371
                            MetaCatUtil.debugMessage("Docid_org was null.", 40);
372
                        }
373
                        docid = docid_org.trim();
374
                        docname = xmldoc.getDocname();
375
                        doctype = xmldoc.getDoctype();
376
                        createDate = xmldoc.getCreateDate();
377
                        updateDate = xmldoc.getUpdateDate();
378
                        rev = xmldoc.getRev();
379

    
380
                        document = new StringBuffer();
381

    
382
                        String completeDocid = docid
383
                                + MetaCatUtil.getOption("accNumSeparator");
384
                        completeDocid += rev;
385
                        document.append("<docid>").append(completeDocid);
386
                        document.append("</docid>");
387
                        if (docname != null) {
388
                            document.append("<docname>" + docname
389
                                    + "</docname>");
390
                        }
391
                        if (doctype != null) {
392
                            document.append("<doctype>" + doctype
393
                                    + "</doctype>");
394
                        }
395
                        if (createDate != null) {
396
                            document.append("<createdate>" + createDate
397
                                    + "</createdate>");
398
                        }
399
                        if (updateDate != null) {
400
                            document.append("<updatedate>" + updateDate
401
                                    + "</updatedate>");
402
                        }
403
                        // Store the document id and the root node id
404
                        docListResult.put(docid, (String) document.toString());
405

    
406
                        // Get the next package document linked to our hit
407
                        hasBtRows = btrs.next();
408
                    }
409
                    npstmt.close();
410
                    btrs.close();
411
                } else if (returndocVec.size() != 0
412
                        && returndocVec.contains(doctype)) {
413

    
414
                    document = new StringBuffer();
415

    
416
                    String completeDocid = docid
417
                            + MetaCatUtil.getOption("accNumSeparator");
418
                    completeDocid += rev;
419
                    document.append("<docid>").append(completeDocid).append(
420
                            "</docid>");
421
                    if (docname != null) {
422
                        document.append("<docname>" + docname + "</docname>");
423
                    }
424
                    if (doctype != null) {
425
                        document.append("<doctype>" + doctype + "</doctype>");
426
                    }
427
                    if (createDate != null) {
428
                        document.append("<createdate>" + createDate
429
                                + "</createdate>");
430
                    }
431
                    if (updateDate != null) {
432
                        document.append("<updatedate>" + updateDate
433
                                + "</updatedate>");
434
                    }
435
                    // Store the document id and the root node id
436
                    docListResult.put(docid, (String) document.toString());
437

    
438
                }
439

    
440
                // Advance to the next record in the cursor
441
                tableHasRows = rs.next();
442
            }
443
            rs.close();
444
            pstmt.close();
445
            double docListTime = System.currentTimeMillis() / 1000;
446
            MetaCatUtil.debugMessage("prepare docid list time: "
447
                    + (docListTime - queryExecuteTime), 30);
448

    
449
            if (qspec.containsExtendedSQL()) {
450
                Vector extendedFields = new Vector(qspec.getReturnFieldList());
451
                Vector results = new Vector();
452
                Enumeration keylist = docListResult.keys();
453
                StringBuffer doclist = new StringBuffer();
454
                Vector parentidList = new Vector();
455
                Hashtable returnFieldValue = new Hashtable();
456
                while (keylist.hasMoreElements()) {
457
                    doclist.append("'");
458
                    doclist.append((String) keylist.nextElement());
459
                    doclist.append("',");
460
                }
461
                if (doclist.length() > 0) {
462
                    Hashtable controlPairs = new Hashtable();
463
                    double extendedQueryStart = System.currentTimeMillis() / 1000;
464
                    doclist.deleteCharAt(doclist.length() - 1); //remove the
465
                                                                // last comma
466
                    // check if user has permission to see the return field
467
                    // data
468
                    String accessControlSQL = qspec
469
                            .printAccessControlSQLForReturnField(doclist
470
                                    .toString());
471
                    pstmt = dbconn.prepareStatement(accessControlSQL);
472
                    //increase dbconnection usage count
473
                    dbconn.increaseUsageCount(1);
474
                    pstmt.execute();
475
                    rs = pstmt.getResultSet();
476
                    tableHasRows = rs.next();
477
                    while (tableHasRows) {
478
                        long startNodeId = rs.getLong(1);
479
                        long endNodeId = rs.getLong(2);
480
                        controlPairs.put(new Long(startNodeId), new Long(
481
                                endNodeId));
482
                        tableHasRows = rs.next();
483
                    }
484

    
485
                    double extendedAccessQueryEnd = System.currentTimeMillis() / 1000;
486
                    MetaCatUtil
487
                            .debugMessage(
488
                                    "Time for execute access extended query: "
489
                                            + (extendedAccessQueryEnd - extendedQueryStart),
490
                                    30);
491

    
492
                    String extendedQuery = qspec.printExtendedSQL(doclist
493
                            .toString(), controlPairs, useXMLIndex);
494
                    MetaCatUtil.debugMessage(
495
                            "Extended query: " + extendedQuery, 30);
496
                    pstmt = dbconn.prepareStatement(extendedQuery);
497
                    //increase dbconnection usage count
498
                    dbconn.increaseUsageCount(1);
499
                    pstmt.execute();
500
                    rs = pstmt.getResultSet();
501
                    double extendedQueryEnd = System.currentTimeMillis() / 1000;
502
                    MetaCatUtil.debugMessage(
503
                            "Time for execute extended query: "
504
                                    + (extendedQueryEnd - extendedQueryStart),
505
                            30);
506
                    tableHasRows = rs.next();
507
                    while (tableHasRows) {
508
                        ReturnFieldValue returnValue = new ReturnFieldValue();
509
                        docid = rs.getString(1).trim();
510
                        fieldname = rs.getString(2);
511
                        fielddata = rs.getString(3);
512
                        fielddata = MetaCatUtil.normalize(fielddata);
513

    
514
                        String parentId = rs.getString(4);
515

    
516
                        StringBuffer value = new StringBuffer();
517
                        if (!containsKey(parentidList, parentId)) {
518
                            // don't need to merger nodedata
519
                            value.append("<param name=\"");
520
                            value.append(fieldname);
521
                            value.append("\">");
522
                            value.append(fielddata);
523
                            value.append("</param>");
524
                            //set returnvalue
525
                            returnValue.setDocid(docid);
526
                            returnValue.setFieldValue(fielddata);
527
                            returnValue.setXMLFieldValue(value.toString());
528
                            // Store it in hastable
529
                            putInArray(parentidList, parentId, returnValue);
530
                        } else {
531
                            // need to merge nodedata if they have same parent
532
                            // id ant
533
                            // node type is text
534
                            fielddata = (String) ((ReturnFieldValue) getArrayValue(
535
                                    parentidList, parentId)).getFieldValue()
536
                                    + fielddata;
537
                            value.append("<param name=\"");
538
                            value.append(fieldname);
539
                            value.append("\">");
540
                            value.append(fielddata);
541
                            value.append("</param>");
542
                            returnValue.setDocid(docid);
543
                            returnValue.setFieldValue(fielddata);
544
                            returnValue.setXMLFieldValue(value.toString());
545
                            // remove the old return value from paretnidList
546
                            parentidList.remove(parentId);
547
                            // store the new return value in parentidlit
548
                            putInArray(parentidList, parentId, returnValue);
549
                        }
550
                        tableHasRows = rs.next();
551
                    }//while
552
                    rs.close();
553
                    pstmt.close();
554

    
555
                    // put the merger node data info into doclistReult
556
                    Enumeration xmlFieldValue = (getElements(parentidList))
557
                            .elements();
558
                    while (xmlFieldValue.hasMoreElements()) {
559
                        ReturnFieldValue object = (ReturnFieldValue) xmlFieldValue
560
                                .nextElement();
561
                        docid = object.getDocid();
562
                        if (docListResult.containsKey(docid)) {
563
                            String removedelement = (String) docListResult
564
                                    .remove(docid);
565
                            docListResult.put(docid, removedelement
566
                                    + object.getXMLFieldValue());
567
                        } else {
568
                            docListResult.put(docid, object.getXMLFieldValue());
569
                        }
570
                    }//while
571
                    double docListResultEnd = System.currentTimeMillis() / 1000;
572
                    MetaCatUtil
573
                            .debugMessage(
574
                                    "Time for prepare doclistresult after"
575
                                            + " execute extended query: "
576
                                            + (docListResultEnd - extendedQueryEnd),
577
                                    30);
578

    
579
                    // get attribures return
580
                    docListResult = getAttributeValueForReturn(qspec,
581
                            docListResult, doclist.toString(), useXMLIndex);
582
                }//if doclist lenght is great than zero
583

    
584
            }//if has extended query
585

    
586
            //this loop adds the relation data to the resultdoc
587
            //this code might be able to be added to the backtracking code
588
            // above
589
            double startRelation = System.currentTimeMillis() / 1000;
590
            Enumeration docidkeys = docListResult.keys();
591
            while (docidkeys.hasMoreElements()) {
592
                //String connstring =
593
                // "metacat://"+util.getOption("server")+"?docid=";
594
                String connstring = "%docid=";
595
                String docidkey = (String) docidkeys.nextElement();
596
                pstmt = dbconn.prepareStatement(QuerySpecification
597
                        .printRelationSQL(docidkey));
598
                pstmt.execute();
599
                rs = pstmt.getResultSet();
600
                tableHasRows = rs.next();
601
                while (tableHasRows) {
602
                    String sub = rs.getString(1);
603
                    String rel = rs.getString(2);
604
                    String obj = rs.getString(3);
605
                    String subDT = rs.getString(4);
606
                    String objDT = rs.getString(5);
607

    
608
                    document = new StringBuffer();
609
                    document.append("<triple>");
610
                    document.append("<subject>").append(
611
                            MetaCatUtil.normalize(sub));
612
                    document.append("</subject>");
613
                    if (subDT != null) {
614
                        document.append("<subjectdoctype>").append(subDT);
615
                        document.append("</subjectdoctype>");
616
                    }
617
                    document.append("<relationship>").append(
618
                            MetaCatUtil.normalize(rel));
619
                    document.append("</relationship>");
620
                    document.append("<object>").append(
621
                            MetaCatUtil.normalize(obj));
622
                    document.append("</object>");
623
                    if (objDT != null) {
624
                        document.append("<objectdoctype>").append(objDT);
625
                        document.append("</objectdoctype>");
626
                    }
627
                    document.append("</triple>");
628

    
629
                    String removedelement = (String) docListResult
630
                            .remove(docidkey);
631
                    docListResult.put(docidkey, removedelement
632
                            + document.toString());
633
                    tableHasRows = rs.next();
634
                }
635
                rs.close();
636
                pstmt.close();
637
            }
638
            double endRelation = System.currentTimeMillis() / 1000;
639
            MetaCatUtil.debugMessage(
640
                    "Time for adding relation to docListResult: "
641
                            + (endRelation - startRelation), 30);
642

    
643
        } catch (SQLException e) {
644
            System.err.println("SQL Error in DBQuery.findDocuments: "
645
                    + e.getMessage());
646
        } catch (Exception ee) {
647
            System.err.println("Exception in DBQuery.findDocuments: "
648
                    + ee.getMessage());
649
            ee.printStackTrace(System.err);
650
        } finally {
651
            try {
652
                pstmt.close();
653
            }//try
654
            catch (SQLException sqlE) {
655
                MetaCatUtil.debugMessage("Error in DBQuery.findDocuments: "
656
                        + sqlE.getMessage(), 30);
657
            }//catch
658
            finally {
659
                DBConnectionPool.returnDBConnection(dbconn, serialNumber);
660
            }//finally
661
        }//finally
662
        //System.out.println("docListResult: ");
663
        //System.out.println(docListResult.toString());
664
        return docListResult;
665
    }
666

    
667
    /*
668
     * A method to search if Vector contains a particular key string
669
     */
670
    private boolean containsKey(Vector parentidList, String parentId)
671
    {
672

    
673
        Vector tempVector = null;
674

    
675
        for (int count = 0; count < parentidList.size(); count++) {
676
            tempVector = (Vector) parentidList.get(count);
677
            if (parentId.compareTo((String) tempVector.get(0)) == 0) { return false; }
678
        }
679
        return false;
680
    }
681

    
682
    /*
683
     * A method to put key and value in Vector
684
     */
685
    private void putInArray(Vector parentidList, String key,
686
            ReturnFieldValue value)
687
    {
688

    
689
        Vector tempVector = null;
690

    
691
        for (int count = 0; count < parentidList.size(); count++) {
692
            tempVector = (Vector) parentidList.get(count);
693

    
694
            if (key.compareTo((String) tempVector.get(0)) == 0) {
695
                tempVector.remove(1);
696
                tempVector.add(1, value);
697
                return;
698
            }
699
        }
700

    
701
        tempVector = new Vector();
702
        tempVector.add(0, key);
703
        tempVector.add(1, value);
704
        parentidList.add(tempVector);
705
        return;
706
    }
707

    
708
    /*
709
     * A method to get value in Vector given a key
710
     */
711
    private ReturnFieldValue getArrayValue(Vector parentidList, String key)
712
    {
713

    
714
        Vector tempVector = null;
715

    
716
        for (int count = 0; count < parentidList.size(); count++) {
717
            tempVector = (Vector) parentidList.get(count);
718

    
719
            if (key.compareTo((String) tempVector.get(0)) == 0) { return (ReturnFieldValue) tempVector
720
                    .get(1); }
721
        }
722
        return null;
723
    }
724

    
725
    /*
726
     * A method to get enumeration of all values in Vector
727
     */
728
    private Vector getElements(Vector parentidList)
729
    {
730
        Vector enum = new Vector();
731
        Vector tempVector = null;
732

    
733
        for (int count = 0; count < parentidList.size(); count++) {
734
            tempVector = (Vector) parentidList.get(count);
735

    
736
            enum.add(tempVector.get(1));
737
        }
738
        return enum;
739
    }
740

    
741
    /*
742
     * A method to return search result after running a query which return
743
     * field have attribue
744
     */
745
    private Hashtable getAttributeValueForReturn(QuerySpecification squery,
746
            Hashtable docInformationList, String docList, boolean useXMLIndex)
747
    {
748
        StringBuffer XML = null;
749
        String sql = null;
750
        DBConnection dbconn = null;
751
        PreparedStatement pstmt = null;
752
        ResultSet rs = null;
753
        int serialNumber = -1;
754
        boolean tableHasRows = false;
755

    
756
        //check the parameter
757
        if (squery == null || docList == null || docList.length() < 0) { return docInformationList; }
758

    
759
        // if has attribute as return field
760
        if (squery.containAttributeReturnField()) {
761
            sql = squery.printAttributeQuery(docList, useXMLIndex);
762
            try {
763
                dbconn = DBConnectionPool
764
                        .getDBConnection("DBQuery.getAttributeValue");
765
                serialNumber = dbconn.getCheckOutSerialNumber();
766
                pstmt = dbconn.prepareStatement(sql);
767
                pstmt.execute();
768
                rs = pstmt.getResultSet();
769
                tableHasRows = rs.next();
770
                while (tableHasRows) {
771
                    String docid = rs.getString(1).trim();
772
                    String fieldname = rs.getString(2);
773
                    String fielddata = rs.getString(3);
774
                    String attirbuteName = rs.getString(4);
775
                    XML = new StringBuffer();
776

    
777
                    XML.append("<param name=\"");
778
                    XML.append(fieldname);
779
                    XML.append(QuerySpecification.ATTRIBUTESYMBOL);
780
                    XML.append(attirbuteName);
781
                    XML.append("\">");
782
                    XML.append(fielddata);
783
                    XML.append("</param>");
784
                    tableHasRows = rs.next();
785

    
786
                    if (docInformationList.containsKey(docid)) {
787
                        String removedelement = (String) docInformationList
788
                                .remove(docid);
789
                        docInformationList.put(docid, removedelement
790
                                + XML.toString());
791
                    } else {
792
                        docInformationList.put(docid, XML.toString());
793
                    }
794
                }//while
795
                rs.close();
796
                pstmt.close();
797
            } catch (Exception se) {
798
                MetaCatUtil.debugMessage(
799
                        "Error in DBQuery.getAttributeValue1: "
800
                                + se.getMessage(), 30);
801
            } finally {
802
                try {
803
                    pstmt.close();
804
                }//try
805
                catch (SQLException sqlE) {
806
                    MetaCatUtil.debugMessage(
807
                            "Error in DBQuery.getAttributeValue2: "
808
                                    + sqlE.getMessage(), 30);
809
                }//catch
810
                finally {
811
                    DBConnectionPool.returnDBConnection(dbconn, serialNumber);
812
                }//finally
813
            }//finally
814
        }//if
815
        return docInformationList;
816

    
817
    }
818

    
819
    /*
820
     * A method to create a query to get owner's docid list
821
     */
822
    private String getOwnerQuery(String owner)
823
    {
824
        if (owner != null) {
825
            owner = owner.toLowerCase();
826
        }
827
        StringBuffer self = new StringBuffer();
828

    
829
        self.append("SELECT docid,docname,doctype,");
830
        self.append("date_created, date_updated, rev ");
831
        self.append("FROM xml_documents WHERE docid IN (");
832
        self.append("(");
833
        self.append("SELECT DISTINCT docid FROM xml_nodes WHERE \n");
834
        self.append("nodedata LIKE '%%%' ");
835
        self.append(") \n");
836
        self.append(") ");
837
        self.append(" AND (");
838
        self.append(" lower(user_owner) = '" + owner + "'");
839
        self.append(") ");
840
        return self.toString();
841
    }
842

    
843
    /**
844
     * format a structured query as an XML document that conforms to the
845
     * pathquery.dtd and is appropriate for submission to the DBQuery
846
     * structured query engine
847
     * 
848
     * @param params The list of parameters that should be included in the
849
     *            query
850
     */
851
    public static String createSQuery(Hashtable params)
852
    {
853
        StringBuffer query = new StringBuffer();
854
        Enumeration elements;
855
        Enumeration keys;
856
        String filterDoctype = null;
857
        String casesensitive = null;
858
        String searchmode = null;
859
        Object nextkey;
860
        Object nextelement;
861
        //add the xml headers
862
        query.append("<?xml version=\"1.0\"?>\n");
863
        query.append("<pathquery version=\"1.0\">\n");
864

    
865
        if (params.containsKey("meta_file_id")) {
866
            query.append("<meta_file_id>");
867
            query.append(((String[]) params.get("meta_file_id"))[0]);
868
            query.append("</meta_file_id>");
869
        }
870

    
871
        if (params.containsKey("returndoctype")) {
872
            String[] returnDoctypes = ((String[]) params.get("returndoctype"));
873
            for (int i = 0; i < returnDoctypes.length; i++) {
874
                String doctype = (String) returnDoctypes[i];
875

    
876
                if (!doctype.equals("any") && !doctype.equals("ANY")
877
                        && !doctype.equals("")) {
878
                    query.append("<returndoctype>").append(doctype);
879
                    query.append("</returndoctype>");
880
                }
881
            }
882
        }
883

    
884
        if (params.containsKey("filterdoctype")) {
885
            String[] filterDoctypes = ((String[]) params.get("filterdoctype"));
886
            for (int i = 0; i < filterDoctypes.length; i++) {
887
                query.append("<filterdoctype>").append(filterDoctypes[i]);
888
                query.append("</filterdoctype>");
889
            }
890
        }
891

    
892
        if (params.containsKey("returnfield")) {
893
            String[] returnfield = ((String[]) params.get("returnfield"));
894
            for (int i = 0; i < returnfield.length; i++) {
895
                query.append("<returnfield>").append(returnfield[i]);
896
                query.append("</returnfield>");
897
            }
898
        }
899

    
900
        if (params.containsKey("owner")) {
901
            String[] owner = ((String[]) params.get("owner"));
902
            for (int i = 0; i < owner.length; i++) {
903
                query.append("<owner>").append(owner[i]);
904
                query.append("</owner>");
905
            }
906
        }
907

    
908
        if (params.containsKey("site")) {
909
            String[] site = ((String[]) params.get("site"));
910
            for (int i = 0; i < site.length; i++) {
911
                query.append("<site>").append(site[i]);
912
                query.append("</site>");
913
            }
914
        }
915

    
916
        //allows the dynamic switching of boolean operators
917
        if (params.containsKey("operator")) {
918
            query.append("<querygroup operator=\""
919
                    + ((String[]) params.get("operator"))[0] + "\">");
920
        } else { //the default operator is UNION
921
            query.append("<querygroup operator=\"UNION\">");
922
        }
923

    
924
        if (params.containsKey("casesensitive")) {
925
            casesensitive = ((String[]) params.get("casesensitive"))[0];
926
        } else {
927
            casesensitive = "false";
928
        }
929

    
930
        if (params.containsKey("searchmode")) {
931
            searchmode = ((String[]) params.get("searchmode"))[0];
932
        } else {
933
            searchmode = "contains";
934
        }
935

    
936
        //anyfield is a special case because it does a
937
        //free text search. It does not have a <pathexpr>
938
        //tag. This allows for a free text search within the structured
939
        //query. This is useful if the INTERSECT operator is used.
940
        if (params.containsKey("anyfield")) {
941
            String[] anyfield = ((String[]) params.get("anyfield"));
942
            //allow for more than one value for anyfield
943
            for (int i = 0; i < anyfield.length; i++) {
944
                if (!anyfield[i].equals("")) {
945
                    query.append("<queryterm casesensitive=\"" + casesensitive
946
                            + "\" " + "searchmode=\"" + searchmode
947
                            + "\"><value>" + anyfield[i]
948
                            + "</value></queryterm>");
949
                }
950
            }
951
        }
952

    
953
        //this while loop finds the rest of the parameters
954
        //and attempts to query for the field specified
955
        //by the parameter.
956
        elements = params.elements();
957
        keys = params.keys();
958
        while (keys.hasMoreElements() && elements.hasMoreElements()) {
959
            nextkey = keys.nextElement();
960
            nextelement = elements.nextElement();
961

    
962
            //make sure we aren't querying for any of these
963
            //parameters since the are already in the query
964
            //in one form or another.
965
            Vector ignoredParams = new Vector();
966
            ignoredParams.add("returndoctype");
967
            ignoredParams.add("filterdoctype");
968
            ignoredParams.add("action");
969
            ignoredParams.add("qformat");
970
            ignoredParams.add("anyfield");
971
            ignoredParams.add("returnfield");
972
            ignoredParams.add("owner");
973
            ignoredParams.add("site");
974
            ignoredParams.add("operator");
975

    
976
            // Also ignore parameters listed in the properties file
977
            // so that they can be passed through to stylesheets
978
            String paramsToIgnore = MetaCatUtil
979
                    .getOption("query.ignored.params");
980
            StringTokenizer st = new StringTokenizer(paramsToIgnore, ",");
981
            while (st.hasMoreTokens()) {
982
                ignoredParams.add(st.nextToken());
983
            }
984
            if (!ignoredParams.contains(nextkey.toString())) {
985
                //allow for more than value per field name
986
                for (int i = 0; i < ((String[]) nextelement).length; i++) {
987
                    if (!((String[]) nextelement)[i].equals("")) {
988
                        query.append("<queryterm casesensitive=\""
989
                                + casesensitive + "\" " + "searchmode=\""
990
                                + searchmode + "\">" + "<value>" + 
991
                                //add the query value
992
                                ((String[]) nextelement)[i]
993
                                + "</value><pathexpr>" + 
994
                                //add the path to query by
995
                                nextkey.toString() + "</pathexpr></queryterm>");
996
                    }
997
                }
998
            }
999
        }
1000
        query.append("</querygroup></pathquery>");
1001
        //append on the end of the xml and return the result as a string
1002
        return query.toString();
1003
    }
1004

    
1005
    /**
1006
     * format a simple free-text value query as an XML document that conforms
1007
     * to the pathquery.dtd and is appropriate for submission to the DBQuery
1008
     * structured query engine
1009
     * 
1010
     * @param value the text string to search for in the xml catalog
1011
     * @param doctype the type of documents to include in the result set -- use
1012
     *            "any" or "ANY" for unfiltered result sets
1013
     */
1014
    public static String createQuery(String value, String doctype)
1015
    {
1016
        StringBuffer xmlquery = new StringBuffer();
1017
        xmlquery.append("<?xml version=\"1.0\"?>\n");
1018
        xmlquery.append("<pathquery version=\"1.0\">");
1019

    
1020
        if (!doctype.equals("any") && !doctype.equals("ANY")) {
1021
            xmlquery.append("<returndoctype>");
1022
            xmlquery.append(doctype).append("</returndoctype>");
1023
        }
1024

    
1025
        xmlquery.append("<querygroup operator=\"UNION\">");
1026
        //chad added - 8/14
1027
        //the if statement allows a query to gracefully handle a null
1028
        //query. Without this if a nullpointerException is thrown.
1029
        if (!value.equals("")) {
1030
            xmlquery.append("<queryterm casesensitive=\"false\" ");
1031
            xmlquery.append("searchmode=\"contains\">");
1032
            xmlquery.append("<value>").append(value).append("</value>");
1033
            xmlquery.append("</queryterm>");
1034
        }
1035
        xmlquery.append("</querygroup>");
1036
        xmlquery.append("</pathquery>");
1037

    
1038
        return (xmlquery.toString());
1039
    }
1040

    
1041
    /**
1042
     * format a simple free-text value query as an XML document that conforms
1043
     * to the pathquery.dtd and is appropriate for submission to the DBQuery
1044
     * structured query engine
1045
     * 
1046
     * @param value the text string to search for in the xml catalog
1047
     */
1048
    public static String createQuery(String value)
1049
    {
1050
        return createQuery(value, "any");
1051
    }
1052

    
1053
    /**
1054
     * Check for "READ" permission on @docid for @user and/or @group from DB
1055
     * connection
1056
     */
1057
    private boolean hasPermission(String user, String[] groups, String docid)
1058
            throws SQLException, Exception
1059
    {
1060
        // Check for READ permission on @docid for @user and/or @groups
1061
        PermissionController controller = new PermissionController(docid);
1062
        return controller.hasPermission(user, groups,
1063
                AccessControlInterface.READSTRING);
1064
    }
1065

    
1066
    /**
1067
     * Get all docIds list for a data packadge
1068
     * 
1069
     * @param dataPackageDocid, the string in docId field of xml_relation table
1070
     */
1071
    private Vector getCurrentDocidListForDataPackage(String dataPackageDocid)
1072
    {
1073
        DBConnection dbConn = null;
1074
        int serialNumber = -1;
1075
        Vector docIdList = new Vector();//return value
1076
        PreparedStatement pStmt = null;
1077
        ResultSet rs = null;
1078
        String docIdInSubjectField = null;
1079
        String docIdInObjectField = null;
1080

    
1081
        // Check the parameter
1082
        if (dataPackageDocid == null || dataPackageDocid.equals("")) { return docIdList; }//if
1083

    
1084
        //the query stirng
1085
        String query = "SELECT subject, object from xml_relation where docId = ?";
1086
        try {
1087
            dbConn = DBConnectionPool
1088
                    .getDBConnection("DBQuery.getCurrentDocidListForDataPackage");
1089
            serialNumber = dbConn.getCheckOutSerialNumber();
1090
            pStmt = dbConn.prepareStatement(query);
1091
            //bind the value to query
1092
            pStmt.setString(1, dataPackageDocid);
1093

    
1094
            //excute the query
1095
            pStmt.execute();
1096
            //get the result set
1097
            rs = pStmt.getResultSet();
1098
            //process the result
1099
            while (rs.next()) {
1100
                //In order to get the whole docIds in a data packadge,
1101
                //we need to put the docIds of subject and object field in
1102
                // xml_relation
1103
                //into the return vector
1104
                docIdInSubjectField = rs.getString(1);//the result docId in
1105
                                                      // subject field
1106
                docIdInObjectField = rs.getString(2);//the result docId in
1107
                                                     // object field
1108

    
1109
                //don't put the duplicate docId into the vector
1110
                if (!docIdList.contains(docIdInSubjectField)) {
1111
                    docIdList.add(docIdInSubjectField);
1112
                }
1113

    
1114
                //don't put the duplicate docId into the vector
1115
                if (!docIdList.contains(docIdInObjectField)) {
1116
                    docIdList.add(docIdInObjectField);
1117
                }
1118
            }//while
1119
            //close the pStmt
1120
            pStmt.close();
1121
        }//try
1122
        catch (SQLException e) {
1123
            MetaCatUtil.debugMessage("Error in getDocidListForDataPackage: "
1124
                    + e.getMessage(), 30);
1125
        }//catch
1126
        finally {
1127
            try {
1128
                pStmt.close();
1129
            }//try
1130
            catch (SQLException ee) {
1131
                MetaCatUtil.debugMessage(
1132
                        "Error in getDocidListForDataPackage: "
1133
                                + ee.getMessage(), 30);
1134
            }//catch
1135
            finally {
1136
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1137
            }//fianlly
1138
        }//finally
1139
        return docIdList;
1140
    }//getCurrentDocidListForDataPackadge()
1141

    
1142
    /**
1143
     * Get all docIds list for a data packadge
1144
     * 
1145
     * @param dataPackageDocid, the string in docId field of xml_relation table
1146
     */
1147
    private Vector getOldVersionDocidListForDataPackage(String dataPackageDocid)
1148
    {
1149

    
1150
        Vector docIdList = new Vector();//return value
1151
        Vector tripleList = null;
1152
        String xml = null;
1153

    
1154
        // Check the parameter
1155
        if (dataPackageDocid == null || dataPackageDocid.equals("")) { return docIdList; }//if
1156

    
1157
        try {
1158
            //initial a documentImpl object
1159
            DocumentImpl packageDocument = new DocumentImpl(dataPackageDocid);
1160
            //transfer to documentImpl object to string
1161
            xml = packageDocument.toString();
1162

    
1163
            //create a tripcollection object
1164
            TripleCollection tripleForPackage = new TripleCollection(
1165
                    new StringReader(xml));
1166
            //get the vetor of triples
1167
            tripleList = tripleForPackage.getCollection();
1168

    
1169
            for (int i = 0; i < tripleList.size(); i++) {
1170
                //put subject docid into docIdlist without duplicate
1171
                if (!docIdList.contains(((Triple) tripleList.elementAt(i))
1172
                        .getSubject())) {
1173
                    //put subject docid into docIdlist
1174
                    docIdList.add(((Triple) tripleList.get(i)).getSubject());
1175
                }
1176
                //put object docid into docIdlist without duplicate
1177
                if (!docIdList.contains(((Triple) tripleList.elementAt(i))
1178
                        .getObject())) {
1179
                    docIdList.add(((Triple) (tripleList.get(i))).getObject());
1180
                }
1181
            }//for
1182
        }//try
1183
        catch (Exception e) {
1184
            MetaCatUtil.debugMessage("Error in getOldVersionAllDocumentImpl: "
1185
                    + e.getMessage(), 30);
1186
        }//catch
1187

    
1188
        // return result
1189
        return docIdList;
1190
    }//getDocidListForPackageInXMLRevisions()
1191

    
1192
    /**
1193
     * Check if the docId is a data packadge id. If the id is a data packadage
1194
     * id, it should be store in the docId fields in xml_relation table. So we
1195
     * can use a query to get the entries which the docId equals the given
1196
     * value. If the result is null. The docId is not a packadge id. Otherwise,
1197
     * it is.
1198
     * 
1199
     * @param docId, the id need to be checked
1200
     */
1201
    private boolean isDataPackageId(String docId)
1202
    {
1203
        boolean result = false;
1204
        PreparedStatement pStmt = null;
1205
        ResultSet rs = null;
1206
        String query = "SELECT docId from xml_relation where docId = ?";
1207
        DBConnection dbConn = null;
1208
        int serialNumber = -1;
1209
        try {
1210
            dbConn = DBConnectionPool
1211
                    .getDBConnection("DBQuery.isDataPackageId");
1212
            serialNumber = dbConn.getCheckOutSerialNumber();
1213
            pStmt = dbConn.prepareStatement(query);
1214
            //bind the value to query
1215
            pStmt.setString(1, docId);
1216
            //execute the query
1217
            pStmt.execute();
1218
            rs = pStmt.getResultSet();
1219
            //process the result
1220
            if (rs.next()) //There are some records for the id in docId fields
1221
            {
1222
                result = true;//It is a data packadge id
1223
            }
1224
            pStmt.close();
1225
        }//try
1226
        catch (SQLException e) {
1227
            MetaCatUtil.debugMessage("Error in isDataPackageId: "
1228
                    + e.getMessage(), 30);
1229
        } finally {
1230
            try {
1231
                pStmt.close();
1232
            }//try
1233
            catch (SQLException ee) {
1234
                MetaCatUtil.debugMessage("Error in isDataPackageId: "
1235
                        + ee.getMessage(), 30);
1236
            }//catch
1237
            finally {
1238
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1239
            }//finally
1240
        }//finally
1241
        return result;
1242
    }//isDataPackageId()
1243

    
1244
    /**
1245
     * Check if the user has the permission to export data package
1246
     * 
1247
     * @param conn, the connection
1248
     * @param docId, the id need to be checked
1249
     * @param user, the name of user
1250
     * @param groups, the user's group
1251
     */
1252
    private boolean hasPermissionToExportPackage(String docId, String user,
1253
            String[] groups) throws Exception
1254
    {
1255
        //DocumentImpl doc=new DocumentImpl(conn,docId);
1256
        return DocumentImpl.hasReadPermission(user, groups, docId);
1257
    }
1258

    
1259
    /**
1260
     * Get the current Rev for a docid in xml_documents table
1261
     * 
1262
     * @param docId, the id need to get version numb If the return value is -5,
1263
     *            means no value in rev field for this docid
1264
     */
1265
    private int getCurrentRevFromXMLDoumentsTable(String docId)
1266
            throws SQLException
1267
    {
1268
        int rev = -5;
1269
        PreparedStatement pStmt = null;
1270
        ResultSet rs = null;
1271
        String query = "SELECT rev from xml_documents where docId = ?";
1272
        DBConnection dbConn = null;
1273
        int serialNumber = -1;
1274
        try {
1275
            dbConn = DBConnectionPool
1276
                    .getDBConnection("DBQuery.getCurrentRevFromXMLDocumentsTable");
1277
            serialNumber = dbConn.getCheckOutSerialNumber();
1278
            pStmt = dbConn.prepareStatement(query);
1279
            //bind the value to query
1280
            pStmt.setString(1, docId);
1281
            //execute the query
1282
            pStmt.execute();
1283
            rs = pStmt.getResultSet();
1284
            //process the result
1285
            if (rs.next()) //There are some records for rev
1286
            {
1287
                rev = rs.getInt(1);
1288
                ;//It is the version for given docid
1289
            } else {
1290
                rev = -5;
1291
            }
1292

    
1293
        }//try
1294
        catch (SQLException e) {
1295
            MetaCatUtil.debugMessage(
1296
                    "Error in getCurrentRevFromXMLDoumentsTable: "
1297
                            + e.getMessage(), 30);
1298
            throw e;
1299
        }//catch
1300
        finally {
1301
            try {
1302
                pStmt.close();
1303
            }//try
1304
            catch (SQLException ee) {
1305
                MetaCatUtil.debugMessage(
1306
                        "Error in getCurrentRevFromXMLDoumentsTable: "
1307
                                + ee.getMessage(), 30);
1308
            }//catch
1309
            finally {
1310
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1311
            }//finally
1312
        }//finally
1313
        return rev;
1314
    }//getCurrentRevFromXMLDoumentsTable
1315

    
1316
    /**
1317
     * put a doc into a zip output stream
1318
     * 
1319
     * @param docImpl, docmentImpl object which will be sent to zip output
1320
     *            stream
1321
     * @param zipOut, zip output stream which the docImpl will be put
1322
     * @param packageZipEntry, the zip entry name for whole package
1323
     */
1324
    private void addDocToZipOutputStream(DocumentImpl docImpl,
1325
            ZipOutputStream zipOut, String packageZipEntry)
1326
            throws ClassNotFoundException, IOException, SQLException,
1327
            McdbException, Exception
1328
    {
1329
        byte[] byteString = null;
1330
        ZipEntry zEntry = null;
1331

    
1332
        byteString = docImpl.toString().getBytes();
1333
        //use docId as the zip entry's name
1334
        zEntry = new ZipEntry(packageZipEntry + "/metadata/"
1335
                + docImpl.getDocID());
1336
        zEntry.setSize(byteString.length);
1337
        zipOut.putNextEntry(zEntry);
1338
        zipOut.write(byteString, 0, byteString.length);
1339
        zipOut.closeEntry();
1340

    
1341
    }//addDocToZipOutputStream()
1342

    
1343
    /**
1344
     * Transfer a docid vetor to a documentImpl vector. The documentImpl vetor
1345
     * only inlcudes current version. If a DocumentImple object couldn't find
1346
     * for a docid, then the String of this docid was added to vetor rather
1347
     * than DocumentImple object.
1348
     * 
1349
     * @param docIdList, a vetor hold a docid list for a data package. In
1350
     *            docid, there is not version number in it.
1351
     */
1352

    
1353
    private Vector getCurrentAllDocumentImpl(Vector docIdList)
1354
            throws McdbException, Exception
1355
    {
1356
        //Connection dbConn=null;
1357
        Vector documentImplList = new Vector();
1358
        int rev = 0;
1359

    
1360
        // Check the parameter
1361
        if (docIdList.isEmpty()) { return documentImplList; }//if
1362

    
1363
        //for every docid in vector
1364
        for (int i = 0; i < docIdList.size(); i++) {
1365
            try {
1366
                //get newest version for this docId
1367
                rev = getCurrentRevFromXMLDoumentsTable((String) docIdList
1368
                        .elementAt(i));
1369

    
1370
                // There is no record for this docId in xml_documents table
1371
                if (rev == -5) {
1372
                    // Rather than put DocumentImple object, put a String
1373
                    // Object(docid)
1374
                    // into the documentImplList
1375
                    documentImplList.add((String) docIdList.elementAt(i));
1376
                    // Skip other code
1377
                    continue;
1378
                }
1379

    
1380
                String docidPlusVersion = ((String) docIdList.elementAt(i))
1381
                        + MetaCatUtil.getOption("accNumSeparator") + rev;
1382

    
1383
                //create new documentImpl object
1384
                DocumentImpl documentImplObject = new DocumentImpl(
1385
                        docidPlusVersion);
1386
                //add them to vector
1387
                documentImplList.add(documentImplObject);
1388
            }//try
1389
            catch (Exception e) {
1390
                MetaCatUtil.debugMessage("Error in getCurrentAllDocumentImpl: "
1391
                        + e.getMessage(), 30);
1392
                // continue the for loop
1393
                continue;
1394
            }
1395
        }//for
1396
        return documentImplList;
1397
    }
1398

    
1399
    /**
1400
     * Transfer a docid vetor to a documentImpl vector. If a DocumentImple
1401
     * object couldn't find for a docid, then the String of this docid was
1402
     * added to vetor rather than DocumentImple object.
1403
     * 
1404
     * @param docIdList, a vetor hold a docid list for a data package. In
1405
     *            docid, t here is version number in it.
1406
     */
1407
    private Vector getOldVersionAllDocumentImpl(Vector docIdList)
1408
    {
1409
        //Connection dbConn=null;
1410
        Vector documentImplList = new Vector();
1411
        String siteCode = null;
1412
        String uniqueId = null;
1413
        int rev = 0;
1414

    
1415
        // Check the parameter
1416
        if (docIdList.isEmpty()) { return documentImplList; }//if
1417

    
1418
        //for every docid in vector
1419
        for (int i = 0; i < docIdList.size(); i++) {
1420

    
1421
            String docidPlusVersion = (String) (docIdList.elementAt(i));
1422

    
1423
            try {
1424
                //create new documentImpl object
1425
                DocumentImpl documentImplObject = new DocumentImpl(
1426
                        docidPlusVersion);
1427
                //add them to vector
1428
                documentImplList.add(documentImplObject);
1429
            }//try
1430
            catch (McdbDocNotFoundException notFoundE) {
1431
                MetaCatUtil.debugMessage(
1432
                        "Error in DBQuery.getOldVersionAllDocument" + "Imple"
1433
                                + notFoundE.getMessage(), 30);
1434
                // Rather than add a DocumentImple object into vetor, a String
1435
                // object
1436
                // - the doicd was added to the vector
1437
                documentImplList.add(docidPlusVersion);
1438
                // Continue the for loop
1439
                continue;
1440
            }//catch
1441
            catch (Exception e) {
1442
                MetaCatUtil.debugMessage(
1443
                        "Error in DBQuery.getOldVersionAllDocument" + "Imple"
1444
                                + e.getMessage(), 30);
1445
                // Continue the for loop
1446
                continue;
1447
            }//catch
1448

    
1449
        }//for
1450
        return documentImplList;
1451
    }//getOldVersionAllDocumentImple
1452

    
1453
    /**
1454
     * put a data file into a zip output stream
1455
     * 
1456
     * @param docImpl, docmentImpl object which will be sent to zip output
1457
     *            stream
1458
     * @param zipOut, the zip output stream which the docImpl will be put
1459
     * @param packageZipEntry, the zip entry name for whole package
1460
     */
1461
    private void addDataFileToZipOutputStream(DocumentImpl docImpl,
1462
            ZipOutputStream zipOut, String packageZipEntry)
1463
            throws ClassNotFoundException, IOException, SQLException,
1464
            McdbException, Exception
1465
    {
1466
        byte[] byteString = null;
1467
        ZipEntry zEntry = null;
1468
        // this is data file; add file to zip
1469
        String filePath = MetaCatUtil.getOption("datafilepath");
1470
        if (!filePath.endsWith("/")) {
1471
            filePath += "/";
1472
        }
1473
        String fileName = filePath + docImpl.getDocID();
1474
        zEntry = new ZipEntry(packageZipEntry + "/data/" + docImpl.getDocID());
1475
        zipOut.putNextEntry(zEntry);
1476
        FileInputStream fin = null;
1477
        try {
1478
            fin = new FileInputStream(fileName);
1479
            byte[] buf = new byte[4 * 1024]; // 4K buffer
1480
            int b = fin.read(buf);
1481
            while (b != -1) {
1482
                zipOut.write(buf, 0, b);
1483
                b = fin.read(buf);
1484
            }//while
1485
            zipOut.closeEntry();
1486
        }//try
1487
        catch (IOException ioe) {
1488
            MetaCatUtil.debugMessage("There is an exception: "
1489
                    + ioe.getMessage(), 30);
1490
        }//catch
1491
    }//addDataFileToZipOutputStream()
1492

    
1493
    /**
1494
     * create a html summary for data package and put it into zip output stream
1495
     * 
1496
     * @param docImplList, the documentImpl ojbects in data package
1497
     * @param zipOut, the zip output stream which the html should be put
1498
     * @param packageZipEntry, the zip entry name for whole package
1499
     */
1500
    private void addHtmlSummaryToZipOutputStream(Vector docImplList,
1501
            ZipOutputStream zipOut, String packageZipEntry) throws Exception
1502
    {
1503
        StringBuffer htmlDoc = new StringBuffer();
1504
        ZipEntry zEntry = null;
1505
        byte[] byteString = null;
1506
        InputStream source;
1507
        DBTransform xmlToHtml;
1508

    
1509
        //create a DBTransform ojbect
1510
        xmlToHtml = new DBTransform();
1511
        //head of html
1512
        htmlDoc.append("<html><head></head><body>");
1513
        for (int i = 0; i < docImplList.size(); i++) {
1514
            // If this String object, this means it is missed data file
1515
            if ((((docImplList.elementAt(i)).getClass()).toString())
1516
                    .equals("class java.lang.String")) {
1517

    
1518
                htmlDoc.append("<a href=\"");
1519
                String dataFileid = (String) docImplList.elementAt(i);
1520
                htmlDoc.append("./data/").append(dataFileid).append("\">");
1521
                htmlDoc.append("Data File: ");
1522
                htmlDoc.append(dataFileid).append("</a><br>");
1523
                htmlDoc.append("<br><hr><br>");
1524

    
1525
            }//if
1526
            else if ((((DocumentImpl) docImplList.elementAt(i)).getDoctype())
1527
                    .compareTo("BIN") != 0) { //this is an xml file so we can
1528
                                              // transform it.
1529
                //transform each file individually then concatenate all of the
1530
                //transformations together.
1531

    
1532
                //for metadata xml title
1533
                htmlDoc.append("<h2>");
1534
                htmlDoc.append(((DocumentImpl) docImplList.elementAt(i))
1535
                        .getDocID());
1536
                //htmlDoc.append(".");
1537
                //htmlDoc.append(((DocumentImpl)docImplList.elementAt(i)).getRev());
1538
                htmlDoc.append("</h2>");
1539
                //do the actual transform
1540
                StringWriter docString = new StringWriter();
1541
                xmlToHtml.transformXMLDocument(((DocumentImpl) docImplList
1542
                        .elementAt(i)).toString(), "-//NCEAS//eml-generic//EN",
1543
                        "-//W3C//HTML//EN", "html", docString);
1544
                htmlDoc.append(docString.toString());
1545
                htmlDoc.append("<br><br><hr><br><br>");
1546
            }//if
1547
            else { //this is a data file so we should link to it in the html
1548
                htmlDoc.append("<a href=\"");
1549
                String dataFileid = ((DocumentImpl) docImplList.elementAt(i))
1550
                        .getDocID();
1551
                htmlDoc.append("./data/").append(dataFileid).append("\">");
1552
                htmlDoc.append("Data File: ");
1553
                htmlDoc.append(dataFileid).append("</a><br>");
1554
                htmlDoc.append("<br><hr><br>");
1555
            }//else
1556
        }//for
1557
        htmlDoc.append("</body></html>");
1558
        byteString = htmlDoc.toString().getBytes();
1559
        zEntry = new ZipEntry(packageZipEntry + "/metadata.html");
1560
        zEntry.setSize(byteString.length);
1561
        zipOut.putNextEntry(zEntry);
1562
        zipOut.write(byteString, 0, byteString.length);
1563
        zipOut.closeEntry();
1564
        //dbConn.close();
1565

    
1566
    }//addHtmlSummaryToZipOutputStream
1567

    
1568
    /**
1569
     * put a data packadge into a zip output stream
1570
     * 
1571
     * @param docId, which the user want to put into zip output stream
1572
     * @param out, a servletoutput stream which the zip output stream will be
1573
     *            put
1574
     * @param user, the username of the user
1575
     * @param groups, the group of the user
1576
     */
1577
    public ZipOutputStream getZippedPackage(String docIdString,
1578
            ServletOutputStream out, String user, String[] groups,
1579
            String passWord) throws ClassNotFoundException, IOException,
1580
            SQLException, McdbException, NumberFormatException, Exception
1581
    {
1582
        ZipOutputStream zOut = null;
1583
        String elementDocid = null;
1584
        DocumentImpl docImpls = null;
1585
        //Connection dbConn = null;
1586
        Vector docIdList = new Vector();
1587
        Vector documentImplList = new Vector();
1588
        Vector htmlDocumentImplList = new Vector();
1589
        String packageId = null;
1590
        String rootName = "package";//the package zip entry name
1591

    
1592
        String docId = null;
1593
        int version = -5;
1594
        // Docid without revision
1595
        docId = MetaCatUtil.getDocIdFromString(docIdString);
1596
        // revision number
1597
        version = MetaCatUtil.getVersionFromString(docIdString);
1598

    
1599
        //check if the reqused docId is a data package id
1600
        if (!isDataPackageId(docId)) {
1601

    
1602
            /*
1603
             * Exception e = new Exception("The request the doc id "
1604
             * +docIdString+ " is not a data package id");
1605
             */
1606

    
1607
            //CB 1/6/03: if the requested docid is not a datapackage, we just
1608
            // zip
1609
            //up the single document and return the zip file.
1610
            if (!hasPermissionToExportPackage(docId, user, groups)) {
1611

    
1612
                Exception e = new Exception("User " + user
1613
                        + " does not have permission"
1614
                        + " to export the data package " + docIdString);
1615
                throw e;
1616
            }
1617

    
1618
            docImpls = new DocumentImpl(docId);
1619
            //checking if the user has the permission to read the documents
1620
            if (DocumentImpl.hasReadPermission(user, groups, docImpls
1621
                    .getDocID())) {
1622
                zOut = new ZipOutputStream(out);
1623
                //if the docImpls is metadata
1624
                if ((docImpls.getDoctype()).compareTo("BIN") != 0) {
1625
                    //add metadata into zip output stream
1626
                    addDocToZipOutputStream(docImpls, zOut, rootName);
1627
                }//if
1628
                else {
1629
                    //it is data file
1630
                    addDataFileToZipOutputStream(docImpls, zOut, rootName);
1631
                    htmlDocumentImplList.add(docImpls);
1632
                }//else
1633
            }//if
1634

    
1635
            zOut.finish(); //terminate the zip file
1636
            return zOut;
1637
        }
1638
        // Check the permission of user
1639
        else if (!hasPermissionToExportPackage(docId, user, groups)) {
1640

    
1641
            Exception e = new Exception("User " + user
1642
                    + " does not have permission"
1643
                    + " to export the data package " + docIdString);
1644
            throw e;
1645
        } else //it is a packadge id
1646
        {
1647
            //store the package id
1648
            packageId = docId;
1649
            //get current version in database
1650
            int currentVersion = getCurrentRevFromXMLDoumentsTable(packageId);
1651
            //If it is for current version (-1 means user didn't specify
1652
            // revision)
1653
            if ((version == -1) || version == currentVersion) {
1654
                //get current version number
1655
                version = currentVersion;
1656
                //get package zip entry name
1657
                //it should be docId.revsion.package
1658
                rootName = packageId + MetaCatUtil.getOption("accNumSeparator")
1659
                        + version + MetaCatUtil.getOption("accNumSeparator")
1660
                        + "package";
1661
                //get the whole id list for data packadge
1662
                docIdList = getCurrentDocidListForDataPackage(packageId);
1663
                //get the whole documentImple object
1664
                documentImplList = getCurrentAllDocumentImpl(docIdList);
1665

    
1666
            }//if
1667
            else if (version > currentVersion || version < -1) {
1668
                throw new Exception("The user specified docid: " + docId + "."
1669
                        + version + " doesn't exist");
1670
            }//else if
1671
            else //for an old version
1672
            {
1673

    
1674
                rootName = docIdString
1675
                        + MetaCatUtil.getOption("accNumSeparator") + "package";
1676
                //get the whole id list for data packadge
1677
                docIdList = getOldVersionDocidListForDataPackage(docIdString);
1678

    
1679
                //get the whole documentImple object
1680
                documentImplList = getOldVersionAllDocumentImpl(docIdList);
1681
            }//else
1682

    
1683
            // Make sure documentImplist is not empty
1684
            if (documentImplList.isEmpty()) { throw new Exception(
1685
                    "Couldn't find component for data package: " + packageId); }//if
1686

    
1687
            zOut = new ZipOutputStream(out);
1688
            //put every element into zip output stream
1689
            for (int i = 0; i < documentImplList.size(); i++) {
1690
                // if the object in the vetor is String, this means we couldn't
1691
                // find
1692
                // the document locally, we need find it remote
1693
                if ((((documentImplList.elementAt(i)).getClass()).toString())
1694
                        .equals("class java.lang.String")) {
1695
                    // Get String object from vetor
1696
                    String documentId = (String) documentImplList.elementAt(i);
1697
                    MetaCatUtil.debugMessage("docid: " + documentId, 30);
1698
                    // Get doicd without revision
1699
                    String docidWithoutRevision = MetaCatUtil
1700
                            .getDocIdFromString(documentId);
1701
                    MetaCatUtil.debugMessage("docidWithoutRevsion: "
1702
                            + docidWithoutRevision, 30);
1703
                    // Get revision
1704
                    String revision = MetaCatUtil
1705
                            .getRevisionStringFromString(documentId);
1706
                    MetaCatUtil.debugMessage("revsion from docIdentifier: "
1707
                            + revision, 30);
1708
                    // Zip entry string
1709
                    String zipEntryPath = rootName + "/data/";
1710
                    // Create a RemoteDocument object
1711
                    RemoteDocument remoteDoc = new RemoteDocument(
1712
                            docidWithoutRevision, revision, user, passWord,
1713
                            zipEntryPath);
1714
                    // Here we only read data file from remote metacat
1715
                    String docType = remoteDoc.getDocType();
1716
                    if (docType != null) {
1717
                        if (docType.equals("BIN")) {
1718
                            // Put remote document to zip output
1719
                            remoteDoc.readDocumentFromRemoteServerByZip(zOut);
1720
                            // Add String object to htmlDocumentImplList
1721
                            String elementInHtmlList = remoteDoc
1722
                                    .getDocIdWithoutRevsion()
1723
                                    + MetaCatUtil.getOption("accNumSeparator")
1724
                                    + remoteDoc.getRevision();
1725
                            htmlDocumentImplList.add(elementInHtmlList);
1726
                        }//if
1727
                    }//if
1728

    
1729
                }//if
1730
                else {
1731
                    //create a docmentImpls object (represent xml doc) base on
1732
                    // the docId
1733
                    docImpls = (DocumentImpl) documentImplList.elementAt(i);
1734
                    //checking if the user has the permission to read the
1735
                    // documents
1736
                    if (DocumentImpl.hasReadPermission(user, groups, docImpls
1737
                            .getDocID())) {
1738
                        //if the docImpls is metadata
1739
                        if ((docImpls.getDoctype()).compareTo("BIN") != 0) {
1740
                            //add metadata into zip output stream
1741
                            addDocToZipOutputStream(docImpls, zOut, rootName);
1742
                            //add the documentImpl into the vetor which will
1743
                            // be used in html
1744
                            htmlDocumentImplList.add(docImpls);
1745

    
1746
                        }//if
1747
                        else {
1748
                            //it is data file
1749
                            addDataFileToZipOutputStream(docImpls, zOut,
1750
                                    rootName);
1751
                            htmlDocumentImplList.add(docImpls);
1752
                        }//else
1753
                    }//if
1754
                }//else
1755
            }//for
1756

    
1757
            //add html summary file
1758
            addHtmlSummaryToZipOutputStream(htmlDocumentImplList, zOut,
1759
                    rootName);
1760
            zOut.finish(); //terminate the zip file
1761
            //dbConn.close();
1762
            return zOut;
1763
        }//else
1764
    }//getZippedPackage()
1765

    
1766
    private class ReturnFieldValue
1767
    {
1768

    
1769
        private String docid = null; //return field value for this docid
1770

    
1771
        private String fieldValue = null;
1772

    
1773
        private String xmlFieldValue = null; //return field value in xml
1774
                                             // format
1775

    
1776
        public void setDocid(String myDocid)
1777
        {
1778
            docid = myDocid;
1779
        }
1780

    
1781
        public String getDocid()
1782
        {
1783
            return docid;
1784
        }
1785

    
1786
        public void setFieldValue(String myValue)
1787
        {
1788
            fieldValue = myValue;
1789
        }
1790

    
1791
        public String getFieldValue()
1792
        {
1793
            return fieldValue;
1794
        }
1795

    
1796
        public void setXMLFieldValue(String xml)
1797
        {
1798
            xmlFieldValue = xml;
1799
        }
1800

    
1801
        public String getXMLFieldValue()
1802
        {
1803
            return xmlFieldValue;
1804
        }
1805

    
1806
    }
1807
}
(22-22/58)