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
 *
12
 *   '$Author: berkley $'
13
 *     '$Date: 2007-03-22 09:59:21 -0700 (Thu, 22 Mar 2007) $'
14
 * '$Revision: 3211 $'
15
 *
16
 * This program is free software; you can redistribute it and/or modify
17
 * it under the terms of the GNU General Public License as published by
18
 * the Free Software Foundation; either version 2 of the License, or
19
 * (at your option) any later version.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 * GNU General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU General Public License
27
 * along with this program; if not, write to the Free Software
28
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29
 */
30

    
31
package edu.ucsb.nceas.metacat;
32

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

    
53
import javax.servlet.ServletOutputStream;
54
import javax.servlet.http.HttpServletResponse;
55
import javax.servlet.http.HttpSession;
56

    
57
import org.apache.log4j.Logger;
58

    
59
import edu.ucsb.nceas.morpho.datapackage.Triple;
60
import edu.ucsb.nceas.morpho.datapackage.TripleCollection;
61

    
62

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

    
72
    static final int ALL = 1;
73

    
74
    static final int WRITE = 2;
75

    
76
    static final int READ = 4;
77

    
78
    //private Connection conn = null;
79
    private String parserName = null;
80

    
81
    private MetaCatUtil util = new MetaCatUtil();
82

    
83
    private Logger logMetacat = Logger.getLogger(DBQuery.class);
84

    
85
    /** true if the metacat spatial option is installed **/
86
    private final boolean METACAT_SPATIAL = true;
87

    
88
    /** useful if you just want to grab a list of docids **/
89
    Vector docidOverride = new Vector();
90

    
91
    /**
92
     * the main routine used to test the DBQuery utility.
93
     * <p>
94
     * Usage: java DBQuery <xmlfile>
95
     *
96
     * @param xmlfile the filename of the xml file containing the query
97
     */
98
    static public void main(String[] args)
99
    {
100

    
101
        if (args.length < 1) {
102
            System.err.println("Wrong number of arguments!!!");
103
            System.err.println("USAGE: java DBQuery [-t] [-index] <xmlfile>");
104
            return;
105
        } else {
106
            try {
107

    
108
                int i = 0;
109
                boolean showRuntime = false;
110
                boolean useXMLIndex = false;
111
                if (args[i].equals("-t")) {
112
                    showRuntime = true;
113
                    i++;
114
                }
115
                if (args[i].equals("-index")) {
116
                    useXMLIndex = true;
117
                    i++;
118
                }
119
                String xmlfile = args[i];
120

    
121
                // Time the request if asked for
122
                double startTime = System.currentTimeMillis();
123

    
124
                // Open a connection to the database
125
                MetaCatUtil util = new MetaCatUtil();
126
                //Connection dbconn = util.openDBConnection();
127

    
128
                double connTime = System.currentTimeMillis();
129

    
130
                // Execute the query
131
                DBQuery queryobj = new DBQuery();
132
                FileReader xml = new FileReader(new File(xmlfile));
133
                Hashtable nodelist = null;
134
                //nodelist = queryobj.findDocuments(xml, null, null, useXMLIndex);
135

    
136
                // Print the reulting document listing
137
                StringBuffer result = new StringBuffer();
138
                String document = null;
139
                String docid = null;
140
                result.append("<?xml version=\"1.0\"?>\n");
141
                result.append("<resultset>\n");
142

    
143
                if (!showRuntime) {
144
                    Enumeration doclist = nodelist.keys();
145
                    while (doclist.hasMoreElements()) {
146
                        docid = (String) doclist.nextElement();
147
                        document = (String) nodelist.get(docid);
148
                        result.append("  <document>\n    " + document
149
                                + "\n  </document>\n");
150
                    }
151

    
152
                    result.append("</resultset>\n");
153
                }
154
                // Time the request if asked for
155
                double stopTime = System.currentTimeMillis();
156
                double dbOpenTime = (connTime - startTime) / 1000;
157
                double readTime = (stopTime - connTime) / 1000;
158
                double executionTime = (stopTime - startTime) / 1000;
159
                if (showRuntime) {
160
                    System.out.print("  " + executionTime);
161
                    System.out.print("  " + dbOpenTime);
162
                    System.out.print("  " + readTime);
163
                    System.out.print("  " + nodelist.size());
164
                    System.out.println();
165
                }
166
                //System.out.println(result);
167
                //write into a file "result.txt"
168
                if (!showRuntime) {
169
                    File f = new File("./result.txt");
170
                    FileWriter fw = new FileWriter(f);
171
                    BufferedWriter out = new BufferedWriter(fw);
172
                    out.write(result.toString());
173
                    out.flush();
174
                    out.close();
175
                    fw.close();
176
                }
177

    
178
            } catch (Exception e) {
179
                System.err.println("Error in DBQuery.main");
180
                System.err.println(e.getMessage());
181
                e.printStackTrace(System.err);
182
            }
183
        }
184
    }
185

    
186
    /**
187
     * construct an instance of the DBQuery class
188
     *
189
     * <p>
190
     * Generally, one would call the findDocuments() routine after creating an
191
     * instance to specify the search query
192
     * </p>
193
     *
194

    
195
     * @param parserName the fully qualified name of a Java class implementing
196
     *            the org.xml.sax.XMLReader interface
197
     */
198
    public DBQuery()
199
    {
200
        String parserName = MetaCatUtil.getOption("saxparser");
201
        this.parserName = parserName;
202
    }
203

    
204
    /**
205
     * 
206
     * Construct an instance of DBQuery Class
207
     * BUT accept a docid Vector that will supersede
208
     * the query.printSQL() method
209
     *
210
     * If a docid Vector is passed in,
211
     * the docids will be used to create a simple IN query 
212
     * without the multiple subselects of the printSQL() method
213
     *
214
     * Using this constructor, we just check for 
215
     * a docidOverride Vector in the findResultDoclist() method
216
     *
217
     * @param docids List of docids to display in the resultset
218
     */
219
    public DBQuery(Vector docids)
220
    {
221
        this.docidOverride = docids;
222
        String parserName = MetaCatUtil.getOption("saxparser");
223
        this.parserName = parserName;
224
    }
225

    
226
  /**
227
   * Method put the search result set into out printerwriter
228
   * @param resoponse the return response
229
   * @param out the output printer
230
   * @param params the paratermer hashtable
231
   * @param user the user name (it maybe different to the one in param)
232
   * @param groups the group array
233
   * @param sessionid  the sessionid
234
   */
235
  public void findDocuments(HttpServletResponse response,
236
                                       PrintWriter out, Hashtable params,
237
                                       String user, String[] groups,
238
                                       String sessionid)
239
  {
240
    boolean useXMLIndex = (new Boolean(MetaCatUtil.getOption("usexmlindex")))
241
               .booleanValue();
242
    findDocuments(response, out, params, user, groups, sessionid, useXMLIndex);
243

    
244
  }
245

    
246

    
247
    /**
248
     * Method put the search result set into out printerwriter
249
     * @param resoponse the return response
250
     * @param out the output printer
251
     * @param params the paratermer hashtable
252
     * @param user the user name (it maybe different to the one in param)
253
     * @param groups the group array
254
     * @param sessionid  the sessionid
255
     */
256
    public void findDocuments(HttpServletResponse response,
257
                                         PrintWriter out, Hashtable params,
258
                                         String user, String[] groups,
259
                                         String sessionid, boolean useXMLIndex)
260
    {
261
      int pagesize = 0;
262
      int pagestart = 0;
263
      
264
      if(params.containsKey("pagesize") && params.containsKey("pagestart"))
265
      {
266
        String pagesizeStr = ((String[])params.get("pagesize"))[0];
267
        String pagestartStr = ((String[])params.get("pagestart"))[0];
268
        if(pagesizeStr != null && pagestartStr != null)
269
        {
270
          pagesize = (new Integer(pagesizeStr)).intValue();
271
          pagestart = (new Integer(pagestartStr)).intValue();
272
        }
273
      }
274
      
275
      // get query and qformat
276
      String xmlquery = ((String[])params.get("query"))[0];
277

    
278
      logMetacat.warn("SESSIONID: " + sessionid);
279
      logMetacat.warn("xmlquery: " + xmlquery);
280
      String qformat = ((String[])params.get("qformat"))[0];
281
      logMetacat.warn("qformat: " + qformat);
282
      // Get the XML query and covert it into a SQL statment
283
      QuerySpecification qspec = null;
284
      if ( xmlquery != null)
285
      {
286
         xmlquery = transformQuery(xmlquery);
287
         try
288
         {
289
           qspec = new QuerySpecification(xmlquery,
290
                                          parserName,
291
                                          MetaCatUtil.getOption("accNumSeparator"));
292
         }
293
         catch (Exception ee)
294
         {
295
           logMetacat.error("error generating QuerySpecification object"
296
                                    +" in DBQuery.findDocuments"
297
                                    + ee.getMessage());
298
         }
299
      }
300

    
301

    
302

    
303
      if (qformat != null && qformat.equals(MetaCatServlet.XMLFORMAT))
304
      {
305
        //xml format
306
        response.setContentType("text/xml");
307
        createResultDocument(xmlquery, qspec, out, user, groups, useXMLIndex, 
308
          pagesize, pagestart, sessionid);
309
      }//if
310
      else
311
      {
312
        //knb format, in this case we will get whole result and sent it out
313
        response.setContentType("text/html");
314
        PrintWriter nonout = null;
315
        StringBuffer xml = createResultDocument(xmlquery, qspec, nonout, user,
316
                                                groups, useXMLIndex, pagesize, 
317
                                                pagestart, sessionid);
318
        
319
        //transfer the xml to html
320
        try
321
        {
322

    
323
         DBTransform trans = new DBTransform();
324
         response.setContentType("text/html");
325

    
326
	       // if the user is a moderator, then pass a param to the 
327
         // xsl specifying the fact
328
         if(MetaCatUtil.isModerator(user, groups)){
329
        	 params.put("isModerator", new String[] {"true"});
330
         }
331

    
332
         trans.transformXMLDocument(xml.toString(), "-//NCEAS//resultset//EN",
333
                                 "-//W3C//HTML//EN", qformat, out, params,
334
                                 sessionid);
335

    
336
        }
337
        catch(Exception e)
338
        {
339
         logMetacat.error("Error in MetaCatServlet.transformResultset:"
340
                                +e.getMessage());
341
         }
342

    
343
      }//else
344

    
345
    }
346

    
347
  /*
348
   * Transforms a hashtable of documents to an xml or html result and sent
349
   * the content to outputstream. Keep going untill hastable is empty. stop it.
350
   * add the QuerySpecification as parameter is for ecogrid. But it is duplicate
351
   * to xmlquery String
352
   */
353
  public StringBuffer createResultDocument(String xmlquery,
354
                                            QuerySpecification qspec,
355
                                            PrintWriter out,
356
                                            String user, String[] groups,
357
                                            boolean useXMLIndex, int pagesize,
358
                                            int pagestart, String sessionid)
359
  {
360
    DBConnection dbconn = null;
361
    int serialNumber = -1;
362
    StringBuffer resultset = new StringBuffer();
363
    resultset.append("<?xml version=\"1.0\"?>\n");
364
    resultset.append("<resultset>\n");
365
    resultset.append("  <query>" + xmlquery + "</query>");
366
    // sent query part out
367
    if (out != null)
368
    {
369
      out.println(resultset.toString());
370
    }
371
    if (qspec != null)
372
    {
373
      try
374
      {
375

    
376
        //checkout the dbconnection
377
        dbconn = DBConnectionPool.getDBConnection("DBQuery.findDocuments");
378
        serialNumber = dbconn.getCheckOutSerialNumber();
379

    
380
        //print out the search result
381
        // search the doc list
382
        resultset = findResultDoclist(qspec, resultset, out, user, groups,
383
                                      dbconn, useXMLIndex, pagesize, pagestart, 
384
                                      sessionid);
385

    
386
        
387

    
388
      } //try
389
      catch (IOException ioe)
390
      {
391
        logMetacat.error("IO error in DBQuery.findDocuments:");
392
        logMetacat.error(ioe.getMessage());
393

    
394
      }
395
      catch (SQLException e)
396
      {
397
        logMetacat.error("SQL Error in DBQuery.findDocuments: "
398
                                 + e.getMessage());
399
      }
400
      catch (Exception ee)
401
      {
402
        logMetacat.error("Exception in DBQuery.findDocuments: "
403
                                 + ee.getMessage());
404
      }
405
      finally
406
      {
407
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
408
      } //finally
409
    }//if
410
    String closeRestultset = "</resultset>";
411
    resultset.append(closeRestultset);
412
    if (out != null)
413
    {
414
      out.println(closeRestultset);
415
    }
416

    
417
    return resultset;
418
  }//createResultDocuments
419

    
420

    
421

    
422
    /*
423
     * Find the doc list which match the query
424
     */
425
    private StringBuffer findResultDoclist(QuerySpecification qspec,
426
                                      StringBuffer resultsetBuffer,
427
                                      PrintWriter out,
428
                                      String user, String[]groups,
429
                                      DBConnection dbconn, boolean useXMLIndex,
430
                                      int pagesize, int pagestart, String sessionid)
431
                                      throws Exception
432
    {
433
      /*
434
      if pagesize != 0 then we need to process the query results in pages
435
      1) check to see what the sessionid is: look in MetacatServlet.getSessionHash()
436
      2) lookup the sessionid and the query in the paged_results table
437
      3) if there is already a page result for the session and query get that
438
         result and look at what our pagesize and pagestart is to get the next
439
         pagesize results
440
      4) if there is not a cached result, do the query, put the result in the 
441
         cache under the correct sessionid and return 0..pagesize results
442
      5) when the session expires or is logged out, delete the cached queryresults
443
      
444
      
445
      paged_results
446
      -------------
447
      sessionid (PK) (String)
448
      query (String)
449
      resultset (String)
450
      
451
      */
452
      Hashtable sessionHash = MetaCatServlet.getSessionHash();
453
      HttpSession sess = (HttpSession)sessionHash.get(sessionid);
454
      //now we have the session object, so we can cache the query there.
455
      
456
      int offset = 1;
457
      // this is a hack for offset
458
      if (out == null)
459
      {
460
        // for html page, we put everything into one page
461
        offset =
462
            (new Integer(MetaCatUtil.getOption("web_resultsetsize"))).intValue();
463
      }
464
      else
465
      {
466
          offset =
467
              (new Integer(MetaCatUtil.getOption("app_resultsetsize"))).intValue();
468
      }
469

    
470
      int count = 0;
471
      int index = 0;
472
      Hashtable docListResult = new Hashtable();
473
      PreparedStatement pstmt = null;
474
      String docid = null;
475
      String docname = null;
476
      String doctype = null;
477
      String createDate = null;
478
      String updateDate = null;
479
      StringBuffer document = null;
480
      int rev = 0;
481

    
482
      String query = null;
483

    
484
      /*
485
       * Check the docidOverride Vector
486
       * if defined, we bypass the qspec.printSQL() method
487
       * and contruct a simpler query based on a 
488
       * list of docids rather than a bunch of subselects
489
       */
490
      if ( this.docidOverride.size() == 0 ) {
491
          query = qspec.printSQL(useXMLIndex);
492
      } else {
493
          logMetacat.info("*** docid override " + this.docidOverride.size());
494
          StringBuffer queryBuffer = new StringBuffer( "SELECT docid,docname,doctype,date_created, date_updated, rev " );
495
          queryBuffer.append( " FROM xml_documents WHERE docid IN (" );
496
          for (int i = 0; i < docidOverride.size(); i++) {  
497
              queryBuffer.append("'");
498
              queryBuffer.append( (String)docidOverride.elementAt(i) );
499
              queryBuffer.append("',");
500
          }
501
          // empty string hack 
502
          queryBuffer.append( "'') " );
503
          query = queryBuffer.toString();
504
      } 
505

    
506
      String ownerQuery = getOwnerQuery(user);
507
      logMetacat.info("\n\n\n query: " + query);
508
      logMetacat.info("\n\n\n owner query: "+ownerQuery);
509
      // if query is not the owner query, we need to check the permission
510
      // otherwise we don't need (owner has all permission by default)
511
      if (!query.equals(ownerQuery))
512
      {
513
        // set user name and group
514
        qspec.setUserName(user);
515
        qspec.setGroup(groups);
516
        // Get access query
517
        String accessQuery = qspec.getAccessQuery();
518
        if(!query.endsWith("WHERE")){
519
            query = query + accessQuery;
520
        } else {
521
            query = query + accessQuery.substring(4, accessQuery.length());
522
        }
523
        logMetacat.warn("\n\n\n final query: " + query);
524
      }
525

    
526
      double startTime = System.currentTimeMillis() / 1000;
527
      pstmt = dbconn.prepareStatement(query);
528
      
529
      // Execute the SQL query using the JDBC connection
530
      pstmt.execute();
531
      ResultSet rs = pstmt.getResultSet();
532
      
533
      double queryExecuteTime = System.currentTimeMillis() / 1000;
534
      logMetacat.warn("Pagesize: " + pstmt.getFetchSize());
535
      logMetacat.warn("Time for execute query: "
536
                    + (queryExecuteTime - startTime));
537
      boolean tableHasRows = rs.next();
538
      while (tableHasRows)
539
      {
540
        docid = rs.getString(1).trim();
541
        docname = rs.getString(2);
542
        doctype = rs.getString(3);
543
        createDate = rs.getString(4);
544
        updateDate = rs.getString(5);
545
        rev = rs.getInt(6);
546

    
547
        // if there are returndocs to match, backtracking can be performed
548
        // otherwise, just return the document that was hit
549
        Vector returndocVec = qspec.getReturnDocList();
550
         if (returndocVec.size() != 0 && !returndocVec.contains(doctype)
551
                        && !qspec.isPercentageSearch())
552
        {
553
           logMetacat.warn("Back tracing now...");
554
           String sep = MetaCatUtil.getOption("accNumSeparator");
555
           StringBuffer btBuf = new StringBuffer();
556
           btBuf.append("select docid from xml_relation where ");
557

    
558
           //build the doctype list for the backtracking sql statement
559
           btBuf.append("packagetype in (");
560
           for (int i = 0; i < returndocVec.size(); i++)
561
           {
562
             btBuf.append("'").append((String) returndocVec.get(i)).append("'");
563
             if (i != (returndocVec.size() - 1))
564
             {
565
                btBuf.append(", ");
566
              }
567
            }
568
            btBuf.append(") ");
569
            btBuf.append("and (subject like '");
570
            btBuf.append(docid).append("'");
571
            btBuf.append("or object like '");
572
            btBuf.append(docid).append("')");
573

    
574
            PreparedStatement npstmt = dbconn.prepareStatement(btBuf.toString());
575
            //should incease usage count
576
            dbconn.increaseUsageCount(1);
577
            npstmt.execute();
578
            ResultSet btrs = npstmt.getResultSet();
579
            boolean hasBtRows = btrs.next();
580
            while (hasBtRows)
581
            {
582
               //there was a backtrackable document found
583
               DocumentImpl xmldoc = null;
584
               String packageDocid = btrs.getString(1);
585
               logMetacat.info("Getting document for docid: "
586
                                         + packageDocid);
587
                try
588
                {
589
                    //  THIS CONSTRUCTOR BUILDS THE WHOLE XML doc not
590
                    // needed here
591
                    // xmldoc = new DocumentImpl(dbconn, packageDocid);
592
                    //  thus use the following to get the doc info only
593
                    //  xmldoc = new DocumentImpl(dbconn);
594
                    String accNumber = packageDocid + MetaCatUtil.getOption("accNumSeparator") +
595
                    DBUtil.getLatestRevisionInDocumentTable(packageDocid);
596
                    xmldoc = new DocumentImpl(accNumber, false);
597
                    if (xmldoc == null)
598
                    {
599
                       logMetacat.info("Document was null for: "
600
                                                + packageDocid);
601
                    }
602
                }
603
                catch (Exception e)
604
                {
605
                    System.out.println("Error getting document in "
606
                                       + "DBQuery.findDocuments: "
607
                                       + e.getMessage());
608
                }
609

    
610
                String docid_org = xmldoc.getDocID();
611
                if (docid_org == null)
612
                {
613
                   logMetacat.info("Docid_org was null.");
614
                   //continue;
615
                }
616
                docid = docid_org.trim();
617
                docname = xmldoc.getDocname();
618
                doctype = xmldoc.getDoctype();
619
                createDate = xmldoc.getCreateDate();
620
                updateDate = xmldoc.getUpdateDate();
621
                rev = xmldoc.getRev();
622
                document = new StringBuffer();
623

    
624
                String completeDocid = docid
625
                                + MetaCatUtil.getOption("accNumSeparator");
626
                completeDocid += rev;
627
                document.append("<docid>").append(completeDocid);
628
                document.append("</docid>");
629
                if (docname != null)
630
                {
631
                  document.append("<docname>" + docname + "</docname>");
632
                }
633
                if (doctype != null)
634
                {
635
                  document.append("<doctype>" + doctype + "</doctype>");
636
                }
637
                if (createDate != null)
638
                {
639
                 document.append("<createdate>" + createDate + "</createdate>");
640
                }
641
                if (updateDate != null)
642
                {
643
                  document.append("<updatedate>" + updateDate+ "</updatedate>");
644
                }
645
                // Store the document id and the root node id
646
                docListResult.put(docid, (String) document.toString());
647
                count++;
648

    
649

    
650
                // Get the next package document linked to our hit
651
                hasBtRows = btrs.next();
652
              }//while
653
              npstmt.close();
654
              btrs.close();
655
        }
656
        else if (returndocVec.size() == 0 || returndocVec.contains(doctype))
657
        {
658

    
659
           document = new StringBuffer();
660

    
661
           String completeDocid = docid
662
                            + MetaCatUtil.getOption("accNumSeparator");
663
           completeDocid += rev;
664
           document.append("<docid>").append(completeDocid).append("</docid>");
665
           if (docname != null)
666
           {
667
               document.append("<docname>" + docname + "</docname>");
668
            }
669
            if (doctype != null)
670
            {
671
               document.append("<doctype>" + doctype + "</doctype>");
672
            }
673
            if (createDate != null)
674
            {
675
                document.append("<createdate>" + createDate + "</createdate>");
676
             }
677
             if (updateDate != null)
678
             {
679
               document.append("<updatedate>" + updateDate + "</updatedate>");
680
             }
681
              // Store the document id and the root node id
682
              docListResult.put(docid, (String) document.toString());
683
              count++;
684

    
685

    
686
        }//else
687
        // when doclist reached the offset number, send out doc list and empty
688
        // the hash table
689
        if (count == offset)
690
        {
691
          //reset count
692
          count = 0;
693
          handleSubsetResult(qspec,resultsetBuffer, out, docListResult,
694
                              user, groups,dbconn, useXMLIndex);
695
          // reset docListResult
696
          docListResult = new Hashtable();
697

    
698
        }
699
       // Advance to the next record in the cursor
700
       tableHasRows = rs.next();
701
     }//while
702
     rs.close();
703
     pstmt.close();
704
     //if docListResult is not empty, it need to be sent.
705
     if (!docListResult.isEmpty())
706
     {
707
       handleSubsetResult(qspec,resultsetBuffer, out, docListResult,
708
                              user, groups,dbconn, useXMLIndex);
709
     }
710
     double docListTime = System.currentTimeMillis() / 1000;
711
     logMetacat.warn("prepare docid list time: "
712
                    + (docListTime - queryExecuteTime));
713

    
714

    
715
     return resultsetBuffer;
716
    }//findReturnDoclist
717

    
718

    
719
    /*
720
     * Send completed search hashtable(part of reulst)to output stream
721
     * and buffer into a buffer stream
722
     */
723
    private StringBuffer handleSubsetResult(QuerySpecification qspec,
724
                                           StringBuffer resultset,
725
                                           PrintWriter out, Hashtable partOfDoclist,
726
                                           String user, String[]groups,
727
                                       DBConnection dbconn, boolean useXMLIndex)
728
                                       throws Exception
729
   {
730

    
731
     // check if there is a record in xml_returnfield
732
     // and get the returnfield_id and usage count
733
     int usage_count = getXmlReturnfieldsTableId(qspec, dbconn);
734
     boolean enterRecords = false;
735

    
736
     // get value of xml_returnfield_count
737
     int count = (new Integer(MetaCatUtil
738
                            .getOption("xml_returnfield_count")))
739
                            .intValue();
740

    
741
     // set enterRecords to true if usage_count is more than the offset
742
     // specified in metacat.properties
743
     if(usage_count > count){
744
         enterRecords = true;
745
     }
746

    
747
     if(returnfield_id < 0){
748
         logMetacat.warn("Error in getting returnfield id from"
749
                                  + "xml_returnfield table");
750
	enterRecords = false;
751
     }
752

    
753
     // get the hashtable containing the docids that already in the
754
     // xml_queryresult table
755
     logMetacat.info("size of partOfDoclist before"
756
                             + " docidsInQueryresultTable(): "
757
                             + partOfDoclist.size());
758
     Hashtable queryresultDocList = docidsInQueryresultTable(returnfield_id,
759
                                                        partOfDoclist, dbconn);
760

    
761
     // remove the keys in queryresultDocList from partOfDoclist
762
     Enumeration _keys = queryresultDocList.keys();
763
     while (_keys.hasMoreElements()){
764
         partOfDoclist.remove(_keys.nextElement());
765
     }
766

    
767
     // backup the keys-elements in partOfDoclist to check later
768
     // if the doc entry is indexed yet
769
     Hashtable partOfDoclistBackup = new Hashtable();
770
     _keys = partOfDoclist.keys();
771
     while (_keys.hasMoreElements()){
772
	 Object key = _keys.nextElement();
773
         partOfDoclistBackup.put(key, partOfDoclist.get(key));
774
     }
775

    
776
     logMetacat.info("size of partOfDoclist after"
777
                             + " docidsInQueryresultTable(): "
778
                             + partOfDoclist.size());
779

    
780
     //add return fields for the documents in partOfDoclist
781
     partOfDoclist = addReturnfield(partOfDoclist, qspec, user, groups,
782
                                        dbconn, useXMLIndex );
783
     //add relationship part part docid list for the documents in partOfDocList
784
     partOfDoclist = addRelationship(partOfDoclist, qspec, dbconn, useXMLIndex);
785

    
786

    
787
     Enumeration keys = partOfDoclist.keys();
788
     String key = null;
789
     String element = null;
790
     String query = null;
791
     int offset = (new Integer(MetaCatUtil
792
                               .getOption("queryresult_string_length")))
793
                               .intValue();
794
     while (keys.hasMoreElements())
795
     {
796
         key = (String) keys.nextElement();
797
         element = (String)partOfDoclist.get(key);
798

    
799
	 // check if the enterRecords is true, elements is not null, element's
800
         // length is less than the limit of table column and if the document
801
         // has been indexed already
802
         if(enterRecords && element != null
803
		&& element.length() < offset
804
		&& element.compareTo((String) partOfDoclistBackup.get(key)) != 0){
805
             query = "INSERT INTO xml_queryresult (returnfield_id, docid, "
806
                 + "queryresult_string) VALUES (?, ?, ?)";
807

    
808
             PreparedStatement pstmt = null;
809
             pstmt = dbconn.prepareStatement(query);
810
             pstmt.setInt(1, returnfield_id);
811
             pstmt.setString(2, key);
812
             pstmt.setString(3, element);
813

    
814
             dbconn.increaseUsageCount(1);
815
             pstmt.execute();
816
             pstmt.close();
817
         }
818

    
819
         // A string with element
820
         String xmlElement = "  <document>" + element + "</document>";
821

    
822
         //send single element to output
823
         if (out != null)
824
         {
825
             out.println(xmlElement);
826
         }
827
         resultset.append(xmlElement);
828
     }//while
829

    
830

    
831
     keys = queryresultDocList.keys();
832
     while (keys.hasMoreElements())
833
     {
834
         key = (String) keys.nextElement();
835
         element = (String)queryresultDocList.get(key);
836
         // A string with element
837
         String xmlElement = "  <document>" + element + "</document>";
838
         //send single element to output
839
         if (out != null)
840
         {
841
             out.println(xmlElement);
842
         }
843
         resultset.append(xmlElement);
844
     }//while
845

    
846
     return resultset;
847
 }
848

    
849
   /**
850
    * Get the docids already in xml_queryresult table and corresponding
851
    * queryresultstring as a hashtable
852
    */
853
   private Hashtable docidsInQueryresultTable(int returnfield_id,
854
                                              Hashtable partOfDoclist,
855
                                              DBConnection dbconn){
856

    
857
         Hashtable returnValue = new Hashtable();
858
         PreparedStatement pstmt = null;
859
         ResultSet rs = null;
860

    
861
         // get partOfDoclist as string for the query
862
         Enumeration keylist = partOfDoclist.keys();
863
         StringBuffer doclist = new StringBuffer();
864
         while (keylist.hasMoreElements())
865
         {
866
             doclist.append("'");
867
             doclist.append((String) keylist.nextElement());
868
             doclist.append("',");
869
         }//while
870

    
871

    
872
         if (doclist.length() > 0)
873
         {
874
             doclist.deleteCharAt(doclist.length() - 1); //remove the last comma
875

    
876
             // the query to find out docids from xml_queryresult
877
             String query = "select docid, queryresult_string from "
878
                          + "xml_queryresult where returnfield_id = " +
879
                          returnfield_id +" and docid in ("+ doclist + ")";
880
             logMetacat.info("Query to get docids from xml_queryresult:"
881
                                      + query);
882

    
883
             try {
884
                 // prepare and execute the query
885
                 pstmt = dbconn.prepareStatement(query);
886
                 dbconn.increaseUsageCount(1);
887
                 pstmt.execute();
888
                 rs = pstmt.getResultSet();
889
                 boolean tableHasRows = rs.next();
890
                 while (tableHasRows) {
891
                     // store the returned results in the returnValue hashtable
892
                     String key = rs.getString(1);
893
                     String element = rs.getString(2);
894

    
895
                     if(element != null){
896
                         returnValue.put(key, element);
897
                     } else {
898
                         logMetacat.info("Null elment found ("
899
                         + "DBQuery.docidsInQueryresultTable)");
900
                     }
901
                     tableHasRows = rs.next();
902
                 }
903
                 rs.close();
904
                 pstmt.close();
905
             } catch (Exception e){
906
                 logMetacat.error("Error getting docids from "
907
                                          + "queryresult in "
908
                                          + "DBQuery.docidsInQueryresultTable: "
909
                                          + e.getMessage());
910
              }
911
         }
912
         return returnValue;
913
     }
914

    
915

    
916
   /**
917
    * Method to get id from xml_returnfield table
918
    * for a given query specification
919
    */
920
   private int returnfield_id;
921
   private int getXmlReturnfieldsTableId(QuerySpecification qspec,
922
                                           DBConnection dbconn){
923
       int id = -1;
924
       int count = 1;
925
       PreparedStatement pstmt = null;
926
       ResultSet rs = null;
927
       String returnfield = qspec.getSortedReturnFieldString();
928

    
929
       // query for finding the id from xml_returnfield
930
       String query = "SELECT returnfield_id, usage_count FROM xml_returnfield "
931
            + "WHERE returnfield_string LIKE ?";
932
       logMetacat.info("ReturnField Query:" + query);
933

    
934
       try {
935
           // prepare and run the query
936
           pstmt = dbconn.prepareStatement(query);
937
           pstmt.setString(1,returnfield);
938
           dbconn.increaseUsageCount(1);
939
           pstmt.execute();
940
           rs = pstmt.getResultSet();
941
           boolean tableHasRows = rs.next();
942

    
943
           // if record found then increase the usage count
944
           // else insert a new record and get the id of the new record
945
           if(tableHasRows){
946
               // get the id
947
               id = rs.getInt(1);
948
               count = rs.getInt(2) + 1;
949
               rs.close();
950
               pstmt.close();
951

    
952
               // increase the usage count
953
               query = "UPDATE xml_returnfield SET usage_count ='" + count
954
                   + "' WHERE returnfield_id ='"+ id +"'";
955
               logMetacat.info("ReturnField Table Update:"+ query);
956

    
957
               pstmt = dbconn.prepareStatement(query);
958
               dbconn.increaseUsageCount(1);
959
               pstmt.execute();
960
               pstmt.close();
961

    
962
           } else {
963
               rs.close();
964
               pstmt.close();
965

    
966
               // insert a new record
967
               query = "INSERT INTO xml_returnfield (returnfield_string, usage_count)"
968
                   + "VALUES (?, '1')";
969
               logMetacat.info("ReturnField Table Insert:"+ query);
970
               pstmt = dbconn.prepareStatement(query);
971
               pstmt.setString(1, returnfield);
972
               dbconn.increaseUsageCount(1);
973
               pstmt.execute();
974
               pstmt.close();
975

    
976
               // get the id of the new record
977
               query = "SELECT returnfield_id FROM xml_returnfield "
978
                   + "WHERE returnfield_string LIKE ?";
979
               logMetacat.info("ReturnField query after Insert:" + query);
980
               pstmt = dbconn.prepareStatement(query);
981
               pstmt.setString(1, returnfield);
982

    
983
               dbconn.increaseUsageCount(1);
984
               pstmt.execute();
985
               rs = pstmt.getResultSet();
986
               if(rs.next()){
987
                   id = rs.getInt(1);
988
               } else {
989
                   id = -1;
990
               }
991
               rs.close();
992
               pstmt.close();
993
           }
994

    
995
       } catch (Exception e){
996
           logMetacat.error("Error getting id from xml_returnfield in "
997
                                     + "DBQuery.getXmlReturnfieldsTableId: "
998
                                     + e.getMessage());
999
           id = -1;
1000
       }
1001

    
1002
       returnfield_id = id;
1003
       return count;
1004
   }
1005

    
1006

    
1007
    /*
1008
     * A method to add return field to return doclist hash table
1009
     */
1010
    private Hashtable addReturnfield(Hashtable docListResult,
1011
                                      QuerySpecification qspec,
1012
                                      String user, String[]groups,
1013
                                      DBConnection dbconn, boolean useXMLIndex )
1014
                                      throws Exception
1015
    {
1016
      PreparedStatement pstmt = null;
1017
      ResultSet rs = null;
1018
      String docid = null;
1019
      String fieldname = null;
1020
      String fielddata = null;
1021
      String relation = null;
1022

    
1023
      if (qspec.containsExtendedSQL())
1024
      {
1025
        qspec.setUserName(user);
1026
        qspec.setGroup(groups);
1027
        Vector extendedFields = new Vector(qspec.getReturnFieldList());
1028
        Vector results = new Vector();
1029
        Enumeration keylist = docListResult.keys();
1030
        StringBuffer doclist = new StringBuffer();
1031
        Vector parentidList = new Vector();
1032
        Hashtable returnFieldValue = new Hashtable();
1033
        while (keylist.hasMoreElements())
1034
        {
1035
          doclist.append("'");
1036
          doclist.append((String) keylist.nextElement());
1037
          doclist.append("',");
1038
        }
1039
        if (doclist.length() > 0)
1040
        {
1041
          Hashtable controlPairs = new Hashtable();
1042
          double extendedQueryStart = System.currentTimeMillis() / 1000;
1043
          doclist.deleteCharAt(doclist.length() - 1); //remove the last comma
1044
          // check if user has permission to see the return field data
1045
          String accessControlSQL =
1046
                 qspec.printAccessControlSQLForReturnField(doclist.toString());
1047
          pstmt = dbconn.prepareStatement(accessControlSQL);
1048
          //increase dbconnection usage count
1049
          dbconn.increaseUsageCount(1);
1050
          pstmt.execute();
1051
          rs = pstmt.getResultSet();
1052
          boolean tableHasRows = rs.next();
1053
          while (tableHasRows)
1054
          {
1055
            long startNodeId = rs.getLong(1);
1056
            long endNodeId = rs.getLong(2);
1057
            controlPairs.put(new Long(startNodeId), new Long(endNodeId));
1058
            tableHasRows = rs.next();
1059
          }
1060

    
1061
           double extendedAccessQueryEnd = System.currentTimeMillis() / 1000;
1062
           logMetacat.info( "Time for execute access extended query: "
1063
                          + (extendedAccessQueryEnd - extendedQueryStart));
1064

    
1065
           String extendedQuery =
1066
               qspec.printExtendedSQL(doclist.toString(), controlPairs, useXMLIndex);
1067
           logMetacat.warn("Extended query: " + extendedQuery);
1068

    
1069
           if(extendedQuery != null){
1070
               pstmt = dbconn.prepareStatement(extendedQuery);
1071
               //increase dbconnection usage count
1072
               dbconn.increaseUsageCount(1);
1073
               pstmt.execute();
1074
               rs = pstmt.getResultSet();
1075
               double extendedQueryEnd = System.currentTimeMillis() / 1000;
1076
               logMetacat.info(
1077
                   "Time for execute extended query: "
1078
                   + (extendedQueryEnd - extendedQueryStart));
1079
               tableHasRows = rs.next();
1080
               while (tableHasRows) {
1081
                   ReturnFieldValue returnValue = new ReturnFieldValue();
1082
                   docid = rs.getString(1).trim();
1083
                   fieldname = rs.getString(2);
1084
                   fielddata = rs.getString(3);
1085
                   fielddata = MetaCatUtil.normalize(fielddata);
1086
                   String parentId = rs.getString(4);
1087
                   StringBuffer value = new StringBuffer();
1088

    
1089
                   // if xml_index is used, there would be just one record per nodeid
1090
                   // as xml_index just keeps one entry for each path
1091
                   if (useXMLIndex || !containsKey(parentidList, parentId)) {
1092
                       // don't need to merger nodedata
1093
                       value.append("<param name=\"");
1094
                       value.append(fieldname);
1095
                       value.append("\">");
1096
                       value.append(fielddata);
1097
                       value.append("</param>");
1098
                       //set returnvalue
1099
                       returnValue.setDocid(docid);
1100
                       returnValue.setFieldValue(fielddata);
1101
                       returnValue.setXMLFieldValue(value.toString());
1102
                       // Store it in hastable
1103
                       putInArray(parentidList, parentId, returnValue);
1104
                   }
1105
                   else {
1106
                       // need to merge nodedata if they have same parent id and
1107
                       // node type is text
1108
                       fielddata = (String) ( (ReturnFieldValue)
1109
                                             getArrayValue(
1110
                           parentidList, parentId)).getFieldValue()
1111
                           + fielddata;
1112
                       value.append("<param name=\"");
1113
                       value.append(fieldname);
1114
                       value.append("\">");
1115
                       value.append(fielddata);
1116
                       value.append("</param>");
1117
                       returnValue.setDocid(docid);
1118
                       returnValue.setFieldValue(fielddata);
1119
                       returnValue.setXMLFieldValue(value.toString());
1120
                       // remove the old return value from paretnidList
1121
                       parentidList.remove(parentId);
1122
                       // store the new return value in parentidlit
1123
                       putInArray(parentidList, parentId, returnValue);
1124
                   }
1125
                   tableHasRows = rs.next();
1126
               } //while
1127
               rs.close();
1128
               pstmt.close();
1129

    
1130
               // put the merger node data info into doclistReult
1131
               Enumeration xmlFieldValue = (getElements(parentidList)).
1132
                   elements();
1133
               while (xmlFieldValue.hasMoreElements()) {
1134
                   ReturnFieldValue object =
1135
                       (ReturnFieldValue) xmlFieldValue.nextElement();
1136
                   docid = object.getDocid();
1137
                   if (docListResult.containsKey(docid)) {
1138
                       String removedelement = (String) docListResult.
1139
                           remove(docid);
1140
                       docListResult.
1141
                           put(docid,
1142
                               removedelement + object.getXMLFieldValue());
1143
                   }
1144
                   else {
1145
                       docListResult.put(docid, object.getXMLFieldValue());
1146
                   }
1147
               } //while
1148
               double docListResultEnd = System.currentTimeMillis() / 1000;
1149
               logMetacat.warn(
1150
                   "Time for prepare doclistresult after"
1151
                   + " execute extended query: "
1152
                   + (docListResultEnd - extendedQueryEnd));
1153
           }
1154

    
1155
           // get attribures return
1156
           docListResult = getAttributeValueForReturn(qspec,
1157
                           docListResult, doclist.toString(), useXMLIndex);
1158
       }//if doclist lenght is great than zero
1159

    
1160
     }//if has extended query
1161

    
1162
      return docListResult;
1163
    }//addReturnfield
1164

    
1165
    /*
1166
    * A method to add relationship to return doclist hash table
1167
    */
1168
   private Hashtable addRelationship(Hashtable docListResult,
1169
                                     QuerySpecification qspec,
1170
                                     DBConnection dbconn, boolean useXMLIndex )
1171
                                     throws Exception
1172
  {
1173
    PreparedStatement pstmt = null;
1174
    ResultSet rs = null;
1175
    StringBuffer document = null;
1176
    double startRelation = System.currentTimeMillis() / 1000;
1177
    Enumeration docidkeys = docListResult.keys();
1178
    while (docidkeys.hasMoreElements())
1179
    {
1180
      //String connstring =
1181
      // "metacat://"+util.getOption("server")+"?docid=";
1182
      String connstring = "%docid=";
1183
      String docidkey = (String) docidkeys.nextElement();
1184
      pstmt = dbconn.prepareStatement(QuerySpecification
1185
                      .printRelationSQL(docidkey));
1186
      pstmt.execute();
1187
      rs = pstmt.getResultSet();
1188
      boolean tableHasRows = rs.next();
1189
      while (tableHasRows)
1190
      {
1191
        String sub = rs.getString(1);
1192
        String rel = rs.getString(2);
1193
        String obj = rs.getString(3);
1194
        String subDT = rs.getString(4);
1195
        String objDT = rs.getString(5);
1196

    
1197
        document = new StringBuffer();
1198
        document.append("<triple>");
1199
        document.append("<subject>").append(MetaCatUtil.normalize(sub));
1200
        document.append("</subject>");
1201
        if (subDT != null)
1202
        {
1203
          document.append("<subjectdoctype>").append(subDT);
1204
          document.append("</subjectdoctype>");
1205
        }
1206
        document.append("<relationship>").append(MetaCatUtil.normalize(rel));
1207
        document.append("</relationship>");
1208
        document.append("<object>").append(MetaCatUtil.normalize(obj));
1209
        document.append("</object>");
1210
        if (objDT != null)
1211
        {
1212
          document.append("<objectdoctype>").append(objDT);
1213
          document.append("</objectdoctype>");
1214
        }
1215
        document.append("</triple>");
1216

    
1217
        String removedelement = (String) docListResult.remove(docidkey);
1218
        docListResult.put(docidkey, removedelement+ document.toString());
1219
        tableHasRows = rs.next();
1220
      }//while
1221
      rs.close();
1222
      pstmt.close();
1223
    }//while
1224
    double endRelation = System.currentTimeMillis() / 1000;
1225
    logMetacat.info("Time for adding relation to docListResult: "
1226
                             + (endRelation - startRelation));
1227

    
1228
    return docListResult;
1229
  }//addRelation
1230

    
1231
  /**
1232
   * removes the <?xml version="1.0"?> tag from the beginning.  This takes a
1233
   * string as a param instead of a hashtable.
1234
   *
1235
   * @param xmlquery a string representing a query.
1236
   */
1237
   private  String transformQuery(String xmlquery)
1238
   {
1239
     xmlquery = xmlquery.trim();
1240
     int index = xmlquery.indexOf("?>");
1241
     if (index != -1)
1242
     {
1243
       return xmlquery.substring(index + 2, xmlquery.length());
1244
     }
1245
     else
1246
     {
1247
       return xmlquery;
1248
     }
1249
   }
1250

    
1251

    
1252
    /*
1253
     * A method to search if Vector contains a particular key string
1254
     */
1255
    private boolean containsKey(Vector parentidList, String parentId)
1256
    {
1257

    
1258
        Vector tempVector = null;
1259

    
1260
        for (int count = 0; count < parentidList.size(); count++) {
1261
            tempVector = (Vector) parentidList.get(count);
1262
            if (parentId.compareTo((String) tempVector.get(0)) == 0) { return true; }
1263
        }
1264
        return false;
1265
    }
1266

    
1267
    /*
1268
     * A method to put key and value in Vector
1269
     */
1270
    private void putInArray(Vector parentidList, String key,
1271
            ReturnFieldValue value)
1272
    {
1273

    
1274
        Vector tempVector = null;
1275

    
1276
        for (int count = 0; count < parentidList.size(); count++) {
1277
            tempVector = (Vector) parentidList.get(count);
1278

    
1279
            if (key.compareTo((String) tempVector.get(0)) == 0) {
1280
                tempVector.remove(1);
1281
                tempVector.add(1, value);
1282
                return;
1283
            }
1284
        }
1285

    
1286
        tempVector = new Vector();
1287
        tempVector.add(0, key);
1288
        tempVector.add(1, value);
1289
        parentidList.add(tempVector);
1290
        return;
1291
    }
1292

    
1293
    /*
1294
     * A method to get value in Vector given a key
1295
     */
1296
    private ReturnFieldValue getArrayValue(Vector parentidList, String key)
1297
    {
1298

    
1299
        Vector tempVector = null;
1300

    
1301
        for (int count = 0; count < parentidList.size(); count++) {
1302
            tempVector = (Vector) parentidList.get(count);
1303

    
1304
            if (key.compareTo((String) tempVector.get(0)) == 0) { return (ReturnFieldValue) tempVector
1305
                    .get(1); }
1306
        }
1307
        return null;
1308
    }
1309

    
1310
    /*
1311
     * A method to get enumeration of all values in Vector
1312
     */
1313
    private Vector getElements(Vector parentidList)
1314
    {
1315
        Vector enumVector = new Vector();
1316
        Vector tempVector = null;
1317

    
1318
        for (int count = 0; count < parentidList.size(); count++) {
1319
            tempVector = (Vector) parentidList.get(count);
1320

    
1321
            enumVector.add(tempVector.get(1));
1322
        }
1323
        return enumVector;
1324
    }
1325

    
1326
    /*
1327
     * A method to return search result after running a query which return
1328
     * field have attribue
1329
     */
1330
    private Hashtable getAttributeValueForReturn(QuerySpecification squery,
1331
            Hashtable docInformationList, String docList, boolean useXMLIndex)
1332
    {
1333
        StringBuffer XML = null;
1334
        String sql = null;
1335
        DBConnection dbconn = null;
1336
        PreparedStatement pstmt = null;
1337
        ResultSet rs = null;
1338
        int serialNumber = -1;
1339
        boolean tableHasRows = false;
1340

    
1341
        //check the parameter
1342
        if (squery == null || docList == null || docList.length() < 0) { return docInformationList; }
1343

    
1344
        // if has attribute as return field
1345
        if (squery.containsAttributeReturnField()) {
1346
            sql = squery.printAttributeQuery(docList, useXMLIndex);
1347
            try {
1348
                dbconn = DBConnectionPool
1349
                        .getDBConnection("DBQuery.getAttributeValue");
1350
                serialNumber = dbconn.getCheckOutSerialNumber();
1351
                pstmt = dbconn.prepareStatement(sql);
1352
                pstmt.execute();
1353
                rs = pstmt.getResultSet();
1354
                tableHasRows = rs.next();
1355
                while (tableHasRows) {
1356
                    String docid = rs.getString(1).trim();
1357
                    String fieldname = rs.getString(2);
1358
                    String fielddata = rs.getString(3);
1359
                    String attirbuteName = rs.getString(4);
1360
                    XML = new StringBuffer();
1361

    
1362
                    XML.append("<param name=\"");
1363
                    XML.append(fieldname);
1364
                    XML.append("/");
1365
                    XML.append(QuerySpecification.ATTRIBUTESYMBOL);
1366
                    XML.append(attirbuteName);
1367
                    XML.append("\">");
1368
                    XML.append(fielddata);
1369
                    XML.append("</param>");
1370
                    tableHasRows = rs.next();
1371

    
1372
                    if (docInformationList.containsKey(docid)) {
1373
                        String removedelement = (String) docInformationList
1374
                                .remove(docid);
1375
                        docInformationList.put(docid, removedelement
1376
                                + XML.toString());
1377
                    } else {
1378
                        docInformationList.put(docid, XML.toString());
1379
                    }
1380
                }//while
1381
                rs.close();
1382
                pstmt.close();
1383
            } catch (Exception se) {
1384
                logMetacat.error(
1385
                        "Error in DBQuery.getAttributeValue1: "
1386
                                + se.getMessage());
1387
            } finally {
1388
                try {
1389
                    pstmt.close();
1390
                }//try
1391
                catch (SQLException sqlE) {
1392
                    logMetacat.error(
1393
                            "Error in DBQuery.getAttributeValue2: "
1394
                                    + sqlE.getMessage());
1395
                }//catch
1396
                finally {
1397
                    DBConnectionPool.returnDBConnection(dbconn, serialNumber);
1398
                }//finally
1399
            }//finally
1400
        }//if
1401
        return docInformationList;
1402

    
1403
    }
1404

    
1405
    /*
1406
     * A method to create a query to get owner's docid list
1407
     */
1408
    private String getOwnerQuery(String owner)
1409
    {
1410
        if (owner != null) {
1411
            owner = owner.toLowerCase();
1412
        }
1413
        StringBuffer self = new StringBuffer();
1414

    
1415
        self.append("SELECT docid,docname,doctype,");
1416
        self.append("date_created, date_updated, rev ");
1417
        self.append("FROM xml_documents WHERE docid IN (");
1418
        self.append("(");
1419
        self.append("SELECT DISTINCT docid FROM xml_nodes WHERE \n");
1420
        self.append("nodedata LIKE '%%%' ");
1421
        self.append(") \n");
1422
        self.append(") ");
1423
        self.append(" AND (");
1424
        self.append(" lower(user_owner) = '" + owner + "'");
1425
        self.append(") ");
1426
        return self.toString();
1427
    }
1428

    
1429
    /**
1430
     * format a structured query as an XML document that conforms to the
1431
     * pathquery.dtd and is appropriate for submission to the DBQuery
1432
     * structured query engine
1433
     *
1434
     * @param params The list of parameters that should be included in the
1435
     *            query
1436
     */
1437
    public static String createSQuery(Hashtable params)
1438
    {
1439
        StringBuffer query = new StringBuffer();
1440
        Enumeration elements;
1441
        Enumeration keys;
1442
        String filterDoctype = null;
1443
        String casesensitive = null;
1444
        String searchmode = null;
1445
        Object nextkey;
1446
        Object nextelement;
1447
        //add the xml headers
1448
        query.append("<?xml version=\"1.0\"?>\n");
1449
        query.append("<pathquery version=\"1.2\">\n");
1450

    
1451

    
1452

    
1453
        if (params.containsKey("meta_file_id")) {
1454
            query.append("<meta_file_id>");
1455
            query.append(((String[]) params.get("meta_file_id"))[0]);
1456
            query.append("</meta_file_id>");
1457
        }
1458

    
1459
        if (params.containsKey("returndoctype")) {
1460
            String[] returnDoctypes = ((String[]) params.get("returndoctype"));
1461
            for (int i = 0; i < returnDoctypes.length; i++) {
1462
                String doctype = (String) returnDoctypes[i];
1463

    
1464
                if (!doctype.equals("any") && !doctype.equals("ANY")
1465
                        && !doctype.equals("")) {
1466
                    query.append("<returndoctype>").append(doctype);
1467
                    query.append("</returndoctype>");
1468
                }
1469
            }
1470
        }
1471

    
1472
        if (params.containsKey("filterdoctype")) {
1473
            String[] filterDoctypes = ((String[]) params.get("filterdoctype"));
1474
            for (int i = 0; i < filterDoctypes.length; i++) {
1475
                query.append("<filterdoctype>").append(filterDoctypes[i]);
1476
                query.append("</filterdoctype>");
1477
            }
1478
        }
1479

    
1480
        if (params.containsKey("returnfield")) {
1481
            String[] returnfield = ((String[]) params.get("returnfield"));
1482
            for (int i = 0; i < returnfield.length; i++) {
1483
                query.append("<returnfield>").append(returnfield[i]);
1484
                query.append("</returnfield>");
1485
            }
1486
        }
1487

    
1488
        if (params.containsKey("owner")) {
1489
            String[] owner = ((String[]) params.get("owner"));
1490
            for (int i = 0; i < owner.length; i++) {
1491
                query.append("<owner>").append(owner[i]);
1492
                query.append("</owner>");
1493
            }
1494
        }
1495

    
1496
        if (params.containsKey("site")) {
1497
            String[] site = ((String[]) params.get("site"));
1498
            for (int i = 0; i < site.length; i++) {
1499
                query.append("<site>").append(site[i]);
1500
                query.append("</site>");
1501
            }
1502
        }
1503

    
1504
        //allows the dynamic switching of boolean operators
1505
        if (params.containsKey("operator")) {
1506
            query.append("<querygroup operator=\""
1507
                    + ((String[]) params.get("operator"))[0] + "\">");
1508
        } else { //the default operator is UNION
1509
            query.append("<querygroup operator=\"UNION\">");
1510
        }
1511

    
1512
        if (params.containsKey("casesensitive")) {
1513
            casesensitive = ((String[]) params.get("casesensitive"))[0];
1514
        } else {
1515
            casesensitive = "false";
1516
        }
1517

    
1518
        if (params.containsKey("searchmode")) {
1519
            searchmode = ((String[]) params.get("searchmode"))[0];
1520
        } else {
1521
            searchmode = "contains";
1522
        }
1523

    
1524
        //anyfield is a special case because it does a
1525
        //free text search. It does not have a <pathexpr>
1526
        //tag. This allows for a free text search within the structured
1527
        //query. This is useful if the INTERSECT operator is used.
1528
        if (params.containsKey("anyfield")) {
1529
            String[] anyfield = ((String[]) params.get("anyfield"));
1530
            //allow for more than one value for anyfield
1531
            for (int i = 0; i < anyfield.length; i++) {
1532
                if (!anyfield[i].equals("")) {
1533
                    query.append("<queryterm casesensitive=\"" + casesensitive
1534
                            + "\" " + "searchmode=\"" + searchmode
1535
                            + "\"><value>" + anyfield[i]
1536
                            + "</value></queryterm>");
1537
                }
1538
            }
1539
        }
1540

    
1541
        //this while loop finds the rest of the parameters
1542
        //and attempts to query for the field specified
1543
        //by the parameter.
1544
        elements = params.elements();
1545
        keys = params.keys();
1546
        while (keys.hasMoreElements() && elements.hasMoreElements()) {
1547
            nextkey = keys.nextElement();
1548
            nextelement = elements.nextElement();
1549

    
1550
            //make sure we aren't querying for any of these
1551
            //parameters since the are already in the query
1552
            //in one form or another.
1553
            Vector ignoredParams = new Vector();
1554
            ignoredParams.add("returndoctype");
1555
            ignoredParams.add("filterdoctype");
1556
            ignoredParams.add("action");
1557
            ignoredParams.add("qformat");
1558
            ignoredParams.add("anyfield");
1559
            ignoredParams.add("returnfield");
1560
            ignoredParams.add("owner");
1561
            ignoredParams.add("site");
1562
            ignoredParams.add("operator");
1563
            ignoredParams.add("sessionid");
1564
            ignoredParams.add("pagesize");
1565
            ignoredParams.add("pagestart");
1566

    
1567
            // Also ignore parameters listed in the properties file
1568
            // so that they can be passed through to stylesheets
1569
            String paramsToIgnore = MetaCatUtil
1570
                    .getOption("query.ignored.params");
1571
            StringTokenizer st = new StringTokenizer(paramsToIgnore, ",");
1572
            while (st.hasMoreTokens()) {
1573
                ignoredParams.add(st.nextToken());
1574
            }
1575
            if (!ignoredParams.contains(nextkey.toString())) {
1576
                //allow for more than value per field name
1577
                for (int i = 0; i < ((String[]) nextelement).length; i++) {
1578
                    if (!((String[]) nextelement)[i].equals("")) {
1579
                        query.append("<queryterm casesensitive=\""
1580
                                + casesensitive + "\" " + "searchmode=\""
1581
                                + searchmode + "\">" + "<value>" +
1582
                                //add the query value
1583
                                ((String[]) nextelement)[i]
1584
                                + "</value><pathexpr>" +
1585
                                //add the path to query by
1586
                                nextkey.toString() + "</pathexpr></queryterm>");
1587
                    }
1588
                }
1589
            }
1590
        }
1591
        query.append("</querygroup></pathquery>");
1592
        //append on the end of the xml and return the result as a string
1593
        return query.toString();
1594
    }
1595

    
1596
    /**
1597
     * format a simple free-text value query as an XML document that conforms
1598
     * to the pathquery.dtd and is appropriate for submission to the DBQuery
1599
     * structured query engine
1600
     *
1601
     * @param value the text string to search for in the xml catalog
1602
     * @param doctype the type of documents to include in the result set -- use
1603
     *            "any" or "ANY" for unfiltered result sets
1604
     */
1605
    public static String createQuery(String value, String doctype)
1606
    {
1607
        StringBuffer xmlquery = new StringBuffer();
1608
        xmlquery.append("<?xml version=\"1.0\"?>\n");
1609
        xmlquery.append("<pathquery version=\"1.0\">");
1610

    
1611
        if (!doctype.equals("any") && !doctype.equals("ANY")) {
1612
            xmlquery.append("<returndoctype>");
1613
            xmlquery.append(doctype).append("</returndoctype>");
1614
        }
1615

    
1616
        xmlquery.append("<querygroup operator=\"UNION\">");
1617
        //chad added - 8/14
1618
        //the if statement allows a query to gracefully handle a null
1619
        //query. Without this if a nullpointerException is thrown.
1620
        if (!value.equals("")) {
1621
            xmlquery.append("<queryterm casesensitive=\"false\" ");
1622
            xmlquery.append("searchmode=\"contains\">");
1623
            xmlquery.append("<value>").append(value).append("</value>");
1624
            xmlquery.append("</queryterm>");
1625
        }
1626
        xmlquery.append("</querygroup>");
1627
        xmlquery.append("</pathquery>");
1628

    
1629
        return (xmlquery.toString());
1630
    }
1631

    
1632
    /**
1633
     * format a simple free-text value query as an XML document that conforms
1634
     * to the pathquery.dtd and is appropriate for submission to the DBQuery
1635
     * structured query engine
1636
     *
1637
     * @param value the text string to search for in the xml catalog
1638
     */
1639
    public static String createQuery(String value)
1640
    {
1641
        return createQuery(value, "any");
1642
    }
1643

    
1644
    /**
1645
     * Check for "READ" permission on @docid for @user and/or @group from DB
1646
     * connection
1647
     */
1648
    private boolean hasPermission(String user, String[] groups, String docid)
1649
            throws SQLException, Exception
1650
    {
1651
        // Check for READ permission on @docid for @user and/or @groups
1652
        PermissionController controller = new PermissionController(docid);
1653
        return controller.hasPermission(user, groups,
1654
                AccessControlInterface.READSTRING);
1655
    }
1656

    
1657
    /**
1658
     * Get all docIds list for a data packadge
1659
     *
1660
     * @param dataPackageDocid, the string in docId field of xml_relation table
1661
     */
1662
    private Vector getCurrentDocidListForDataPackage(String dataPackageDocid)
1663
    {
1664
        DBConnection dbConn = null;
1665
        int serialNumber = -1;
1666
        Vector docIdList = new Vector();//return value
1667
        PreparedStatement pStmt = null;
1668
        ResultSet rs = null;
1669
        String docIdInSubjectField = null;
1670
        String docIdInObjectField = null;
1671

    
1672
        // Check the parameter
1673
        if (dataPackageDocid == null || dataPackageDocid.equals("")) { return docIdList; }//if
1674

    
1675
        //the query stirng
1676
        String query = "SELECT subject, object from xml_relation where docId = ?";
1677
        try {
1678
            dbConn = DBConnectionPool
1679
                    .getDBConnection("DBQuery.getCurrentDocidListForDataPackage");
1680
            serialNumber = dbConn.getCheckOutSerialNumber();
1681
            pStmt = dbConn.prepareStatement(query);
1682
            //bind the value to query
1683
            pStmt.setString(1, dataPackageDocid);
1684

    
1685
            //excute the query
1686
            pStmt.execute();
1687
            //get the result set
1688
            rs = pStmt.getResultSet();
1689
            //process the result
1690
            while (rs.next()) {
1691
                //In order to get the whole docIds in a data packadge,
1692
                //we need to put the docIds of subject and object field in
1693
                // xml_relation
1694
                //into the return vector
1695
                docIdInSubjectField = rs.getString(1);//the result docId in
1696
                                                      // subject field
1697
                docIdInObjectField = rs.getString(2);//the result docId in
1698
                                                     // object field
1699

    
1700
                //don't put the duplicate docId into the vector
1701
                if (!docIdList.contains(docIdInSubjectField)) {
1702
                    docIdList.add(docIdInSubjectField);
1703
                }
1704

    
1705
                //don't put the duplicate docId into the vector
1706
                if (!docIdList.contains(docIdInObjectField)) {
1707
                    docIdList.add(docIdInObjectField);
1708
                }
1709
            }//while
1710
            //close the pStmt
1711
            pStmt.close();
1712
        }//try
1713
        catch (SQLException e) {
1714
            logMetacat.error("Error in getDocidListForDataPackage: "
1715
                    + e.getMessage());
1716
        }//catch
1717
        finally {
1718
            try {
1719
                pStmt.close();
1720
            }//try
1721
            catch (SQLException ee) {
1722
                logMetacat.error(
1723
                        "Error in getDocidListForDataPackage: "
1724
                                + ee.getMessage());
1725
            }//catch
1726
            finally {
1727
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1728
            }//fianlly
1729
        }//finally
1730
        return docIdList;
1731
    }//getCurrentDocidListForDataPackadge()
1732

    
1733
    /**
1734
     * Get all docIds list for a data packadge
1735
     *
1736
     * @param dataPackageDocid, the string in docId field of xml_relation table
1737
     */
1738
    private Vector getOldVersionDocidListForDataPackage(String dataPackageDocidWithRev)
1739
    {
1740

    
1741
        Vector docIdList = new Vector();//return value
1742
        Vector tripleList = null;
1743
        String xml = null;
1744

    
1745
        // Check the parameter
1746
        if (dataPackageDocidWithRev == null || dataPackageDocidWithRev.equals("")) { return docIdList; }//if
1747

    
1748
        try {
1749
            //initial a documentImpl object
1750
            DocumentImpl packageDocument = new DocumentImpl(dataPackageDocidWithRev);
1751
            //transfer to documentImpl object to string
1752
            xml = packageDocument.toString();
1753

    
1754
            //create a tripcollection object
1755
            TripleCollection tripleForPackage = new TripleCollection(
1756
                    new StringReader(xml));
1757
            //get the vetor of triples
1758
            tripleList = tripleForPackage.getCollection();
1759

    
1760
            for (int i = 0; i < tripleList.size(); i++) {
1761
                //put subject docid into docIdlist without duplicate
1762
                if (!docIdList.contains(((Triple) tripleList.elementAt(i))
1763
                        .getSubject())) {
1764
                    //put subject docid into docIdlist
1765
                    docIdList.add(((Triple) tripleList.get(i)).getSubject());
1766
                }
1767
                //put object docid into docIdlist without duplicate
1768
                if (!docIdList.contains(((Triple) tripleList.elementAt(i))
1769
                        .getObject())) {
1770
                    docIdList.add(((Triple) (tripleList.get(i))).getObject());
1771
                }
1772
            }//for
1773
        }//try
1774
        catch (Exception e) {
1775
            logMetacat.error("Error in getOldVersionAllDocumentImpl: "
1776
                    + e.getMessage());
1777
        }//catch
1778

    
1779
        // return result
1780
        return docIdList;
1781
    }//getDocidListForPackageInXMLRevisions()
1782

    
1783
    /**
1784
     * Check if the docId is a data packadge id. If the id is a data packadage
1785
     * id, it should be store in the docId fields in xml_relation table. So we
1786
     * can use a query to get the entries which the docId equals the given
1787
     * value. If the result is null. The docId is not a packadge id. Otherwise,
1788
     * it is.
1789
     *
1790
     * @param docId, the id need to be checked
1791
     */
1792
    private boolean isDataPackageId(String docId)
1793
    {
1794
        boolean result = false;
1795
        PreparedStatement pStmt = null;
1796
        ResultSet rs = null;
1797
        String query = "SELECT docId from xml_relation where docId = ?";
1798
        DBConnection dbConn = null;
1799
        int serialNumber = -1;
1800
        try {
1801
            dbConn = DBConnectionPool
1802
                    .getDBConnection("DBQuery.isDataPackageId");
1803
            serialNumber = dbConn.getCheckOutSerialNumber();
1804
            pStmt = dbConn.prepareStatement(query);
1805
            //bind the value to query
1806
            pStmt.setString(1, docId);
1807
            //execute the query
1808
            pStmt.execute();
1809
            rs = pStmt.getResultSet();
1810
            //process the result
1811
            if (rs.next()) //There are some records for the id in docId fields
1812
            {
1813
                result = true;//It is a data packadge id
1814
            }
1815
            pStmt.close();
1816
        }//try
1817
        catch (SQLException e) {
1818
            logMetacat.error("Error in isDataPackageId: "
1819
                    + e.getMessage());
1820
        } finally {
1821
            try {
1822
                pStmt.close();
1823
            }//try
1824
            catch (SQLException ee) {
1825
                logMetacat.error("Error in isDataPackageId: "
1826
                        + ee.getMessage());
1827
            }//catch
1828
            finally {
1829
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1830
            }//finally
1831
        }//finally
1832
        return result;
1833
    }//isDataPackageId()
1834

    
1835
    /**
1836
     * Check if the user has the permission to export data package
1837
     *
1838
     * @param conn, the connection
1839
     * @param docId, the id need to be checked
1840
     * @param user, the name of user
1841
     * @param groups, the user's group
1842
     */
1843
    private boolean hasPermissionToExportPackage(String docId, String user,
1844
            String[] groups) throws Exception
1845
    {
1846
        //DocumentImpl doc=new DocumentImpl(conn,docId);
1847
        return DocumentImpl.hasReadPermission(user, groups, docId);
1848
    }
1849

    
1850
    /**
1851
     * Get the current Rev for a docid in xml_documents table
1852
     *
1853
     * @param docId, the id need to get version numb If the return value is -5,
1854
     *            means no value in rev field for this docid
1855
     */
1856
    private int getCurrentRevFromXMLDoumentsTable(String docId)
1857
            throws SQLException
1858
    {
1859
        int rev = -5;
1860
        PreparedStatement pStmt = null;
1861
        ResultSet rs = null;
1862
        String query = "SELECT rev from xml_documents where docId = ?";
1863
        DBConnection dbConn = null;
1864
        int serialNumber = -1;
1865
        try {
1866
            dbConn = DBConnectionPool
1867
                    .getDBConnection("DBQuery.getCurrentRevFromXMLDocumentsTable");
1868
            serialNumber = dbConn.getCheckOutSerialNumber();
1869
            pStmt = dbConn.prepareStatement(query);
1870
            //bind the value to query
1871
            pStmt.setString(1, docId);
1872
            //execute the query
1873
            pStmt.execute();
1874
            rs = pStmt.getResultSet();
1875
            //process the result
1876
            if (rs.next()) //There are some records for rev
1877
            {
1878
                rev = rs.getInt(1);
1879
                ;//It is the version for given docid
1880
            } else {
1881
                rev = -5;
1882
            }
1883

    
1884
        }//try
1885
        catch (SQLException e) {
1886
            logMetacat.error(
1887
                    "Error in getCurrentRevFromXMLDoumentsTable: "
1888
                            + e.getMessage());
1889
            throw e;
1890
        }//catch
1891
        finally {
1892
            try {
1893
                pStmt.close();
1894
            }//try
1895
            catch (SQLException ee) {
1896
                logMetacat.error(
1897
                        "Error in getCurrentRevFromXMLDoumentsTable: "
1898
                                + ee.getMessage());
1899
            }//catch
1900
            finally {
1901
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1902
            }//finally
1903
        }//finally
1904
        return rev;
1905
    }//getCurrentRevFromXMLDoumentsTable
1906

    
1907
    /**
1908
     * put a doc into a zip output stream
1909
     *
1910
     * @param docImpl, docmentImpl object which will be sent to zip output
1911
     *            stream
1912
     * @param zipOut, zip output stream which the docImpl will be put
1913
     * @param packageZipEntry, the zip entry name for whole package
1914
     */
1915
    private void addDocToZipOutputStream(DocumentImpl docImpl,
1916
            ZipOutputStream zipOut, String packageZipEntry)
1917
            throws ClassNotFoundException, IOException, SQLException,
1918
            McdbException, Exception
1919
    {
1920
        byte[] byteString = null;
1921
        ZipEntry zEntry = null;
1922

    
1923
        byteString = docImpl.toString().getBytes();
1924
        //use docId as the zip entry's name
1925
        zEntry = new ZipEntry(packageZipEntry + "/metadata/"
1926
                + docImpl.getDocID());
1927
        zEntry.setSize(byteString.length);
1928
        zipOut.putNextEntry(zEntry);
1929
        zipOut.write(byteString, 0, byteString.length);
1930
        zipOut.closeEntry();
1931

    
1932
    }//addDocToZipOutputStream()
1933

    
1934
    /**
1935
     * Transfer a docid vetor to a documentImpl vector. The documentImpl vetor
1936
     * only inlcudes current version. If a DocumentImple object couldn't find
1937
     * for a docid, then the String of this docid was added to vetor rather
1938
     * than DocumentImple object.
1939
     *
1940
     * @param docIdList, a vetor hold a docid list for a data package. In
1941
     *            docid, there is not version number in it.
1942
     */
1943

    
1944
    private Vector getCurrentAllDocumentImpl(Vector docIdList)
1945
            throws McdbException, Exception
1946
    {
1947
        //Connection dbConn=null;
1948
        Vector documentImplList = new Vector();
1949
        int rev = 0;
1950

    
1951
        // Check the parameter
1952
        if (docIdList.isEmpty()) { return documentImplList; }//if
1953

    
1954
        //for every docid in vector
1955
        for (int i = 0; i < docIdList.size(); i++) {
1956
            try {
1957
                //get newest version for this docId
1958
                rev = getCurrentRevFromXMLDoumentsTable((String) docIdList
1959
                        .elementAt(i));
1960

    
1961
                // There is no record for this docId in xml_documents table
1962
                if (rev == -5) {
1963
                    // Rather than put DocumentImple object, put a String
1964
                    // Object(docid)
1965
                    // into the documentImplList
1966
                    documentImplList.add((String) docIdList.elementAt(i));
1967
                    // Skip other code
1968
                    continue;
1969
                }
1970

    
1971
                String docidPlusVersion = ((String) docIdList.elementAt(i))
1972
                        + MetaCatUtil.getOption("accNumSeparator") + rev;
1973

    
1974
                //create new documentImpl object
1975
                DocumentImpl documentImplObject = new DocumentImpl(
1976
                        docidPlusVersion);
1977
                //add them to vector
1978
                documentImplList.add(documentImplObject);
1979
            }//try
1980
            catch (Exception e) {
1981
                logMetacat.error("Error in getCurrentAllDocumentImpl: "
1982
                        + e.getMessage());
1983
                // continue the for loop
1984
                continue;
1985
            }
1986
        }//for
1987
        return documentImplList;
1988
    }
1989

    
1990
    /**
1991
     * Transfer a docid vetor to a documentImpl vector. If a DocumentImple
1992
     * object couldn't find for a docid, then the String of this docid was
1993
     * added to vetor rather than DocumentImple object.
1994
     *
1995
     * @param docIdList, a vetor hold a docid list for a data package. In
1996
     *            docid, t here is version number in it.
1997
     */
1998
    private Vector getOldVersionAllDocumentImpl(Vector docIdList)
1999
    {
2000
        //Connection dbConn=null;
2001
        Vector documentImplList = new Vector();
2002
        String siteCode = null;
2003
        String uniqueId = null;
2004
        int rev = 0;
2005

    
2006
        // Check the parameter
2007
        if (docIdList.isEmpty()) { return documentImplList; }//if
2008

    
2009
        //for every docid in vector
2010
        for (int i = 0; i < docIdList.size(); i++) {
2011

    
2012
            String docidPlusVersion = (String) (docIdList.elementAt(i));
2013

    
2014
            try {
2015
                //create new documentImpl object
2016
                DocumentImpl documentImplObject = new DocumentImpl(
2017
                        docidPlusVersion);
2018
                //add them to vector
2019
                documentImplList.add(documentImplObject);
2020
            }//try
2021
            catch (McdbDocNotFoundException notFoundE) {
2022
                logMetacat.error(
2023
                        "Error in DBQuery.getOldVersionAllDocument" + "Imple"
2024
                                + notFoundE.getMessage());
2025
                // Rather than add a DocumentImple object into vetor, a String
2026
                // object
2027
                // - the doicd was added to the vector
2028
                documentImplList.add(docidPlusVersion);
2029
                // Continue the for loop
2030
                continue;
2031
            }//catch
2032
            catch (Exception e) {
2033
                logMetacat.error(
2034
                        "Error in DBQuery.getOldVersionAllDocument" + "Imple"
2035
                                + e.getMessage());
2036
                // Continue the for loop
2037
                continue;
2038
            }//catch
2039

    
2040
        }//for
2041
        return documentImplList;
2042
    }//getOldVersionAllDocumentImple
2043

    
2044
    /**
2045
     * put a data file into a zip output stream
2046
     *
2047
     * @param docImpl, docmentImpl object which will be sent to zip output
2048
     *            stream
2049
     * @param zipOut, the zip output stream which the docImpl will be put
2050
     * @param packageZipEntry, the zip entry name for whole package
2051
     */
2052
    private void addDataFileToZipOutputStream(DocumentImpl docImpl,
2053
            ZipOutputStream zipOut, String packageZipEntry)
2054
            throws ClassNotFoundException, IOException, SQLException,
2055
            McdbException, Exception
2056
    {
2057
        byte[] byteString = null;
2058
        ZipEntry zEntry = null;
2059
        // this is data file; add file to zip
2060
        String filePath = MetaCatUtil.getOption("datafilepath");
2061
        if (!filePath.endsWith("/")) {
2062
            filePath += "/";
2063
        }
2064
        String fileName = filePath + docImpl.getDocID();
2065
        zEntry = new ZipEntry(packageZipEntry + "/data/" + docImpl.getDocID());
2066
        zipOut.putNextEntry(zEntry);
2067
        FileInputStream fin = null;
2068
        try {
2069
            fin = new FileInputStream(fileName);
2070
            byte[] buf = new byte[4 * 1024]; // 4K buffer
2071
            int b = fin.read(buf);
2072
            while (b != -1) {
2073
                zipOut.write(buf, 0, b);
2074
                b = fin.read(buf);
2075
            }//while
2076
            zipOut.closeEntry();
2077
        }//try
2078
        catch (IOException ioe) {
2079
            logMetacat.error("There is an exception: "
2080
                    + ioe.getMessage());
2081
        }//catch
2082
    }//addDataFileToZipOutputStream()
2083

    
2084
    /**
2085
     * create a html summary for data package and put it into zip output stream
2086
     *
2087
     * @param docImplList, the documentImpl ojbects in data package
2088
     * @param zipOut, the zip output stream which the html should be put
2089
     * @param packageZipEntry, the zip entry name for whole package
2090
     */
2091
    private void addHtmlSummaryToZipOutputStream(Vector docImplList,
2092
            ZipOutputStream zipOut, String packageZipEntry) throws Exception
2093
    {
2094
        StringBuffer htmlDoc = new StringBuffer();
2095
        ZipEntry zEntry = null;
2096
        byte[] byteString = null;
2097
        InputStream source;
2098
        DBTransform xmlToHtml;
2099

    
2100
        //create a DBTransform ojbect
2101
        xmlToHtml = new DBTransform();
2102
        //head of html
2103
        htmlDoc.append("<html><head></head><body>");
2104
        for (int i = 0; i < docImplList.size(); i++) {
2105
            // If this String object, this means it is missed data file
2106
            if ((((docImplList.elementAt(i)).getClass()).toString())
2107
                    .equals("class java.lang.String")) {
2108

    
2109
                htmlDoc.append("<a href=\"");
2110
                String dataFileid = (String) docImplList.elementAt(i);
2111
                htmlDoc.append("./data/").append(dataFileid).append("\">");
2112
                htmlDoc.append("Data File: ");
2113
                htmlDoc.append(dataFileid).append("</a><br>");
2114
                htmlDoc.append("<br><hr><br>");
2115

    
2116
            }//if
2117
            else if ((((DocumentImpl) docImplList.elementAt(i)).getDoctype())
2118
                    .compareTo("BIN") != 0) { //this is an xml file so we can
2119
                                              // transform it.
2120
                //transform each file individually then concatenate all of the
2121
                //transformations together.
2122

    
2123
                //for metadata xml title
2124
                htmlDoc.append("<h2>");
2125
                htmlDoc.append(((DocumentImpl) docImplList.elementAt(i))
2126
                        .getDocID());
2127
                //htmlDoc.append(".");
2128
                //htmlDoc.append(((DocumentImpl)docImplList.elementAt(i)).getRev());
2129
                htmlDoc.append("</h2>");
2130
                //do the actual transform
2131
                StringWriter docString = new StringWriter();
2132
                xmlToHtml.transformXMLDocument(((DocumentImpl) docImplList
2133
                        .elementAt(i)).toString(), "-//NCEAS//eml-generic//EN",
2134
                        "-//W3C//HTML//EN", "html", docString);
2135
                htmlDoc.append(docString.toString());
2136
                htmlDoc.append("<br><br><hr><br><br>");
2137
            }//if
2138
            else { //this is a data file so we should link to it in the html
2139
                htmlDoc.append("<a href=\"");
2140
                String dataFileid = ((DocumentImpl) docImplList.elementAt(i))
2141
                        .getDocID();
2142
                htmlDoc.append("./data/").append(dataFileid).append("\">");
2143
                htmlDoc.append("Data File: ");
2144
                htmlDoc.append(dataFileid).append("</a><br>");
2145
                htmlDoc.append("<br><hr><br>");
2146
            }//else
2147
        }//for
2148
        htmlDoc.append("</body></html>");
2149
        byteString = htmlDoc.toString().getBytes();
2150
        zEntry = new ZipEntry(packageZipEntry + "/metadata.html");
2151
        zEntry.setSize(byteString.length);
2152
        zipOut.putNextEntry(zEntry);
2153
        zipOut.write(byteString, 0, byteString.length);
2154
        zipOut.closeEntry();
2155
        //dbConn.close();
2156

    
2157
    }//addHtmlSummaryToZipOutputStream
2158

    
2159
    /**
2160
     * put a data packadge into a zip output stream
2161
     *
2162
     * @param docId, which the user want to put into zip output stream,it has version
2163
     * @param out, a servletoutput stream which the zip output stream will be
2164
     *            put
2165
     * @param user, the username of the user
2166
     * @param groups, the group of the user
2167
     */
2168
    public ZipOutputStream getZippedPackage(String docIdString,
2169
            ServletOutputStream out, String user, String[] groups,
2170
            String passWord) throws ClassNotFoundException, IOException,
2171
            SQLException, McdbException, NumberFormatException, Exception
2172
    {
2173
        ZipOutputStream zOut = null;
2174
        String elementDocid = null;
2175
        DocumentImpl docImpls = null;
2176
        //Connection dbConn = null;
2177
        Vector docIdList = new Vector();
2178
        Vector documentImplList = new Vector();
2179
        Vector htmlDocumentImplList = new Vector();
2180
        String packageId = null;
2181
        String rootName = "package";//the package zip entry name
2182

    
2183
        String docId = null;
2184
        int version = -5;
2185
        // Docid without revision
2186
        docId = MetaCatUtil.getDocIdFromString(docIdString);
2187
        // revision number
2188
        version = MetaCatUtil.getVersionFromString(docIdString);
2189

    
2190
        //check if the reqused docId is a data package id
2191
        if (!isDataPackageId(docId)) {
2192

    
2193
            /*
2194
             * Exception e = new Exception("The request the doc id "
2195
             * +docIdString+ " is not a data package id");
2196
             */
2197

    
2198
            //CB 1/6/03: if the requested docid is not a datapackage, we just
2199
            // zip
2200
            //up the single document and return the zip file.
2201
            if (!hasPermissionToExportPackage(docId, user, groups)) {
2202

    
2203
                Exception e = new Exception("User " + user
2204
                        + " does not have permission"
2205
                        + " to export the data package " + docIdString);
2206
                throw e;
2207
            }
2208

    
2209
            docImpls = new DocumentImpl(docIdString);
2210
            //checking if the user has the permission to read the documents
2211
            if (DocumentImpl.hasReadPermission(user, groups, docImpls
2212
                    .getDocID())) {
2213
                zOut = new ZipOutputStream(out);
2214
                //if the docImpls is metadata
2215
                if ((docImpls.getDoctype()).compareTo("BIN") != 0) {
2216
                    //add metadata into zip output stream
2217
                    addDocToZipOutputStream(docImpls, zOut, rootName);
2218
                }//if
2219
                else {
2220
                    //it is data file
2221
                    addDataFileToZipOutputStream(docImpls, zOut, rootName);
2222
                    htmlDocumentImplList.add(docImpls);
2223
                }//else
2224
            }//if
2225

    
2226
            zOut.finish(); //terminate the zip file
2227
            return zOut;
2228
        }
2229
        // Check the permission of user
2230
        else if (!hasPermissionToExportPackage(docId, user, groups)) {
2231

    
2232
            Exception e = new Exception("User " + user
2233
                    + " does not have permission"
2234
                    + " to export the data package " + docIdString);
2235
            throw e;
2236
        } else //it is a packadge id
2237
        {
2238
            //store the package id
2239
            packageId = docId;
2240
            //get current version in database
2241
            int currentVersion = getCurrentRevFromXMLDoumentsTable(packageId);
2242
            //If it is for current version (-1 means user didn't specify
2243
            // revision)
2244
            if ((version == -1) || version == currentVersion) {
2245
                //get current version number
2246
                version = currentVersion;
2247
                //get package zip entry name
2248
                //it should be docId.revsion.package
2249
                rootName = packageId + MetaCatUtil.getOption("accNumSeparator")
2250
                        + version + MetaCatUtil.getOption("accNumSeparator")
2251
                        + "package";
2252
                //get the whole id list for data packadge
2253
                docIdList = getCurrentDocidListForDataPackage(packageId);
2254
                //get the whole documentImple object
2255
                documentImplList = getCurrentAllDocumentImpl(docIdList);
2256

    
2257
            }//if
2258
            else if (version > currentVersion || version < -1) {
2259
                throw new Exception("The user specified docid: " + docId + "."
2260
                        + version + " doesn't exist");
2261
            }//else if
2262
            else //for an old version
2263
            {
2264

    
2265
                rootName = docIdString
2266
                        + MetaCatUtil.getOption("accNumSeparator") + "package";
2267
                //get the whole id list for data packadge
2268
                docIdList = getOldVersionDocidListForDataPackage(docIdString);
2269

    
2270
                //get the whole documentImple object
2271
                documentImplList = getOldVersionAllDocumentImpl(docIdList);
2272
            }//else
2273

    
2274
            // Make sure documentImplist is not empty
2275
            if (documentImplList.isEmpty()) { throw new Exception(
2276
                    "Couldn't find component for data package: " + packageId); }//if
2277

    
2278
            zOut = new ZipOutputStream(out);
2279
            //put every element into zip output stream
2280
            for (int i = 0; i < documentImplList.size(); i++) {
2281
                // if the object in the vetor is String, this means we couldn't
2282
                // find
2283
                // the document locally, we need find it remote
2284
                if ((((documentImplList.elementAt(i)).getClass()).toString())
2285
                        .equals("class java.lang.String")) {
2286
                    // Get String object from vetor
2287
                    String documentId = (String) documentImplList.elementAt(i);
2288
                    logMetacat.info("docid: " + documentId);
2289
                    // Get doicd without revision
2290
                    String docidWithoutRevision = MetaCatUtil
2291
                            .getDocIdFromString(documentId);
2292
                    logMetacat.info("docidWithoutRevsion: "
2293
                            + docidWithoutRevision);
2294
                    // Get revision
2295
                    String revision = MetaCatUtil
2296
                            .getRevisionStringFromString(documentId);
2297
                    logMetacat.info("revsion from docIdentifier: "
2298
                            + revision);
2299
                    // Zip entry string
2300
                    String zipEntryPath = rootName + "/data/";
2301
                    // Create a RemoteDocument object
2302
                    RemoteDocument remoteDoc = new RemoteDocument(
2303
                            docidWithoutRevision, revision, user, passWord,
2304
                            zipEntryPath);
2305
                    // Here we only read data file from remote metacat
2306
                    String docType = remoteDoc.getDocType();
2307
                    if (docType != null) {
2308
                        if (docType.equals("BIN")) {
2309
                            // Put remote document to zip output
2310
                            remoteDoc.readDocumentFromRemoteServerByZip(zOut);
2311
                            // Add String object to htmlDocumentImplList
2312
                            String elementInHtmlList = remoteDoc
2313
                                    .getDocIdWithoutRevsion()
2314
                                    + MetaCatUtil.getOption("accNumSeparator")
2315
                                    + remoteDoc.getRevision();
2316
                            htmlDocumentImplList.add(elementInHtmlList);
2317
                        }//if
2318
                    }//if
2319

    
2320
                }//if
2321
                else {
2322
                    //create a docmentImpls object (represent xml doc) base on
2323
                    // the docId
2324
                    docImpls = (DocumentImpl) documentImplList.elementAt(i);
2325
                    //checking if the user has the permission to read the
2326
                    // documents
2327
                    if (DocumentImpl.hasReadPermission(user, groups, docImpls
2328
                            .getDocID())) {
2329
                        //if the docImpls is metadata
2330
                        if ((docImpls.getDoctype()).compareTo("BIN") != 0) {
2331
                            //add metadata into zip output stream
2332
                            addDocToZipOutputStream(docImpls, zOut, rootName);
2333
                            //add the documentImpl into the vetor which will
2334
                            // be used in html
2335
                            htmlDocumentImplList.add(docImpls);
2336

    
2337
                        }//if
2338
                        else {
2339
                            //it is data file
2340
                            addDataFileToZipOutputStream(docImpls, zOut,
2341
                                    rootName);
2342
                            htmlDocumentImplList.add(docImpls);
2343
                        }//else
2344
                    }//if
2345
                }//else
2346
            }//for
2347

    
2348
            //add html summary file
2349
            addHtmlSummaryToZipOutputStream(htmlDocumentImplList, zOut,
2350
                    rootName);
2351
            zOut.finish(); //terminate the zip file
2352
            //dbConn.close();
2353
            return zOut;
2354
        }//else
2355
    }//getZippedPackage()
2356

    
2357
    private class ReturnFieldValue
2358
    {
2359

    
2360
        private String docid = null; //return field value for this docid
2361

    
2362
        private String fieldValue = null;
2363

    
2364
        private String xmlFieldValue = null; //return field value in xml
2365
                                             // format
2366

    
2367
        public void setDocid(String myDocid)
2368
        {
2369
            docid = myDocid;
2370
        }
2371

    
2372
        public String getDocid()
2373
        {
2374
            return docid;
2375
        }
2376

    
2377
        public void setFieldValue(String myValue)
2378
        {
2379
            fieldValue = myValue;
2380
        }
2381

    
2382
        public String getFieldValue()
2383
        {
2384
            return fieldValue;
2385
        }
2386

    
2387
        public void setXMLFieldValue(String xml)
2388
        {
2389
            xmlFieldValue = xml;
2390
        }
2391

    
2392
        public String getXMLFieldValue()
2393
        {
2394
            return xmlFieldValue;
2395
        }
2396

    
2397
    }
2398
}
(21-21/65)