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: daigle $'
13
 *     '$Date: 2009-08-04 14:32:58 -0700 (Tue, 04 Aug 2009) $'
14
 * '$Revision: 5015 $'
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.*;
34
import java.util.zip.*;
35
import java.sql.PreparedStatement;
36
import java.sql.ResultSet;
37
import java.sql.SQLException;
38
import java.util.*;
39

    
40
import javax.servlet.ServletOutputStream;
41
import javax.servlet.http.HttpServletResponse;
42
import javax.servlet.http.HttpSession;
43

    
44
import org.apache.log4j.Logger;
45

    
46
import org.w3c.dom.*;
47
import javax.xml.parsers.DocumentBuilderFactory;
48
import org.xml.sax.InputSource;
49
import org.w3c.dom.ls.*;
50

    
51
import edu.ucsb.nceas.metacat.database.DBConnection;
52
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
53
import edu.ucsb.nceas.metacat.service.PropertyService;
54
import edu.ucsb.nceas.metacat.util.AuthUtil;
55
import edu.ucsb.nceas.metacat.util.MetacatUtil;
56
import edu.ucsb.nceas.morpho.datapackage.Triple;
57
import edu.ucsb.nceas.morpho.datapackage.TripleCollection;
58
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
59

    
60

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

    
70
    static final int ALL = 1;
71

    
72
    static final int WRITE = 2;
73

    
74
    static final int READ = 4;
75

    
76
    //private Connection conn = null;
77
    private String parserName = null;
78

    
79
    private Logger logMetacat = Logger.getLogger(DBQuery.class);
80

    
81
    /** true if the metacat spatial option is installed **/
82
    private final boolean METACAT_SPATIAL = true;
83

    
84
    /** useful if you just want to grab a list of docids. Since the docids can be very long,
85
         it is a vector of vector  **/
86
    Vector docidOverride = new Vector();
87
    
88
    // a hash table serves as query reuslt cache. Key of hashtable
89
    // is a query string and value is result xml string
90
    private static Hashtable queryResultCache = new Hashtable();
91
    
92
    // Capacity of the query result cache
93
    private static final int QUERYRESULTCACHESIZE;
94
    static {
95
    	int qryRsltCacheSize = 0;
96
    	try {
97
    		qryRsltCacheSize = Integer.parseInt(PropertyService.getProperty("database.queryresultCacheSize"));
98
    	} catch (PropertyNotFoundException pnfe) {
99
    		System.err.println("Could not get QUERYRESULTCACHESIZE property in static block: "
100
					+ pnfe.getMessage());
101
    	}
102
    	QUERYRESULTCACHESIZE = qryRsltCacheSize;
103
    }
104
    
105

    
106
    // Size of page for non paged query
107
    private static final int NONPAGESIZE = 99999999;
108
    /**
109
     * the main routine used to test the DBQuery utility.
110
     * <p>
111
     * Usage: java DBQuery <xmlfile>
112
     *
113
     * @param xmlfile the filename of the xml file containing the query
114
     */
115
    static public void main(String[] args)
116
    {
117

    
118
        if (args.length < 1) {
119
            System.err.println("Wrong number of arguments!!!");
120
            System.err.println("USAGE: java DBQuery [-t] [-index] <xmlfile>");
121
            return;
122
        } else {
123
            try {
124

    
125
                int i = 0;
126
                boolean showRuntime = false;
127
                boolean useXMLIndex = false;
128
                if (args[i].equals("-t")) {
129
                    showRuntime = true;
130
                    i++;
131
                }
132
                if (args[i].equals("-index")) {
133
                    useXMLIndex = true;
134
                    i++;
135
                }
136
                String xmlfile = args[i];
137

    
138
                // Time the request if asked for
139
                double startTime = System.currentTimeMillis();
140

    
141
                // Open a connection to the database
142
                //Connection dbconn = util.openDBConnection();
143

    
144
                double connTime = System.currentTimeMillis();
145

    
146
                // Execute the query
147
                DBQuery queryobj = new DBQuery();
148
                FileReader xml = new FileReader(new File(xmlfile));
149
                Hashtable nodelist = null;
150
                //nodelist = queryobj.findDocuments(xml, null, null, useXMLIndex);
151

    
152
                // Print the reulting document listing
153
                StringBuffer result = new StringBuffer();
154
                String document = null;
155
                String docid = null;
156
                result.append("<?xml version=\"1.0\"?>\n");
157
                result.append("<resultset>\n");
158

    
159
                if (!showRuntime) {
160
                    Enumeration doclist = nodelist.keys();
161
                    while (doclist.hasMoreElements()) {
162
                        docid = (String) doclist.nextElement();
163
                        document = (String) nodelist.get(docid);
164
                        result.append("  <document>\n    " + document
165
                                + "\n  </document>\n");
166
                    }
167

    
168
                    result.append("</resultset>\n");
169
                }
170
                // Time the request if asked for
171
                double stopTime = System.currentTimeMillis();
172
                double dbOpenTime = (connTime - startTime) / 1000;
173
                double readTime = (stopTime - connTime) / 1000;
174
                double executionTime = (stopTime - startTime) / 1000;
175
                if (showRuntime) {
176
                    System.out.print("  " + executionTime);
177
                    System.out.print("  " + dbOpenTime);
178
                    System.out.print("  " + readTime);
179
                    System.out.print("  " + nodelist.size());
180
                    System.out.println();
181
                }
182
                //System.out.println(result);
183
                //write into a file "result.txt"
184
                if (!showRuntime) {
185
                    File f = new File("./result.txt");
186
                    FileWriter fw = new FileWriter(f);
187
                    BufferedWriter out = new BufferedWriter(fw);
188
                    out.write(result.toString());
189
                    out.flush();
190
                    out.close();
191
                    fw.close();
192
                }
193

    
194
            } catch (Exception e) {
195
                System.err.println("Error in DBQuery.main");
196
                System.err.println(e.getMessage());
197
                e.printStackTrace(System.err);
198
            }
199
        }
200
    }
201

    
202
    /**
203
     * construct an instance of the DBQuery class
204
     *
205
     * <p>
206
     * Generally, one would call the findDocuments() routine after creating an
207
     * instance to specify the search query
208
     * </p>
209
     *
210

    
211
     * @param parserName the fully qualified name of a Java class implementing
212
     *            the org.xml.sax.XMLReader interface
213
     */
214
    public DBQuery() throws PropertyNotFoundException
215
    {
216
        String parserName = PropertyService.getProperty("xml.saxparser");
217
        this.parserName = parserName;
218
    }
219

    
220
    /**
221
     * 
222
     * Construct an instance of DBQuery Class
223
     * BUT accept a docid Vector that will supersede
224
     * the query.printSQL() method
225
     *
226
     * If a docid Vector is passed in,
227
     * the docids will be used to create a simple IN query 
228
     * without the multiple subselects of the printSQL() method
229
     *
230
     * Using this constructor, we just check for 
231
     * a docidOverride Vector in the findResultDoclist() method
232
     *
233
     * @param docids List of docids to display in the resultset
234
     */
235
    public DBQuery(Vector docids) throws PropertyNotFoundException
236
    {
237
    	// since the query will be too long to be handled, so we divided the 
238
    	// docids vector into couple vectors.
239
    	int size = (new Integer(PropertyService.getProperty("database.appResultsetSize"))).intValue();
240
    	logMetacat.info("The size of select doicds is "+docids.size());
241
    	logMetacat.info("The application result size in metacat.properties is "+size);
242
    	Vector subset = new Vector();
243
    	if (docids != null && docids.size() > size)
244
    	{
245
    		int index = 0;
246
    		for (int i=0; i< docids.size(); i++)
247
    		{
248
    			
249
    			if (index < size)
250
    			{  	
251
    				subset.add(docids.elementAt(i));
252
    				index ++;
253
    			}
254
    			else
255
    			{
256
    				docidOverride.add(subset);
257
    				subset = new Vector();
258
    				subset.add(docids.elementAt(i));
259
    			    index = 1;
260
    			}
261
    		}
262
    		if (!subset.isEmpty())
263
    		{
264
    			docidOverride.add(subset);
265
    		}
266
    		
267
    	}
268
    	else
269
    	{
270
    		this.docidOverride.add(docids);
271
    	}
272
        
273
        String parserName = PropertyService.getProperty("xml.saxparser");
274
        this.parserName = parserName;
275
    }
276

    
277
  /**
278
   * Method put the search result set into out printerwriter
279
   * @param resoponse the return response
280
   * @param out the output printer
281
   * @param params the paratermer hashtable
282
   * @param user the user name (it maybe different to the one in param)
283
   * @param groups the group array
284
   * @param sessionid  the sessionid
285
   */
286
  public void findDocuments(HttpServletResponse response,
287
                                       PrintWriter out, Hashtable params,
288
                                       String user, String[] groups,
289
                                       String sessionid) throws PropertyNotFoundException
290
  {
291
    boolean useXMLIndex = (new Boolean(PropertyService.getProperty("database.usexmlindex")))
292
               .booleanValue();
293
    findDocuments(response, out, params, user, groups, sessionid, useXMLIndex);
294

    
295
  }
296

    
297

    
298
    /**
299
     * Method put the search result set into out printerwriter
300
     * @param resoponse the return response
301
     * @param out the output printer
302
     * @param params the paratermer hashtable
303
     * @param user the user name (it maybe different to the one in param)
304
     * @param groups the group array
305
     * @param sessionid  the sessionid
306
     */
307
    public void findDocuments(HttpServletResponse response,
308
                                         PrintWriter out, Hashtable params,
309
                                         String user, String[] groups,
310
                                         String sessionid, boolean useXMLIndex)
311
    {
312
      int pagesize = 0;
313
      int pagestart = 0;
314
      
315
      if(params.containsKey("pagesize") && params.containsKey("pagestart"))
316
      {
317
        String pagesizeStr = ((String[])params.get("pagesize"))[0];
318
        String pagestartStr = ((String[])params.get("pagestart"))[0];
319
        if(pagesizeStr != null && pagestartStr != null)
320
        {
321
          pagesize = (new Integer(pagesizeStr)).intValue();
322
          pagestart = (new Integer(pagestartStr)).intValue();
323
        }
324
      }
325
      
326
      String xmlquery = null;
327
      String qformat = null;
328
      // get query and qformat
329
      try {
330
    	xmlquery = ((String[])params.get("query"))[0];
331

    
332
        logMetacat.info("SESSIONID: " + sessionid);
333
        logMetacat.info("xmlquery: " + xmlquery);
334
        qformat = ((String[])params.get("qformat"))[0];
335
        logMetacat.info("qformat: " + qformat);
336
      }
337
      catch (Exception ee)
338
      {
339
        logMetacat.error("Couldn't retrieve xmlquery or qformat value from "
340
                  +"params hashtable in DBQuery.findDocuments: "
341
                  + ee.getMessage()); 
342
      }
343
      // Get the XML query and covert it into a SQL statment
344
      QuerySpecification qspec = null;
345
      if ( xmlquery != null)
346
      {
347
         xmlquery = transformQuery(xmlquery);
348
         try
349
         {
350
           qspec = new QuerySpecification(xmlquery,
351
                                          parserName,
352
                                          PropertyService.getProperty("document.accNumSeparator"));
353
         }
354
         catch (Exception ee)
355
         {
356
           logMetacat.error("error generating QuerySpecification object"
357
                                    +" in DBQuery.findDocuments"
358
                                    + ee.getMessage());
359
         }
360
      }
361

    
362

    
363

    
364
      if (qformat != null && qformat.equals(MetaCatServlet.XMLFORMAT))
365
      {
366
        //xml format
367
        response.setContentType("text/xml");
368
        createResultDocument(xmlquery, qspec, out, user, groups, useXMLIndex, 
369
          pagesize, pagestart, sessionid);
370
      }//if
371
      else
372
      {
373
        //knb format, in this case we will get whole result and sent it out
374
        response.setContentType("text/html");
375
        PrintWriter nonout = null;
376
        StringBuffer xml = createResultDocument(xmlquery, qspec, nonout, user,
377
                                                groups, useXMLIndex, pagesize, 
378
                                                pagestart, sessionid);
379
        
380
        //transfer the xml to html
381
        try
382
        {
383
         double startHTMLTransform = System.currentTimeMillis()/1000;
384
         DBTransform trans = new DBTransform();
385
         response.setContentType("text/html");
386

    
387
         // if the user is a moderator, then pass a param to the 
388
         // xsl specifying the fact
389
         if(AuthUtil.isModerator(user, groups)){
390
        	 params.put("isModerator", new String[] {"true"});
391
         }
392

    
393
         trans.transformXMLDocument(xml.toString(), "-//NCEAS//resultset//EN",
394
                                 "-//W3C//HTML//EN", qformat, out, params,
395
                                 sessionid);
396
         double endHTMLTransform = System.currentTimeMillis()/1000;
397
          logMetacat.warn("The time to transfrom resultset from xml to html format is "
398
                  		                             +(endHTMLTransform -startHTMLTransform));
399
          MetacatUtil.writeDebugToFile("---------------------------------------------------------------------------------------------------------------Transfrom xml to html  "
400
                             +(endHTMLTransform -startHTMLTransform));
401
          MetacatUtil.writeDebugToDelimiteredFile(" "+(endHTMLTransform -startHTMLTransform), false);
402
        }
403
        catch(Exception e)
404
        {
405
         logMetacat.error("Error in MetaCatServlet.transformResultset:"
406
                                +e.getMessage());
407
         }
408

    
409
      }//else
410

    
411
  }
412
  
413
  /**
414
   * Transforms a hashtable of documents to an xml or html result and sent
415
   * the content to outputstream. Keep going untill hastable is empty. stop it.
416
   * add the QuerySpecification as parameter is for ecogrid. But it is duplicate
417
   * to xmlquery String
418
   * @param xmlquery
419
   * @param qspec
420
   * @param out
421
   * @param user
422
   * @param groups
423
   * @param useXMLIndex
424
   * @param sessionid
425
   * @return
426
   */
427
    public StringBuffer createResultDocument(String xmlquery,
428
                                              QuerySpecification qspec,
429
                                              PrintWriter out,
430
                                              String user, String[] groups,
431
                                              boolean useXMLIndex)
432
    {
433
    	return createResultDocument(xmlquery,qspec,out, user,groups, useXMLIndex, 0, 0,"");
434
    }
435

    
436
  /*
437
   * Transforms a hashtable of documents to an xml or html result and sent
438
   * the content to outputstream. Keep going untill hastable is empty. stop it.
439
   * add the QuerySpecification as parameter is for ecogrid. But it is duplicate
440
   * to xmlquery String
441
   */
442
  public StringBuffer createResultDocument(String xmlquery,
443
                                            QuerySpecification qspec,
444
                                            PrintWriter out,
445
                                            String user, String[] groups,
446
                                            boolean useXMLIndex, int pagesize,
447
                                            int pagestart, String sessionid)
448
  {
449
    DBConnection dbconn = null;
450
    int serialNumber = -1;
451
    StringBuffer resultset = new StringBuffer();
452

    
453
    //try to get the cached version first    
454
    // Hashtable sessionHash = MetaCatServlet.getSessionHash();
455
    // HttpSession sess = (HttpSession)sessionHash.get(sessionid);
456

    
457
    
458
    resultset.append("<?xml version=\"1.0\"?>\n");
459
    resultset.append("<resultset>\n");
460
    resultset.append("  <pagestart>" + pagestart + "</pagestart>\n");
461
    resultset.append("  <pagesize>" + pagesize + "</pagesize>\n");
462
    resultset.append("  <nextpage>" + (pagestart + 1) + "</nextpage>\n");
463
    resultset.append("  <previouspage>" + (pagestart - 1) + "</previouspage>\n");
464

    
465
    resultset.append("  <query>" + xmlquery + "</query>");
466
    //send out a new query
467
    if (out != null)
468
    {
469
      out.println(resultset.toString());
470
    }
471
    if (qspec != null)
472
    {
473
      try
474
      {
475

    
476
        //checkout the dbconnection
477
        dbconn = DBConnectionPool.getDBConnection("DBQuery.findDocuments");
478
        serialNumber = dbconn.getCheckOutSerialNumber();
479

    
480
        //print out the search result
481
        // search the doc list
482
        Vector givenDocids = new Vector();
483
        StringBuffer resultContent = new StringBuffer();
484
        if (docidOverride == null || docidOverride.size() == 0)
485
        {
486
        	logMetacat.info("Not in map query");
487
        	resultContent = findResultDoclist(qspec, out, user, groups,
488
                    dbconn, useXMLIndex, pagesize, pagestart, 
489
                    sessionid, givenDocids);
490
        }
491
        else
492
        {
493
        	logMetacat.info("In map query");
494
        	// since docid can be too long to be handled. We divide it into several parts
495
        	for (int i= 0; i<docidOverride.size(); i++)
496
        	{
497
        	   logMetacat.info("in loop===== "+i);
498
        		givenDocids = (Vector)docidOverride.elementAt(i);
499
        		StringBuffer subset = findResultDoclist(qspec, out, user, groups,
500
                        dbconn, useXMLIndex, pagesize, pagestart, 
501
                        sessionid, givenDocids);
502
        		resultContent.append(subset);
503
        	}
504
        }
505
           
506
        resultset.append(resultContent);
507
      } //try
508
      catch (IOException ioe)
509
      {
510
        logMetacat.error("IO error in DBQuery.findDocuments:");
511
        logMetacat.error(ioe.getMessage());
512

    
513
      }
514
      catch (SQLException e)
515
      {
516
        logMetacat.error("SQL Error in DBQuery.findDocuments: "
517
                                 + e.getMessage());
518
      }
519
      catch (Exception ee)
520
      {
521
        logMetacat.error("Exception in DBQuery.findDocuments: "
522
                                 + ee.getMessage());
523
        ee.printStackTrace();
524
      }
525
      finally
526
      {
527
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
528
      } //finally
529
    }//if
530
    String closeRestultset = "</resultset>";
531
    resultset.append(closeRestultset);
532
    if (out != null)
533
    {
534
      out.println(closeRestultset);
535
    }
536

    
537
    //default to returning the whole resultset
538
    return resultset;
539
  }//createResultDocuments
540

    
541
    /*
542
     * Find the doc list which match the query
543
     */
544
    private StringBuffer findResultDoclist(QuerySpecification qspec,
545
                                      PrintWriter out,
546
                                      String user, String[]groups,
547
                                      DBConnection dbconn, boolean useXMLIndex,
548
                                      int pagesize, int pagestart, String sessionid, Vector givenDocids)
549
                                      throws Exception
550
    {
551
      StringBuffer resultsetBuffer = new StringBuffer();
552
      String query = null;
553
      int count = 0;
554
      int index = 0;
555
      ResultDocumentSet docListResult = new ResultDocumentSet();
556
      PreparedStatement pstmt = null;
557
      String docid = null;
558
      String docname = null;
559
      String doctype = null;
560
      String createDate = null;
561
      String updateDate = null;
562
      StringBuffer document = null;
563
      boolean lastpage = false;
564
      int rev = 0;
565
      double startTime = 0;
566
      int offset = 1;
567
      double startSelectionTime = System.currentTimeMillis()/1000;
568
      ResultSet rs = null;
569
           
570
   
571
      // this is a hack for offset. in postgresql 7, if the returned docid list is too long,
572
      //the extend query which base on the docid will be too long to be run. So we 
573
      // have to cut them into different parts. Page query don't need it somehow.
574
      if (out == null)
575
      {
576
        // for html page, we put everything into one page
577
        offset =
578
            (new Integer(PropertyService.getProperty("database.webResultsetSize"))).intValue();
579
      }
580
      else
581
      {
582
          offset =
583
              (new Integer(PropertyService.getProperty("database.appResultsetSize"))).intValue();
584
      }
585

    
586
      /*
587
       * Check the docidOverride Vector
588
       * if defined, we bypass the qspec.printSQL() method
589
       * and contruct a simpler query based on a 
590
       * list of docids rather than a bunch of subselects
591
       */
592
      if ( givenDocids == null || givenDocids.size() == 0 ) {
593
          query = qspec.printSQL(useXMLIndex);
594
      } else {
595
          logMetacat.info("*** docid override " + givenDocids.size());
596
          StringBuffer queryBuffer = new StringBuffer( "SELECT docid,docname,doctype,date_created, date_updated, rev " );
597
          queryBuffer.append( " FROM xml_documents WHERE docid IN (" );
598
          for (int i = 0; i < givenDocids.size(); i++) {  
599
              queryBuffer.append("'");
600
              queryBuffer.append( (String)givenDocids.elementAt(i) );
601
              queryBuffer.append("',");
602
          }
603
          // empty string hack 
604
          queryBuffer.append( "'') " );
605
          query = queryBuffer.toString();
606
      } 
607
      String ownerQuery = getOwnerQuery(user);
608
      //logMetacat.debug("query: " + query);
609
      logMetacat.debug("owner query: "+ownerQuery);
610
      // if query is not the owner query, we need to check the permission
611
      // otherwise we don't need (owner has all permission by default)
612
      if (!query.equals(ownerQuery))
613
      {
614
        // set user name and group
615
        qspec.setUserName(user);
616
        qspec.setGroup(groups);
617
        // Get access query
618
        String accessQuery = qspec.getAccessQuery();
619
        if(!query.endsWith("WHERE")){
620
            query = query + accessQuery;
621
        } else {
622
            query = query + accessQuery.substring(4, accessQuery.length());
623
        }
624
        
625
      }
626
      logMetacat.debug("============ final selection query: " + query);
627
      String selectionAndExtendedQuery = null;
628
      // we only get cache for public
629
      if (user != null && user.equalsIgnoreCase("public") 
630
     		 && pagesize == 0 && PropertyService.getProperty("database.queryCacheOn").equals("true"))
631
      {
632
    	  selectionAndExtendedQuery = query +qspec.getReturnDocList()+qspec.getReturnFieldList();
633
   	      String cachedResult = getResultXMLFromCache(selectionAndExtendedQuery);
634
   	      logMetacat.debug("The key of query cache is "+selectionAndExtendedQuery);
635
   	      //System.out.println("==========the string from cache is "+cachedResult);
636
   	      if (cachedResult != null)
637
   	      {
638
   	    	logMetacat.info("result from cache !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
639
   	    	 if (out != null)
640
   	         {
641
   	             out.println(cachedResult);
642
   	         }
643
   	    	 resultsetBuffer.append(cachedResult);
644
   	    	 return resultsetBuffer;
645
   	      }
646
      }
647
      
648
      startTime = System.currentTimeMillis() / 1000;
649
      pstmt = dbconn.prepareStatement(query);
650
      rs = pstmt.executeQuery();
651

    
652
      double queryExecuteTime = System.currentTimeMillis() / 1000;
653
      logMetacat.debug("Time to execute select docid query is "
654
                    + (queryExecuteTime - startTime));
655
      MetacatUtil.writeDebugToFile("\n\n\n\n\n\nExecute selection query  "
656
              + (queryExecuteTime - startTime));
657
      MetacatUtil.writeDebugToDelimiteredFile(""+(queryExecuteTime - startTime), false);
658

    
659
      boolean tableHasRows = rs.next();
660
      
661
      if(pagesize == 0)
662
      { //this makes sure we get all results if there is no paging
663
        pagesize = NONPAGESIZE;
664
        pagestart = NONPAGESIZE;
665
      } 
666
      
667
      int currentIndex = 0;
668
      while (tableHasRows)
669
      {
670
        logMetacat.debug("############getting result: " + currentIndex);
671
        docid = rs.getString(1).trim();
672
        logMetacat.debug("############processing: " + docid);
673
        docname = rs.getString(2);
674
        doctype = rs.getString(3);
675
        logMetacat.debug("############processing: " + doctype);
676
        createDate = rs.getString(4);
677
        updateDate = rs.getString(5);
678
        rev = rs.getInt(6);
679
        
680
         Vector returndocVec = qspec.getReturnDocList();
681
       if (returndocVec.size() == 0 || returndocVec.contains(doctype))
682
        {
683
          logMetacat.debug("NOT Back tracing now...");
684
           document = new StringBuffer();
685

    
686
           String completeDocid = docid
687
                            + PropertyService.getProperty("document.accNumSeparator");
688
           completeDocid += rev;
689
           document.append("<docid>").append(completeDocid).append("</docid>");
690
           if (docname != null)
691
           {
692
               document.append("<docname>" + docname + "</docname>");
693
           }
694
           if (doctype != null)
695
           {
696
              document.append("<doctype>" + doctype + "</doctype>");
697
           }
698
           if (createDate != null)
699
           {
700
               document.append("<createdate>" + createDate + "</createdate>");
701
           }
702
           if (updateDate != null)
703
           {
704
             document.append("<updatedate>" + updateDate + "</updatedate>");
705
           }
706
           // Store the document id and the root node id
707
           
708
           docListResult.addResultDocument(
709
             new ResultDocument(docid, (String) document.toString()));
710
           logMetacat.info("$$$$$$$real result: " + docid);
711
           currentIndex++;
712
           count++;
713
        }//else
714
        
715
        // when doclist reached the offset number, send out doc list and empty
716
        // the hash table
717
        if (count == offset && pagesize == NONPAGESIZE)
718
        { //if pagesize is not 0, do this later.
719
          //reset count
720
          //logMetacat.warn("############doing subset cache");
721
          count = 0;
722
          handleSubsetResult(qspec, resultsetBuffer, out, docListResult,
723
                              user, groups,dbconn, useXMLIndex);
724
          //reset docListResult
725
          docListResult = new ResultDocumentSet();
726
        }
727
       
728
       logMetacat.debug("currentIndex: " + currentIndex);
729
       logMetacat.debug("page comparator: " + (pagesize * pagestart) + pagesize);
730
       if(currentIndex >= ((pagesize * pagestart) + pagesize))
731
       {
732
         ResultDocumentSet pagedResultsHash = new ResultDocumentSet();
733
         for(int i=pagesize*pagestart; i<docListResult.size(); i++)
734
         {
735
           pagedResultsHash.put(docListResult.get(i));
736
         }
737
         
738
         docListResult = pagedResultsHash;
739
         break;
740
       }
741
       // Advance to the next record in the cursor
742
       tableHasRows = rs.next();
743
       if(!tableHasRows)
744
       {
745
         ResultDocumentSet pagedResultsHash = new ResultDocumentSet();
746
         //get the last page of information then break
747
         if(pagesize != NONPAGESIZE)
748
         {
749
           for(int i=pagesize*pagestart; i<docListResult.size(); i++)
750
           {
751
             pagedResultsHash.put(docListResult.get(i));
752
           }
753
           docListResult = pagedResultsHash;
754
         }
755
         
756
         lastpage = true;
757
         break;
758
       }
759
     }//while
760
     
761
     rs.close();
762
     pstmt.close();
763
     double docListTime = System.currentTimeMillis() / 1000;
764
     logMetacat.warn("======Total time to get docid list is: "
765
                          + (docListTime - startSelectionTime ));
766
     MetacatUtil.writeDebugToFile("---------------------------------------------------------------------------------------------------------------Total selection: "
767
             + (docListTime - startSelectionTime ));
768
     MetacatUtil.writeDebugToDelimiteredFile(" "+ (docListTime - startSelectionTime ), false);
769
     //if docListResult is not empty, it need to be sent.
770
     if (docListResult.size() != 0)
771
     {
772
      
773
       handleSubsetResult(qspec,resultsetBuffer, out, docListResult,
774
                              user, groups,dbconn, useXMLIndex);
775
     }
776

    
777
     resultsetBuffer.append("\n<lastpage>" + lastpage + "</lastpage>\n");
778
     if (out != null)
779
     {
780
         out.println("\n<lastpage>" + lastpage + "</lastpage>\n");
781
     }
782
     
783
     // now we only cached none-paged query and user is public
784
     if (user != null && user.equalsIgnoreCase("public") 
785
    		 && pagesize == NONPAGESIZE && PropertyService.getProperty("database.queryCacheOn").equals("true"))
786
     {
787
       //System.out.println("the string stored into cache is "+ resultsetBuffer.toString());
788
  	   storeQueryResultIntoCache(selectionAndExtendedQuery, resultsetBuffer.toString());
789
     }
790
          
791
     return resultsetBuffer;
792
    }//findReturnDoclist
793

    
794

    
795
    /*
796
     * Send completed search hashtable(part of reulst)to output stream
797
     * and buffer into a buffer stream
798
     */
799
    private StringBuffer handleSubsetResult(QuerySpecification qspec,
800
                                           StringBuffer resultset,
801
                                           PrintWriter out, ResultDocumentSet partOfDoclist,
802
                                           String user, String[]groups,
803
                                       DBConnection dbconn, boolean useXMLIndex)
804
                                       throws Exception
805
   {
806
     double startReturnField = System.currentTimeMillis()/1000;
807
     // check if there is a record in xml_returnfield
808
     // and get the returnfield_id and usage count
809
     int usage_count = getXmlReturnfieldsTableId(qspec, dbconn);
810
     boolean enterRecords = false;
811

    
812
     // get value of database.xmlReturnfieldCount
813
     int count = (new Integer(PropertyService
814
                            .getProperty("database.xmlReturnfieldCount")))
815
                            .intValue();
816

    
817
     // set enterRecords to true if usage_count is more than the offset
818
     // specified in metacat.properties
819
     if(usage_count > count){
820
         enterRecords = true;
821
     }
822

    
823
     if(returnfield_id < 0){
824
         logMetacat.warn("Error in getting returnfield id from"
825
                                  + "xml_returnfield table");
826
         enterRecords = false;
827
     }
828

    
829
     // get the hashtable containing the docids that already in the
830
     // xml_queryresult table
831
     logMetacat.info("size of partOfDoclist before"
832
                             + " docidsInQueryresultTable(): "
833
                             + partOfDoclist.size());
834
     double startGetReturnValueFromQueryresultable = System.currentTimeMillis()/1000;
835
     Hashtable queryresultDocList = docidsInQueryresultTable(returnfield_id,
836
                                                        partOfDoclist, dbconn);
837

    
838
     // remove the keys in queryresultDocList from partOfDoclist
839
     Enumeration _keys = queryresultDocList.keys();
840
     while (_keys.hasMoreElements()){
841
         partOfDoclist.remove((String)_keys.nextElement());
842
     }
843
     double endGetReturnValueFromQueryresultable = System.currentTimeMillis()/1000;
844
     logMetacat.warn("Time to get return fields from xml_queryresult table is (Part1 in return fields) " +
845
          		               (endGetReturnValueFromQueryresultable-startGetReturnValueFromQueryresultable));
846
     MetacatUtil.writeDebugToFile("-----------------------------------------Get fields from xml_queryresult(Part1 in return fields) " +
847
               (endGetReturnValueFromQueryresultable-startGetReturnValueFromQueryresultable));
848
     MetacatUtil.writeDebugToDelimiteredFile(" " +
849
             (endGetReturnValueFromQueryresultable-startGetReturnValueFromQueryresultable),false);
850
     // backup the keys-elements in partOfDoclist to check later
851
     // if the doc entry is indexed yet
852
     Hashtable partOfDoclistBackup = new Hashtable();
853
     Iterator itt = partOfDoclist.getDocids();
854
     while (itt.hasNext()){
855
       Object key = itt.next();
856
         partOfDoclistBackup.put(key, partOfDoclist.get(key));
857
     }
858

    
859
     logMetacat.info("size of partOfDoclist after"
860
                             + " docidsInQueryresultTable(): "
861
                             + partOfDoclist.size());
862

    
863
     //add return fields for the documents in partOfDoclist
864
     partOfDoclist = addReturnfield(partOfDoclist, qspec, user, groups,
865
                                        dbconn, useXMLIndex);
866
     double endExtendedQuery = System.currentTimeMillis()/1000;
867
     logMetacat.warn("Get fields from index and node table (Part2 in return fields) "
868
        		                                          + (endExtendedQuery - endGetReturnValueFromQueryresultable));
869
     MetacatUtil.writeDebugToFile("-----------------------------------------Get fields from extened query(Part2 in return fields) "
870
             + (endExtendedQuery - endGetReturnValueFromQueryresultable));
871
     MetacatUtil.writeDebugToDelimiteredFile(" "
872
             + (endExtendedQuery - endGetReturnValueFromQueryresultable), false);
873
     //add relationship part part docid list for the documents in partOfDocList
874
     //partOfDoclist = addRelationship(partOfDoclist, qspec, dbconn, useXMLIndex);
875

    
876
     double startStoreReturnField = System.currentTimeMillis()/1000;
877
     Iterator keys = partOfDoclist.getDocids();
878
     String key = null;
879
     String element = null;
880
     String query = null;
881
     int offset = (new Integer(PropertyService
882
                               .getProperty("database.queryresultStringLength")))
883
                               .intValue();
884
     while (keys.hasNext())
885
     {
886
         key = (String) keys.next();
887
         element = (String)partOfDoclist.get(key);
888
         
889
	 // check if the enterRecords is true, elements is not null, element's
890
         // length is less than the limit of table column and if the document
891
         // has been indexed already
892
         if(enterRecords && element != null
893
		&& element.length() < offset
894
		&& element.compareTo((String) partOfDoclistBackup.get(key)) != 0){
895
             query = "INSERT INTO xml_queryresult (returnfield_id, docid, "
896
                 + "queryresult_string) VALUES (?, ?, ?)";
897

    
898
             PreparedStatement pstmt = null;
899
             pstmt = dbconn.prepareStatement(query);
900
             pstmt.setInt(1, returnfield_id);
901
             pstmt.setString(2, key);
902
             pstmt.setString(3, element);
903
            
904
             dbconn.increaseUsageCount(1);
905
             try
906
             {
907
            	 pstmt.execute();
908
             }
909
             catch(Exception e)
910
             {
911
            	 logMetacat.warn("couldn't insert the element to xml_queryresult table "+e.getLocalizedMessage());
912
             }
913
             finally
914
             {
915
                pstmt.close();
916
             }
917
         }
918
        
919
         // A string with element
920
         String xmlElement = "  <document>" + element + "</document>";
921

    
922
         //send single element to output
923
         if (out != null)
924
         {
925
             out.println(xmlElement);
926
         }
927
         resultset.append(xmlElement);
928
     }//while
929
     
930
     double endStoreReturnField = System.currentTimeMillis()/1000;
931
     logMetacat.warn("Time to store new return fields into xml_queryresult table (Part4 in return fields) "
932
                   + (endStoreReturnField -startStoreReturnField));
933
     MetacatUtil.writeDebugToFile("-----------------------------------------Insert new record to xml_queryresult(Part4 in return fields) "
934
             + (endStoreReturnField -startStoreReturnField));
935
     MetacatUtil.writeDebugToDelimiteredFile(" "
936
             + (endStoreReturnField -startStoreReturnField), false);
937
     
938
     Enumeration keysE = queryresultDocList.keys();
939
     while (keysE.hasMoreElements())
940
     {
941
         key = (String) keysE.nextElement();
942
         element = (String)queryresultDocList.get(key);
943
         // A string with element
944
         String xmlElement = "  <document>" + element + "</document>";
945
         //send single element to output
946
         if (out != null)
947
         {
948
             out.println(xmlElement);
949
         }
950
         resultset.append(xmlElement);
951
     }//while
952
     double returnFieldTime = System.currentTimeMillis() / 1000;
953
     logMetacat.warn("======Total time to get return fields is: "
954
                           + (returnFieldTime - startReturnField));
955
     MetacatUtil.writeDebugToFile("---------------------------------------------------------------------------------------------------------------"+
956
    		 "Total to get return fields  "
957
                                   + (returnFieldTime - startReturnField));
958
     MetacatUtil.writeDebugToDelimiteredFile(" "+ (returnFieldTime - startReturnField), false);
959
     return resultset;
960
 }
961

    
962
   /**
963
    * Get the docids already in xml_queryresult table and corresponding
964
    * queryresultstring as a hashtable
965
    */
966
   private Hashtable docidsInQueryresultTable(int returnfield_id,
967
                                              ResultDocumentSet partOfDoclist,
968
                                              DBConnection dbconn){
969

    
970
         Hashtable returnValue = new Hashtable();
971
         PreparedStatement pstmt = null;
972
         ResultSet rs = null;
973

    
974
         // get partOfDoclist as string for the query
975
         Iterator keylist = partOfDoclist.getDocids();
976
         StringBuffer doclist = new StringBuffer();
977
         while (keylist.hasNext())
978
         {
979
             doclist.append("'");
980
             doclist.append((String) keylist.next());
981
             doclist.append("',");
982
         }//while
983

    
984

    
985
         if (doclist.length() > 0)
986
         {
987
             doclist.deleteCharAt(doclist.length() - 1); //remove the last comma
988

    
989
             // the query to find out docids from xml_queryresult
990
             String query = "select docid, queryresult_string from "
991
                          + "xml_queryresult where returnfield_id = " +
992
                          returnfield_id +" and docid in ("+ doclist + ")";
993
             logMetacat.info("Query to get docids from xml_queryresult:"
994
                                      + query);
995

    
996
             try {
997
                 // prepare and execute the query
998
                 pstmt = dbconn.prepareStatement(query);
999
                 dbconn.increaseUsageCount(1);
1000
                 pstmt.execute();
1001
                 rs = pstmt.getResultSet();
1002
                 boolean tableHasRows = rs.next();
1003
                 while (tableHasRows) {
1004
                     // store the returned results in the returnValue hashtable
1005
                     String key = rs.getString(1);
1006
                     String element = rs.getString(2);
1007

    
1008
                     if(element != null){
1009
                         returnValue.put(key, element);
1010
                     } else {
1011
                         logMetacat.info("Null elment found ("
1012
                         + "DBQuery.docidsInQueryresultTable)");
1013
                     }
1014
                     tableHasRows = rs.next();
1015
                 }
1016
                 rs.close();
1017
                 pstmt.close();
1018
             } catch (Exception e){
1019
                 logMetacat.error("Error getting docids from "
1020
                                          + "queryresult in "
1021
                                          + "DBQuery.docidsInQueryresultTable: "
1022
                                          + e.getMessage());
1023
              }
1024
         }
1025
         return returnValue;
1026
     }
1027

    
1028

    
1029
   /**
1030
    * Method to get id from xml_returnfield table
1031
    * for a given query specification
1032
    */
1033
   private int returnfield_id;
1034
   private int getXmlReturnfieldsTableId(QuerySpecification qspec,
1035
                                           DBConnection dbconn){
1036
       int id = -1;
1037
       int count = 1;
1038
       PreparedStatement pstmt = null;
1039
       ResultSet rs = null;
1040
       String returnfield = qspec.getSortedReturnFieldString();
1041

    
1042
       // query for finding the id from xml_returnfield
1043
       String query = "SELECT returnfield_id, usage_count FROM xml_returnfield "
1044
            + "WHERE returnfield_string LIKE ?";
1045
       logMetacat.info("ReturnField Query:" + query);
1046

    
1047
       try {
1048
           // prepare and run the query
1049
           pstmt = dbconn.prepareStatement(query);
1050
           pstmt.setString(1,returnfield);
1051
           dbconn.increaseUsageCount(1);
1052
           pstmt.execute();
1053
           rs = pstmt.getResultSet();
1054
           boolean tableHasRows = rs.next();
1055

    
1056
           // if record found then increase the usage count
1057
           // else insert a new record and get the id of the new record
1058
           if(tableHasRows){
1059
               // get the id
1060
               id = rs.getInt(1);
1061
               count = rs.getInt(2) + 1;
1062
               rs.close();
1063
               pstmt.close();
1064

    
1065
               // increase the usage count
1066
               query = "UPDATE xml_returnfield SET usage_count ='" + count
1067
                   + "' WHERE returnfield_id ='"+ id +"'";
1068
               logMetacat.info("ReturnField Table Update:"+ query);
1069

    
1070
               pstmt = dbconn.prepareStatement(query);
1071
               dbconn.increaseUsageCount(1);
1072
               pstmt.execute();
1073
               pstmt.close();
1074

    
1075
           } else {
1076
               rs.close();
1077
               pstmt.close();
1078

    
1079
               // insert a new record
1080
               query = "INSERT INTO xml_returnfield (returnfield_string, usage_count)"
1081
                   + "VALUES (?, '1')";
1082
               logMetacat.info("ReturnField Table Insert:"+ query);
1083
               pstmt = dbconn.prepareStatement(query);
1084
               pstmt.setString(1, returnfield);
1085
               dbconn.increaseUsageCount(1);
1086
               pstmt.execute();
1087
               pstmt.close();
1088

    
1089
               // get the id of the new record
1090
               query = "SELECT returnfield_id FROM xml_returnfield "
1091
                   + "WHERE returnfield_string LIKE ?";
1092
               logMetacat.info("ReturnField query after Insert:" + query);
1093
               pstmt = dbconn.prepareStatement(query);
1094
               pstmt.setString(1, returnfield);
1095

    
1096
               dbconn.increaseUsageCount(1);
1097
               pstmt.execute();
1098
               rs = pstmt.getResultSet();
1099
               if(rs.next()){
1100
                   id = rs.getInt(1);
1101
               } else {
1102
                   id = -1;
1103
               }
1104
               rs.close();
1105
               pstmt.close();
1106
           }
1107

    
1108
       } catch (Exception e){
1109
           logMetacat.error("Error getting id from xml_returnfield in "
1110
                                     + "DBQuery.getXmlReturnfieldsTableId: "
1111
                                     + e.getMessage());
1112
           id = -1;
1113
       }
1114

    
1115
       returnfield_id = id;
1116
       return count;
1117
   }
1118

    
1119

    
1120
    /*
1121
     * A method to add return field to return doclist hash table
1122
     */
1123
    private ResultDocumentSet addReturnfield(ResultDocumentSet docListResult,
1124
                                      QuerySpecification qspec,
1125
                                      String user, String[]groups,
1126
                                      DBConnection dbconn, boolean useXMLIndex )
1127
                                      throws Exception
1128
    {
1129
      PreparedStatement pstmt = null;
1130
      ResultSet rs = null;
1131
      String docid = null;
1132
      String fieldname = null;
1133
      String fieldtype = null;
1134
      String fielddata = null;
1135
      String relation = null;
1136

    
1137
      if (qspec.containsExtendedSQL())
1138
      {
1139
        qspec.setUserName(user);
1140
        qspec.setGroup(groups);
1141
        Vector extendedFields = new Vector(qspec.getReturnFieldList());
1142
        Vector results = new Vector();
1143
        Iterator keylist = docListResult.getDocids();
1144
        StringBuffer doclist = new StringBuffer();
1145
        Vector parentidList = new Vector();
1146
        Hashtable returnFieldValue = new Hashtable();
1147
        while (keylist.hasNext())
1148
        {
1149
          doclist.append("'");
1150
          doclist.append((String) keylist.next());
1151
          doclist.append("',");
1152
        }
1153
        if (doclist.length() > 0)
1154
        {
1155
          Hashtable controlPairs = new Hashtable();
1156
          doclist.deleteCharAt(doclist.length() - 1); //remove the last comma
1157
          boolean tableHasRows = false;
1158
        
1159

    
1160
           String extendedQuery =
1161
               qspec.printExtendedSQL(doclist.toString(), useXMLIndex);
1162
           logMetacat.info("Extended query: " + extendedQuery);
1163

    
1164
           if(extendedQuery != null){
1165
        	   double extendedQueryStart = System.currentTimeMillis() / 1000;
1166
               pstmt = dbconn.prepareStatement(extendedQuery);
1167
               //increase dbconnection usage count
1168
               dbconn.increaseUsageCount(1);
1169
               pstmt.execute();
1170
               rs = pstmt.getResultSet();
1171
               double extendedQueryEnd = System.currentTimeMillis() / 1000;
1172
               logMetacat.warn(
1173
                   "Time to execute extended query: "
1174
                   + (extendedQueryEnd - extendedQueryStart));
1175
               MetacatUtil.writeDebugToFile(
1176
                       "Execute extended query "
1177
                       + (extendedQueryEnd - extendedQueryStart));
1178
               MetacatUtil.writeDebugToDelimiteredFile(" "+ (extendedQueryEnd - extendedQueryStart), false);
1179
               tableHasRows = rs.next();
1180
               while (tableHasRows) {
1181
                   ReturnFieldValue returnValue = new ReturnFieldValue();
1182
                   docid = rs.getString(1).trim();
1183
                   fieldname = rs.getString(2);
1184
                   fielddata = rs.getString(3);
1185
                   fielddata = MetacatUtil.normalize(fielddata);
1186
                   String parentId = rs.getString(4);
1187
                   fieldtype = rs.getString(5);
1188
                   StringBuffer value = new StringBuffer();
1189

    
1190
                   //handle case when usexmlindex is true differently
1191
                   //at one point merging the nodedata (for large text elements) was 
1192
                   //deemed unnecessary - but now it is needed.  but not for attribute nodes
1193
                   if (useXMLIndex || !containsKey(parentidList, parentId)) {
1194
                	   //merge node data only for non-ATTRIBUTEs
1195
                	   if (fieldtype != null && !fieldtype.equals("ATTRIBUTE")) {
1196
	                	   //try merging the data
1197
	                	   ReturnFieldValue existingRFV =
1198
	                		   getArrayValue(parentidList, parentId);
1199
	                	   if (existingRFV != null) {
1200
	                		   fielddata = existingRFV.getFieldValue() + fielddata;
1201
	                	   }
1202
                	   }
1203
                       value.append("<param name=\"");
1204
                       value.append(fieldname);
1205
                       value.append("\">");
1206
                       value.append(fielddata);
1207
                       value.append("</param>");
1208
                       //set returnvalue
1209
                       returnValue.setDocid(docid);
1210
                       returnValue.setFieldValue(fielddata);
1211
                       returnValue.setFieldType(fieldtype);
1212
                       returnValue.setXMLFieldValue(value.toString());
1213
                       // Store it in hastable
1214
                       putInArray(parentidList, parentId, returnValue);
1215
                   }
1216
                   else {
1217
                       // need to merge nodedata if they have same parent id and
1218
                       // node type is text
1219
                       fielddata = (String) ( (ReturnFieldValue)
1220
                                             getArrayValue(
1221
                           parentidList, parentId)).getFieldValue()
1222
                           + fielddata;
1223
                       value.append("<param name=\"");
1224
                       value.append(fieldname);
1225
                       value.append("\">");
1226
                       value.append(fielddata);
1227
                       value.append("</param>");
1228
                       returnValue.setDocid(docid);
1229
                       returnValue.setFieldValue(fielddata);
1230
                       returnValue.setFieldType(fieldtype);
1231
                       returnValue.setXMLFieldValue(value.toString());
1232
                       // remove the old return value from paretnidList
1233
                       parentidList.remove(parentId);
1234
                       // store the new return value in parentidlit
1235
                       putInArray(parentidList, parentId, returnValue);
1236
                   }
1237
                   tableHasRows = rs.next();
1238
               } //while
1239
               rs.close();
1240
               pstmt.close();
1241

    
1242
               // put the merger node data info into doclistReult
1243
               Enumeration xmlFieldValue = (getElements(parentidList)).
1244
                   elements();
1245
               while (xmlFieldValue.hasMoreElements()) {
1246
                   ReturnFieldValue object =
1247
                       (ReturnFieldValue) xmlFieldValue.nextElement();
1248
                   docid = object.getDocid();
1249
                   if (docListResult.containsDocid(docid)) {
1250
                       String removedelement = (String) docListResult.
1251
                           remove(docid);
1252
                       docListResult.
1253
                           addResultDocument(new ResultDocument(docid,
1254
                               removedelement + object.getXMLFieldValue()));
1255
                   }
1256
                   else {
1257
                       docListResult.addResultDocument(
1258
                         new ResultDocument(docid, object.getXMLFieldValue()));
1259
                   }
1260
               } //while
1261
               double docListResultEnd = System.currentTimeMillis() / 1000;
1262
               logMetacat.warn(
1263
                   "Time to prepare ResultDocumentSet after"
1264
                   + " execute extended query: "
1265
                   + (docListResultEnd - extendedQueryEnd));
1266
           }
1267

    
1268
         
1269
           
1270
           
1271
       }//if doclist lenght is great than zero
1272

    
1273
     }//if has extended query
1274

    
1275
      return docListResult;
1276
    }//addReturnfield
1277

    
1278
  
1279
  /**
1280
   * removes the <?xml version="1.0"?> tag from the beginning.  This takes a
1281
   * string as a param instead of a hashtable.
1282
   *
1283
   * @param xmlquery a string representing a query.
1284
   */
1285
   private  String transformQuery(String xmlquery)
1286
   {
1287
     xmlquery = xmlquery.trim();
1288
     int index = xmlquery.indexOf("?>");
1289
     if (index != -1)
1290
     {
1291
       return xmlquery.substring(index + 2, xmlquery.length());
1292
     }
1293
     else
1294
     {
1295
       return xmlquery;
1296
     }
1297
   }
1298
   
1299
   /*
1300
    * Method to store query string and result xml string into query result
1301
    * cache. If the size alreay reache the limitation, the cache will be
1302
    * cleared first, then store them.
1303
    */
1304
   private void storeQueryResultIntoCache(String query, String resultXML)
1305
   {
1306
	   synchronized (queryResultCache)
1307
	   {
1308
		   if (queryResultCache.size() >= QUERYRESULTCACHESIZE)
1309
		   {
1310
			   queryResultCache.clear();
1311
		   }
1312
		   queryResultCache.put(query, resultXML);
1313
		   
1314
	   }
1315
   }
1316
   
1317
   /*
1318
    * Method to get result xml string from query result cache. 
1319
    * Note: the returned string can be null.
1320
    */
1321
   private String getResultXMLFromCache(String query)
1322
   {
1323
	   String resultSet = null;
1324
	   synchronized (queryResultCache)
1325
	   {
1326
          try
1327
          {
1328
        	 logMetacat.info("Get query from cache ===");
1329
		     resultSet = (String)queryResultCache.get(query);
1330
		   
1331
          }
1332
          catch (Exception e)
1333
          {
1334
        	  resultSet = null;
1335
          }
1336
		   
1337
	   }
1338
	   return resultSet;
1339
   }
1340
   
1341
   /**
1342
    * Method to clear the query result cache.
1343
    */
1344
   public static void clearQueryResultCache()
1345
   {
1346
	   synchronized (queryResultCache)
1347
	   {
1348
		   queryResultCache.clear();
1349
	   }
1350
   }
1351

    
1352

    
1353
    /*
1354
     * A method to search if Vector contains a particular key string
1355
     */
1356
    private boolean containsKey(Vector parentidList, String parentId)
1357
    {
1358

    
1359
        Vector tempVector = null;
1360

    
1361
        for (int count = 0; count < parentidList.size(); count++) {
1362
            tempVector = (Vector) parentidList.get(count);
1363
            if (parentId.compareTo((String) tempVector.get(0)) == 0) { return true; }
1364
        }
1365
        return false;
1366
    }
1367
    
1368
    /*
1369
     * A method to put key and value in Vector
1370
     */
1371
    private void putInArray(Vector parentidList, String key,
1372
            ReturnFieldValue value)
1373
    {
1374

    
1375
        Vector tempVector = null;
1376
        //only filter if the field type is NOT an attribute (say, for text)
1377
        String fieldType = value.getFieldType();
1378
        if (fieldType != null && !fieldType.equals("ATTRIBUTE")) {
1379
        
1380
	        for (int count = 0; count < parentidList.size(); count++) {
1381
	            tempVector = (Vector) parentidList.get(count);
1382
	
1383
	            if (key.compareTo((String) tempVector.get(0)) == 0) {
1384
	                tempVector.remove(1);
1385
	                tempVector.add(1, value);
1386
	                return;
1387
	            }
1388
	        }
1389
        }
1390

    
1391
        tempVector = new Vector();
1392
        tempVector.add(0, key);
1393
        tempVector.add(1, value);
1394
        parentidList.add(tempVector);
1395
        return;
1396
    }
1397

    
1398
    /*
1399
     * A method to get value in Vector given a key
1400
     */
1401
    private ReturnFieldValue getArrayValue(Vector parentidList, String key)
1402
    {
1403

    
1404
        Vector tempVector = null;
1405

    
1406
        for (int count = 0; count < parentidList.size(); count++) {
1407
            tempVector = (Vector) parentidList.get(count);
1408

    
1409
            if (key.compareTo((String) tempVector.get(0)) == 0) { return (ReturnFieldValue) tempVector
1410
                    .get(1); }
1411
        }
1412
        return null;
1413
    }
1414

    
1415
    /*
1416
     * A method to get enumeration of all values in Vector
1417
     */
1418
    private Vector getElements(Vector parentidList)
1419
    {
1420
        Vector enumVector = new Vector();
1421
        Vector tempVector = null;
1422

    
1423
        for (int count = 0; count < parentidList.size(); count++) {
1424
            tempVector = (Vector) parentidList.get(count);
1425

    
1426
            enumVector.add(tempVector.get(1));
1427
        }
1428
        return enumVector;
1429
    }
1430

    
1431
  
1432

    
1433
    /*
1434
     * A method to create a query to get owner's docid list
1435
     */
1436
    private String getOwnerQuery(String owner)
1437
    {
1438
        if (owner != null) {
1439
            owner = owner.toLowerCase();
1440
        }
1441
        StringBuffer self = new StringBuffer();
1442

    
1443
        self.append("SELECT docid,docname,doctype,");
1444
        self.append("date_created, date_updated, rev ");
1445
        self.append("FROM xml_documents WHERE docid IN (");
1446
        self.append("(");
1447
        self.append("SELECT DISTINCT docid FROM xml_nodes WHERE \n");
1448
        self.append("nodedata LIKE '%%%' ");
1449
        self.append(") \n");
1450
        self.append(") ");
1451
        self.append(" AND (");
1452
        self.append(" lower(user_owner) = '" + owner + "'");
1453
        self.append(") ");
1454
        return self.toString();
1455
    }
1456

    
1457
    /**
1458
     * format a structured query as an XML document that conforms to the
1459
     * pathquery.dtd and is appropriate for submission to the DBQuery
1460
     * structured query engine
1461
     *
1462
     * @param params The list of parameters that should be included in the
1463
     *            query
1464
     */
1465
    public static String createSQuery(Hashtable params) throws PropertyNotFoundException
1466
    {
1467
        StringBuffer query = new StringBuffer();
1468
        Enumeration elements;
1469
        Enumeration keys;
1470
        String filterDoctype = null;
1471
        String casesensitive = null;
1472
        String searchmode = null;
1473
        Object nextkey;
1474
        Object nextelement;
1475
        //add the xml headers
1476
        query.append("<?xml version=\"1.0\"?>\n");
1477
        query.append("<pathquery version=\"1.2\">\n");
1478

    
1479

    
1480

    
1481
        if (params.containsKey("meta_file_id")) {
1482
            query.append("<meta_file_id>");
1483
            query.append(((String[]) params.get("meta_file_id"))[0]);
1484
            query.append("</meta_file_id>");
1485
        }
1486

    
1487
        if (params.containsKey("returndoctype")) {
1488
            String[] returnDoctypes = ((String[]) params.get("returndoctype"));
1489
            for (int i = 0; i < returnDoctypes.length; i++) {
1490
                String doctype = (String) returnDoctypes[i];
1491

    
1492
                if (!doctype.equals("any") && !doctype.equals("ANY")
1493
                        && !doctype.equals("")) {
1494
                    query.append("<returndoctype>").append(doctype);
1495
                    query.append("</returndoctype>");
1496
                }
1497
            }
1498
        }
1499

    
1500
        if (params.containsKey("filterdoctype")) {
1501
            String[] filterDoctypes = ((String[]) params.get("filterdoctype"));
1502
            for (int i = 0; i < filterDoctypes.length; i++) {
1503
                query.append("<filterdoctype>").append(filterDoctypes[i]);
1504
                query.append("</filterdoctype>");
1505
            }
1506
        }
1507

    
1508
        if (params.containsKey("returnfield")) {
1509
            String[] returnfield = ((String[]) params.get("returnfield"));
1510
            for (int i = 0; i < returnfield.length; i++) {
1511
                query.append("<returnfield>").append(returnfield[i]);
1512
                query.append("</returnfield>");
1513
            }
1514
        }
1515

    
1516
        if (params.containsKey("owner")) {
1517
            String[] owner = ((String[]) params.get("owner"));
1518
            for (int i = 0; i < owner.length; i++) {
1519
                query.append("<owner>").append(owner[i]);
1520
                query.append("</owner>");
1521
            }
1522
        }
1523

    
1524
        if (params.containsKey("site")) {
1525
            String[] site = ((String[]) params.get("site"));
1526
            for (int i = 0; i < site.length; i++) {
1527
                query.append("<site>").append(site[i]);
1528
                query.append("</site>");
1529
            }
1530
        }
1531

    
1532
        //allows the dynamic switching of boolean operators
1533
        if (params.containsKey("operator")) {
1534
            query.append("<querygroup operator=\""
1535
                    + ((String[]) params.get("operator"))[0] + "\">");
1536
        } else { //the default operator is UNION
1537
            query.append("<querygroup operator=\"UNION\">");
1538
        }
1539

    
1540
        if (params.containsKey("casesensitive")) {
1541
            casesensitive = ((String[]) params.get("casesensitive"))[0];
1542
        } else {
1543
            casesensitive = "false";
1544
        }
1545

    
1546
        if (params.containsKey("searchmode")) {
1547
            searchmode = ((String[]) params.get("searchmode"))[0];
1548
        } else {
1549
            searchmode = "contains";
1550
        }
1551

    
1552
        //anyfield is a special case because it does a
1553
        //free text search. It does not have a <pathexpr>
1554
        //tag. This allows for a free text search within the structured
1555
        //query. This is useful if the INTERSECT operator is used.
1556
        if (params.containsKey("anyfield")) {
1557
            String[] anyfield = ((String[]) params.get("anyfield"));
1558
            //allow for more than one value for anyfield
1559
            for (int i = 0; i < anyfield.length; i++) {
1560
                if (anyfield[i] != null && !anyfield[i].equals("")) {
1561
                    query.append("<queryterm casesensitive=\"" + casesensitive
1562
                            + "\" " + "searchmode=\"" + searchmode
1563
                            + "\"><value>" + anyfield[i]
1564
                            + "</value></queryterm>");
1565
                }
1566
            }
1567
        }
1568

    
1569
        //this while loop finds the rest of the parameters
1570
        //and attempts to query for the field specified
1571
        //by the parameter.
1572
        elements = params.elements();
1573
        keys = params.keys();
1574
        while (keys.hasMoreElements() && elements.hasMoreElements()) {
1575
            nextkey = keys.nextElement();
1576
            nextelement = elements.nextElement();
1577

    
1578
            //make sure we aren't querying for any of these
1579
            //parameters since the are already in the query
1580
            //in one form or another.
1581
            Vector ignoredParams = new Vector();
1582
            ignoredParams.add("returndoctype");
1583
            ignoredParams.add("filterdoctype");
1584
            ignoredParams.add("action");
1585
            ignoredParams.add("qformat");
1586
            ignoredParams.add("anyfield");
1587
            ignoredParams.add("returnfield");
1588
            ignoredParams.add("owner");
1589
            ignoredParams.add("site");
1590
            ignoredParams.add("operator");
1591
            ignoredParams.add("sessionid");
1592
            ignoredParams.add("pagesize");
1593
            ignoredParams.add("pagestart");
1594
            ignoredParams.add("searchmode");
1595

    
1596
            // Also ignore parameters listed in the properties file
1597
            // so that they can be passed through to stylesheets
1598
            String paramsToIgnore = PropertyService
1599
                    .getProperty("database.queryignoredparams");
1600
            StringTokenizer st = new StringTokenizer(paramsToIgnore, ",");
1601
            while (st.hasMoreTokens()) {
1602
                ignoredParams.add(st.nextToken());
1603
            }
1604
            if (!ignoredParams.contains(nextkey.toString())) {
1605
                //allow for more than value per field name
1606
                for (int i = 0; i < ((String[]) nextelement).length; i++) {
1607
                    if (!((String[]) nextelement)[i].equals("")) {
1608
                        query.append("<queryterm casesensitive=\""
1609
                                + casesensitive + "\" " + "searchmode=\""
1610
                                + searchmode + "\">" + "<value>" +
1611
                                //add the query value
1612
                                ((String[]) nextelement)[i]
1613
                                + "</value><pathexpr>" +
1614
                                //add the path to query by
1615
                                nextkey.toString() + "</pathexpr></queryterm>");
1616
                    }
1617
                }
1618
            }
1619
        }
1620
        query.append("</querygroup></pathquery>");
1621
        //append on the end of the xml and return the result as a string
1622
        return query.toString();
1623
    }
1624

    
1625
    /**
1626
     * format a simple free-text value query as an XML document that conforms
1627
     * to the pathquery.dtd and is appropriate for submission to the DBQuery
1628
     * structured query engine
1629
     *
1630
     * @param value the text string to search for in the xml catalog
1631
     * @param doctype the type of documents to include in the result set -- use
1632
     *            "any" or "ANY" for unfiltered result sets
1633
     */
1634
    public static String createQuery(String value, String doctype)
1635
    {
1636
        StringBuffer xmlquery = new StringBuffer();
1637
        xmlquery.append("<?xml version=\"1.0\"?>\n");
1638
        xmlquery.append("<pathquery version=\"1.0\">");
1639

    
1640
        if (!doctype.equals("any") && !doctype.equals("ANY")) {
1641
            xmlquery.append("<returndoctype>");
1642
            xmlquery.append(doctype).append("</returndoctype>");
1643
        }
1644

    
1645
        xmlquery.append("<querygroup operator=\"UNION\">");
1646
        //chad added - 8/14
1647
        //the if statement allows a query to gracefully handle a null
1648
        //query. Without this if a nullpointerException is thrown.
1649
        if (!value.equals("")) {
1650
            xmlquery.append("<queryterm casesensitive=\"false\" ");
1651
            xmlquery.append("searchmode=\"contains\">");
1652
            xmlquery.append("<value>").append(value).append("</value>");
1653
            xmlquery.append("</queryterm>");
1654
        }
1655
        xmlquery.append("</querygroup>");
1656
        xmlquery.append("</pathquery>");
1657

    
1658
        return (xmlquery.toString());
1659
    }
1660

    
1661
    /**
1662
     * format a simple free-text value query as an XML document that conforms
1663
     * to the pathquery.dtd and is appropriate for submission to the DBQuery
1664
     * structured query engine
1665
     *
1666
     * @param value the text string to search for in the xml catalog
1667
     */
1668
    public static String createQuery(String value)
1669
    {
1670
        return createQuery(value, "any");
1671
    }
1672

    
1673
    /**
1674
     * Check for "READ" permission on @docid for @user and/or @group from DB
1675
     * connection
1676
     */
1677
    private boolean hasPermission(String user, String[] groups, String docid)
1678
            throws SQLException, Exception
1679
    {
1680
        // Check for READ permission on @docid for @user and/or @groups
1681
        PermissionController controller = new PermissionController(docid);
1682
        return controller.hasPermission(user, groups,
1683
                AccessControlInterface.READSTRING);
1684
    }
1685

    
1686
    /**
1687
     * Get all docIds list for a data packadge
1688
     *
1689
     * @param dataPackageDocid, the string in docId field of xml_relation table
1690
     */
1691
    private Vector getCurrentDocidListForDataPackage(String dataPackageDocid)
1692
    {
1693
        DBConnection dbConn = null;
1694
        int serialNumber = -1;
1695
        Vector docIdList = new Vector();//return value
1696
        PreparedStatement pStmt = null;
1697
        ResultSet rs = null;
1698
        String docIdInSubjectField = null;
1699
        String docIdInObjectField = null;
1700

    
1701
        // Check the parameter
1702
        if (dataPackageDocid == null || dataPackageDocid.equals("")) { return docIdList; }//if
1703

    
1704
        //the query stirng
1705
        String query = "SELECT subject, object from xml_relation where docId = ?";
1706
        try {
1707
            dbConn = DBConnectionPool
1708
                    .getDBConnection("DBQuery.getCurrentDocidListForDataPackage");
1709
            serialNumber = dbConn.getCheckOutSerialNumber();
1710
            pStmt = dbConn.prepareStatement(query);
1711
            //bind the value to query
1712
            pStmt.setString(1, dataPackageDocid);
1713

    
1714
            //excute the query
1715
            pStmt.execute();
1716
            //get the result set
1717
            rs = pStmt.getResultSet();
1718
            //process the result
1719
            while (rs.next()) {
1720
                //In order to get the whole docIds in a data packadge,
1721
                //we need to put the docIds of subject and object field in
1722
                // xml_relation
1723
                //into the return vector
1724
                docIdInSubjectField = rs.getString(1);//the result docId in
1725
                                                      // subject field
1726
                docIdInObjectField = rs.getString(2);//the result docId in
1727
                                                     // object field
1728

    
1729
                //don't put the duplicate docId into the vector
1730
                if (!docIdList.contains(docIdInSubjectField)) {
1731
                    docIdList.add(docIdInSubjectField);
1732
                }
1733

    
1734
                //don't put the duplicate docId into the vector
1735
                if (!docIdList.contains(docIdInObjectField)) {
1736
                    docIdList.add(docIdInObjectField);
1737
                }
1738
            }//while
1739
            //close the pStmt
1740
            pStmt.close();
1741
        }//try
1742
        catch (SQLException e) {
1743
            logMetacat.error("Error in getDocidListForDataPackage: "
1744
                    + e.getMessage());
1745
        }//catch
1746
        finally {
1747
            try {
1748
                pStmt.close();
1749
            }//try
1750
            catch (SQLException ee) {
1751
                logMetacat.error(
1752
                        "Error in getDocidListForDataPackage: "
1753
                                + ee.getMessage());
1754
            }//catch
1755
            finally {
1756
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1757
            }//fianlly
1758
        }//finally
1759
        return docIdList;
1760
    }//getCurrentDocidListForDataPackadge()
1761

    
1762
    /**
1763
     * Get all docIds list for a data packadge
1764
     *
1765
     * @param dataPackageDocid, the string in docId field of xml_relation table
1766
     */
1767
    private Vector getOldVersionDocidListForDataPackage(String dataPackageDocidWithRev)
1768
    {
1769

    
1770
        Vector docIdList = new Vector();//return value
1771
        Vector tripleList = null;
1772
        String xml = null;
1773

    
1774
        // Check the parameter
1775
        if (dataPackageDocidWithRev == null || dataPackageDocidWithRev.equals("")) { return docIdList; }//if
1776

    
1777
        try {
1778
            //initial a documentImpl object
1779
            DocumentImpl packageDocument = new DocumentImpl(dataPackageDocidWithRev);
1780
            //transfer to documentImpl object to string
1781
            xml = packageDocument.toString();
1782

    
1783
            //create a tripcollection object
1784
            TripleCollection tripleForPackage = new TripleCollection(
1785
                    new StringReader(xml));
1786
            //get the vetor of triples
1787
            tripleList = tripleForPackage.getCollection();
1788

    
1789
            for (int i = 0; i < tripleList.size(); i++) {
1790
                //put subject docid into docIdlist without duplicate
1791
                if (!docIdList.contains(((Triple) tripleList.elementAt(i))
1792
                        .getSubject())) {
1793
                    //put subject docid into docIdlist
1794
                    docIdList.add(((Triple) tripleList.get(i)).getSubject());
1795
                }
1796
                //put object docid into docIdlist without duplicate
1797
                if (!docIdList.contains(((Triple) tripleList.elementAt(i))
1798
                        .getObject())) {
1799
                    docIdList.add(((Triple) (tripleList.get(i))).getObject());
1800
                }
1801
            }//for
1802
        }//try
1803
        catch (Exception e) {
1804
            logMetacat.error("Error in getOldVersionAllDocumentImpl: "
1805
                    + e.getMessage());
1806
        }//catch
1807

    
1808
        // return result
1809
        return docIdList;
1810
    }//getDocidListForPackageInXMLRevisions()
1811

    
1812
    /**
1813
     * Check if the docId is a data packadge id. If the id is a data packadage
1814
     * id, it should be store in the docId fields in xml_relation table. So we
1815
     * can use a query to get the entries which the docId equals the given
1816
     * value. If the result is null. The docId is not a packadge id. Otherwise,
1817
     * it is.
1818
     *
1819
     * @param docId, the id need to be checked
1820
     */
1821
    private boolean isDataPackageId(String docId)
1822
    {
1823
        boolean result = false;
1824
        PreparedStatement pStmt = null;
1825
        ResultSet rs = null;
1826
        String query = "SELECT docId from xml_relation where docId = ?";
1827
        DBConnection dbConn = null;
1828
        int serialNumber = -1;
1829
        try {
1830
            dbConn = DBConnectionPool
1831
                    .getDBConnection("DBQuery.isDataPackageId");
1832
            serialNumber = dbConn.getCheckOutSerialNumber();
1833
            pStmt = dbConn.prepareStatement(query);
1834
            //bind the value to query
1835
            pStmt.setString(1, docId);
1836
            //execute the query
1837
            pStmt.execute();
1838
            rs = pStmt.getResultSet();
1839
            //process the result
1840
            if (rs.next()) //There are some records for the id in docId fields
1841
            {
1842
                result = true;//It is a data packadge id
1843
            }
1844
            pStmt.close();
1845
        }//try
1846
        catch (SQLException e) {
1847
            logMetacat.error("Error in isDataPackageId: "
1848
                    + e.getMessage());
1849
        } finally {
1850
            try {
1851
                pStmt.close();
1852
            }//try
1853
            catch (SQLException ee) {
1854
                logMetacat.error("Error in isDataPackageId: "
1855
                        + ee.getMessage());
1856
            }//catch
1857
            finally {
1858
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1859
            }//finally
1860
        }//finally
1861
        return result;
1862
    }//isDataPackageId()
1863

    
1864
    /**
1865
     * Check if the user has the permission to export data package
1866
     *
1867
     * @param conn, the connection
1868
     * @param docId, the id need to be checked
1869
     * @param user, the name of user
1870
     * @param groups, the user's group
1871
     */
1872
    private boolean hasPermissionToExportPackage(String docId, String user,
1873
            String[] groups) throws Exception
1874
    {
1875
        //DocumentImpl doc=new DocumentImpl(conn,docId);
1876
        return DocumentImpl.hasReadPermission(user, groups, docId);
1877
    }
1878

    
1879
    /**
1880
     * Get the current Rev for a docid in xml_documents table
1881
     *
1882
     * @param docId, the id need to get version numb If the return value is -5,
1883
     *            means no value in rev field for this docid
1884
     */
1885
    private int getCurrentRevFromXMLDoumentsTable(String docId)
1886
            throws SQLException
1887
    {
1888
        int rev = -5;
1889
        PreparedStatement pStmt = null;
1890
        ResultSet rs = null;
1891
        String query = "SELECT rev from xml_documents where docId = ?";
1892
        DBConnection dbConn = null;
1893
        int serialNumber = -1;
1894
        try {
1895
            dbConn = DBConnectionPool
1896
                    .getDBConnection("DBQuery.getCurrentRevFromXMLDocumentsTable");
1897
            serialNumber = dbConn.getCheckOutSerialNumber();
1898
            pStmt = dbConn.prepareStatement(query);
1899
            //bind the value to query
1900
            pStmt.setString(1, docId);
1901
            //execute the query
1902
            pStmt.execute();
1903
            rs = pStmt.getResultSet();
1904
            //process the result
1905
            if (rs.next()) //There are some records for rev
1906
            {
1907
                rev = rs.getInt(1);
1908
                ;//It is the version for given docid
1909
            } else {
1910
                rev = -5;
1911
            }
1912

    
1913
        }//try
1914
        catch (SQLException e) {
1915
            logMetacat.error(
1916
                    "Error in getCurrentRevFromXMLDoumentsTable: "
1917
                            + e.getMessage());
1918
            throw e;
1919
        }//catch
1920
        finally {
1921
            try {
1922
                pStmt.close();
1923
            }//try
1924
            catch (SQLException ee) {
1925
                logMetacat.error(
1926
                        "Error in getCurrentRevFromXMLDoumentsTable: "
1927
                                + ee.getMessage());
1928
            }//catch
1929
            finally {
1930
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1931
            }//finally
1932
        }//finally
1933
        return rev;
1934
    }//getCurrentRevFromXMLDoumentsTable
1935

    
1936
    /**
1937
     * put a doc into a zip output stream
1938
     *
1939
     * @param docImpl, docmentImpl object which will be sent to zip output
1940
     *            stream
1941
     * @param zipOut, zip output stream which the docImpl will be put
1942
     * @param packageZipEntry, the zip entry name for whole package
1943
     */
1944
    private void addDocToZipOutputStream(DocumentImpl docImpl,
1945
            ZipOutputStream zipOut, String packageZipEntry)
1946
            throws ClassNotFoundException, IOException, SQLException,
1947
            McdbException, Exception
1948
    {
1949
        byte[] byteString = null;
1950
        ZipEntry zEntry = null;
1951

    
1952
        byteString = docImpl.toString().getBytes();
1953
        //use docId as the zip entry's name
1954
        zEntry = new ZipEntry(packageZipEntry + "/metadata/"
1955
                + docImpl.getDocID());
1956
        zEntry.setSize(byteString.length);
1957
        zipOut.putNextEntry(zEntry);
1958
        zipOut.write(byteString, 0, byteString.length);
1959
        zipOut.closeEntry();
1960

    
1961
    }//addDocToZipOutputStream()
1962

    
1963
    /**
1964
     * Transfer a docid vetor to a documentImpl vector. The documentImpl vetor
1965
     * only inlcudes current version. If a DocumentImple object couldn't find
1966
     * for a docid, then the String of this docid was added to vetor rather
1967
     * than DocumentImple object.
1968
     *
1969
     * @param docIdList, a vetor hold a docid list for a data package. In
1970
     *            docid, there is not version number in it.
1971
     */
1972

    
1973
    private Vector getCurrentAllDocumentImpl(Vector docIdList)
1974
            throws McdbException, Exception
1975
    {
1976
        //Connection dbConn=null;
1977
        Vector documentImplList = new Vector();
1978
        int rev = 0;
1979

    
1980
        // Check the parameter
1981
        if (docIdList.isEmpty()) { return documentImplList; }//if
1982

    
1983
        //for every docid in vector
1984
        for (int i = 0; i < docIdList.size(); i++) {
1985
            try {
1986
                //get newest version for this docId
1987
                rev = getCurrentRevFromXMLDoumentsTable((String) docIdList
1988
                        .elementAt(i));
1989

    
1990
                // There is no record for this docId in xml_documents table
1991
                if (rev == -5) {
1992
                    // Rather than put DocumentImple object, put a String
1993
                    // Object(docid)
1994
                    // into the documentImplList
1995
                    documentImplList.add((String) docIdList.elementAt(i));
1996
                    // Skip other code
1997
                    continue;
1998
                }
1999

    
2000
                String docidPlusVersion = ((String) docIdList.elementAt(i))
2001
                        + PropertyService.getProperty("document.accNumSeparator") + rev;
2002

    
2003
                //create new documentImpl object
2004
                DocumentImpl documentImplObject = new DocumentImpl(
2005
                        docidPlusVersion);
2006
                //add them to vector
2007
                documentImplList.add(documentImplObject);
2008
            }//try
2009
            catch (Exception e) {
2010
                logMetacat.error("Error in getCurrentAllDocumentImpl: "
2011
                        + e.getMessage());
2012
                // continue the for loop
2013
                continue;
2014
            }
2015
        }//for
2016
        return documentImplList;
2017
    }
2018

    
2019
    /**
2020
     * Transfer a docid vetor to a documentImpl vector. If a DocumentImple
2021
     * object couldn't find for a docid, then the String of this docid was
2022
     * added to vetor rather than DocumentImple object.
2023
     *
2024
     * @param docIdList, a vetor hold a docid list for a data package. In
2025
     *            docid, t here is version number in it.
2026
     */
2027
    private Vector getOldVersionAllDocumentImpl(Vector docIdList)
2028
    {
2029
        //Connection dbConn=null;
2030
        Vector documentImplList = new Vector();
2031
        String siteCode = null;
2032
        String uniqueId = null;
2033
        int rev = 0;
2034

    
2035
        // Check the parameter
2036
        if (docIdList.isEmpty()) { return documentImplList; }//if
2037

    
2038
        //for every docid in vector
2039
        for (int i = 0; i < docIdList.size(); i++) {
2040

    
2041
            String docidPlusVersion = (String) (docIdList.elementAt(i));
2042

    
2043
            try {
2044
                //create new documentImpl object
2045
                DocumentImpl documentImplObject = new DocumentImpl(
2046
                        docidPlusVersion);
2047
                //add them to vector
2048
                documentImplList.add(documentImplObject);
2049
            }//try
2050
            catch (McdbDocNotFoundException notFoundE) {
2051
                logMetacat.error(
2052
                        "Error in DBQuery.getOldVersionAllDocument" + "Imple"
2053
                                + notFoundE.getMessage());
2054
                // Rather than add a DocumentImple object into vetor, a String
2055
                // object
2056
                // - the doicd was added to the vector
2057
                documentImplList.add(docidPlusVersion);
2058
                // Continue the for loop
2059
                continue;
2060
            }//catch
2061
            catch (Exception e) {
2062
                logMetacat.error(
2063
                        "Error in DBQuery.getOldVersionAllDocument" + "Imple"
2064
                                + e.getMessage());
2065
                // Continue the for loop
2066
                continue;
2067
            }//catch
2068

    
2069
        }//for
2070
        return documentImplList;
2071
    }//getOldVersionAllDocumentImple
2072

    
2073
    /**
2074
     * put a data file into a zip output stream
2075
     *
2076
     * @param docImpl, docmentImpl object which will be sent to zip output
2077
     *            stream
2078
     * @param zipOut, the zip output stream which the docImpl will be put
2079
     * @param packageZipEntry, the zip entry name for whole package
2080
     */
2081
    private void addDataFileToZipOutputStream(DocumentImpl docImpl,
2082
            ZipOutputStream zipOut, String packageZipEntry)
2083
            throws ClassNotFoundException, IOException, SQLException,
2084
            McdbException, Exception
2085
    {
2086
        byte[] byteString = null;
2087
        ZipEntry zEntry = null;
2088
        // this is data file; add file to zip
2089
        String filePath = PropertyService.getProperty("application.datafilepath");
2090
        if (!filePath.endsWith("/")) {
2091
            filePath += "/";
2092
        }
2093
        String fileName = filePath + docImpl.getDocID();
2094
        zEntry = new ZipEntry(packageZipEntry + "/data/" + docImpl.getDocID());
2095
        zipOut.putNextEntry(zEntry);
2096
        FileInputStream fin = null;
2097
        try {
2098
            fin = new FileInputStream(fileName);
2099
            byte[] buf = new byte[4 * 1024]; // 4K buffer
2100
            int b = fin.read(buf);
2101
            while (b != -1) {
2102
                zipOut.write(buf, 0, b);
2103
                b = fin.read(buf);
2104
            }//while
2105
            zipOut.closeEntry();
2106
        }//try
2107
        catch (IOException ioe) {
2108
            logMetacat.error("There is an exception: "
2109
                    + ioe.getMessage());
2110
        }//catch
2111
    }//addDataFileToZipOutputStream()
2112

    
2113
    /**
2114
     * create a html summary for data package and put it into zip output stream
2115
     *
2116
     * @param docImplList, the documentImpl ojbects in data package
2117
     * @param zipOut, the zip output stream which the html should be put
2118
     * @param packageZipEntry, the zip entry name for whole package
2119
     */
2120
    private void addHtmlSummaryToZipOutputStream(Vector docImplList,
2121
            ZipOutputStream zipOut, String packageZipEntry) throws Exception
2122
    {
2123
        StringBuffer htmlDoc = new StringBuffer();
2124
        ZipEntry zEntry = null;
2125
        byte[] byteString = null;
2126
        InputStream source;
2127
        DBTransform xmlToHtml;
2128

    
2129
        //create a DBTransform ojbect
2130
        xmlToHtml = new DBTransform();
2131
        //head of html
2132
        htmlDoc.append("<html><head></head><body>");
2133
        for (int i = 0; i < docImplList.size(); i++) {
2134
            // If this String object, this means it is missed data file
2135
            if ((((docImplList.elementAt(i)).getClass()).toString())
2136
                    .equals("class java.lang.String")) {
2137

    
2138
                htmlDoc.append("<a href=\"");
2139
                String dataFileid = (String) docImplList.elementAt(i);
2140
                htmlDoc.append("./data/").append(dataFileid).append("\">");
2141
                htmlDoc.append("Data File: ");
2142
                htmlDoc.append(dataFileid).append("</a><br>");
2143
                htmlDoc.append("<br><hr><br>");
2144

    
2145
            }//if
2146
            else if ((((DocumentImpl) docImplList.elementAt(i)).getDoctype())
2147
                    .compareTo("BIN") != 0) { //this is an xml file so we can
2148
                                              // transform it.
2149
                //transform each file individually then concatenate all of the
2150
                //transformations together.
2151

    
2152
                //for metadata xml title
2153
                htmlDoc.append("<h2>");
2154
                htmlDoc.append(((DocumentImpl) docImplList.elementAt(i))
2155
                        .getDocID());
2156
                //htmlDoc.append(".");
2157
                //htmlDoc.append(((DocumentImpl)docImplList.elementAt(i)).getRev());
2158
                htmlDoc.append("</h2>");
2159
                //do the actual transform
2160
                StringWriter docString = new StringWriter();
2161
                xmlToHtml.transformXMLDocument(((DocumentImpl) docImplList
2162
                        .elementAt(i)).toString(), "-//NCEAS//eml-generic//EN",
2163
                        "-//W3C//HTML//EN", "html", docString);
2164
                htmlDoc.append(docString.toString());
2165
                htmlDoc.append("<br><br><hr><br><br>");
2166
            }//if
2167
            else { //this is a data file so we should link to it in the html
2168
                htmlDoc.append("<a href=\"");
2169
                String dataFileid = ((DocumentImpl) docImplList.elementAt(i))
2170
                        .getDocID();
2171
                htmlDoc.append("./data/").append(dataFileid).append("\">");
2172
                htmlDoc.append("Data File: ");
2173
                htmlDoc.append(dataFileid).append("</a><br>");
2174
                htmlDoc.append("<br><hr><br>");
2175
            }//else
2176
        }//for
2177
        htmlDoc.append("</body></html>");
2178
        byteString = htmlDoc.toString().getBytes();
2179
        zEntry = new ZipEntry(packageZipEntry + "/metadata.html");
2180
        zEntry.setSize(byteString.length);
2181
        zipOut.putNextEntry(zEntry);
2182
        zipOut.write(byteString, 0, byteString.length);
2183
        zipOut.closeEntry();
2184
        //dbConn.close();
2185

    
2186
    }//addHtmlSummaryToZipOutputStream
2187

    
2188
    /**
2189
     * put a data packadge into a zip output stream
2190
     *
2191
     * @param docId, which the user want to put into zip output stream,it has version
2192
     * @param out, a servletoutput stream which the zip output stream will be
2193
     *            put
2194
     * @param user, the username of the user
2195
     * @param groups, the group of the user
2196
     */
2197
    public ZipOutputStream getZippedPackage(String docIdString,
2198
            ServletOutputStream out, String user, String[] groups,
2199
            String passWord) throws ClassNotFoundException, IOException,
2200
            SQLException, McdbException, NumberFormatException, Exception
2201
    {
2202
        ZipOutputStream zOut = null;
2203
        String elementDocid = null;
2204
        DocumentImpl docImpls = null;
2205
        //Connection dbConn = null;
2206
        Vector docIdList = new Vector();
2207
        Vector documentImplList = new Vector();
2208
        Vector htmlDocumentImplList = new Vector();
2209
        String packageId = null;
2210
        String rootName = "package";//the package zip entry name
2211

    
2212
        String docId = null;
2213
        int version = -5;
2214
        // Docid without revision
2215
        docId = MetacatUtil.getDocIdFromString(docIdString);
2216
        // revision number
2217
        version = MetacatUtil.getVersionFromString(docIdString);
2218

    
2219
        //check if the reqused docId is a data package id
2220
        if (!isDataPackageId(docId)) {
2221

    
2222
            /*
2223
             * Exception e = new Exception("The request the doc id "
2224
             * +docIdString+ " is not a data package id");
2225
             */
2226

    
2227
            //CB 1/6/03: if the requested docid is not a datapackage, we just
2228
            // zip
2229
            //up the single document and return the zip file.
2230
            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
            }
2237

    
2238
            docImpls = new DocumentImpl(docIdString);
2239
            //checking if the user has the permission to read the documents
2240
            if (DocumentImpl.hasReadPermission(user, groups, docImpls
2241
                    .getDocID())) {
2242
                zOut = new ZipOutputStream(out);
2243
                //if the docImpls is metadata
2244
                if ((docImpls.getDoctype()).compareTo("BIN") != 0) {
2245
                    //add metadata into zip output stream
2246
                    addDocToZipOutputStream(docImpls, zOut, rootName);
2247
                }//if
2248
                else {
2249
                    //it is data file
2250
                    addDataFileToZipOutputStream(docImpls, zOut, rootName);
2251
                    htmlDocumentImplList.add(docImpls);
2252
                }//else
2253
            }//if
2254

    
2255
            zOut.finish(); //terminate the zip file
2256
            return zOut;
2257
        }
2258
        // Check the permission of user
2259
        else if (!hasPermissionToExportPackage(docId, user, groups)) {
2260

    
2261
            Exception e = new Exception("User " + user
2262
                    + " does not have permission"
2263
                    + " to export the data package " + docIdString);
2264
            throw e;
2265
        } else //it is a packadge id
2266
        {
2267
            //store the package id
2268
            packageId = docId;
2269
            //get current version in database
2270
            int currentVersion = getCurrentRevFromXMLDoumentsTable(packageId);
2271
            //If it is for current version (-1 means user didn't specify
2272
            // revision)
2273
            if ((version == -1) || version == currentVersion) {
2274
                //get current version number
2275
                version = currentVersion;
2276
                //get package zip entry name
2277
                //it should be docId.revsion.package
2278
                rootName = packageId + PropertyService.getProperty("document.accNumSeparator")
2279
                        + version + PropertyService.getProperty("document.accNumSeparator")
2280
                        + "package";
2281
                //get the whole id list for data packadge
2282
                docIdList = getCurrentDocidListForDataPackage(packageId);
2283
                //get the whole documentImple object
2284
                documentImplList = getCurrentAllDocumentImpl(docIdList);
2285

    
2286
            }//if
2287
            else if (version > currentVersion || version < -1) {
2288
                throw new Exception("The user specified docid: " + docId + "."
2289
                        + version + " doesn't exist");
2290
            }//else if
2291
            else //for an old version
2292
            {
2293

    
2294
                rootName = docIdString
2295
                        + PropertyService.getProperty("document.accNumSeparator") + "package";
2296
                //get the whole id list for data packadge
2297
                docIdList = getOldVersionDocidListForDataPackage(docIdString);
2298

    
2299
                //get the whole documentImple object
2300
                documentImplList = getOldVersionAllDocumentImpl(docIdList);
2301
            }//else
2302

    
2303
            // Make sure documentImplist is not empty
2304
            if (documentImplList.isEmpty()) { throw new Exception(
2305
                    "Couldn't find component for data package: " + packageId); }//if
2306

    
2307
            zOut = new ZipOutputStream(out);
2308
            //put every element into zip output stream
2309
            for (int i = 0; i < documentImplList.size(); i++) {
2310
                // if the object in the vetor is String, this means we couldn't
2311
                // find
2312
                // the document locally, we need find it remote
2313
                if ((((documentImplList.elementAt(i)).getClass()).toString())
2314
                        .equals("class java.lang.String")) {
2315
                    // Get String object from vetor
2316
                    String documentId = (String) documentImplList.elementAt(i);
2317
                    logMetacat.info("docid: " + documentId);
2318
                    // Get doicd without revision
2319
                    String docidWithoutRevision = MetacatUtil
2320
                            .getDocIdFromString(documentId);
2321
                    logMetacat.info("docidWithoutRevsion: "
2322
                            + docidWithoutRevision);
2323
                    // Get revision
2324
                    String revision = MetacatUtil
2325
                            .getRevisionStringFromString(documentId);
2326
                    logMetacat.info("revsion from docIdentifier: "
2327
                            + revision);
2328
                    // Zip entry string
2329
                    String zipEntryPath = rootName + "/data/";
2330
                    // Create a RemoteDocument object
2331
                    RemoteDocument remoteDoc = new RemoteDocument(
2332
                            docidWithoutRevision, revision, user, passWord,
2333
                            zipEntryPath);
2334
                    // Here we only read data file from remote metacat
2335
                    String docType = remoteDoc.getDocType();
2336
                    if (docType != null) {
2337
                        if (docType.equals("BIN")) {
2338
                            // Put remote document to zip output
2339
                            remoteDoc.readDocumentFromRemoteServerByZip(zOut);
2340
                            // Add String object to htmlDocumentImplList
2341
                            String elementInHtmlList = remoteDoc
2342
                                    .getDocIdWithoutRevsion()
2343
                                    + PropertyService.getProperty("document.accNumSeparator")
2344
                                    + remoteDoc.getRevision();
2345
                            htmlDocumentImplList.add(elementInHtmlList);
2346
                        }//if
2347
                    }//if
2348

    
2349
                }//if
2350
                else {
2351
                    //create a docmentImpls object (represent xml doc) base on
2352
                    // the docId
2353
                    docImpls = (DocumentImpl) documentImplList.elementAt(i);
2354
                    //checking if the user has the permission to read the
2355
                    // documents
2356
                    if (DocumentImpl.hasReadPermission(user, groups, docImpls
2357
                            .getDocID())) {
2358
                        //if the docImpls is metadata
2359
                        if ((docImpls.getDoctype()).compareTo("BIN") != 0) {
2360
                            //add metadata into zip output stream
2361
                            addDocToZipOutputStream(docImpls, zOut, rootName);
2362
                            //add the documentImpl into the vetor which will
2363
                            // be used in html
2364
                            htmlDocumentImplList.add(docImpls);
2365

    
2366
                        }//if
2367
                        else {
2368
                            //it is data file
2369
                            addDataFileToZipOutputStream(docImpls, zOut,
2370
                                    rootName);
2371
                            htmlDocumentImplList.add(docImpls);
2372
                        }//else
2373
                    }//if
2374
                }//else
2375
            }//for
2376

    
2377
            //add html summary file
2378
            addHtmlSummaryToZipOutputStream(htmlDocumentImplList, zOut,
2379
                    rootName);
2380
            zOut.finish(); //terminate the zip file
2381
            //dbConn.close();
2382
            return zOut;
2383
        }//else
2384
    }//getZippedPackage()
2385

    
2386
    private class ReturnFieldValue
2387
    {
2388

    
2389
        private String docid = null; //return field value for this docid
2390

    
2391
        private String fieldValue = null;
2392

    
2393
        private String xmlFieldValue = null; //return field value in xml
2394
                                             // format
2395
        private String fieldType = null; //ATTRIBUTE, TEXT...
2396

    
2397
        public void setDocid(String myDocid)
2398
        {
2399
            docid = myDocid;
2400
        }
2401

    
2402
        public String getDocid()
2403
        {
2404
            return docid;
2405
        }
2406

    
2407
        public void setFieldValue(String myValue)
2408
        {
2409
            fieldValue = myValue;
2410
        }
2411

    
2412
        public String getFieldValue()
2413
        {
2414
            return fieldValue;
2415
        }
2416

    
2417
        public void setXMLFieldValue(String xml)
2418
        {
2419
            xmlFieldValue = xml;
2420
        }
2421

    
2422
        public String getXMLFieldValue()
2423
        {
2424
            return xmlFieldValue;
2425
        }
2426
        
2427
        public void setFieldType(String myType)
2428
        {
2429
            fieldType = myType;
2430
        }
2431

    
2432
        public String getFieldType()
2433
        {
2434
            return fieldType;
2435
        }
2436

    
2437
    }
2438
    
2439
    /**
2440
     * a class to store one result document consisting of a docid and a document
2441
     */
2442
    private class ResultDocument
2443
    {
2444
      public String docid;
2445
      public String document;
2446
      
2447
      public ResultDocument(String docid, String document)
2448
      {
2449
        this.docid = docid;
2450
        this.document = document;
2451
      }
2452
    }
2453
    
2454
    /**
2455
     * a private class to handle a set of resultDocuments
2456
     */
2457
    private class ResultDocumentSet
2458
    {
2459
      private Vector docids;
2460
      private Vector documents;
2461
      
2462
      public ResultDocumentSet()
2463
      {
2464
        docids = new Vector();
2465
        documents = new Vector();
2466
      }
2467
      
2468
      /**
2469
       * adds a result document to the set
2470
       */
2471
      public void addResultDocument(ResultDocument rd)
2472
      {
2473
        if(rd.docid == null)
2474
          return;
2475
        if(rd.document == null)
2476
          rd.document = "";
2477
       
2478
           docids.addElement(rd.docid);
2479
           documents.addElement(rd.document);
2480
        
2481
      }
2482
      
2483
      /**
2484
       * gets an iterator of docids
2485
       */
2486
      public Iterator getDocids()
2487
      {
2488
        return docids.iterator();
2489
      }
2490
      
2491
      /**
2492
       * gets an iterator of documents
2493
       */
2494
      public Iterator getDocuments()
2495
      {
2496
        return documents.iterator();
2497
      }
2498
      
2499
      /**
2500
       * returns the size of the set
2501
       */
2502
      public int size()
2503
      {
2504
        return docids.size();
2505
      }
2506
      
2507
      /**
2508
       * tests to see if this set contains the given docid
2509
       */
2510
      private boolean containsDocid(String docid)
2511
      {
2512
        for(int i=0; i<docids.size(); i++)
2513
        {
2514
          String docid0 = (String)docids.elementAt(i);
2515
          if(docid0.trim().equals(docid.trim()))
2516
          {
2517
            return true;
2518
          }
2519
        }
2520
        return false;
2521
      }
2522
      
2523
      /**
2524
       * removes the element with the given docid
2525
       */
2526
      public String remove(String docid)
2527
      {
2528
        for(int i=0; i<docids.size(); i++)
2529
        {
2530
          String docid0 = (String)docids.elementAt(i);
2531
          if(docid0.trim().equals(docid.trim()))
2532
          {
2533
            String returnDoc = (String)documents.elementAt(i);
2534
            documents.remove(i);
2535
            docids.remove(i);
2536
            return returnDoc;
2537
          }
2538
        }
2539
        return null;
2540
      }
2541
      
2542
      /**
2543
       * add a result document
2544
       */
2545
      public void put(ResultDocument rd)
2546
      {
2547
        addResultDocument(rd);
2548
      }
2549
      
2550
      /**
2551
       * add a result document by components
2552
       */
2553
      public void put(String docid, String document)
2554
      {
2555
        addResultDocument(new ResultDocument(docid, document));
2556
      }
2557
      
2558
      /**
2559
       * get the document part of the result document by docid
2560
       */
2561
      public Object get(String docid)
2562
      {
2563
        for(int i=0; i<docids.size(); i++)
2564
        {
2565
          String docid0 = (String)docids.elementAt(i);
2566
          if(docid0.trim().equals(docid.trim()))
2567
          {
2568
            return documents.elementAt(i);
2569
          }
2570
        }
2571
        return null;
2572
      }
2573
      
2574
      /**
2575
       * get the document part of the result document by an object
2576
       */
2577
      public Object get(Object o)
2578
      {
2579
        return get((String)o);
2580
      }
2581
      
2582
      /**
2583
       * get an entire result document by index number
2584
       */
2585
      public ResultDocument get(int index)
2586
      {
2587
        return new ResultDocument((String)docids.elementAt(index), 
2588
          (String)documents.elementAt(index));
2589
      }
2590
      
2591
      /**
2592
       * return a string representation of this object
2593
       */
2594
      public String toString()
2595
      {
2596
        String s = "";
2597
        for(int i=0; i<docids.size(); i++)
2598
        {
2599
          s += (String)docids.elementAt(i) + "\n";
2600
        }
2601
        return s;
2602
      }
2603
      /*
2604
       * Set a new document value for a given docid
2605
       */
2606
      public void set(String docid, String document)
2607
      {
2608
    	   for(int i=0; i<docids.size(); i++)
2609
           {
2610
             String docid0 = (String)docids.elementAt(i);
2611
             if(docid0.trim().equals(docid.trim()))
2612
             {
2613
                 documents.set(i, document);
2614
             }
2615
           }
2616
           
2617
      }
2618
    }
2619
}
(21-21/63)