Project

General

Profile

1 155 jones
/**
2 203 jones
 *  '$RCSfile$'
3 2043 sgarg
 *    Purpose: A Class that searches a relational DB for elements and
4 203 jones
 *             attributes that have free text matches a query string,
5 2043 sgarg
 *             or structured query matches to a path specified node in the
6
 *             XML hierarchy.  It returns a result set consisting of the
7 203 jones
 *             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 155 jones
 *
12 203 jones
 *   '$Author$'
13
 *     '$Date$'
14
 * '$Revision$'
15 669 jones
 *
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 155 jones
 */
30
31 607 bojilova
package edu.ucsb.nceas.metacat;
32 155 jones
33 5752 leinfelder
import java.io.BufferedWriter;
34
import java.io.File;
35
import java.io.FileInputStream;
36
import java.io.FileOutputStream;
37
import java.io.IOException;
38
import java.io.InputStream;
39
import java.io.InputStreamReader;
40
import java.io.OutputStreamWriter;
41
import java.io.Reader;
42
import java.io.StringReader;
43
import java.io.StringWriter;
44
import java.io.Writer;
45 2074 jones
import java.sql.PreparedStatement;
46
import java.sql.ResultSet;
47
import java.sql.SQLException;
48 6602 leinfelder
import java.sql.Timestamp;
49
import java.util.ArrayList;
50
import java.util.Date;
51 5752 leinfelder
import java.util.Enumeration;
52
import java.util.Hashtable;
53
import java.util.Iterator;
54 6602 leinfelder
import java.util.List;
55 5752 leinfelder
import java.util.StringTokenizer;
56
import java.util.Vector;
57
import java.util.zip.ZipEntry;
58
import java.util.zip.ZipOutputStream;
59 2074 jones
60 940 tao
import javax.servlet.ServletOutputStream;
61 2087 tao
import javax.servlet.http.HttpServletResponse;
62 155 jones
63 7677 leinfelder
import org.apache.commons.lang.StringEscapeUtils;
64 2663 sgarg
import org.apache.log4j.Logger;
65 2087 tao
66 5015 daigle
import edu.ucsb.nceas.metacat.database.DBConnection;
67
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
68 5030 daigle
import edu.ucsb.nceas.metacat.properties.PropertyService;
69 4589 daigle
import edu.ucsb.nceas.metacat.util.AuthUtil;
70 5025 daigle
import edu.ucsb.nceas.metacat.util.DocumentUtil;
71 4698 daigle
import edu.ucsb.nceas.metacat.util.MetacatUtil;
72 4080 daigle
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
73 2074 jones
74 7475 leinfelder
import edu.ucsb.nceas.utilities.access.AccessControlInterface;
75 7403 leinfelder
import edu.ucsb.nceas.utilities.triple.Triple;
76
import edu.ucsb.nceas.utilities.triple.TripleCollection;
77 2912 harris
78 7403 leinfelder
79 2043 sgarg
/**
80 2075 jones
 * A Class that searches a relational DB for elements and attributes that have
81
 * free text matches a query string, or structured query matches to a path
82
 * specified node in the XML hierarchy. It returns a result set consisting of
83
 * the document ID for each document that satisfies the query
84 155 jones
 */
85 2075 jones
public class DBQuery
86
{
87 155 jones
88 2075 jones
    static final int ALL = 1;
89 2043 sgarg
90 2075 jones
    static final int WRITE = 2;
91 2043 sgarg
92 2075 jones
    static final int READ = 4;
93 5490 berkley
94
    private String qformat = "xml";
95 6035 leinfelder
96
    // are we combining the query with docid list and, if so, using INTERSECT or UNION?
97
    private String operator = null;
98 155 jones
99 2075 jones
    //private Connection conn = null;
100
    private String parserName = null;
101 706 bojilova
102 2663 sgarg
    private Logger logMetacat = Logger.getLogger(DBQuery.class);
103
104 2912 harris
    /** true if the metacat spatial option is installed **/
105
    private final boolean METACAT_SPATIAL = true;
106
107 3392 tao
    /** useful if you just want to grab a list of docids. Since the docids can be very long,
108
         it is a vector of vector  **/
109 3047 perry
    Vector docidOverride = new Vector();
110 3340 tao
111
    // a hash table serves as query reuslt cache. Key of hashtable
112 3342 tao
    // is a query string and value is result xml string
113 3340 tao
    private static Hashtable queryResultCache = new Hashtable();
114
115
    // Capacity of the query result cache
116 4080 daigle
    private static final int QUERYRESULTCACHESIZE;
117
    static {
118
    	int qryRsltCacheSize = 0;
119
    	try {
120 4212 daigle
    		qryRsltCacheSize = Integer.parseInt(PropertyService.getProperty("database.queryresultCacheSize"));
121 4080 daigle
    	} catch (PropertyNotFoundException pnfe) {
122
    		System.err.println("Could not get QUERYRESULTCACHESIZE property in static block: "
123
					+ pnfe.getMessage());
124
    	}
125
    	QUERYRESULTCACHESIZE = qryRsltCacheSize;
126
    }
127
128 3047 perry
129 3368 tao
    // Size of page for non paged query
130
    private static final int NONPAGESIZE = 99999999;
131 2075 jones
    /**
132
     * the main routine used to test the DBQuery utility.
133
     * <p>
134
     * Usage: java DBQuery <xmlfile>
135 5752 leinfelder
     * NOTE: encoding should be provided for best results
136 2075 jones
     * @param xmlfile the filename of the xml file containing the query
137
     */
138
    static public void main(String[] args)
139
    {
140 706 bojilova
141 2075 jones
        if (args.length < 1) {
142
            System.err.println("Wrong number of arguments!!!");
143
            System.err.println("USAGE: java DBQuery [-t] [-index] <xmlfile>");
144
            return;
145
        } else {
146
            try {
147 706 bojilova
148 2075 jones
                int i = 0;
149
                boolean showRuntime = false;
150
                boolean useXMLIndex = false;
151
                if (args[i].equals("-t")) {
152
                    showRuntime = true;
153
                    i++;
154
                }
155
                if (args[i].equals("-index")) {
156
                    useXMLIndex = true;
157
                    i++;
158
                }
159
                String xmlfile = args[i];
160 706 bojilova
161 2075 jones
                // Time the request if asked for
162
                double startTime = System.currentTimeMillis();
163 2043 sgarg
164 2075 jones
                // Open a connection to the database
165
                //Connection dbconn = util.openDBConnection();
166 2043 sgarg
167 2075 jones
                double connTime = System.currentTimeMillis();
168 2043 sgarg
169 2075 jones
                // Execute the query
170 2752 jones
                DBQuery queryobj = new DBQuery();
171 5752 leinfelder
                Reader xml = new InputStreamReader(new FileInputStream(new File(xmlfile)));
172 2075 jones
                Hashtable nodelist = null;
173 2087 tao
                //nodelist = queryobj.findDocuments(xml, null, null, useXMLIndex);
174 2043 sgarg
175 2075 jones
                // Print the reulting document listing
176
                StringBuffer result = new StringBuffer();
177
                String document = null;
178
                String docid = null;
179
                result.append("<?xml version=\"1.0\"?>\n");
180
                result.append("<resultset>\n");
181 2043 sgarg
182 2075 jones
                if (!showRuntime) {
183
                    Enumeration doclist = nodelist.keys();
184
                    while (doclist.hasMoreElements()) {
185
                        docid = (String) doclist.nextElement();
186
                        document = (String) nodelist.get(docid);
187
                        result.append("  <document>\n    " + document
188
                                + "\n  </document>\n");
189
                    }
190 706 bojilova
191 2075 jones
                    result.append("</resultset>\n");
192
                }
193
                // Time the request if asked for
194
                double stopTime = System.currentTimeMillis();
195
                double dbOpenTime = (connTime - startTime) / 1000;
196
                double readTime = (stopTime - connTime) / 1000;
197
                double executionTime = (stopTime - startTime) / 1000;
198
                if (showRuntime) {
199
                    System.out.print("  " + executionTime);
200
                    System.out.print("  " + dbOpenTime);
201
                    System.out.print("  " + readTime);
202
                    System.out.print("  " + nodelist.size());
203
                    System.out.println();
204
                }
205
                //System.out.println(result);
206
                //write into a file "result.txt"
207
                if (!showRuntime) {
208
                    File f = new File("./result.txt");
209 5752 leinfelder
                    Writer fw = new OutputStreamWriter(new FileOutputStream(f));
210 2075 jones
                    BufferedWriter out = new BufferedWriter(fw);
211
                    out.write(result.toString());
212
                    out.flush();
213
                    out.close();
214
                    fw.close();
215
                }
216 2043 sgarg
217 2075 jones
            } catch (Exception e) {
218
                System.err.println("Error in DBQuery.main");
219
                System.err.println(e.getMessage());
220
                e.printStackTrace(System.err);
221
            }
222
        }
223
    }
224 2043 sgarg
225 2075 jones
    /**
226
     * construct an instance of the DBQuery class
227 2087 tao
     *
228 2075 jones
     * <p>
229
     * Generally, one would call the findDocuments() routine after creating an
230
     * instance to specify the search query
231
     * </p>
232 2087 tao
     *
233
234 2075 jones
     * @param parserName the fully qualified name of a Java class implementing
235
     *            the org.xml.sax.XMLReader interface
236
     */
237 4080 daigle
    public DBQuery() throws PropertyNotFoundException
238 2075 jones
    {
239 4213 daigle
        String parserName = PropertyService.getProperty("xml.saxparser");
240 2752 jones
        this.parserName = parserName;
241 2075 jones
    }
242 2043 sgarg
243 3047 perry
    /**
244
     *
245
     * Construct an instance of DBQuery Class
246
     * BUT accept a docid Vector that will supersede
247
     * the query.printSQL() method
248
     *
249
     * If a docid Vector is passed in,
250
     * the docids will be used to create a simple IN query
251
     * without the multiple subselects of the printSQL() method
252
     *
253
     * Using this constructor, we just check for
254
     * a docidOverride Vector in the findResultDoclist() method
255
     *
256
     * @param docids List of docids to display in the resultset
257
     */
258 4080 daigle
    public DBQuery(Vector docids) throws PropertyNotFoundException
259 3047 perry
    {
260 3392 tao
    	// since the query will be too long to be handled, so we divided the
261
    	// docids vector into couple vectors.
262 4212 daigle
    	int size = (new Integer(PropertyService.getProperty("database.appResultsetSize"))).intValue();
263 5165 daigle
    	logMetacat.info("DBQuery.DBQuery - The size of select doicds is "+docids.size());
264
    	logMetacat.info("DBQuery.DBQuery - The application result size in metacat.properties is "+size);
265 3392 tao
    	Vector subset = new Vector();
266
    	if (docids != null && docids.size() > size)
267
    	{
268
    		int index = 0;
269
    		for (int i=0; i< docids.size(); i++)
270
    		{
271
272
    			if (index < size)
273
    			{
274
    				subset.add(docids.elementAt(i));
275
    				index ++;
276
    			}
277
    			else
278
    			{
279
    				docidOverride.add(subset);
280
    				subset = new Vector();
281
    				subset.add(docids.elementAt(i));
282
    			    index = 1;
283
    			}
284
    		}
285
    		if (!subset.isEmpty())
286
    		{
287
    			docidOverride.add(subset);
288
    		}
289
290
    	}
291
    	else
292
    	{
293
    		this.docidOverride.add(docids);
294
    	}
295
296 4213 daigle
        String parserName = PropertyService.getProperty("xml.saxparser");
297 3047 perry
        this.parserName = parserName;
298
    }
299 2087 tao
300
  /**
301
   * Method put the search result set into out printerwriter
302
   * @param resoponse the return response
303
   * @param out the output printer
304
   * @param params the paratermer hashtable
305
   * @param user the user name (it maybe different to the one in param)
306
   * @param groups the group array
307
   * @param sessionid  the sessionid
308
   */
309
  public void findDocuments(HttpServletResponse response,
310 5752 leinfelder
                                       Writer out, Hashtable params,
311 2087 tao
                                       String user, String[] groups,
312 4080 daigle
                                       String sessionid) throws PropertyNotFoundException
313 2087 tao
  {
314 4173 daigle
    boolean useXMLIndex = (new Boolean(PropertyService.getProperty("database.usexmlindex")))
315 2087 tao
               .booleanValue();
316
    findDocuments(response, out, params, user, groups, sessionid, useXMLIndex);
317
318
  }
319
320
321 2075 jones
    /**
322 2087 tao
     * Method put the search result set into out printerwriter
323
     * @param resoponse the return response
324
     * @param out the output printer
325
     * @param params the paratermer hashtable
326
     * @param user the user name (it maybe different to the one in param)
327
     * @param groups the group array
328
     * @param sessionid  the sessionid
329 2075 jones
     */
330 2087 tao
    public void findDocuments(HttpServletResponse response,
331 5752 leinfelder
                                         Writer out, Hashtable params,
332 2087 tao
                                         String user, String[] groups,
333
                                         String sessionid, boolean useXMLIndex)
334 2075 jones
    {
335 3211 berkley
      int pagesize = 0;
336
      int pagestart = 0;
337 5165 daigle
      long transferWarnLimit = 0;
338 3211 berkley
339
      if(params.containsKey("pagesize") && params.containsKey("pagestart"))
340
      {
341
        String pagesizeStr = ((String[])params.get("pagesize"))[0];
342
        String pagestartStr = ((String[])params.get("pagestart"))[0];
343
        if(pagesizeStr != null && pagestartStr != null)
344
        {
345
          pagesize = (new Integer(pagesizeStr)).intValue();
346
          pagestart = (new Integer(pagestartStr)).intValue();
347
        }
348
      }
349
350 3780 daigle
      String xmlquery = null;
351
      String qformat = null;
352 2087 tao
      // get query and qformat
353 3780 daigle
      try {
354
    	xmlquery = ((String[])params.get("query"))[0];
355 2168 tao
356 5165 daigle
        logMetacat.info("DBQuery.findDocuments - SESSIONID: " + sessionid);
357
        logMetacat.info("DBQuery.findDocuments - xmlquery: " + xmlquery);
358 3780 daigle
        qformat = ((String[])params.get("qformat"))[0];
359 5165 daigle
        logMetacat.info("DBQuery.findDocuments - qformat: " + qformat);
360 3780 daigle
      }
361
      catch (Exception ee)
362
      {
363 5165 daigle
        logMetacat.error("DBQuery.findDocuments - Couldn't retrieve xmlquery or qformat value from "
364 3780 daigle
                  +"params hashtable in DBQuery.findDocuments: "
365
                  + ee.getMessage());
366
      }
367 2168 tao
      // Get the XML query and covert it into a SQL statment
368
      QuerySpecification qspec = null;
369
      if ( xmlquery != null)
370
      {
371
         xmlquery = transformQuery(xmlquery);
372
         try
373
         {
374
           qspec = new QuerySpecification(xmlquery,
375
                                          parserName,
376 4212 daigle
                                          PropertyService.getProperty("document.accNumSeparator"));
377 2168 tao
         }
378
         catch (Exception ee)
379
         {
380 5165 daigle
           logMetacat.error("DBQuery.findDocuments - error generating QuerySpecification object: "
381 2663 sgarg
                                    + ee.getMessage());
382 2168 tao
         }
383
      }
384 2087 tao
385 2168 tao
386
387 5025 daigle
      if (qformat != null && qformat.equals(MetacatUtil.XMLFORMAT))
388 2087 tao
      {
389
        //xml format
390 5491 berkley
        if(response != null)
391
        {
392
            response.setContentType("text/xml");
393
        }
394 5490 berkley
        createResultDocument(xmlquery, qspec, out, user, groups, useXMLIndex,
395 7417 leinfelder
          pagesize, pagestart, sessionid, qformat, false);
396 2087 tao
      }//if
397
      else
398
      {
399
        //knb format, in this case we will get whole result and sent it out
400 3257 berkley
        response.setContentType("text/html");
401 5752 leinfelder
        Writer nonout = null;
402 2168 tao
        StringBuffer xml = createResultDocument(xmlquery, qspec, nonout, user,
403 3211 berkley
                                                groups, useXMLIndex, pagesize,
404 7417 leinfelder
                                                pagestart, sessionid, qformat, false);
405 2658 sgarg
406 2087 tao
        //transfer the xml to html
407
        try
408
        {
409 5165 daigle
         long startHTMLTransform = System.currentTimeMillis();
410 2087 tao
         DBTransform trans = new DBTransform();
411
         response.setContentType("text/html");
412 2787 sgarg
413 3219 berkley
         // if the user is a moderator, then pass a param to the
414 2787 sgarg
         // xsl specifying the fact
415 4589 daigle
         if(AuthUtil.isModerator(user, groups)){
416 2787 sgarg
        	 params.put("isModerator", new String[] {"true"});
417
         }
418
419 2087 tao
         trans.transformXMLDocument(xml.toString(), "-//NCEAS//resultset//EN",
420
                                 "-//W3C//HTML//EN", qformat, out, params,
421
                                 sessionid);
422 5165 daigle
         long transformRunTime = System.currentTimeMillis() - startHTMLTransform;
423
424
         transferWarnLimit = Long.parseLong(PropertyService.getProperty("dbquery.transformTimeWarnLimit"));
425
426
         if (transformRunTime > transferWarnLimit) {
427
         	logMetacat.warn("DBQuery.findDocuments - The time to transfrom resultset from xml to html format is "
428
                  		                             + transformRunTime);
429
         }
430 4698 daigle
          MetacatUtil.writeDebugToFile("---------------------------------------------------------------------------------------------------------------Transfrom xml to html  "
431 5165 daigle
                             + transformRunTime);
432
          MetacatUtil.writeDebugToDelimiteredFile(" " + transformRunTime, false);
433 2087 tao
        }
434
        catch(Exception e)
435
        {
436 5165 daigle
         logMetacat.error("DBQuery.findDocuments - Error in MetaCatServlet.transformResultset:"
437 2663 sgarg
                                +e.getMessage());
438 2087 tao
         }
439
440
      }//else
441
442 3219 berkley
  }
443 5490 berkley
444 3220 tao
  /**
445
   * Transforms a hashtable of documents to an xml or html result and sent
446
   * the content to outputstream. Keep going untill hastable is empty. stop it.
447
   * add the QuerySpecification as parameter is for ecogrid. But it is duplicate
448
   * to xmlquery String
449
   * @param xmlquery
450
   * @param qspec
451
   * @param out
452
   * @param user
453
   * @param groups
454
   * @param useXMLIndex
455
   * @param sessionid
456
   * @return
457
   */
458
    public StringBuffer createResultDocument(String xmlquery,
459
                                              QuerySpecification qspec,
460 5752 leinfelder
                                              Writer out,
461 3220 tao
                                              String user, String[] groups,
462
                                              boolean useXMLIndex)
463
    {
464 7417 leinfelder
    	return createResultDocument(xmlquery,qspec,out, user,groups, useXMLIndex, 0, 0,"", qformat, false);
465 3220 tao
    }
466 7417 leinfelder
467
    /**
468
     *
469
     * @param xmlquery
470
     * @param user
471
     * @param groups
472
     * @param useXMLIndex
473
     * @return
474
     * @throws IOException
475
     * @throws PropertyNotFoundException
476
     */
477
	public String performPathquery(String xmlquery, String user,
478
			String[] groups) throws PropertyNotFoundException, IOException {
479
480
		// get the XML query and convert it to query specification
481
		xmlquery = transformQuery(xmlquery);
482
		QuerySpecification qspec = new QuerySpecification(xmlquery, parserName, PropertyService.getProperty("document.accNumSeparator"));
483
484
		// force it to output the results to the string buffer, not outputstream
485
		Writer nonout = null;
486
		boolean useXMLIndex = (new Boolean(PropertyService.getProperty("database.usexmlindex"))).booleanValue();
487
		StringBuffer xml = createResultDocument(xmlquery, qspec, nonout, user, groups, useXMLIndex, 0, 0, "", qformat, true);
488 2043 sgarg
489 7417 leinfelder
		return xml.toString();
490
491
	}
492
493 2087 tao
  /*
494
   * Transforms a hashtable of documents to an xml or html result and sent
495 2168 tao
   * the content to outputstream. Keep going untill hastable is empty. stop it.
496
   * add the QuerySpecification as parameter is for ecogrid. But it is duplicate
497
   * to xmlquery String
498 2087 tao
   */
499 2168 tao
  public StringBuffer createResultDocument(String xmlquery,
500
                                            QuerySpecification qspec,
501 5752 leinfelder
                                            Writer out,
502 2087 tao
                                            String user, String[] groups,
503 3211 berkley
                                            boolean useXMLIndex, int pagesize,
504 5490 berkley
                                            int pagestart, String sessionid,
505 7417 leinfelder
                                            String qformat, boolean includeGuid)
506 2087 tao
  {
507
    DBConnection dbconn = null;
508
    int serialNumber = -1;
509
    StringBuffer resultset = new StringBuffer();
510 3219 berkley
511
    //try to get the cached version first
512 4080 daigle
    // Hashtable sessionHash = MetaCatServlet.getSessionHash();
513
    // HttpSession sess = (HttpSession)sessionHash.get(sessionid);
514 3219 berkley
515 3220 tao
516 2087 tao
    resultset.append("<?xml version=\"1.0\"?>\n");
517
    resultset.append("<resultset>\n");
518 3257 berkley
    resultset.append("  <pagestart>" + pagestart + "</pagestart>\n");
519
    resultset.append("  <pagesize>" + pagesize + "</pagesize>\n");
520
    resultset.append("  <nextpage>" + (pagestart + 1) + "</nextpage>\n");
521
    resultset.append("  <previouspage>" + (pagestart - 1) + "</previouspage>\n");
522
523 7427 leinfelder
    resultset.append("  <query><![CDATA[" + xmlquery + "]]></query>");
524 3219 berkley
    //send out a new query
525 2087 tao
    if (out != null)
526 2075 jones
    {
527 5752 leinfelder
    	try {
528
    	  out.write(resultset.toString());
529
		} catch (IOException e) {
530
			logMetacat.error(e.getMessage(), e);
531
		}
532 2075 jones
    }
533 2168 tao
    if (qspec != null)
534 2087 tao
    {
535 2168 tao
      try
536
      {
537 2043 sgarg
538 2168 tao
        //checkout the dbconnection
539
        dbconn = DBConnectionPool.getDBConnection("DBQuery.findDocuments");
540
        serialNumber = dbconn.getCheckOutSerialNumber();
541 2087 tao
542 2168 tao
        //print out the search result
543
        // search the doc list
544 3392 tao
        Vector givenDocids = new Vector();
545
        StringBuffer resultContent = new StringBuffer();
546
        if (docidOverride == null || docidOverride.size() == 0)
547
        {
548 5165 daigle
        	logMetacat.debug("DBQuery.createResultDocument - Not in map query");
549 3392 tao
        	resultContent = findResultDoclist(qspec, out, user, groups,
550
                    dbconn, useXMLIndex, pagesize, pagestart,
551 7417 leinfelder
                    sessionid, givenDocids, qformat, includeGuid);
552 3392 tao
        }
553
        else
554
        {
555 5165 daigle
        	logMetacat.debug("DBQuery.createResultDocument - In map query");
556 3392 tao
        	// since docid can be too long to be handled. We divide it into several parts
557
        	for (int i= 0; i<docidOverride.size(); i++)
558
        	{
559 5165 daigle
        	   logMetacat.debug("DBQuery.createResultDocument - in loop===== "+i);
560 3392 tao
        		givenDocids = (Vector)docidOverride.elementAt(i);
561
        		StringBuffer subset = findResultDoclist(qspec, out, user, groups,
562
                        dbconn, useXMLIndex, pagesize, pagestart,
563 7417 leinfelder
                        sessionid, givenDocids, qformat, includeGuid);
564 3392 tao
        		resultContent.append(subset);
565
        	}
566
        }
567
568 3342 tao
        resultset.append(resultContent);
569 2168 tao
      } //try
570
      catch (IOException ioe)
571
      {
572 5165 daigle
        logMetacat.error("DBQuery.createResultDocument - IO error: " + ioe.getMessage());
573 2168 tao
      }
574
      catch (SQLException e)
575
      {
576 5165 daigle
        logMetacat.error("DBQuery.createResultDocument - SQL Error: " + e.getMessage());
577 2168 tao
      }
578
      catch (Exception ee)
579
      {
580 5165 daigle
        logMetacat.error("DBQuery.createResultDocument - General exception: "
581 2663 sgarg
                                 + ee.getMessage());
582 3219 berkley
        ee.printStackTrace();
583 2168 tao
      }
584
      finally
585
      {
586
        DBConnectionPool.returnDBConnection(dbconn, serialNumber);
587
      } //finally
588
    }//if
589 2087 tao
    String closeRestultset = "</resultset>";
590
    resultset.append(closeRestultset);
591
    if (out != null)
592
    {
593 5752 leinfelder
      try {
594
		out.write(closeRestultset);
595
		} catch (IOException e) {
596
			logMetacat.error(e.getMessage(), e);
597
		}
598 2087 tao
    }
599 2168 tao
600 3221 berkley
    //default to returning the whole resultset
601 2087 tao
    return resultset;
602
  }//createResultDocuments
603 2043 sgarg
604 2087 tao
    /*
605
     * Find the doc list which match the query
606
     */
607
    private StringBuffer findResultDoclist(QuerySpecification qspec,
608 5752 leinfelder
                                      Writer out,
609 2087 tao
                                      String user, String[]groups,
610 3211 berkley
                                      DBConnection dbconn, boolean useXMLIndex,
611 5490 berkley
                                      int pagesize, int pagestart, String sessionid,
612 7417 leinfelder
                                      Vector givenDocids, String qformat, boolean includeGuid)
613 2087 tao
                                      throws Exception
614
    {
615 6602 leinfelder
    	// keep track of the values we add as prepared statement question marks (?)
616
  	  List<Object> parameterValues = new ArrayList<Object>();
617
618 3342 tao
      StringBuffer resultsetBuffer = new StringBuffer();
619 3219 berkley
      String query = null;
620
      int count = 0;
621
      int index = 0;
622 3246 berkley
      ResultDocumentSet docListResult = new ResultDocumentSet();
623 3219 berkley
      PreparedStatement pstmt = null;
624
      String docid = null;
625 7417 leinfelder
      String guid = null;
626 3219 berkley
      String docname = null;
627
      String doctype = null;
628
      String createDate = null;
629
      String updateDate = null;
630
      StringBuffer document = null;
631 3262 berkley
      boolean lastpage = false;
632 3219 berkley
      int rev = 0;
633
      double startTime = 0;
634 3368 tao
      int offset = 1;
635 5165 daigle
      long startSelectionTime = System.currentTimeMillis();
636 3219 berkley
      ResultSet rs = null;
637 3368 tao
638
639
      // this is a hack for offset. in postgresql 7, if the returned docid list is too long,
640
      //the extend query which base on the docid will be too long to be run. So we
641
      // have to cut them into different parts. Page query don't need it somehow.
642
      if (out == null)
643 2091 tao
      {
644
        // for html page, we put everything into one page
645 2421 sgarg
        offset =
646 4212 daigle
            (new Integer(PropertyService.getProperty("database.webResultsetSize"))).intValue();
647 2091 tao
      }
648
      else
649
      {
650
          offset =
651 4212 daigle
              (new Integer(PropertyService.getProperty("database.appResultsetSize"))).intValue();
652 3368 tao
      }
653 2421 sgarg
654 3047 perry
      /*
655
       * Check the docidOverride Vector
656
       * if defined, we bypass the qspec.printSQL() method
657
       * and contruct a simpler query based on a
658
       * list of docids rather than a bunch of subselects
659
       */
660 6602 leinfelder
      // keep track of the values we add as prepared statement question marks (?)
661
	  List<Object> docidValues = new ArrayList<Object>();
662 3392 tao
      if ( givenDocids == null || givenDocids.size() == 0 ) {
663 6602 leinfelder
          query = qspec.printSQL(useXMLIndex, docidValues);
664
          parameterValues.addAll(docidValues);
665 3047 perry
      } else {
666 6035 leinfelder
    	  // condition for the docids
667 6629 leinfelder
    	  List<Object> docidConditionValues = new ArrayList<Object>();
668 6035 leinfelder
    	  StringBuffer docidCondition = new StringBuffer();
669 7407 leinfelder
    	  docidCondition.append( " xml_documents.docid IN (" );
670 3392 tao
          for (int i = 0; i < givenDocids.size(); i++) {
671 6629 leinfelder
        	  docidCondition.append("?");
672 6035 leinfelder
        	  if (i < givenDocids.size()-1) {
673
        		  docidCondition.append(",");
674
        	  }
675 6629 leinfelder
        	  docidConditionValues.add((String)givenDocids.elementAt(i));
676 3047 perry
          }
677 6035 leinfelder
          docidCondition.append( ") " );
678
679
    	  // include the docids, either exclusively, or in conjuction with the query
680
    	  if (operator == null) {
681 7417 leinfelder
    		  query = "SELECT xml_documents.docid, identifier.guid, docname, doctype, date_created, date_updated, xml_documents.rev " +
682 7407 leinfelder
    		  		"FROM xml_documents, identifier " +
683
    		  		"WHERE xml_documents.docid = identifier.docid AND xml_documents.rev = identifier.rev AND ";
684 6035 leinfelder
              query = query + docidCondition.toString();
685 6629 leinfelder
              parameterValues.addAll(docidConditionValues);
686 6035 leinfelder
    	  } else {
687
    		  // start with the keyword query, but add conditions
688 6602 leinfelder
              query = qspec.printSQL(useXMLIndex, docidValues);
689
              parameterValues.addAll(docidValues);
690 6035 leinfelder
              String myOperator = "";
691 7408 leinfelder
              if (!query.endsWith("WHERE") && !query.endsWith("OR") && !query.endsWith("AND")) {
692 6035 leinfelder
	              if (operator.equalsIgnoreCase(QueryGroup.UNION)) {
693
	            	  myOperator =  " OR ";
694
	              }
695
	              else {
696
	            	  myOperator =  " AND ";
697
	              }
698
              }
699
              query = query + myOperator + docidCondition.toString();
700 6629 leinfelder
              parameterValues.addAll(docidConditionValues);
701 6035 leinfelder
702
    	  }
703 3047 perry
      }
704 6629 leinfelder
      // we don't actually use this query for anything
705
      List<Object> ownerValues = new ArrayList<Object>();
706
      String ownerQuery = getOwnerQuery(user, ownerValues);
707 4574 daigle
      //logMetacat.debug("query: " + query);
708 5165 daigle
      logMetacat.debug("DBQuery.findResultDoclist - owner query: " + ownerQuery);
709 2087 tao
      // if query is not the owner query, we need to check the permission
710
      // otherwise we don't need (owner has all permission by default)
711
      if (!query.equals(ownerQuery))
712
      {
713
        // set user name and group
714
        qspec.setUserName(user);
715
        qspec.setGroup(groups);
716
        // Get access query
717
        String accessQuery = qspec.getAccessQuery();
718 7408 leinfelder
        if(!query.endsWith("AND")){
719 2366 sgarg
            query = query + accessQuery;
720
        } else {
721
            query = query + accessQuery.substring(4, accessQuery.length());
722
        }
723 3309 tao
724 2087 tao
      }
725 5165 daigle
      logMetacat.debug("DBQuery.findResultDoclist - final selection query: " + query);
726 6774 tao
727
728
      pstmt = dbconn.prepareStatement(query);
729
      // set all the values we have collected
730
      pstmt = setPreparedStatementValues(parameterValues, pstmt);
731
732
      String queryCacheKey = null;
733 3342 tao
      // we only get cache for public
734
      if (user != null && user.equalsIgnoreCase("public")
735 6774 tao
         && pagesize == 0 && PropertyService.getProperty("database.queryCacheOn").equals("true"))
736 3342 tao
      {
737 6774 tao
          queryCacheKey = pstmt.toString() +qspec.getReturnDocList()+qspec.getReturnFieldList();
738
          String cachedResult = getResultXMLFromCache(queryCacheKey);
739
          logMetacat.debug("=======DBQuery.findResultDoclist - The key of query cache is " + queryCacheKey);
740
          //System.out.println("==========the string from cache is "+cachedResult);
741
          if (cachedResult != null)
742
          {
743
          logMetacat.info("DBQuery.findResultDoclist - result from cache !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
744
           if (out != null)
745
             {
746
                 out.write(cachedResult);
747
             }
748
           resultsetBuffer.append(cachedResult);
749
           pstmt.close();
750
           return resultsetBuffer;
751
          }
752 3342 tao
      }
753
754 3219 berkley
      startTime = System.currentTimeMillis() / 1000;
755 6602 leinfelder
      logMetacat.debug("Prepared statement after setting parameter values: " + pstmt.toString());
756 3219 berkley
      rs = pstmt.executeQuery();
757 3246 berkley
758 2087 tao
      double queryExecuteTime = System.currentTimeMillis() / 1000;
759 5165 daigle
      logMetacat.debug("DBQuery.findResultDoclist - Time to execute select docid query is "
760 2663 sgarg
                    + (queryExecuteTime - startTime));
761 4698 daigle
      MetacatUtil.writeDebugToFile("\n\n\n\n\n\nExecute selection query  "
762 3271 tao
              + (queryExecuteTime - startTime));
763 4698 daigle
      MetacatUtil.writeDebugToDelimiteredFile(""+(queryExecuteTime - startTime), false);
764 3246 berkley
765 3247 berkley
      boolean tableHasRows = rs.next();
766 3246 berkley
767
      if(pagesize == 0)
768
      { //this makes sure we get all results if there is no paging
769 3368 tao
        pagesize = NONPAGESIZE;
770
        pagestart = NONPAGESIZE;
771 3246 berkley
      }
772
773
      int currentIndex = 0;
774 2087 tao
      while (tableHasRows)
775
      {
776 5165 daigle
        logMetacat.debug("DBQuery.findResultDoclist - getting result: " + currentIndex);
777 2087 tao
        docid = rs.getString(1).trim();
778 7417 leinfelder
        logMetacat.debug("DBQuery.findResultDoclist -  docid: " + docid);
779
        guid = rs.getString(2).trim();
780
        logMetacat.debug("DBQuery.findResultDoclist -  guid: " + guid);
781
        docname = rs.getString(3);
782
        doctype = rs.getString(4);
783
        logMetacat.debug("DBQuery.findResultDoclist - doctype: " + doctype);
784
        createDate = rs.getString(5);
785
        updateDate = rs.getString(6);
786
        rev = rs.getInt(7);
787 3246 berkley
788 3307 tao
         Vector returndocVec = qspec.getReturnDocList();
789
       if (returndocVec.size() == 0 || returndocVec.contains(doctype))
790 2087 tao
        {
791 5165 daigle
          logMetacat.debug("DBQuery.findResultDoclist - NOT Back tracing now...");
792 2087 tao
           document = new StringBuffer();
793 2043 sgarg
794 2087 tao
           String completeDocid = docid
795 4212 daigle
                            + PropertyService.getProperty("document.accNumSeparator");
796 2087 tao
           completeDocid += rev;
797
           document.append("<docid>").append(completeDocid).append("</docid>");
798 7417 leinfelder
           if (includeGuid) {
799
        	   document.append("<guid>").append(guid).append("</guid>");
800
           }
801 2087 tao
           if (docname != null)
802
           {
803
               document.append("<docname>" + docname + "</docname>");
804 3219 berkley
           }
805
           if (doctype != null)
806
           {
807
              document.append("<doctype>" + doctype + "</doctype>");
808
           }
809
           if (createDate != null)
810
           {
811
               document.append("<createdate>" + createDate + "</createdate>");
812
           }
813
           if (updateDate != null)
814
           {
815
             document.append("<updatedate>" + updateDate + "</updatedate>");
816
           }
817
           // Store the document id and the root node id
818 3246 berkley
819
           docListResult.addResultDocument(
820
             new ResultDocument(docid, (String) document.toString()));
821 5165 daigle
           logMetacat.info("DBQuery.findResultDoclist - real result: " + docid);
822 3246 berkley
           currentIndex++;
823 3219 berkley
           count++;
824 2087 tao
        }//else
825 3246 berkley
826 2087 tao
        // when doclist reached the offset number, send out doc list and empty
827
        // the hash table
828 3368 tao
        if (count == offset && pagesize == NONPAGESIZE)
829 3246 berkley
        { //if pagesize is not 0, do this later.
830 2087 tao
          //reset count
831 3262 berkley
          //logMetacat.warn("############doing subset cache");
832 2087 tao
          count = 0;
833 3246 berkley
          handleSubsetResult(qspec, resultsetBuffer, out, docListResult,
834 5490 berkley
                              user, groups,dbconn, useXMLIndex, qformat);
835 3246 berkley
          //reset docListResult
836
          docListResult = new ResultDocumentSet();
837 3368 tao
        }
838 3246 berkley
839 5165 daigle
       logMetacat.debug("DBQuery.findResultDoclist - currentIndex: " + currentIndex);
840
       logMetacat.debug("DBQuery.findResultDoclist - page comparator: " + (pagesize * pagestart) + pagesize);
841 3246 berkley
       if(currentIndex >= ((pagesize * pagestart) + pagesize))
842
       {
843
         ResultDocumentSet pagedResultsHash = new ResultDocumentSet();
844
         for(int i=pagesize*pagestart; i<docListResult.size(); i++)
845
         {
846
           pagedResultsHash.put(docListResult.get(i));
847
         }
848
849
         docListResult = pagedResultsHash;
850
         break;
851
       }
852 2087 tao
       // Advance to the next record in the cursor
853
       tableHasRows = rs.next();
854 3246 berkley
       if(!tableHasRows)
855
       {
856 3262 berkley
         ResultDocumentSet pagedResultsHash = new ResultDocumentSet();
857
         //get the last page of information then break
858 3368 tao
         if(pagesize != NONPAGESIZE)
859 3262 berkley
         {
860
           for(int i=pagesize*pagestart; i<docListResult.size(); i++)
861
           {
862
             pagedResultsHash.put(docListResult.get(i));
863
           }
864
           docListResult = pagedResultsHash;
865
         }
866
867
         lastpage = true;
868 3246 berkley
         break;
869
       }
870 2087 tao
     }//while
871 3246 berkley
872 2087 tao
     rs.close();
873
     pstmt.close();
874 5165 daigle
     long docListTime = System.currentTimeMillis() - startSelectionTime;
875
     long docListWarnLimit = Long.parseLong(PropertyService.getProperty("dbquery.findDocListTimeWarnLimit"));
876
     if (docListTime > docListWarnLimit) {
877
    	 logMetacat.warn("DBQuery.findResultDoclist - Total time to get docid list is: "
878
                          + docListTime);
879
     }
880 4698 daigle
     MetacatUtil.writeDebugToFile("---------------------------------------------------------------------------------------------------------------Total selection: "
881 5165 daigle
             + docListTime);
882
     MetacatUtil.writeDebugToDelimiteredFile(" "+ docListTime, false);
883 2087 tao
     //if docListResult is not empty, it need to be sent.
884 3246 berkley
     if (docListResult.size() != 0)
885 2087 tao
     {
886 3342 tao
887 2087 tao
       handleSubsetResult(qspec,resultsetBuffer, out, docListResult,
888 5490 berkley
                              user, groups,dbconn, useXMLIndex, qformat);
889 2087 tao
     }
890 2091 tao
891 3262 berkley
     resultsetBuffer.append("\n<lastpage>" + lastpage + "</lastpage>\n");
892
     if (out != null)
893
     {
894 5752 leinfelder
         out.write("\n<lastpage>" + lastpage + "</lastpage>\n");
895 3262 berkley
     }
896 3342 tao
897
     // now we only cached none-paged query and user is public
898
     if (user != null && user.equalsIgnoreCase("public")
899 4212 daigle
    		 && pagesize == NONPAGESIZE && PropertyService.getProperty("database.queryCacheOn").equals("true"))
900 3342 tao
     {
901
       //System.out.println("the string stored into cache is "+ resultsetBuffer.toString());
902 6774 tao
  	   storeQueryResultIntoCache(queryCacheKey, resultsetBuffer.toString());
903 3342 tao
     }
904 3262 berkley
905 2087 tao
     return resultsetBuffer;
906
    }//findReturnDoclist
907 2043 sgarg
908
909 2087 tao
    /*
910
     * Send completed search hashtable(part of reulst)to output stream
911
     * and buffer into a buffer stream
912
     */
913
    private StringBuffer handleSubsetResult(QuerySpecification qspec,
914
                                           StringBuffer resultset,
915 5752 leinfelder
                                           Writer out, ResultDocumentSet partOfDoclist,
916 2087 tao
                                           String user, String[]groups,
917 5490 berkley
                                       DBConnection dbconn, boolean useXMLIndex,
918
                                       String qformat)
919 2087 tao
                                       throws Exception
920
   {
921 5165 daigle
     double startReturnFieldTime = System.currentTimeMillis();
922 2424 sgarg
     // check if there is a record in xml_returnfield
923
     // and get the returnfield_id and usage count
924
     int usage_count = getXmlReturnfieldsTableId(qspec, dbconn);
925
     boolean enterRecords = false;
926
927 4212 daigle
     // get value of database.xmlReturnfieldCount
928 4080 daigle
     int count = (new Integer(PropertyService
929 4212 daigle
                            .getProperty("database.xmlReturnfieldCount")))
930 2424 sgarg
                            .intValue();
931 2430 sgarg
932 2446 sgarg
     // set enterRecords to true if usage_count is more than the offset
933 2430 sgarg
     // specified in metacat.properties
934 2424 sgarg
     if(usage_count > count){
935
         enterRecords = true;
936
     }
937 3257 berkley
938 2421 sgarg
     if(returnfield_id < 0){
939 5165 daigle
         logMetacat.warn("DBQuery.handleSubsetResult - Error in getting returnfield id from"
940 2663 sgarg
                                  + "xml_returnfield table");
941 3227 berkley
         enterRecords = false;
942 2421 sgarg
     }
943
944
     // get the hashtable containing the docids that already in the
945
     // xml_queryresult table
946 5165 daigle
     logMetacat.info("DBQuery.handleSubsetResult - size of partOfDoclist before"
947 2421 sgarg
                             + " docidsInQueryresultTable(): "
948 2663 sgarg
                             + partOfDoclist.size());
949 5165 daigle
     long startGetReturnValueFromQueryresultable = System.currentTimeMillis();
950 2421 sgarg
     Hashtable queryresultDocList = docidsInQueryresultTable(returnfield_id,
951
                                                        partOfDoclist, dbconn);
952
953
     // remove the keys in queryresultDocList from partOfDoclist
954
     Enumeration _keys = queryresultDocList.keys();
955
     while (_keys.hasMoreElements()){
956 3246 berkley
         partOfDoclist.remove((String)_keys.nextElement());
957 2421 sgarg
     }
958 5165 daigle
959
     long queryResultReturnValuetime = System.currentTimeMillis() - startGetReturnValueFromQueryresultable;
960
     long queryResultWarnLimit =
961
    	 Long.parseLong(PropertyService.getProperty("dbquery.findQueryResultsTimeWarnLimit"));
962
963
     if (queryResultReturnValuetime > queryResultWarnLimit) {
964
    	 logMetacat.warn("DBQuery.handleSubsetResult - Time to get return fields from xml_queryresult table is (Part1 in return fields) " +
965
    		 queryResultReturnValuetime);
966
     }
967 4698 daigle
     MetacatUtil.writeDebugToFile("-----------------------------------------Get fields from xml_queryresult(Part1 in return fields) " +
968 5165 daigle
    		 queryResultReturnValuetime);
969
     MetacatUtil.writeDebugToDelimiteredFile(" " + queryResultReturnValuetime,false);
970
971
     long startExtendedQuery = System.currentTimeMillis();
972 2425 sgarg
     // backup the keys-elements in partOfDoclist to check later
973
     // if the doc entry is indexed yet
974
     Hashtable partOfDoclistBackup = new Hashtable();
975 3246 berkley
     Iterator itt = partOfDoclist.getDocids();
976
     while (itt.hasNext()){
977
       Object key = itt.next();
978 2425 sgarg
         partOfDoclistBackup.put(key, partOfDoclist.get(key));
979
     }
980
981 5165 daigle
     logMetacat.info("DBQuery.handleSubsetResult - size of partOfDoclist after"
982 2421 sgarg
                             + " docidsInQueryresultTable(): "
983 2663 sgarg
                             + partOfDoclist.size());
984 2421 sgarg
985
     //add return fields for the documents in partOfDoclist
986
     partOfDoclist = addReturnfield(partOfDoclist, qspec, user, groups,
987 5490 berkley
                                        dbconn, useXMLIndex, qformat);
988 5165 daigle
     long extendedQueryRunTime = startExtendedQuery - System.currentTimeMillis();
989
     long extendedQueryWarnLimit =
990
    	 Long.parseLong(PropertyService.getProperty("dbquery.extendedQueryRunTimeWarnLimit"));
991
992
     if (extendedQueryRunTime > extendedQueryWarnLimit) {
993
    	 logMetacat.warn("DBQuery.handleSubsetResult - Get fields from index and node table (Part2 in return fields) "
994
        		                                          + extendedQueryRunTime);
995
     }
996 4698 daigle
     MetacatUtil.writeDebugToFile("-----------------------------------------Get fields from extened query(Part2 in return fields) "
997 5165 daigle
             + extendedQueryRunTime);
998 4698 daigle
     MetacatUtil.writeDebugToDelimiteredFile(" "
999 5165 daigle
             + extendedQueryRunTime, false);
1000 2421 sgarg
     //add relationship part part docid list for the documents in partOfDocList
1001 3730 tao
     //partOfDoclist = addRelationship(partOfDoclist, qspec, dbconn, useXMLIndex);
1002 2421 sgarg
1003 5165 daigle
     long startStoreReturnField = System.currentTimeMillis();
1004 3246 berkley
     Iterator keys = partOfDoclist.getDocids();
1005 2087 tao
     String key = null;
1006
     String element = null;
1007 2421 sgarg
     String query = null;
1008 4080 daigle
     int offset = (new Integer(PropertyService
1009 4212 daigle
                               .getProperty("database.queryresultStringLength")))
1010 2421 sgarg
                               .intValue();
1011 3246 berkley
     while (keys.hasNext())
1012 2087 tao
     {
1013 3246 berkley
         key = (String) keys.next();
1014 2421 sgarg
         element = (String)partOfDoclist.get(key);
1015 3350 tao
1016 2446 sgarg
	 // check if the enterRecords is true, elements is not null, element's
1017
         // length is less than the limit of table column and if the document
1018 2425 sgarg
         // has been indexed already
1019 2446 sgarg
         if(enterRecords && element != null
1020 2425 sgarg
		&& element.length() < offset
1021
		&& element.compareTo((String) partOfDoclistBackup.get(key)) != 0){
1022 2421 sgarg
             query = "INSERT INTO xml_queryresult (returnfield_id, docid, "
1023 2446 sgarg
                 + "queryresult_string) VALUES (?, ?, ?)";
1024
1025 2421 sgarg
             PreparedStatement pstmt = null;
1026
             pstmt = dbconn.prepareStatement(query);
1027 2446 sgarg
             pstmt.setInt(1, returnfield_id);
1028
             pstmt.setString(2, key);
1029
             pstmt.setString(3, element);
1030 3350 tao
1031 2421 sgarg
             dbconn.increaseUsageCount(1);
1032 3350 tao
             try
1033
             {
1034
            	 pstmt.execute();
1035
             }
1036
             catch(Exception e)
1037
             {
1038 5165 daigle
            	 logMetacat.warn("DBQuery.handleSubsetResult - couldn't insert the element to xml_queryresult table "+e.getLocalizedMessage());
1039 3350 tao
             }
1040
             finally
1041
             {
1042
                pstmt.close();
1043
             }
1044 2421 sgarg
         }
1045 3263 tao
1046 2421 sgarg
         // A string with element
1047
         String xmlElement = "  <document>" + element + "</document>";
1048 3257 berkley
1049 2421 sgarg
         //send single element to output
1050
         if (out != null)
1051
         {
1052 5752 leinfelder
             out.write(xmlElement);
1053 2421 sgarg
         }
1054
         resultset.append(xmlElement);
1055
     }//while
1056 3263 tao
1057 5165 daigle
     double storeReturnFieldTime = System.currentTimeMillis() - startStoreReturnField;
1058
     long storeReturnFieldWarnLimit =
1059
    	 Long.parseLong(PropertyService.getProperty("dbquery.storeReturnFieldTimeWarnLimit"));
1060
1061
     if (storeReturnFieldTime > storeReturnFieldWarnLimit) {
1062
    	 logMetacat.warn("DBQuery.handleSubsetResult - Time to store new return fields into xml_queryresult table (Part4 in return fields) "
1063
                   + storeReturnFieldTime);
1064
     }
1065 4698 daigle
     MetacatUtil.writeDebugToFile("-----------------------------------------Insert new record to xml_queryresult(Part4 in return fields) "
1066 5165 daigle
             + storeReturnFieldTime);
1067
     MetacatUtil.writeDebugToDelimiteredFile(" " + storeReturnFieldTime, false);
1068 3263 tao
1069 3246 berkley
     Enumeration keysE = queryresultDocList.keys();
1070
     while (keysE.hasMoreElements())
1071 2421 sgarg
     {
1072 3246 berkley
         key = (String) keysE.nextElement();
1073 2421 sgarg
         element = (String)queryresultDocList.get(key);
1074
         // A string with element
1075
         String xmlElement = "  <document>" + element + "</document>";
1076
         //send single element to output
1077
         if (out != null)
1078
         {
1079 5752 leinfelder
             out.write(xmlElement);
1080 2421 sgarg
         }
1081
         resultset.append(xmlElement);
1082
     }//while
1083 5165 daigle
     double returnFieldTime = System.currentTimeMillis() - startReturnFieldTime;
1084
     long totalReturnFieldWarnLimit =
1085
    	 Long.parseLong(PropertyService.getProperty("dbquery.totalReturnFieldTimeWarnLimit"));
1086
1087
     if (returnFieldTime > totalReturnFieldWarnLimit) {
1088
    	 logMetacat.warn("DBQuery.handleSubsetResult - Total time to get return fields is: "
1089
                           + returnFieldTime);
1090
     }
1091
     MetacatUtil.writeDebugToFile("DBQuery.handleSubsetResult - ---------------------------------------------------------------------------------------------------------------"+
1092
    		 "Total to get return fields  " + returnFieldTime);
1093
     MetacatUtil.writeDebugToDelimiteredFile("DBQuery.handleSubsetResult - "+ returnFieldTime, false);
1094 2421 sgarg
     return resultset;
1095
 }
1096
1097
   /**
1098
    * Get the docids already in xml_queryresult table and corresponding
1099
    * queryresultstring as a hashtable
1100
    */
1101
   private Hashtable docidsInQueryresultTable(int returnfield_id,
1102 3246 berkley
                                              ResultDocumentSet partOfDoclist,
1103 2421 sgarg
                                              DBConnection dbconn){
1104
1105
         Hashtable returnValue = new Hashtable();
1106
         PreparedStatement pstmt = null;
1107
         ResultSet rs = null;
1108 6629 leinfelder
1109
         // keep track of parameter values
1110
         List<Object> parameterValues = new ArrayList<Object>();
1111 2421 sgarg
1112
         // get partOfDoclist as string for the query
1113 3246 berkley
         Iterator keylist = partOfDoclist.getDocids();
1114 2421 sgarg
         StringBuffer doclist = new StringBuffer();
1115 3246 berkley
         while (keylist.hasNext())
1116 2421 sgarg
         {
1117 6629 leinfelder
             doclist.append("?,");
1118
             parameterValues.add((String) keylist.next());
1119 2421 sgarg
         }//while
1120
1121
         if (doclist.length() > 0)
1122
         {
1123
             doclist.deleteCharAt(doclist.length() - 1); //remove the last comma
1124
1125
             // the query to find out docids from xml_queryresult
1126
             String query = "select docid, queryresult_string from "
1127
                          + "xml_queryresult where returnfield_id = " +
1128
                          returnfield_id +" and docid in ("+ doclist + ")";
1129 5165 daigle
             logMetacat.info("DBQuery.docidsInQueryresultTable - Query to get docids from xml_queryresult:"
1130 2663 sgarg
                                      + query);
1131 2421 sgarg
1132
             try {
1133
                 // prepare and execute the query
1134
                 pstmt = dbconn.prepareStatement(query);
1135 6629 leinfelder
                 // bind parameter values
1136
                 pstmt = setPreparedStatementValues(parameterValues, pstmt);
1137
1138 2421 sgarg
                 dbconn.increaseUsageCount(1);
1139
                 pstmt.execute();
1140
                 rs = pstmt.getResultSet();
1141
                 boolean tableHasRows = rs.next();
1142
                 while (tableHasRows) {
1143
                     // store the returned results in the returnValue hashtable
1144
                     String key = rs.getString(1);
1145
                     String element = rs.getString(2);
1146
1147
                     if(element != null){
1148
                         returnValue.put(key, element);
1149
                     } else {
1150 5165 daigle
                         logMetacat.info("DBQuery.docidsInQueryresultTable - Null elment found ("
1151 2663 sgarg
                         + "DBQuery.docidsInQueryresultTable)");
1152 2421 sgarg
                     }
1153
                     tableHasRows = rs.next();
1154
                 }
1155
                 rs.close();
1156
                 pstmt.close();
1157
             } catch (Exception e){
1158 5165 daigle
                 logMetacat.error("DBQuery.docidsInQueryresultTable - Error getting docids from "
1159
                                          + "queryresult: " + e.getMessage());
1160 2421 sgarg
              }
1161
         }
1162
         return returnValue;
1163
     }
1164
1165
1166
   /**
1167
    * Method to get id from xml_returnfield table
1168
    * for a given query specification
1169
    */
1170 2424 sgarg
   private int returnfield_id;
1171 2421 sgarg
   private int getXmlReturnfieldsTableId(QuerySpecification qspec,
1172
                                           DBConnection dbconn){
1173
       int id = -1;
1174 2424 sgarg
       int count = 1;
1175 2421 sgarg
       PreparedStatement pstmt = null;
1176
       ResultSet rs = null;
1177
       String returnfield = qspec.getSortedReturnFieldString();
1178
1179
       // query for finding the id from xml_returnfield
1180 2446 sgarg
       String query = "SELECT returnfield_id, usage_count FROM xml_returnfield "
1181
            + "WHERE returnfield_string LIKE ?";
1182 5165 daigle
       logMetacat.info("DBQuery.getXmlReturnfieldsTableId - ReturnField Query:" + query);
1183 2421 sgarg
1184
       try {
1185
           // prepare and run the query
1186
           pstmt = dbconn.prepareStatement(query);
1187 2446 sgarg
           pstmt.setString(1,returnfield);
1188 2421 sgarg
           dbconn.increaseUsageCount(1);
1189
           pstmt.execute();
1190
           rs = pstmt.getResultSet();
1191
           boolean tableHasRows = rs.next();
1192
1193
           // if record found then increase the usage count
1194
           // else insert a new record and get the id of the new record
1195
           if(tableHasRows){
1196
               // get the id
1197
               id = rs.getInt(1);
1198 2424 sgarg
               count = rs.getInt(2) + 1;
1199 2421 sgarg
               rs.close();
1200
               pstmt.close();
1201
1202
               // increase the usage count
1203 6629 leinfelder
               query = "UPDATE xml_returnfield SET usage_count = ?"
1204
                   + " WHERE returnfield_id = ?";
1205 5165 daigle
               logMetacat.info("DBQuery.getXmlReturnfieldsTableId - ReturnField Table Update:"+ query);
1206 2421 sgarg
1207
               pstmt = dbconn.prepareStatement(query);
1208 6629 leinfelder
               pstmt.setInt(1, count);
1209
               pstmt.setInt(2, id);
1210 2421 sgarg
               dbconn.increaseUsageCount(1);
1211
               pstmt.execute();
1212
               pstmt.close();
1213
1214
           } else {
1215
               rs.close();
1216
               pstmt.close();
1217
1218
               // insert a new record
1219
               query = "INSERT INTO xml_returnfield (returnfield_string, usage_count)"
1220 2446 sgarg
                   + "VALUES (?, '1')";
1221 5165 daigle
               logMetacat.info("DBQuery.getXmlReturnfieldsTableId - ReturnField Table Insert:"+ query);
1222 2421 sgarg
               pstmt = dbconn.prepareStatement(query);
1223 2446 sgarg
               pstmt.setString(1, returnfield);
1224 2421 sgarg
               dbconn.increaseUsageCount(1);
1225
               pstmt.execute();
1226
               pstmt.close();
1227
1228
               // get the id of the new record
1229 2446 sgarg
               query = "SELECT returnfield_id FROM xml_returnfield "
1230
                   + "WHERE returnfield_string LIKE ?";
1231 5165 daigle
               logMetacat.info("DBQuery.getXmlReturnfieldsTableId - ReturnField query after Insert:" + query);
1232 2421 sgarg
               pstmt = dbconn.prepareStatement(query);
1233 2446 sgarg
               pstmt.setString(1, returnfield);
1234
1235 2421 sgarg
               dbconn.increaseUsageCount(1);
1236
               pstmt.execute();
1237
               rs = pstmt.getResultSet();
1238
               if(rs.next()){
1239
                   id = rs.getInt(1);
1240
               } else {
1241
                   id = -1;
1242
               }
1243
               rs.close();
1244
               pstmt.close();
1245 2087 tao
           }
1246 2091 tao
1247 2421 sgarg
       } catch (Exception e){
1248 5165 daigle
           logMetacat.error("DBQuery.getXmlReturnfieldsTableId - Error getting id from xml_returnfield in "
1249 2421 sgarg
                                     + "DBQuery.getXmlReturnfieldsTableId: "
1250 2663 sgarg
                                     + e.getMessage());
1251 2421 sgarg
           id = -1;
1252
       }
1253 2424 sgarg
1254
       returnfield_id = id;
1255
       return count;
1256 2087 tao
   }
1257 2043 sgarg
1258
1259 2087 tao
    /*
1260
     * A method to add return field to return doclist hash table
1261
     */
1262 3246 berkley
    private ResultDocumentSet addReturnfield(ResultDocumentSet docListResult,
1263 2087 tao
                                      QuerySpecification qspec,
1264
                                      String user, String[]groups,
1265 5490 berkley
                                      DBConnection dbconn, boolean useXMLIndex,
1266
                                      String qformat)
1267 2087 tao
                                      throws Exception
1268
    {
1269
      PreparedStatement pstmt = null;
1270
      ResultSet rs = null;
1271
      String docid = null;
1272
      String fieldname = null;
1273 3635 leinfelder
      String fieldtype = null;
1274 2087 tao
      String fielddata = null;
1275
      String relation = null;
1276 6629 leinfelder
      // keep track of parameter values
1277
      List<Object> parameterValues = new ArrayList<Object>();
1278 2087 tao
1279
      if (qspec.containsExtendedSQL())
1280
      {
1281
        qspec.setUserName(user);
1282
        qspec.setGroup(groups);
1283
        Vector extendedFields = new Vector(qspec.getReturnFieldList());
1284
        Vector results = new Vector();
1285 3246 berkley
        Iterator keylist = docListResult.getDocids();
1286 2087 tao
        StringBuffer doclist = new StringBuffer();
1287 6629 leinfelder
        List<Object> doclistValues = new ArrayList<Object>();
1288 2087 tao
        Vector parentidList = new Vector();
1289
        Hashtable returnFieldValue = new Hashtable();
1290 3246 berkley
        while (keylist.hasNext())
1291 2087 tao
        {
1292 5490 berkley
          String key = (String)keylist.next();
1293 6629 leinfelder
          doclist.append("?,");
1294
          doclistValues.add(key);
1295 2087 tao
        }
1296
        if (doclist.length() > 0)
1297
        {
1298
          Hashtable controlPairs = new Hashtable();
1299
          doclist.deleteCharAt(doclist.length() - 1); //remove the last comma
1300 3248 tao
          boolean tableHasRows = false;
1301 3349 tao
1302 2087 tao
1303 6629 leinfelder
1304 2087 tao
           String extendedQuery =
1305 6734 leinfelder
               qspec.printExtendedSQL(doclist.toString(), useXMLIndex, parameterValues, doclistValues);
1306
           // DO not add doclist values -- they are included in the query
1307
           //parameterValues.addAll(doclistValues);
1308 5165 daigle
           logMetacat.info("DBQuery.addReturnfield - Extended query: " + extendedQuery);
1309 2376 sgarg
1310 2474 sgarg
           if(extendedQuery != null){
1311 5165 daigle
//        	   long extendedQueryStart = System.currentTimeMillis();
1312 2474 sgarg
               pstmt = dbconn.prepareStatement(extendedQuery);
1313 6602 leinfelder
               // set the parameter values
1314
               pstmt = DBQuery.setPreparedStatementValues(parameterValues, pstmt);
1315 2474 sgarg
               //increase dbconnection usage count
1316
               dbconn.increaseUsageCount(1);
1317
               pstmt.execute();
1318
               rs = pstmt.getResultSet();
1319
               tableHasRows = rs.next();
1320
               while (tableHasRows) {
1321
                   ReturnFieldValue returnValue = new ReturnFieldValue();
1322
                   docid = rs.getString(1).trim();
1323
                   fieldname = rs.getString(2);
1324 5490 berkley
1325
                   if(qformat.toLowerCase().trim().equals("xml"))
1326
                   {
1327
                       byte[] b = rs.getBytes(3);
1328 5756 leinfelder
                       fielddata = new String(b, 0, b.length, MetaCatServlet.DEFAULT_ENCODING);
1329 5490 berkley
                   }
1330
                   else
1331
                   {
1332
                       fielddata = rs.getString(3);
1333
                   }
1334
1335
                   //System.out.println("raw fielddata: " + fielddata);
1336 4698 daigle
                   fielddata = MetacatUtil.normalize(fielddata);
1337 5490 berkley
                   //System.out.println("normalized fielddata: " + fielddata);
1338 2474 sgarg
                   String parentId = rs.getString(4);
1339 3635 leinfelder
                   fieldtype = rs.getString(5);
1340 2474 sgarg
                   StringBuffer value = new StringBuffer();
1341 2043 sgarg
1342 3635 leinfelder
                   //handle case when usexmlindex is true differently
1343
                   //at one point merging the nodedata (for large text elements) was
1344
                   //deemed unnecessary - but now it is needed.  but not for attribute nodes
1345 2474 sgarg
                   if (useXMLIndex || !containsKey(parentidList, parentId)) {
1346 3635 leinfelder
                	   //merge node data only for non-ATTRIBUTEs
1347
                	   if (fieldtype != null && !fieldtype.equals("ATTRIBUTE")) {
1348
	                	   //try merging the data
1349
	                	   ReturnFieldValue existingRFV =
1350
	                		   getArrayValue(parentidList, parentId);
1351 5387 berkley
	                	   if (existingRFV != null && !existingRFV.getFieldType().equals("ATTRIBUTE")) {
1352 3635 leinfelder
	                		   fielddata = existingRFV.getFieldValue() + fielddata;
1353
	                	   }
1354
                	   }
1355 5387 berkley
                	   //System.out.println("fieldname: " + fieldname + " fielddata: " + fielddata);
1356 5490 berkley
1357 2474 sgarg
                       value.append("<param name=\"");
1358
                       value.append(fieldname);
1359
                       value.append("\">");
1360
                       value.append(fielddata);
1361
                       value.append("</param>");
1362
                       //set returnvalue
1363
                       returnValue.setDocid(docid);
1364
                       returnValue.setFieldValue(fielddata);
1365 3635 leinfelder
                       returnValue.setFieldType(fieldtype);
1366 2474 sgarg
                       returnValue.setXMLFieldValue(value.toString());
1367
                       // Store it in hastable
1368
                       putInArray(parentidList, parentId, returnValue);
1369
                   }
1370
                   else {
1371 5490 berkley
1372 2474 sgarg
                       // need to merge nodedata if they have same parent id and
1373
                       // node type is text
1374
                       fielddata = (String) ( (ReturnFieldValue)
1375
                                             getArrayValue(
1376
                           parentidList, parentId)).getFieldValue()
1377
                           + fielddata;
1378 5490 berkley
                       //System.out.println("fieldname: " + fieldname + " fielddata: " + fielddata);
1379 2474 sgarg
                       value.append("<param name=\"");
1380
                       value.append(fieldname);
1381
                       value.append("\">");
1382
                       value.append(fielddata);
1383
                       value.append("</param>");
1384
                       returnValue.setDocid(docid);
1385
                       returnValue.setFieldValue(fielddata);
1386 3635 leinfelder
                       returnValue.setFieldType(fieldtype);
1387 2474 sgarg
                       returnValue.setXMLFieldValue(value.toString());
1388
                       // remove the old return value from paretnidList
1389
                       parentidList.remove(parentId);
1390
                       // store the new return value in parentidlit
1391
                       putInArray(parentidList, parentId, returnValue);
1392
                   }
1393
                   tableHasRows = rs.next();
1394
               } //while
1395
               rs.close();
1396
               pstmt.close();
1397 2043 sgarg
1398 2474 sgarg
               // put the merger node data info into doclistReult
1399
               Enumeration xmlFieldValue = (getElements(parentidList)).
1400
                   elements();
1401
               while (xmlFieldValue.hasMoreElements()) {
1402
                   ReturnFieldValue object =
1403
                       (ReturnFieldValue) xmlFieldValue.nextElement();
1404
                   docid = object.getDocid();
1405 3246 berkley
                   if (docListResult.containsDocid(docid)) {
1406 2474 sgarg
                       String removedelement = (String) docListResult.
1407
                           remove(docid);
1408
                       docListResult.
1409 3246 berkley
                           addResultDocument(new ResultDocument(docid,
1410
                               removedelement + object.getXMLFieldValue()));
1411 2474 sgarg
                   }
1412
                   else {
1413 3246 berkley
                       docListResult.addResultDocument(
1414
                         new ResultDocument(docid, object.getXMLFieldValue()));
1415 2474 sgarg
                   }
1416
               } //while
1417 5165 daigle
//               double docListResultEnd = System.currentTimeMillis() / 1000;
1418
//               logMetacat.warn(
1419
//                   "Time to prepare ResultDocumentSet after"
1420
//                   + " execute extended query: "
1421
//                   + (docListResultEnd - extendedQueryEnd));
1422 2474 sgarg
           }
1423 2087 tao
       }//if doclist lenght is great than zero
1424
     }//if has extended query
1425 2043 sgarg
1426 2087 tao
      return docListResult;
1427
    }//addReturnfield
1428 2043 sgarg
1429 3730 tao
1430 2087 tao
  /**
1431
   * removes the <?xml version="1.0"?> tag from the beginning.  This takes a
1432
   * string as a param instead of a hashtable.
1433
   *
1434
   * @param xmlquery a string representing a query.
1435
   */
1436
   private  String transformQuery(String xmlquery)
1437
   {
1438
     xmlquery = xmlquery.trim();
1439
     int index = xmlquery.indexOf("?>");
1440
     if (index != -1)
1441
     {
1442
       return xmlquery.substring(index + 2, xmlquery.length());
1443
     }
1444
     else
1445
     {
1446
       return xmlquery;
1447
     }
1448
   }
1449 3340 tao
1450
   /*
1451 3342 tao
    * Method to store query string and result xml string into query result
1452 3340 tao
    * cache. If the size alreay reache the limitation, the cache will be
1453
    * cleared first, then store them.
1454
    */
1455 3342 tao
   private void storeQueryResultIntoCache(String query, String resultXML)
1456 3340 tao
   {
1457
	   synchronized (queryResultCache)
1458
	   {
1459
		   if (queryResultCache.size() >= QUERYRESULTCACHESIZE)
1460
		   {
1461
			   queryResultCache.clear();
1462
		   }
1463 3342 tao
		   queryResultCache.put(query, resultXML);
1464 3340 tao
1465
	   }
1466
   }
1467
1468
   /*
1469 3342 tao
    * Method to get result xml string from query result cache.
1470
    * Note: the returned string can be null.
1471 3340 tao
    */
1472 3342 tao
   private String getResultXMLFromCache(String query)
1473 3340 tao
   {
1474 3342 tao
	   String resultSet = null;
1475 3340 tao
	   synchronized (queryResultCache)
1476
	   {
1477
          try
1478
          {
1479 5165 daigle
        	 logMetacat.info("DBQuery.getResultXMLFromCache - Get query from cache");
1480 3342 tao
		     resultSet = (String)queryResultCache.get(query);
1481 3340 tao
1482
          }
1483
          catch (Exception e)
1484
          {
1485
        	  resultSet = null;
1486
          }
1487
1488
	   }
1489
	   return resultSet;
1490
   }
1491
1492
   /**
1493
    * Method to clear the query result cache.
1494
    */
1495
   public static void clearQueryResultCache()
1496
   {
1497
	   synchronized (queryResultCache)
1498
	   {
1499
		   queryResultCache.clear();
1500
	   }
1501
   }
1502 6602 leinfelder
1503
   /**
1504
    * Set the parameter values in the prepared statement using instrospection
1505
    * of the given value objects
1506
    * @param parameterValues
1507
    * @param pstmt
1508
    * @return
1509
    * @throws SQLException
1510
    */
1511
   public static PreparedStatement setPreparedStatementValues(List<Object> parameterValues, PreparedStatement pstmt) throws SQLException {
1512
	   // set all the values we have collected
1513
      int parameterIndex = 1;
1514
      for (Object parameterValue: parameterValues) {
1515
    	  if (parameterValue instanceof String) {
1516
    		  pstmt.setString(parameterIndex, (String) parameterValue);
1517
    	  }
1518
    	  else if (parameterValue instanceof Integer) {
1519
    		  pstmt.setInt(parameterIndex, (Integer) parameterValue);
1520
    	  }
1521
    	  else if (parameterValue instanceof Float) {
1522
    		  pstmt.setFloat(parameterIndex, (Float) parameterValue);
1523
    	  }
1524
    	  else if (parameterValue instanceof Double) {
1525
    		  pstmt.setDouble(parameterIndex, (Double) parameterValue);
1526
    	  }
1527
    	  else if (parameterValue instanceof Date) {
1528
    		  pstmt.setTimestamp(parameterIndex, new Timestamp(((Date) parameterValue).getTime()));
1529
    	  }
1530
    	  else {
1531
    		  pstmt.setObject(parameterIndex, parameterValue);
1532
    	  }
1533
    	  parameterIndex++;
1534
      }
1535
      return pstmt;
1536
   }
1537 2087 tao
1538
1539 2075 jones
    /*
1540
     * A method to search if Vector contains a particular key string
1541
     */
1542
    private boolean containsKey(Vector parentidList, String parentId)
1543
    {
1544 2043 sgarg
1545 2075 jones
        Vector tempVector = null;
1546 2043 sgarg
1547 2075 jones
        for (int count = 0; count < parentidList.size(); count++) {
1548
            tempVector = (Vector) parentidList.get(count);
1549 2360 sgarg
            if (parentId.compareTo((String) tempVector.get(0)) == 0) { return true; }
1550 2075 jones
        }
1551
        return false;
1552 2043 sgarg
    }
1553 3635 leinfelder
1554 2075 jones
    /*
1555
     * A method to put key and value in Vector
1556
     */
1557
    private void putInArray(Vector parentidList, String key,
1558
            ReturnFieldValue value)
1559
    {
1560 2043 sgarg
1561 2075 jones
        Vector tempVector = null;
1562 3635 leinfelder
        //only filter if the field type is NOT an attribute (say, for text)
1563
        String fieldType = value.getFieldType();
1564
        if (fieldType != null && !fieldType.equals("ATTRIBUTE")) {
1565
1566
	        for (int count = 0; count < parentidList.size(); count++) {
1567
	            tempVector = (Vector) parentidList.get(count);
1568
1569
	            if (key.compareTo((String) tempVector.get(0)) == 0) {
1570
	                tempVector.remove(1);
1571
	                tempVector.add(1, value);
1572
	                return;
1573
	            }
1574
	        }
1575 2075 jones
        }
1576 2043 sgarg
1577 2075 jones
        tempVector = new Vector();
1578
        tempVector.add(0, key);
1579
        tempVector.add(1, value);
1580
        parentidList.add(tempVector);
1581
        return;
1582 2043 sgarg
    }
1583
1584 2075 jones
    /*
1585
     * A method to get value in Vector given a key
1586
     */
1587
    private ReturnFieldValue getArrayValue(Vector parentidList, String key)
1588 1353 tao
    {
1589 2043 sgarg
1590 2075 jones
        Vector tempVector = null;
1591 2043 sgarg
1592 5490 berkley
        for (int count = 0; count < parentidList.size(); count++) {
1593 2075 jones
            tempVector = (Vector) parentidList.get(count);
1594 2043 sgarg
1595 5490 berkley
            if (key.compareTo((String) tempVector.get(0)) == 0) { return (ReturnFieldValue) tempVector
1596
                    .get(1); }
1597 2075 jones
        }
1598
        return null;
1599 2045 tao
    }
1600 436 berkley
1601 2075 jones
    /*
1602
     * A method to get enumeration of all values in Vector
1603
     */
1604
    private Vector getElements(Vector parentidList)
1605 342 berkley
    {
1606 2446 sgarg
        Vector enumVector = new Vector();
1607 2075 jones
        Vector tempVector = null;
1608 2043 sgarg
1609 2075 jones
        for (int count = 0; count < parentidList.size(); count++) {
1610
            tempVector = (Vector) parentidList.get(count);
1611 744 jones
1612 2446 sgarg
            enumVector.add(tempVector.get(1));
1613 744 jones
        }
1614 2446 sgarg
        return enumVector;
1615 372 berkley
    }
1616 2043 sgarg
1617 3308 tao
1618 2043 sgarg
1619 2075 jones
    /*
1620
     * A method to create a query to get owner's docid list
1621
     */
1622 6629 leinfelder
    private String getOwnerQuery(String owner, List<Object> parameterValues)
1623 372 berkley
    {
1624 2075 jones
        if (owner != null) {
1625
            owner = owner.toLowerCase();
1626
        }
1627
        StringBuffer self = new StringBuffer();
1628 2043 sgarg
1629 2075 jones
        self.append("SELECT docid,docname,doctype,");
1630
        self.append("date_created, date_updated, rev ");
1631
        self.append("FROM xml_documents WHERE docid IN (");
1632
        self.append("(");
1633
        self.append("SELECT DISTINCT docid FROM xml_nodes WHERE \n");
1634
        self.append("nodedata LIKE '%%%' ");
1635
        self.append(") \n");
1636
        self.append(") ");
1637
        self.append(" AND (");
1638 6629 leinfelder
        self.append(" lower(user_owner) = ?");
1639 2075 jones
        self.append(") ");
1640 6629 leinfelder
        parameterValues.add(owner);
1641 2075 jones
        return self.toString();
1642 342 berkley
    }
1643 2043 sgarg
1644 2075 jones
    /**
1645
     * format a structured query as an XML document that conforms to the
1646
     * pathquery.dtd and is appropriate for submission to the DBQuery
1647
     * structured query engine
1648 2087 tao
     *
1649 2075 jones
     * @param params The list of parameters that should be included in the
1650
     *            query
1651
     */
1652 4080 daigle
    public static String createSQuery(Hashtable params) throws PropertyNotFoundException
1653 342 berkley
    {
1654 2075 jones
        StringBuffer query = new StringBuffer();
1655
        Enumeration elements;
1656
        Enumeration keys;
1657
        String filterDoctype = null;
1658
        String casesensitive = null;
1659
        String searchmode = null;
1660
        Object nextkey;
1661
        Object nextelement;
1662
        //add the xml headers
1663
        query.append("<?xml version=\"1.0\"?>\n");
1664 2091 tao
        query.append("<pathquery version=\"1.2\">\n");
1665 372 berkley
1666 2091 tao
1667
1668 2075 jones
        if (params.containsKey("meta_file_id")) {
1669
            query.append("<meta_file_id>");
1670
            query.append(((String[]) params.get("meta_file_id"))[0]);
1671
            query.append("</meta_file_id>");
1672 372 berkley
        }
1673 2043 sgarg
1674 2075 jones
        if (params.containsKey("returndoctype")) {
1675
            String[] returnDoctypes = ((String[]) params.get("returndoctype"));
1676
            for (int i = 0; i < returnDoctypes.length; i++) {
1677
                String doctype = (String) returnDoctypes[i];
1678 181 jones
1679 2075 jones
                if (!doctype.equals("any") && !doctype.equals("ANY")
1680
                        && !doctype.equals("")) {
1681
                    query.append("<returndoctype>").append(doctype);
1682
                    query.append("</returndoctype>");
1683
                }
1684
            }
1685
        }
1686 181 jones
1687 2075 jones
        if (params.containsKey("filterdoctype")) {
1688
            String[] filterDoctypes = ((String[]) params.get("filterdoctype"));
1689
            for (int i = 0; i < filterDoctypes.length; i++) {
1690
                query.append("<filterdoctype>").append(filterDoctypes[i]);
1691
                query.append("</filterdoctype>");
1692
            }
1693
        }
1694 181 jones
1695 2075 jones
        if (params.containsKey("returnfield")) {
1696
            String[] returnfield = ((String[]) params.get("returnfield"));
1697
            for (int i = 0; i < returnfield.length; i++) {
1698
                query.append("<returnfield>").append(returnfield[i]);
1699
                query.append("</returnfield>");
1700
            }
1701
        }
1702 2043 sgarg
1703 2075 jones
        if (params.containsKey("owner")) {
1704
            String[] owner = ((String[]) params.get("owner"));
1705
            for (int i = 0; i < owner.length; i++) {
1706
                query.append("<owner>").append(owner[i]);
1707
                query.append("</owner>");
1708
            }
1709
        }
1710 181 jones
1711 2075 jones
        if (params.containsKey("site")) {
1712
            String[] site = ((String[]) params.get("site"));
1713
            for (int i = 0; i < site.length; i++) {
1714
                query.append("<site>").append(site[i]);
1715
                query.append("</site>");
1716
            }
1717
        }
1718 2043 sgarg
1719 2075 jones
        //allows the dynamic switching of boolean operators
1720
        if (params.containsKey("operator")) {
1721
            query.append("<querygroup operator=\""
1722
                    + ((String[]) params.get("operator"))[0] + "\">");
1723
        } else { //the default operator is UNION
1724
            query.append("<querygroup operator=\"UNION\">");
1725
        }
1726 940 tao
1727 2075 jones
        if (params.containsKey("casesensitive")) {
1728
            casesensitive = ((String[]) params.get("casesensitive"))[0];
1729
        } else {
1730
            casesensitive = "false";
1731
        }
1732 2043 sgarg
1733 2075 jones
        if (params.containsKey("searchmode")) {
1734
            searchmode = ((String[]) params.get("searchmode"))[0];
1735
        } else {
1736
            searchmode = "contains";
1737 940 tao
        }
1738
1739 2075 jones
        //anyfield is a special case because it does a
1740
        //free text search. It does not have a <pathexpr>
1741
        //tag. This allows for a free text search within the structured
1742
        //query. This is useful if the INTERSECT operator is used.
1743
        if (params.containsKey("anyfield")) {
1744
            String[] anyfield = ((String[]) params.get("anyfield"));
1745
            //allow for more than one value for anyfield
1746
            for (int i = 0; i < anyfield.length; i++) {
1747 4135 berkley
                if (anyfield[i] != null && !anyfield[i].equals("")) {
1748 2075 jones
                    query.append("<queryterm casesensitive=\"" + casesensitive
1749
                            + "\" " + "searchmode=\"" + searchmode
1750 7677 leinfelder
                            + "\"><value>"
1751
                            + StringEscapeUtils.escapeXml(anyfield[i])
1752 2075 jones
                            + "</value></queryterm>");
1753
                }
1754
            }
1755 940 tao
        }
1756 2043 sgarg
1757 2075 jones
        //this while loop finds the rest of the parameters
1758
        //and attempts to query for the field specified
1759
        //by the parameter.
1760
        elements = params.elements();
1761
        keys = params.keys();
1762
        while (keys.hasMoreElements() && elements.hasMoreElements()) {
1763
            nextkey = keys.nextElement();
1764
            nextelement = elements.nextElement();
1765 2043 sgarg
1766 2075 jones
            //make sure we aren't querying for any of these
1767
            //parameters since the are already in the query
1768
            //in one form or another.
1769
            Vector ignoredParams = new Vector();
1770
            ignoredParams.add("returndoctype");
1771
            ignoredParams.add("filterdoctype");
1772
            ignoredParams.add("action");
1773
            ignoredParams.add("qformat");
1774
            ignoredParams.add("anyfield");
1775
            ignoredParams.add("returnfield");
1776
            ignoredParams.add("owner");
1777
            ignoredParams.add("site");
1778
            ignoredParams.add("operator");
1779 2091 tao
            ignoredParams.add("sessionid");
1780 3211 berkley
            ignoredParams.add("pagesize");
1781
            ignoredParams.add("pagestart");
1782 4135 berkley
            ignoredParams.add("searchmode");
1783 2043 sgarg
1784 2075 jones
            // Also ignore parameters listed in the properties file
1785
            // so that they can be passed through to stylesheets
1786 4080 daigle
            String paramsToIgnore = PropertyService
1787 4173 daigle
                    .getProperty("database.queryignoredparams");
1788 2075 jones
            StringTokenizer st = new StringTokenizer(paramsToIgnore, ",");
1789
            while (st.hasMoreTokens()) {
1790
                ignoredParams.add(st.nextToken());
1791
            }
1792
            if (!ignoredParams.contains(nextkey.toString())) {
1793
                //allow for more than value per field name
1794
                for (int i = 0; i < ((String[]) nextelement).length; i++) {
1795
                    if (!((String[]) nextelement)[i].equals("")) {
1796
                        query.append("<queryterm casesensitive=\""
1797
                                + casesensitive + "\" " + "searchmode=\""
1798 2087 tao
                                + searchmode + "\">" + "<value>" +
1799 2075 jones
                                //add the query value
1800 7677 leinfelder
                                StringEscapeUtils.escapeXml(((String[]) nextelement)[i])
1801 2087 tao
                                + "</value><pathexpr>" +
1802 2075 jones
                                //add the path to query by
1803
                                nextkey.toString() + "</pathexpr></queryterm>");
1804
                    }
1805
                }
1806
            }
1807
        }
1808
        query.append("</querygroup></pathquery>");
1809
        //append on the end of the xml and return the result as a string
1810
        return query.toString();
1811
    }
1812 2043 sgarg
1813 2075 jones
    /**
1814
     * format a simple free-text value query as an XML document that conforms
1815
     * to the pathquery.dtd and is appropriate for submission to the DBQuery
1816
     * structured query engine
1817 2087 tao
     *
1818 2075 jones
     * @param value the text string to search for in the xml catalog
1819
     * @param doctype the type of documents to include in the result set -- use
1820
     *            "any" or "ANY" for unfiltered result sets
1821
     */
1822
    public static String createQuery(String value, String doctype)
1823 1292 tao
    {
1824 2075 jones
        StringBuffer xmlquery = new StringBuffer();
1825
        xmlquery.append("<?xml version=\"1.0\"?>\n");
1826
        xmlquery.append("<pathquery version=\"1.0\">");
1827 2043 sgarg
1828 2075 jones
        if (!doctype.equals("any") && !doctype.equals("ANY")) {
1829
            xmlquery.append("<returndoctype>");
1830
            xmlquery.append(doctype).append("</returndoctype>");
1831
        }
1832 2043 sgarg
1833 2075 jones
        xmlquery.append("<querygroup operator=\"UNION\">");
1834
        //chad added - 8/14
1835
        //the if statement allows a query to gracefully handle a null
1836
        //query. Without this if a nullpointerException is thrown.
1837
        if (!value.equals("")) {
1838
            xmlquery.append("<queryterm casesensitive=\"false\" ");
1839
            xmlquery.append("searchmode=\"contains\">");
1840
            xmlquery.append("<value>").append(value).append("</value>");
1841
            xmlquery.append("</queryterm>");
1842 1217 tao
        }
1843 2075 jones
        xmlquery.append("</querygroup>");
1844
        xmlquery.append("</pathquery>");
1845 2043 sgarg
1846 2075 jones
        return (xmlquery.toString());
1847
    }
1848 2043 sgarg
1849 2075 jones
    /**
1850
     * format a simple free-text value query as an XML document that conforms
1851
     * to the pathquery.dtd and is appropriate for submission to the DBQuery
1852
     * structured query engine
1853 2087 tao
     *
1854 2075 jones
     * @param value the text string to search for in the xml catalog
1855
     */
1856
    public static String createQuery(String value)
1857 940 tao
    {
1858 2075 jones
        return createQuery(value, "any");
1859 940 tao
    }
1860 2043 sgarg
1861 2075 jones
    /**
1862
     * Check for "READ" permission on @docid for @user and/or @group from DB
1863
     * connection
1864
     */
1865
    private boolean hasPermission(String user, String[] groups, String docid)
1866
            throws SQLException, Exception
1867 940 tao
    {
1868 2075 jones
        // Check for READ permission on @docid for @user and/or @groups
1869
        PermissionController controller = new PermissionController(docid);
1870
        return controller.hasPermission(user, groups,
1871
                AccessControlInterface.READSTRING);
1872
    }
1873 2043 sgarg
1874 2075 jones
    /**
1875
     * Get all docIds list for a data packadge
1876 2087 tao
     *
1877 2075 jones
     * @param dataPackageDocid, the string in docId field of xml_relation table
1878
     */
1879
    private Vector getCurrentDocidListForDataPackage(String dataPackageDocid)
1880 940 tao
    {
1881 2075 jones
        DBConnection dbConn = null;
1882
        int serialNumber = -1;
1883
        Vector docIdList = new Vector();//return value
1884
        PreparedStatement pStmt = null;
1885
        ResultSet rs = null;
1886
        String docIdInSubjectField = null;
1887
        String docIdInObjectField = null;
1888 2043 sgarg
1889 2075 jones
        // Check the parameter
1890
        if (dataPackageDocid == null || dataPackageDocid.equals("")) { return docIdList; }//if
1891 940 tao
1892 2075 jones
        //the query stirng
1893
        String query = "SELECT subject, object from xml_relation where docId = ?";
1894
        try {
1895
            dbConn = DBConnectionPool
1896
                    .getDBConnection("DBQuery.getCurrentDocidListForDataPackage");
1897
            serialNumber = dbConn.getCheckOutSerialNumber();
1898
            pStmt = dbConn.prepareStatement(query);
1899
            //bind the value to query
1900
            pStmt.setString(1, dataPackageDocid);
1901 2043 sgarg
1902 2075 jones
            //excute the query
1903
            pStmt.execute();
1904
            //get the result set
1905
            rs = pStmt.getResultSet();
1906
            //process the result
1907
            while (rs.next()) {
1908
                //In order to get the whole docIds in a data packadge,
1909
                //we need to put the docIds of subject and object field in
1910
                // xml_relation
1911
                //into the return vector
1912
                docIdInSubjectField = rs.getString(1);//the result docId in
1913
                                                      // subject field
1914
                docIdInObjectField = rs.getString(2);//the result docId in
1915
                                                     // object field
1916 940 tao
1917 2075 jones
                //don't put the duplicate docId into the vector
1918
                if (!docIdList.contains(docIdInSubjectField)) {
1919
                    docIdList.add(docIdInSubjectField);
1920
                }
1921 2043 sgarg
1922 2075 jones
                //don't put the duplicate docId into the vector
1923
                if (!docIdList.contains(docIdInObjectField)) {
1924
                    docIdList.add(docIdInObjectField);
1925
                }
1926
            }//while
1927
            //close the pStmt
1928
            pStmt.close();
1929
        }//try
1930
        catch (SQLException e) {
1931 5165 daigle
            logMetacat.error("DBQuery.getCurrentDocidListForDataPackage - Error in getDocidListForDataPackage: "
1932 2663 sgarg
                    + e.getMessage());
1933 2075 jones
        }//catch
1934
        finally {
1935
            try {
1936
                pStmt.close();
1937
            }//try
1938
            catch (SQLException ee) {
1939 5165 daigle
                logMetacat.error("DBQuery.getCurrentDocidListForDataPackage - SQL Error: "
1940 2663 sgarg
                                + ee.getMessage());
1941 2075 jones
            }//catch
1942
            finally {
1943
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
1944
            }//fianlly
1945
        }//finally
1946
        return docIdList;
1947
    }//getCurrentDocidListForDataPackadge()
1948 2043 sgarg
1949 2075 jones
    /**
1950
     * Get all docIds list for a data packadge
1951 2087 tao
     *
1952 2075 jones
     * @param dataPackageDocid, the string in docId field of xml_relation table
1953
     */
1954 2641 tao
    private Vector getOldVersionDocidListForDataPackage(String dataPackageDocidWithRev)
1955 940 tao
    {
1956 2043 sgarg
1957 2075 jones
        Vector docIdList = new Vector();//return value
1958
        Vector tripleList = null;
1959
        String xml = null;
1960 2043 sgarg
1961 2075 jones
        // Check the parameter
1962 2641 tao
        if (dataPackageDocidWithRev == null || dataPackageDocidWithRev.equals("")) { return docIdList; }//if
1963 2043 sgarg
1964 2075 jones
        try {
1965
            //initial a documentImpl object
1966 2641 tao
            DocumentImpl packageDocument = new DocumentImpl(dataPackageDocidWithRev);
1967 2075 jones
            //transfer to documentImpl object to string
1968
            xml = packageDocument.toString();
1969 2043 sgarg
1970 2075 jones
            //create a tripcollection object
1971
            TripleCollection tripleForPackage = new TripleCollection(
1972
                    new StringReader(xml));
1973
            //get the vetor of triples
1974
            tripleList = tripleForPackage.getCollection();
1975 2043 sgarg
1976 2075 jones
            for (int i = 0; i < tripleList.size(); i++) {
1977
                //put subject docid into docIdlist without duplicate
1978
                if (!docIdList.contains(((Triple) tripleList.elementAt(i))
1979
                        .getSubject())) {
1980
                    //put subject docid into docIdlist
1981
                    docIdList.add(((Triple) tripleList.get(i)).getSubject());
1982
                }
1983
                //put object docid into docIdlist without duplicate
1984
                if (!docIdList.contains(((Triple) tripleList.elementAt(i))
1985
                        .getObject())) {
1986
                    docIdList.add(((Triple) (tripleList.get(i))).getObject());
1987
                }
1988
            }//for
1989
        }//try
1990
        catch (Exception e) {
1991 5165 daigle
            logMetacat.error("DBQuery.getCurrentDocidListForDataPackage - General error: "
1992 2663 sgarg
                    + e.getMessage());
1993 2075 jones
        }//catch
1994 2043 sgarg
1995 2075 jones
        // return result
1996
        return docIdList;
1997
    }//getDocidListForPackageInXMLRevisions()
1998 2043 sgarg
1999 2075 jones
    /**
2000
     * Check if the docId is a data packadge id. If the id is a data packadage
2001
     * id, it should be store in the docId fields in xml_relation table. So we
2002
     * can use a query to get the entries which the docId equals the given
2003
     * value. If the result is null. The docId is not a packadge id. Otherwise,
2004
     * it is.
2005 2087 tao
     *
2006 2075 jones
     * @param docId, the id need to be checked
2007
     */
2008
    private boolean isDataPackageId(String docId)
2009 940 tao
    {
2010 2075 jones
        boolean result = false;
2011
        PreparedStatement pStmt = null;
2012
        ResultSet rs = null;
2013
        String query = "SELECT docId from xml_relation where docId = ?";
2014
        DBConnection dbConn = null;
2015
        int serialNumber = -1;
2016
        try {
2017
            dbConn = DBConnectionPool
2018
                    .getDBConnection("DBQuery.isDataPackageId");
2019
            serialNumber = dbConn.getCheckOutSerialNumber();
2020
            pStmt = dbConn.prepareStatement(query);
2021
            //bind the value to query
2022
            pStmt.setString(1, docId);
2023
            //execute the query
2024
            pStmt.execute();
2025
            rs = pStmt.getResultSet();
2026
            //process the result
2027
            if (rs.next()) //There are some records for the id in docId fields
2028
            {
2029
                result = true;//It is a data packadge id
2030
            }
2031
            pStmt.close();
2032
        }//try
2033
        catch (SQLException e) {
2034 5165 daigle
            logMetacat.error("DBQuery.isDataPackageId - SQL Error: "
2035 2663 sgarg
                    + e.getMessage());
2036 2075 jones
        } finally {
2037
            try {
2038
                pStmt.close();
2039
            }//try
2040
            catch (SQLException ee) {
2041 5165 daigle
                logMetacat.error("DBQuery.isDataPackageId - SQL Error in isDataPackageId: "
2042 2663 sgarg
                        + ee.getMessage());
2043 2075 jones
            }//catch
2044
            finally {
2045
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2046
            }//finally
2047
        }//finally
2048
        return result;
2049
    }//isDataPackageId()
2050 2043 sgarg
2051 6035 leinfelder
    public String getOperator() {
2052
		return operator;
2053
	}
2054
2055 2075 jones
    /**
2056 6035 leinfelder
     * Specifies if and how docid overrides should be included in the general query
2057
     * @param operator null, UNION, or INTERSECT (see QueryGroup)
2058
     */
2059
	public void setOperator(String operator) {
2060
		this.operator = operator;
2061
	}
2062
2063 7671 leinfelder
	public String getQformat() {
2064
		return qformat;
2065
	}
2066
2067
	public void setQformat(String qformat) {
2068
		this.qformat = qformat;
2069
	}
2070
2071 6035 leinfelder
	/**
2072 2075 jones
     * Check if the user has the permission to export data package
2073 2087 tao
     *
2074 2075 jones
     * @param conn, the connection
2075
     * @param docId, the id need to be checked
2076
     * @param user, the name of user
2077
     * @param groups, the user's group
2078
     */
2079
    private boolean hasPermissionToExportPackage(String docId, String user,
2080
            String[] groups) throws Exception
2081 940 tao
    {
2082 2075 jones
        //DocumentImpl doc=new DocumentImpl(conn,docId);
2083
        return DocumentImpl.hasReadPermission(user, groups, docId);
2084
    }
2085 2043 sgarg
2086 2075 jones
    /**
2087
     * Get the current Rev for a docid in xml_documents table
2088 2087 tao
     *
2089 2075 jones
     * @param docId, the id need to get version numb If the return value is -5,
2090
     *            means no value in rev field for this docid
2091
     */
2092
    private int getCurrentRevFromXMLDoumentsTable(String docId)
2093
            throws SQLException
2094
    {
2095
        int rev = -5;
2096
        PreparedStatement pStmt = null;
2097
        ResultSet rs = null;
2098
        String query = "SELECT rev from xml_documents where docId = ?";
2099
        DBConnection dbConn = null;
2100
        int serialNumber = -1;
2101
        try {
2102
            dbConn = DBConnectionPool
2103
                    .getDBConnection("DBQuery.getCurrentRevFromXMLDocumentsTable");
2104
            serialNumber = dbConn.getCheckOutSerialNumber();
2105
            pStmt = dbConn.prepareStatement(query);
2106
            //bind the value to query
2107
            pStmt.setString(1, docId);
2108
            //execute the query
2109
            pStmt.execute();
2110
            rs = pStmt.getResultSet();
2111
            //process the result
2112
            if (rs.next()) //There are some records for rev
2113
            {
2114
                rev = rs.getInt(1);
2115
                ;//It is the version for given docid
2116
            } else {
2117
                rev = -5;
2118
            }
2119 2043 sgarg
2120 1292 tao
        }//try
2121 2075 jones
        catch (SQLException e) {
2122 5165 daigle
            logMetacat.error("DBQuery.getCurrentRevFromXMLDoumentsTable - SQL Error: "
2123 2663 sgarg
                            + e.getMessage());
2124 2075 jones
            throw e;
2125 1292 tao
        }//catch
2126 2075 jones
        finally {
2127
            try {
2128
                pStmt.close();
2129
            }//try
2130
            catch (SQLException ee) {
2131 2663 sgarg
                logMetacat.error(
2132 5165 daigle
                        "DBQuery.getCurrentRevFromXMLDoumentsTable - SQL Error: "
2133 2663 sgarg
                                + ee.getMessage());
2134 2075 jones
            }//catch
2135
            finally {
2136
                DBConnectionPool.returnDBConnection(dbConn, serialNumber);
2137
            }//finally
2138
        }//finally
2139
        return rev;
2140
    }//getCurrentRevFromXMLDoumentsTable
2141 2043 sgarg
2142 2075 jones
    /**
2143
     * put a doc into a zip output stream
2144 2087 tao
     *
2145 2075 jones
     * @param docImpl, docmentImpl object which will be sent to zip output
2146
     *            stream
2147
     * @param zipOut, zip output stream which the docImpl will be put
2148
     * @param packageZipEntry, the zip entry name for whole package
2149
     */
2150
    private void addDocToZipOutputStream(DocumentImpl docImpl,
2151
            ZipOutputStream zipOut, String packageZipEntry)
2152
            throws ClassNotFoundException, IOException, SQLException,
2153
            McdbException, Exception
2154
    {
2155
        byte[] byteString = null;
2156
        ZipEntry zEntry = null;
2157 2043 sgarg
2158 5760 leinfelder
        byteString = docImpl.getBytes();
2159 2075 jones
        //use docId as the zip entry's name
2160 7671 leinfelder
        String fullDocId = docImpl.getDocID() + PropertyService.getProperty("document.accNumSeparator") + docImpl.getRev();
2161
		zEntry = new ZipEntry(packageZipEntry + "/metadata/" + fullDocId );
2162 2075 jones
        zEntry.setSize(byteString.length);
2163
        zipOut.putNextEntry(zEntry);
2164
        zipOut.write(byteString, 0, byteString.length);
2165
        zipOut.closeEntry();
2166 2043 sgarg
2167 2075 jones
    }//addDocToZipOutputStream()
2168 940 tao
2169 2075 jones
    /**
2170
     * Transfer a docid vetor to a documentImpl vector. The documentImpl vetor
2171
     * only inlcudes current version. If a DocumentImple object couldn't find
2172
     * for a docid, then the String of this docid was added to vetor rather
2173
     * than DocumentImple object.
2174 2087 tao
     *
2175 2075 jones
     * @param docIdList, a vetor hold a docid list for a data package. In
2176
     *            docid, there is not version number in it.
2177
     */
2178 2043 sgarg
2179 2075 jones
    private Vector getCurrentAllDocumentImpl(Vector docIdList)
2180
            throws McdbException, Exception
2181 940 tao
    {
2182 2075 jones
        //Connection dbConn=null;
2183
        Vector documentImplList = new Vector();
2184
        int rev = 0;
2185 2043 sgarg
2186 2075 jones
        // Check the parameter
2187
        if (docIdList.isEmpty()) { return documentImplList; }//if
2188 2043 sgarg
2189 2075 jones
        //for every docid in vector
2190
        for (int i = 0; i < docIdList.size(); i++) {
2191
            try {
2192 7665 leinfelder
				//get newest version for this docId
2193
                String smartDocid = DocumentUtil.getSmartDocId((String) docIdList.elementAt(i));
2194
                rev = getCurrentRevFromXMLDoumentsTable(smartDocid);
2195 940 tao
2196 2075 jones
                // There is no record for this docId in xml_documents table
2197
                if (rev == -5) {
2198
                    // Rather than put DocumentImple object, put a String
2199
                    // Object(docid)
2200
                    // into the documentImplList
2201
                    documentImplList.add((String) docIdList.elementAt(i));
2202
                    // Skip other code
2203
                    continue;
2204
                }
2205 2043 sgarg
2206 7665 leinfelder
                String docidPlusVersion = smartDocid
2207 4212 daigle
                        + PropertyService.getProperty("document.accNumSeparator") + rev;
2208 2043 sgarg
2209 2075 jones
                //create new documentImpl object
2210
                DocumentImpl documentImplObject = new DocumentImpl(
2211
                        docidPlusVersion);
2212
                //add them to vector
2213
                documentImplList.add(documentImplObject);
2214
            }//try
2215
            catch (Exception e) {
2216 5165 daigle
                logMetacat.error("DBQuery.getCurrentAllDocumentImpl - General error: "
2217 2663 sgarg
                        + e.getMessage());
2218 2075 jones
                // continue the for loop
2219
                continue;
2220
            }
2221
        }//for
2222
        return documentImplList;
2223
    }
2224 2043 sgarg
2225 2075 jones
    /**
2226
     * Transfer a docid vetor to a documentImpl vector. If a DocumentImple
2227
     * object couldn't find for a docid, then the String of this docid was
2228
     * added to vetor rather than DocumentImple object.
2229 2087 tao
     *
2230 2075 jones
     * @param docIdList, a vetor hold a docid list for a data package. In
2231
     *            docid, t here is version number in it.
2232
     */
2233
    private Vector getOldVersionAllDocumentImpl(Vector docIdList)
2234
    {
2235
        //Connection dbConn=null;
2236
        Vector documentImplList = new Vector();
2237
        String siteCode = null;
2238
        String uniqueId = null;
2239
        int rev = 0;
2240 2043 sgarg
2241 2075 jones
        // Check the parameter
2242
        if (docIdList.isEmpty()) { return documentImplList; }//if
2243 2043 sgarg
2244 2075 jones
        //for every docid in vector
2245
        for (int i = 0; i < docIdList.size(); i++) {
2246 2043 sgarg
2247 2075 jones
            String docidPlusVersion = (String) (docIdList.elementAt(i));
2248
2249
            try {
2250
                //create new documentImpl object
2251
                DocumentImpl documentImplObject = new DocumentImpl(
2252
                        docidPlusVersion);
2253
                //add them to vector
2254
                documentImplList.add(documentImplObject);
2255
            }//try
2256
            catch (McdbDocNotFoundException notFoundE) {
2257 5165 daigle
                logMetacat.error("DBQuery.getOldVersionAllDocument - Error finding doc "
2258
                		+ docidPlusVersion + " : " + notFoundE.getMessage());
2259 2075 jones
                // Rather than add a DocumentImple object into vetor, a String
2260
                // object
2261
                // - the doicd was added to the vector
2262
                documentImplList.add(docidPlusVersion);
2263
                // Continue the for loop
2264
                continue;
2265
            }//catch
2266
            catch (Exception e) {
2267 2663 sgarg
                logMetacat.error(
2268 5165 daigle
                        "DBQuery.getOldVersionAllDocument - General error: "
2269 2663 sgarg
                                + e.getMessage());
2270 2075 jones
                // Continue the for loop
2271
                continue;
2272
            }//catch
2273
2274
        }//for
2275
        return documentImplList;
2276
    }//getOldVersionAllDocumentImple
2277
2278
    /**
2279
     * put a data file into a zip output stream
2280 2087 tao
     *
2281 2075 jones
     * @param docImpl, docmentImpl object which will be sent to zip output
2282
     *            stream
2283
     * @param zipOut, the zip output stream which the docImpl will be put
2284
     * @param packageZipEntry, the zip entry name for whole package
2285
     */
2286
    private void addDataFileToZipOutputStream(DocumentImpl docImpl,
2287
            ZipOutputStream zipOut, String packageZipEntry)
2288
            throws ClassNotFoundException, IOException, SQLException,
2289
            McdbException, Exception
2290 940 tao
    {
2291 2075 jones
        byte[] byteString = null;
2292
        ZipEntry zEntry = null;
2293
        // this is data file; add file to zip
2294 4080 daigle
        String filePath = PropertyService.getProperty("application.datafilepath");
2295 2075 jones
        if (!filePath.endsWith("/")) {
2296
            filePath += "/";
2297
        }
2298 7671 leinfelder
        String fileName = docImpl.getDocID() + PropertyService.getProperty("document.accNumSeparator") + docImpl.getRev();
2299
        String entityName = docImpl.getDocname();
2300
        filePath = filePath + fileName;
2301
        zEntry = new ZipEntry(packageZipEntry + "/data/" + fileName + "-" + entityName);
2302 2075 jones
        zipOut.putNextEntry(zEntry);
2303
        FileInputStream fin = null;
2304
        try {
2305 7671 leinfelder
            fin = new FileInputStream(filePath);
2306 2075 jones
            byte[] buf = new byte[4 * 1024]; // 4K buffer
2307
            int b = fin.read(buf);
2308
            while (b != -1) {
2309
                zipOut.write(buf, 0, b);
2310
                b = fin.read(buf);
2311
            }//while
2312
            zipOut.closeEntry();
2313
        }//try
2314
        catch (IOException ioe) {
2315 5165 daigle
            logMetacat.error("DBQuery.addDataFileToZipOutputStream - I/O error: "
2316 2663 sgarg
                    + ioe.getMessage());
2317 2075 jones
        }//catch
2318
    }//addDataFileToZipOutputStream()
2319 2043 sgarg
2320 2075 jones
    /**
2321
     * create a html summary for data package and put it into zip output stream
2322 2087 tao
     *
2323 2075 jones
     * @param docImplList, the documentImpl ojbects in data package
2324
     * @param zipOut, the zip output stream which the html should be put
2325
     * @param packageZipEntry, the zip entry name for whole package
2326
     */
2327
    private void addHtmlSummaryToZipOutputStream(Vector docImplList,
2328
            ZipOutputStream zipOut, String packageZipEntry) throws Exception
2329
    {
2330
        StringBuffer htmlDoc = new StringBuffer();
2331
        ZipEntry zEntry = null;
2332
        byte[] byteString = null;
2333
        InputStream source;
2334
        DBTransform xmlToHtml;
2335 2043 sgarg
2336 2075 jones
        //create a DBTransform ojbect
2337
        xmlToHtml = new DBTransform();
2338
        //head of html
2339
        htmlDoc.append("<html><head></head><body>");
2340
        for (int i = 0; i < docImplList.size(); i++) {
2341
            // If this String object, this means it is missed data file
2342
            if ((((docImplList.elementAt(i)).getClass()).toString())
2343
                    .equals("class java.lang.String")) {
2344 2043 sgarg
2345 2075 jones
                htmlDoc.append("<a href=\"");
2346
                String dataFileid = (String) docImplList.elementAt(i);
2347
                htmlDoc.append("./data/").append(dataFileid).append("\">");
2348
                htmlDoc.append("Data File: ");
2349
                htmlDoc.append(dataFileid).append("</a><br>");
2350
                htmlDoc.append("<br><hr><br>");
2351 1356 tao
2352 2075 jones
            }//if
2353
            else if ((((DocumentImpl) docImplList.elementAt(i)).getDoctype())
2354
                    .compareTo("BIN") != 0) { //this is an xml file so we can
2355
                                              // transform it.
2356
                //transform each file individually then concatenate all of the
2357
                //transformations together.
2358 1356 tao
2359 2075 jones
                //for metadata xml title
2360
                htmlDoc.append("<h2>");
2361
                htmlDoc.append(((DocumentImpl) docImplList.elementAt(i))
2362
                        .getDocID());
2363
                //htmlDoc.append(".");
2364
                //htmlDoc.append(((DocumentImpl)docImplList.elementAt(i)).getRev());
2365
                htmlDoc.append("</h2>");
2366
                //do the actual transform
2367 7859 leinfelder
                Writer docString = new StringWriter();
2368 7671 leinfelder
                xmlToHtml.transformXMLDocument(
2369
                		((DocumentImpl) docImplList.elementAt(i)).toString(),
2370
                		((DocumentImpl) docImplList.elementAt(i)).getDoctype(), //"-//NCEAS//eml-generic//EN",
2371
                        "-//W3C//HTML//EN",
2372
                        qformat,
2373
                        docString,
2374
                        null,
2375
                        null);
2376 2075 jones
                htmlDoc.append(docString.toString());
2377
                htmlDoc.append("<br><br><hr><br><br>");
2378
            }//if
2379
            else { //this is a data file so we should link to it in the html
2380
                htmlDoc.append("<a href=\"");
2381
                String dataFileid = ((DocumentImpl) docImplList.elementAt(i))
2382
                        .getDocID();
2383
                htmlDoc.append("./data/").append(dataFileid).append("\">");
2384
                htmlDoc.append("Data File: ");
2385
                htmlDoc.append(dataFileid).append("</a><br>");
2386
                htmlDoc.append("<br><hr><br>");
2387
            }//else
2388
        }//for
2389
        htmlDoc.append("</body></html>");
2390 5760 leinfelder
        // use standard encoding even though the different docs might have use different encodings,
2391
        // the String objects in java should be correct and able to be encoded as the same Metacat default
2392
        byteString = htmlDoc.toString().getBytes(MetaCatServlet.DEFAULT_ENCODING);
2393 2075 jones
        zEntry = new ZipEntry(packageZipEntry + "/metadata.html");
2394
        zEntry.setSize(byteString.length);
2395
        zipOut.putNextEntry(zEntry);
2396
        zipOut.write(byteString, 0, byteString.length);
2397
        zipOut.closeEntry();
2398
        //dbConn.close();
2399 1356 tao
2400 2075 jones
    }//addHtmlSummaryToZipOutputStream
2401 1356 tao
2402 2075 jones
    /**
2403
     * put a data packadge into a zip output stream
2404 2087 tao
     *
2405 2641 tao
     * @param docId, which the user want to put into zip output stream,it has version
2406 2075 jones
     * @param out, a servletoutput stream which the zip output stream will be
2407
     *            put
2408
     * @param user, the username of the user
2409
     * @param groups, the group of the user
2410
     */
2411
    public ZipOutputStream getZippedPackage(String docIdString,
2412
            ServletOutputStream out, String user, String[] groups,
2413
            String passWord) throws ClassNotFoundException, IOException,
2414
            SQLException, McdbException, NumberFormatException, Exception
2415 945 tao
    {
2416 2075 jones
        ZipOutputStream zOut = null;
2417
        String elementDocid = null;
2418
        DocumentImpl docImpls = null;
2419
        //Connection dbConn = null;
2420
        Vector docIdList = new Vector();
2421
        Vector documentImplList = new Vector();
2422
        Vector htmlDocumentImplList = new Vector();
2423
        String packageId = null;
2424
        String rootName = "package";//the package zip entry name
2425 2043 sgarg
2426 2075 jones
        String docId = null;
2427
        int version = -5;
2428
        // Docid without revision
2429 5025 daigle
        docId = DocumentUtil.getDocIdFromString(docIdString);
2430 2075 jones
        // revision number
2431 5025 daigle
        version = DocumentUtil.getVersionFromString(docIdString);
2432 2043 sgarg
2433 2075 jones
        //check if the reqused docId is a data package id
2434
        if (!isDataPackageId(docId)) {
2435 2043 sgarg
2436 2075 jones
            /*
2437
             * Exception e = new Exception("The request the doc id "
2438
             * +docIdString+ " is not a data package id");
2439
             */
2440 940 tao
2441 2075 jones
            //CB 1/6/03: if the requested docid is not a datapackage, we just
2442
            // zip
2443
            //up the single document and return the zip file.
2444
            if (!hasPermissionToExportPackage(docId, user, groups)) {
2445 2043 sgarg
2446 2075 jones
                Exception e = new Exception("User " + user
2447
                        + " does not have permission"
2448
                        + " to export the data package " + docIdString);
2449
                throw e;
2450
            }
2451 2043 sgarg
2452 2641 tao
            docImpls = new DocumentImpl(docIdString);
2453 2075 jones
            //checking if the user has the permission to read the documents
2454
            if (DocumentImpl.hasReadPermission(user, groups, docImpls
2455
                    .getDocID())) {
2456
                zOut = new ZipOutputStream(out);
2457
                //if the docImpls is metadata
2458
                if ((docImpls.getDoctype()).compareTo("BIN") != 0) {
2459
                    //add metadata into zip output stream
2460
                    addDocToZipOutputStream(docImpls, zOut, rootName);
2461
                }//if
2462
                else {
2463
                    //it is data file
2464
                    addDataFileToZipOutputStream(docImpls, zOut, rootName);
2465
                    htmlDocumentImplList.add(docImpls);
2466
                }//else
2467 1292 tao
            }//if
2468 2043 sgarg
2469 2075 jones
            zOut.finish(); //terminate the zip file
2470
            return zOut;
2471
        }
2472
        // Check the permission of user
2473 7665 leinfelder
        else if (!hasPermissionToExportPackage(docIdString, user, groups)) {
2474 2075 jones
2475
            Exception e = new Exception("User " + user
2476
                    + " does not have permission"
2477
                    + " to export the data package " + docIdString);
2478
            throw e;
2479
        } else //it is a packadge id
2480 1292 tao
        {
2481 2075 jones
            //store the package id
2482
            packageId = docId;
2483
            //get current version in database
2484
            int currentVersion = getCurrentRevFromXMLDoumentsTable(packageId);
2485
            //If it is for current version (-1 means user didn't specify
2486
            // revision)
2487
            if ((version == -1) || version == currentVersion) {
2488
                //get current version number
2489
                version = currentVersion;
2490
                //get package zip entry name
2491
                //it should be docId.revsion.package
2492 4212 daigle
                rootName = packageId + PropertyService.getProperty("document.accNumSeparator")
2493
                        + version + PropertyService.getProperty("document.accNumSeparator")
2494 2075 jones
                        + "package";
2495
                //get the whole id list for data packadge
2496
                docIdList = getCurrentDocidListForDataPackage(packageId);
2497
                //get the whole documentImple object
2498
                documentImplList = getCurrentAllDocumentImpl(docIdList);
2499 2043 sgarg
2500 1292 tao
            }//if
2501 2075 jones
            else if (version > currentVersion || version < -1) {
2502
                throw new Exception("The user specified docid: " + docId + "."
2503
                        + version + " doesn't exist");
2504
            }//else if
2505
            else //for an old version
2506 1292 tao
            {
2507 2075 jones
2508
                rootName = docIdString
2509 4212 daigle
                        + PropertyService.getProperty("document.accNumSeparator") + "package";
2510 2075 jones
                //get the whole id list for data packadge
2511
                docIdList = getOldVersionDocidListForDataPackage(docIdString);
2512
2513
                //get the whole documentImple object
2514
                documentImplList = getOldVersionAllDocumentImpl(docIdList);
2515 1292 tao
            }//else
2516 940 tao
2517 2075 jones
            // Make sure documentImplist is not empty
2518
            if (documentImplList.isEmpty()) { throw new Exception(
2519
                    "Couldn't find component for data package: " + packageId); }//if
2520 2043 sgarg
2521 2075 jones
            zOut = new ZipOutputStream(out);
2522
            //put every element into zip output stream
2523
            for (int i = 0; i < documentImplList.size(); i++) {
2524
                // if the object in the vetor is String, this means we couldn't
2525
                // find
2526
                // the document locally, we need find it remote
2527
                if ((((documentImplList.elementAt(i)).getClass()).toString())
2528
                        .equals("class java.lang.String")) {
2529
                    // Get String object from vetor
2530
                    String documentId = (String) documentImplList.elementAt(i);
2531 5165 daigle
                    logMetacat.info("DBQuery.getZippedPackage - docid: " + documentId);
2532 2075 jones
                    // Get doicd without revision
2533 5025 daigle
                    String docidWithoutRevision =
2534
                    	DocumentUtil.getDocIdFromString(documentId);
2535 5165 daigle
                    logMetacat.info("DBQuery.getZippedPackage - docidWithoutRevsion: "
2536 2663 sgarg
                            + docidWithoutRevision);
2537 2075 jones
                    // Get revision
2538 5025 daigle
                    String revision =
2539
                    	DocumentUtil.getRevisionStringFromString(documentId);
2540 5165 daigle
                    logMetacat.info("DBQuery.getZippedPackage - revision from docIdentifier: "
2541 2663 sgarg
                            + revision);
2542 2075 jones
                    // Zip entry string
2543
                    String zipEntryPath = rootName + "/data/";
2544
                    // Create a RemoteDocument object
2545
                    RemoteDocument remoteDoc = new RemoteDocument(
2546
                            docidWithoutRevision, revision, user, passWord,
2547
                            zipEntryPath);
2548
                    // Here we only read data file from remote metacat
2549
                    String docType = remoteDoc.getDocType();
2550
                    if (docType != null) {
2551
                        if (docType.equals("BIN")) {
2552
                            // Put remote document to zip output
2553
                            remoteDoc.readDocumentFromRemoteServerByZip(zOut);
2554
                            // Add String object to htmlDocumentImplList
2555
                            String elementInHtmlList = remoteDoc
2556
                                    .getDocIdWithoutRevsion()
2557 4212 daigle
                                    + PropertyService.getProperty("document.accNumSeparator")
2558 2075 jones
                                    + remoteDoc.getRevision();
2559
                            htmlDocumentImplList.add(elementInHtmlList);
2560
                        }//if
2561
                    }//if
2562 1361 tao
2563 2075 jones
                }//if
2564
                else {
2565
                    //create a docmentImpls object (represent xml doc) base on
2566
                    // the docId
2567
                    docImpls = (DocumentImpl) documentImplList.elementAt(i);
2568
                    //checking if the user has the permission to read the
2569
                    // documents
2570 7665 leinfelder
2571
                    String fullDocId = docImpls.getDocID() + PropertyService.getProperty("document.accNumSeparator") + docImpls.getRev();
2572
					if (DocumentImpl.hasReadPermission(user, groups, fullDocId )) {
2573 2075 jones
                        //if the docImpls is metadata
2574
                        if ((docImpls.getDoctype()).compareTo("BIN") != 0) {
2575
                            //add metadata into zip output stream
2576
                            addDocToZipOutputStream(docImpls, zOut, rootName);
2577
                            //add the documentImpl into the vetor which will
2578
                            // be used in html
2579
                            htmlDocumentImplList.add(docImpls);
2580 2043 sgarg
2581 2075 jones
                        }//if
2582
                        else {
2583
                            //it is data file
2584
                            addDataFileToZipOutputStream(docImpls, zOut,
2585
                                    rootName);
2586
                            htmlDocumentImplList.add(docImpls);
2587
                        }//else
2588
                    }//if
2589
                }//else
2590
            }//for
2591 2043 sgarg
2592 2075 jones
            //add html summary file
2593
            addHtmlSummaryToZipOutputStream(htmlDocumentImplList, zOut,
2594
                    rootName);
2595
            zOut.finish(); //terminate the zip file
2596
            //dbConn.close();
2597
            return zOut;
2598
        }//else
2599
    }//getZippedPackage()
2600 2043 sgarg
2601 2075 jones
    private class ReturnFieldValue
2602 1361 tao
    {
2603 2043 sgarg
2604 2075 jones
        private String docid = null; //return field value for this docid
2605 2043 sgarg
2606 2075 jones
        private String fieldValue = null;
2607 2043 sgarg
2608 2075 jones
        private String xmlFieldValue = null; //return field value in xml
2609
                                             // format
2610 3635 leinfelder
        private String fieldType = null; //ATTRIBUTE, TEXT...
2611 2075 jones
2612
        public void setDocid(String myDocid)
2613
        {
2614
            docid = myDocid;
2615
        }
2616
2617
        public String getDocid()
2618
        {
2619
            return docid;
2620
        }
2621
2622
        public void setFieldValue(String myValue)
2623
        {
2624
            fieldValue = myValue;
2625
        }
2626
2627
        public String getFieldValue()
2628
        {
2629
            return fieldValue;
2630
        }
2631
2632
        public void setXMLFieldValue(String xml)
2633
        {
2634
            xmlFieldValue = xml;
2635
        }
2636
2637
        public String getXMLFieldValue()
2638
        {
2639
            return xmlFieldValue;
2640
        }
2641 3635 leinfelder
2642
        public void setFieldType(String myType)
2643
        {
2644
            fieldType = myType;
2645
        }
2646 2075 jones
2647 3635 leinfelder
        public String getFieldType()
2648
        {
2649
            return fieldType;
2650
        }
2651
2652 1361 tao
    }
2653 3246 berkley
2654
    /**
2655
     * a class to store one result document consisting of a docid and a document
2656
     */
2657
    private class ResultDocument
2658
    {
2659
      public String docid;
2660
      public String document;
2661
2662
      public ResultDocument(String docid, String document)
2663
      {
2664
        this.docid = docid;
2665
        this.document = document;
2666
      }
2667
    }
2668
2669
    /**
2670
     * a private class to handle a set of resultDocuments
2671
     */
2672
    private class ResultDocumentSet
2673
    {
2674
      private Vector docids;
2675
      private Vector documents;
2676
2677
      public ResultDocumentSet()
2678
      {
2679
        docids = new Vector();
2680
        documents = new Vector();
2681
      }
2682
2683
      /**
2684
       * adds a result document to the set
2685
       */
2686
      public void addResultDocument(ResultDocument rd)
2687
      {
2688
        if(rd.docid == null)
2689 3263 tao
          return;
2690 3246 berkley
        if(rd.document == null)
2691
          rd.document = "";
2692 3349 tao
2693 3263 tao
           docids.addElement(rd.docid);
2694
           documents.addElement(rd.document);
2695 3349 tao
2696 3246 berkley
      }
2697
2698
      /**
2699
       * gets an iterator of docids
2700
       */
2701
      public Iterator getDocids()
2702
      {
2703
        return docids.iterator();
2704
      }
2705
2706
      /**
2707
       * gets an iterator of documents
2708
       */
2709
      public Iterator getDocuments()
2710
      {
2711
        return documents.iterator();
2712
      }
2713
2714
      /**
2715
       * returns the size of the set
2716
       */
2717
      public int size()
2718
      {
2719
        return docids.size();
2720
      }
2721
2722
      /**
2723
       * tests to see if this set contains the given docid
2724
       */
2725 3337 tao
      private boolean containsDocid(String docid)
2726 3246 berkley
      {
2727
        for(int i=0; i<docids.size(); i++)
2728
        {
2729
          String docid0 = (String)docids.elementAt(i);
2730
          if(docid0.trim().equals(docid.trim()))
2731
          {
2732
            return true;
2733
          }
2734
        }
2735
        return false;
2736
      }
2737
2738
      /**
2739
       * removes the element with the given docid
2740
       */
2741
      public String remove(String docid)
2742
      {
2743
        for(int i=0; i<docids.size(); i++)
2744
        {
2745
          String docid0 = (String)docids.elementAt(i);
2746
          if(docid0.trim().equals(docid.trim()))
2747
          {
2748
            String returnDoc = (String)documents.elementAt(i);
2749
            documents.remove(i);
2750
            docids.remove(i);
2751
            return returnDoc;
2752
          }
2753
        }
2754
        return null;
2755
      }
2756
2757
      /**
2758
       * add a result document
2759
       */
2760
      public void put(ResultDocument rd)
2761
      {
2762
        addResultDocument(rd);
2763
      }
2764
2765
      /**
2766
       * add a result document by components
2767
       */
2768
      public void put(String docid, String document)
2769
      {
2770
        addResultDocument(new ResultDocument(docid, document));
2771
      }
2772
2773
      /**
2774
       * get the document part of the result document by docid
2775
       */
2776
      public Object get(String docid)
2777
      {
2778
        for(int i=0; i<docids.size(); i++)
2779
        {
2780
          String docid0 = (String)docids.elementAt(i);
2781
          if(docid0.trim().equals(docid.trim()))
2782
          {
2783
            return documents.elementAt(i);
2784
          }
2785
        }
2786
        return null;
2787
      }
2788
2789
      /**
2790
       * get the document part of the result document by an object
2791
       */
2792
      public Object get(Object o)
2793
      {
2794
        return get((String)o);
2795
      }
2796
2797
      /**
2798
       * get an entire result document by index number
2799
       */
2800
      public ResultDocument get(int index)
2801
      {
2802
        return new ResultDocument((String)docids.elementAt(index),
2803
          (String)documents.elementAt(index));
2804
      }
2805
2806
      /**
2807
       * return a string representation of this object
2808
       */
2809
      public String toString()
2810
      {
2811
        String s = "";
2812
        for(int i=0; i<docids.size(); i++)
2813
        {
2814
          s += (String)docids.elementAt(i) + "\n";
2815
        }
2816
        return s;
2817
      }
2818 3263 tao
      /*
2819
       * Set a new document value for a given docid
2820
       */
2821
      public void set(String docid, String document)
2822
      {
2823
    	   for(int i=0; i<docids.size(); i++)
2824
           {
2825
             String docid0 = (String)docids.elementAt(i);
2826
             if(docid0.trim().equals(docid.trim()))
2827
             {
2828
                 documents.set(i, document);
2829
             }
2830
           }
2831
2832
      }
2833 3246 berkley
    }
2834 155 jones
}