Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that searches a relational DB for elements and 
4
 *             attributes that have free text matches a query string,
5
 *             or structured query matches to a path specified node in the 
6
 *             XML hierarchy.  It returns a result set consisting of the 
7
 *             document ID for each document that satisfies the query
8
 *  Copyright: 2000 Regents of the University of California and the
9
 *             National Center for Ecological Analysis and Synthesis
10
 *    Authors: Matt Jones
11
 *    Release: @release@
12
 *
13
 *   '$Author: berkley $'
14
 *     '$Date: 2000-09-26 15:06:52 -0700 (Tue, 26 Sep 2000) $'
15
 * '$Revision: 465 $'
16
 */
17

    
18
package edu.ucsb.nceas.metacat;
19

    
20
import java.io.*;
21
import java.util.Vector;
22
import java.net.URL;
23
import java.net.MalformedURLException;
24
import java.sql.*;
25
import java.util.Stack;
26
import java.util.Hashtable;
27
import java.util.Enumeration;
28

    
29
/** 
30
 * A Class that searches a relational DB for elements and 
31
 * attributes that have free text matches a query string,
32
 * or structured query matches to a path specified node in the 
33
 * XML hierarchy.  It returns a result set consisting of the 
34
 * document ID for each document that satisfies the query
35
 */
36
public class DBQuery {
37

    
38
  static final int ALL = 1;
39
  static final int WRITE = 2;
40
  static final int READ = 4;
41

    
42
  private Connection	conn = null;
43
  private String	parserName = null;
44
  private MetaCatUtil util = new MetaCatUtil();
45
  /**
46
   * the main routine used to test the DBQuery utility.
47
   * <p>
48
   * Usage: java DBQuery <xmlfile>
49
   *
50
   * @param xmlfile the filename of the xml file containing the query
51
   */
52
  static public void main(String[] args) {
53
     
54
     if (args.length < 1)
55
     {
56
        System.err.println("Wrong number of arguments!!!");
57
        System.err.println("USAGE: java DBQuery <xmlfile>");
58
        return;
59
     } else {
60
        try {
61
                    
62
          String xmlfile  = args[0];
63

    
64
          // Open a connection to the database
65
          MetaCatUtil   util = new MetaCatUtil();
66
          Connection dbconn = util.openDBConnection();
67

    
68
          // Execute the query
69
          DBQuery queryobj = new DBQuery(dbconn, util.getOption("saxparser"));
70
          FileReader xml = new FileReader(new File(xmlfile));
71
          Hashtable nodelist = null;
72
          nodelist = queryobj.findDocuments(xml, null, null);
73

    
74
          // Print the reulting document listing
75
          StringBuffer result = new StringBuffer();
76
          String document = null;
77
          String docid = null;
78
          result.append("<?xml version=\"1.0\"?>\n");
79
          result.append("<resultset>\n"); 
80
  // following line removed by Dan Higgins to avoid insertion of query XML inside returned XML doc
81
  //        result.append("  <query>" + xmlfile + "</query>\n");
82
          Enumeration doclist = nodelist.keys(); 
83
          while (doclist.hasMoreElements()) {
84
            docid = (String)doclist.nextElement();
85
            document = (String)nodelist.get(docid);
86
            result.append("  <document>\n    " + document + 
87
                          "\n  </document>\n");
88
          }
89
          result.append("</resultset>\n");
90

    
91
          System.out.println(result);
92

    
93
        } catch (Exception e) {
94
          System.err.println("EXCEPTION HANDLING REQUIRED");
95
          System.err.println(e.getMessage());
96
          e.printStackTrace(System.err);
97
        }
98
     }
99
  }
100
  
101
  /**
102
   * construct an instance of the DBQuery class 
103
   *
104
   * <p>Generally, one would call the findDocuments() routine after creating 
105
   * an instance to specify the search query</p>
106
   *
107
   * @param conn the JDBC connection that we use for the query
108
   * @param parserName the fully qualified name of a Java class implementing
109
   *                   the org.xml.sax.XMLReader interface
110
   */
111
  public DBQuery( Connection conn, String parserName ) 
112
                  throws IOException, 
113
                         SQLException, 
114
                         ClassNotFoundException {
115
    this.conn = conn;
116
    this.parserName = parserName;
117
  }
118
  
119
  public Hashtable findDocuments(Reader xmlquery, String user, String group)
120
  {
121
    return findDocuments(xmlquery, user, group, null);
122
  }
123
  
124
  /** 
125
   * routine to search the elements and attributes looking to match query
126
   *
127
   * @param xmlquery the xml serialization of the query (@see pathquery.dtd)
128
   * @param user the username of the user
129
   * @param group the group of the user
130
   * @param returndoc an array of document types to backtrack against.
131
   */
132
  public Hashtable findDocuments(Reader xmlquery, String user, String group,
133
                                 String[] returndoc)
134
  {
135
      Hashtable	 docListResult = new Hashtable();
136
      PreparedStatement pstmt;
137
      String docid = null;
138
      String docname = null;
139
      String doctype = null;
140
      String doctitle = null;
141
      String createDate = null;
142
      String updateDate = null;
143
      String fieldname = null;
144
      String fielddata = null;
145
      String relation = null;
146
      StringBuffer document = null; 
147
      Vector returndocVec = new Vector();
148
      
149
      if(returndoc != null)
150
      {//add the returndoc elements to a vector for easier manipulation
151
        for(int i=0; i<returndoc.length; i++)
152
        {
153
          returndocVec.add(new String((String)returndoc[i]));
154
        }
155
      }
156
      
157
      try {
158
        // Get the XML query and covert it into a SQL statment
159
        QuerySpecification qspec = new QuerySpecification(xmlquery, 
160
                                   parserName);
161
        //System.out.println(qspec.printSQL());
162
        pstmt = conn.prepareStatement( qspec.printSQL() );
163

    
164
        // Execute the SQL query using the JDBC connection
165
        pstmt.execute();
166
        ResultSet rs = pstmt.getResultSet();
167
        boolean tableHasRows = rs.next();
168
        while (tableHasRows) {
169
          docid = rs.getString(1);
170
          if ( !hasReadPermission(conn, docid, user, group) ) {continue;}
171
          docname = rs.getString(2);
172
          doctype = rs.getString(3);
173
          doctitle = rs.getString(4);
174
          createDate = rs.getString(5);
175
          updateDate = rs.getString(6);
176
          
177
          if(returndocVec.size() != 0 && !returndocVec.contains(doctype))
178
          { //there are returndocs to match (backtracking can now be performed). 
179
            //System.out.println("olddoctype: " + doctype);
180
            StringBuffer btBuf = new StringBuffer();
181
            btBuf.append("select object from xml_relation where ");
182
            btBuf.append("objdoctype in (");
183
            //build the doctype list for the backtracking sql statement
184
            for(int i=0; i<returndocVec.size(); i++)
185
            {
186
              btBuf.append("'").append((String)returndocVec.get(i)).append("'");
187
              if(i != (returndocVec.size() - 1))
188
              {
189
                btBuf.append(", ");
190
              }
191
            }
192
            btBuf.append(") ");
193
            btBuf.append("and subject like '");
194
            btBuf.append("metacat://docid#").append(docid).append("'");
195
            pstmt = conn.prepareStatement(btBuf.toString());
196
            pstmt.execute();
197
            ResultSet btrs = pstmt.getResultSet();
198
            boolean hasBtRows = btrs.next();
199
            if(hasBtRows)
200
            { //there was a backtrackable document found
201
              DocumentImpl xmldoc = null;
202
              //System.out.println("document found is: " + btrs.getString(1));
203
              metacatURL objURL = new metacatURL(btrs.getString(1));
204
              try
205
              {
206
                xmldoc = new DocumentImpl(conn, objURL.getParam(0)[1]);
207
              }
208
              catch(Exception e)
209
              {
210
                System.out.println("Error getting document: " + e.getMessage());
211
              }
212
              
213
              docid   = xmldoc.getDocID();
214
              docname = xmldoc.getDocname();
215
              doctype = xmldoc.getDoctype();
216
              doctitle = xmldoc.getDocTitle();
217
              createDate = xmldoc.getCreateDate();
218
              updateDate = xmldoc.getUpdateDate();
219
              //System.out.println("docname: " + docname + " doctype: " + doctype + 
220
              //                   " doctitle: " + doctitle + " createdate: " +
221
              //                   createDate + " updatedate: " + updateDate);
222
            }
223
            btrs.close();
224
          }
225
          
226
          document = new StringBuffer();
227
          //System.out.println("packagdoctype: " + util.getOption("packagedoctype"));
228
          if(!doctype.equals(util.getOption("packagedoctype")))
229
          {
230
            document.append("<docid>").append(docid).append("</docid>");
231
            if (docname != null) {
232
              document.append("<docname>" + docname + "</docname>");
233
            }
234
            if (doctype != null) {
235
              document.append("<doctype>" + doctype + "</doctype>");
236
            }
237
            if (doctitle != null) {
238
              document.append("<doctitle>" + doctitle + "</doctitle>");
239
            }
240
            if(createDate != null) {
241
              document.append("<createdate>" + createDate + "</createdate>");
242
            }
243
            if(updateDate != null) {
244
              document.append("<updatedate>" + updateDate + "</updatedate>");
245
            }
246
            // Store the document id and the root node id
247
            docListResult.put(docid,(String)document.toString());
248
          }
249

    
250
          // Advance to the next record in the cursor
251
          tableHasRows = rs.next();
252
        }
253
        
254
        if(qspec.containsExtendedSQL())
255
        {
256
          Vector extendedFields = new Vector(qspec.getReturnFieldList());
257
          Vector results = new Vector();
258
          Enumeration keylist = docListResult.keys();
259
          StringBuffer doclist = new StringBuffer();
260
          while(keylist.hasMoreElements())
261
          {
262
            doclist.append("'");
263
            doclist.append((String)keylist.nextElement());
264
            doclist.append("',");
265
          }
266
          doclist.deleteCharAt(doclist.length()-1); //remove the last comma
267
          pstmt = conn.prepareStatement(qspec.printExtendedSQL(
268
                                        doclist.toString()));
269
          pstmt.execute();
270
          rs = pstmt.getResultSet();
271
          tableHasRows = rs.next();
272
          while(tableHasRows) 
273
          {
274
            docid = rs.getString(1);
275
            if ( !hasReadPermission(conn, docid, user, group) ) {continue;}
276
            fieldname = rs.getString(2);
277
            fielddata = rs.getString(3);
278
            
279
            document = new StringBuffer();
280

    
281
            document.append("<param name=\"");
282
            document.append(fieldname);
283
            document.append("\">");
284
            document.append(fielddata);
285
            document.append("</param>");
286

    
287
            tableHasRows = rs.next();
288
            if(docListResult.containsKey(docid))
289
            {
290
              String removedelement = (String)docListResult.remove(docid);
291
              docListResult.put(docid, removedelement + document.toString());
292
            }
293
            else
294
            {
295
              docListResult.put(docid, document.toString()); 
296
            }
297
          }
298
        }
299

    
300
        //this loop adds the relation data to the resultdoc
301
        //this code might be able to be added to the backtracking code above
302
        Enumeration docidkeys = docListResult.keys();
303
        while(docidkeys.hasMoreElements())
304
        {
305
          String docidkey = (String)docidkeys.nextElement();
306
          pstmt = conn.prepareStatement(
307
                  qspec.printRelationSQL("metacat://docid#" + docidkey));
308
          pstmt.execute();
309
          rs = pstmt.getResultSet();
310
          tableHasRows = rs.next();
311
          while(tableHasRows)
312
          {
313
            String sub = rs.getString(1);
314
            String rel = rs.getString(2);
315
            String obj = rs.getString(3);
316
            metacatURL murl = new metacatURL(sub);
317
            if(murl.getURLType().equals("metacat"))
318
            {//we only want to process metacat urls here.
319
              String[] tempparam = murl.getParam(0);
320
              if(tempparam[0].equals("docid") && tempparam[1].equals(docidkey))
321
              {
322
                document = new StringBuffer();
323
                document.append("<relation>");
324
                document.append("<relationtype>").append(rel);
325
                document.append("</relationtype>");
326
                document.append("<relationdoc>").append(obj);
327
                document.append("</relationdoc>");
328
                document.append("</relation>");
329
                
330
                String removedelement = (String)docListResult.remove(docidkey);
331
                docListResult.put(docidkey, removedelement + document.toString());
332
                
333
              }
334
            }
335
            tableHasRows = rs.next();
336
          }
337
        }
338
        pstmt.close();
339
      } catch (SQLException e) {
340
        System.err.println("Error getting id: " + e.getMessage());
341
      } catch (IOException ioe) {
342
        System.err.println("Error printing qspec:");
343
        System.err.println(ioe.getMessage());
344
      }
345
    //System.out.println("docListResult: ");
346
    //System.out.println(docListResult.toString());
347
    return docListResult;
348
  }
349
  
350
  /**
351
   * returns a string array of the contents of a particular node. 
352
   * If the node appears more than once, the contents are returned 
353
   * in the order in which they appearred in the document.
354
   * @param nodename the name or path of the particular node.
355
   * @param docid the docid of the document you want the node from.
356
   * @param conn a database connection-this allows this method to be static
357
   */
358
  public static Object[] getNodeContent(String nodename, String docid, 
359
                                        Connection conn)
360
  {
361
    StringBuffer query = new StringBuffer();
362
    Vector result = new Vector();
363
    PreparedStatement pstmt;
364
    query.append("select nodedata from xml_nodes where parentnodeid in ");
365
    query.append("(select nodeid from xml_index where path like '");
366
    query.append(nodename);
367
    query.append("' and docid like '").append(docid).append("')");
368
    try
369
    {
370
      pstmt = conn.prepareStatement(query.toString());
371

    
372
      // Execute the SQL query using the JDBC connection
373
      pstmt.execute();
374
      ResultSet rs = pstmt.getResultSet();
375
      boolean tableHasRows = rs.next();
376
      while (tableHasRows) 
377
      {
378
        result.add(rs.getString(1));
379
        System.out.println(rs.getString(1));
380
        tableHasRows = rs.next();
381
      }
382
    } 
383
    catch (SQLException e) 
384
    {
385
      System.err.println("Error getting id: " + e.getMessage());
386
    } 
387
    
388
    return result.toArray();
389
  }
390
  
391
  /**
392
   * format a structured query as an XML document that conforms
393
   * to the pathquery.dtd and is appropriate for submission to the DBQuery
394
   * structured query engine
395
   *
396
   * @param params The list of parameters that  should be included in the query
397
   */
398
  public static String createSQuery(Hashtable params)
399
  { 
400
    StringBuffer query = new StringBuffer();
401
    Enumeration elements;
402
    Enumeration keys;
403
    String doctype = null;
404
    String casesensitive = null;
405
    String searchmode = null;
406
    Object nextkey;
407
    Object nextelement;
408
    //add the xml headers
409
    query.append("<?xml version=\"1.0\"?>\n");
410
    query.append("<pathquery version=\"1.0\"><meta_file_id>");
411
    
412
    if(params.containsKey("meta_file_id"))
413
    {
414
      query.append( ((String[])params.get("meta_file_id"))[0]);
415
    	query.append("</meta_file_id>");
416
    }
417
    else
418
    {
419
      query.append("unspecified</meta_file_id>");
420
    }
421
    
422
    query.append("<querytitle>");
423
    if(params.containsKey("querytitle"))
424
    {
425
      query.append(((String[])params.get("querytitle"))[0]);
426
    	query.append("</querytitle>");
427
    }
428
    else
429
    {
430
    	query.append("unspecified</querytitle>");
431
    }
432
    
433
    if(params.containsKey("doctype"))
434
    {
435
      doctype = ((String[])params.get("doctype"))[0]; 
436
    }
437
    else
438
    {
439
      doctype = "ANY";  
440
    }
441
    
442
    if(params.containsKey("returnfield"))
443
    {
444
      String[] returnfield = ((String[])params.get("returnfield"));
445
      for(int i=0; i<returnfield.length; i++)
446
      {
447
        query.append("<returnfield>").append(returnfield[i]);
448
        query.append("</returnfield>");
449
      }
450
    }
451
    
452
    //if you don't limit the query by doctype, then it just creates
453
    //an empty returndoctype tag.
454
    if (!doctype.equals("any") && 
455
        !doctype.equals("ANY") &&
456
        !doctype.equals("") ) 
457
    {
458
       query.append("<returndoctype>");
459
       query.append(doctype).append("</returndoctype>");
460
    }
461
    else
462
    { 
463
      query.append("<returndoctype></returndoctype>");
464
    }
465
    
466
    //allows the dynamic switching of boolean operators
467
    if(params.containsKey("operator"))
468
    {
469
      query.append("<querygroup operator=\"" + 
470
    		        ((String[])params.get("operator"))[0] + "\">");
471
    }
472
    else
473
    { //the default operator is UNION
474
      query.append("<querygroup operator=\"UNION\">"); 
475
    }
476
    		
477
    if(params.containsKey("casesensitive"))
478
    {
479
      casesensitive = ((String[])params.get("casesensitive"))[0]; 
480
    }
481
    else
482
    {
483
      casesensitive = "false"; 
484
    }
485
    
486
    if(params.containsKey("searchmode"))
487
    {
488
      searchmode = ((String[])params.get("searchmode"))[0]; 
489
    }
490
    else
491
    {
492
      searchmode = "contains"; 
493
    }
494
    		
495
    //anyfield is a special case because it does a 
496
    //free text search.  It does not have a <pathexpr>
497
    //tag.  This allows for a free text search within the structured
498
    //query.  This is useful if the INTERSECT operator is used.
499
    if(params.containsKey("anyfield"))
500
    {
501
       String[] anyfield = ((String[])params.get("anyfield"));
502
       //allow for more than one value for anyfield
503
       for(int i=0; i<anyfield.length; i++)
504
       {
505
         if(!anyfield[i].equals(""))
506
         {
507
           query.append("<queryterm casesensitive=\"" + casesensitive + 
508
                        "\" " + "searchmode=\"" + searchmode + "\"><value>" +
509
    			              anyfield[i] +
510
    			              "</value></queryterm>"); 
511
         }
512
       }
513
    }
514
    		
515
    //this while loop finds the rest of the parameters
516
    //and attempts to query for the field specified
517
    //by the parameter.
518
    elements = params.elements();
519
    keys = params.keys();
520
    while(keys.hasMoreElements() && elements.hasMoreElements())
521
    {
522
      nextkey = keys.nextElement();
523
    	nextelement = elements.nextElement();
524

    
525
    	//make sure we aren't querying for any of these
526
    	//parameters since the are already in the query
527
      //in one form or another.
528
    	if(!nextkey.toString().equals("doctype") && 
529
    		 !nextkey.toString().equals("action")  &&
530
    		 !nextkey.toString().equals("qformat") && 
531
    		 !nextkey.toString().equals("anyfield") &&
532
         !nextkey.toString().equals("returnfield") &&
533
    		 !nextkey.toString().equals("operator") )
534
    	{
535
        //allow for more than value per field name
536
        for(int i=0; i<((String[])nextelement).length; i++)
537
        {
538
          if(!((String[])nextelement)[i].equals(""))
539
          {
540
            query.append("<queryterm casesensitive=\"" + casesensitive +"\" " + 
541
    				             "searchmode=\"" + searchmode + "\">" +
542
    		                 "<value>" +
543
                         //add the query value
544
    		                 ((String[])nextelement)[i] +
545
    		                 "</value><pathexpr>" +
546
    		                 //add the path to query by 
547
                         nextkey.toString() + 
548
                         "</pathexpr></queryterm>");
549
          }
550
        }
551
    	}
552
    }
553
    query.append("</querygroup></pathquery>");
554
    //append on the end of the xml and return the result as a string
555
    return query.toString();
556
  }
557
  
558
  /**
559
   * format a simple free-text value query as an XML document that conforms
560
   * to the pathquery.dtd and is appropriate for submission to the DBQuery
561
   * structured query engine
562
   *
563
   * @param value the text string to search for in the xml catalog
564
   * @param doctype the type of documents to include in the result set -- use
565
   *        "any" or "ANY" for unfiltered result sets
566
   */
567
   public static String createQuery(String value, String doctype) {
568
     StringBuffer xmlquery = new StringBuffer();
569
     xmlquery.append("<?xml version=\"1.0\"?>\n");
570
     xmlquery.append("<pathquery version=\"1.0\">");
571
     xmlquery.append("<meta_file_id>Unspecified</meta_file_id>");
572
     xmlquery.append("<querytitle>Unspecified</querytitle>");
573

    
574
     if (!doctype.equals("any") && !doctype.equals("ANY")) {
575
       xmlquery.append("<returndoctype>");
576
       xmlquery.append(doctype).append("</returndoctype>");
577
     }
578

    
579
     xmlquery.append("<querygroup operator=\"UNION\">");
580
     //chad added - 8/14
581
     //the if statement allows a query to gracefully handle a null 
582
     //query.  Without this if a nullpointerException is thrown.
583
     if(!value.equals(""))
584
     {
585
       xmlquery.append("<queryterm casesensitive=\"false\" ");
586
       xmlquery.append("searchmode=\"contains\">");
587
       xmlquery.append("<value>").append(value).append("</value>");
588
       xmlquery.append("</queryterm>");
589
     }
590
     xmlquery.append("</querygroup>");
591
     xmlquery.append("</pathquery>");
592

    
593
     
594
     return (xmlquery.toString());
595
   }
596

    
597
  /**
598
   * format a simple free-text value query as an XML document that conforms
599
   * to the pathquery.dtd and is appropriate for submission to the DBQuery
600
   * structured query engine
601
   *
602
   * @param value the text string to search for in the xml catalog
603
   */
604
   public static String createQuery(String value) {
605
     return createQuery(value, "any");
606
   }
607
   
608
  /** Check for "read" permissions from DB connection */
609
  private boolean hasReadPermission(Connection conn, String docid, 
610
                                     String user, String group) 
611
                                     throws SQLException {
612
    // b' of the command line invocation
613
    if ( (user == null) && (group == null) ) {
614
      return true;
615
    }
616
    
617
    PreparedStatement pstmt;
618
    // checking if user is owner of docid or if docid has public access
619
    try {
620
      pstmt = conn.prepareStatement(
621
                   "SELECT 'x' FROM xml_documents " +
622
                   "WHERE docid LIKE ? AND user_owner LIKE ? " + 
623
                   "UNION " +
624
                   "SELECT 'x' FROM xml_documents " +
625
                   "WHERE docid LIKE ? AND public_access = 1");
626
      // Bind the values to the query
627
      pstmt.setString(1, docid);
628
      pstmt.setString(2, user);
629
      pstmt.setString(3, docid);
630

    
631
      pstmt.execute();
632
      ResultSet rs = pstmt.getResultSet();
633
      boolean hasRow = rs.next();
634
      pstmt.close();
635
      if (hasRow) {
636
        return true;
637
      }
638
      
639
    } catch (SQLException e) {
640
      throw new 
641
        SQLException("Error checking document's owner or public access: "
642
                      + e.getMessage());
643
    }
644

    
645
    // checking if docid has public access at this time
646
    try {
647
      pstmt = conn.prepareStatement(
648
                   "SELECT 'x' FROM xml_access " +
649
                   "WHERE docid LIKE ? " +
650
                   "AND principal_name = 'public' " +
651
                   "AND principal_type = 'user' " +
652
                   "AND sysdate BETWEEN nvl(begin_time,sysdate) " +
653
                                   "AND nvl(end_time,sysdate)");
654
      // Bind the values to the query
655
      pstmt.setString(1, docid);
656

    
657
      pstmt.execute();
658
      ResultSet rs = pstmt.getResultSet();
659
      boolean hasRow = rs.next();
660
      pstmt.close();
661
      if (hasRow) {
662
        return true;
663
      }
664
      
665
    } catch (SQLException e) {
666
      throw new 
667
        SQLException("Error checking doc's public access: " + e.getMessage());
668
    }
669

    
670
    // checking access type from xml_access table
671
    int accesstype = 0;
672
    try {
673
      pstmt = conn.prepareStatement(
674
                   "SELECT access_type FROM xml_access " +
675
                   "WHERE docid LIKE ? " + 
676
                   "AND principal_name LIKE ? " +
677
                   "AND principal_type = 'user' " +
678
                   "AND sysdate BETWEEN nvl(begin_time,sysdate) " +
679
                                   "AND nvl(end_time,sysdate) " +
680
                   "UNION " +
681
                   "SELECT access_type FROM xml_access " +
682
                   "WHERE docid LIKE ? " + 
683
                   "AND principal_name LIKE ? " +
684
                   "AND principal_type = 'group' " +
685
                   "AND sysdate BETWEEN nvl(begin_time,sysdate) " +
686
                                   "AND nvl(end_time,sysdate)");
687
      // Bind the values to the query
688
      pstmt.setString(1, docid);
689
      pstmt.setString(2, user);
690
      pstmt.setString(3, docid);
691
      pstmt.setString(2, group);
692

    
693
      pstmt.execute();
694
      ResultSet rs = pstmt.getResultSet();
695
      boolean hasRows = rs.next();
696
      while ( hasRows ) {
697
        accesstype = rs.getInt(1);
698
        if ( (accesstype & READ) == READ ) {
699
          pstmt.close();
700
          return true;
701
        }
702
        hasRows = rs.next();
703
      }
704

    
705
      pstmt.close();
706
      return false;
707
      
708
    } catch (SQLException e) {
709
      throw new 
710
      SQLException("Error getting document's permissions: " + e.getMessage());
711
    }
712
  }
713
   
714
}
715

    
716
/**
717
 * '$Log$
718
 * 'Revision 1.20  2000/09/15 19:52:11  berkley
719
 * 'Added functionality for package specifications.  metacatservlet now contains a new action called getrelateddocument that handles retrieving related documents using the metacatURL specification (metacatURL.java).  DBQuery contains new code in runQuery that embeds relation tags in the returned hashtable describing the documents related to each docid.  querySpecification contains a new method which prints the sql that does the relation query.
720
 * '
721
 * 'Revision 1.19  2000/09/12 17:37:07  bojilova
722
 * 'added check from "read" permission on "query" and "squery" actions
723
 * 'for connected user or for "public" connection
724
 * '
725
 * 'Revision 1.18  2000/09/05 20:50:56  berkley
726
 * 'Added a method called getNodeContent which retrieves the content of a node in a document.  If there are more than one nodes with the same name returned, it returns an array with all of the data.
727
 * '
728
 * 'Revision 1.17  2000/08/31 21:20:39  berkley
729
 * 'changed xslf for new returnfield scheme.  the returnfields are now returned as <param name="<returnfield>"> tags.
730
 * 'hThe sql for the returnfield query was redone to fix a previous problem with slow queries
731
 * '
732
 * 'Revision 1.16  2000/08/23 22:55:25  berkley
733
 * 'changed the field names to be case-sensitive in the returnfields
734
 * '
735
 * 'Revision 1.15  2000/08/23 17:22:07  berkley
736
 * 'added support for the returnfield parameter
737
 * '-added the dynamic parameters to the returned hash table of documents
738
 * '
739
 * 'Revision 1.14  2000/08/17 16:02:34  berkley
740
 * 'Made changes to createSQuery to allow for multiple parameters of the same name.  Also changed the param list to include only "Hashtable params" without a "String doctype" since the doctype is already contained in the params.
741
 * '
742
 * 'Revision 1.13  2000/08/14 21:26:12  berkley
743
 * 'Added createSQuery() to handle structured queries of an arbitrary number of parameters.  Also modified createQuery() to handle a null query in a graceful manner.
744
 * '
745
 * 'Revision 1.12  2000/08/14 20:53:33  jones
746
 * 'Added "release" keyword to all metacat source files so that the release
747
 * 'number will be evident in software distributions.
748
 * '
749
 * 'Revision 1.11  2000/08/11 18:26:07  berkley
750
 * 'added createSQuery
751
 * '
752
 * 'Revision 1.10  2000/07/26 20:40:41  higgins
753
 * 'no message
754
 * '
755
 * 'Revision 1.9  2000/06/26 10:35:04  jones
756
 * 'Merged in substantial changes to DBWriter and associated classes and to
757
 * 'the MetaCatServlet in order to accomodate the new UPDATE and DELETE
758
 * 'functions.  The command line tools and the parameters for the
759
 * 'servlet have changed substantially.
760
 * '
761
 * 'Revision 1.8.2.2  2000/06/25 23:38:16  jones
762
 * 'Added RCSfile keyword
763
 * '
764
 * 'Revision 1.8.2.1  2000/06/25 23:34:17  jones
765
 * 'Changed documentation formatting, added log entries at bottom of source files
766
 * ''
767
 */
(8-8/28)