Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that represents a structured query, and can be 
4
 *             constructed from an XML serialization conforming to 
5
 *             pathquery.dtd. The printSQL() method can be used to print 
6
 *             a SQL serialization of the query.
7
 *  Copyright: 2000 Regents of the University of California and the
8
 *             National Center for Ecological Analysis and Synthesis
9
 *    Authors: Matt Jones
10
 *    Release: @release@
11
 *
12
 *   '$Author: tao $'
13
 *     '$Date: 2004-03-15 14:08:39 -0800 (Mon, 15 Mar 2004) $'
14
 * '$Revision: 2045 $'
15
 *
16
 * This program is free software; you can redistribute it and/or modify
17
 * it under the terms of the GNU General Public License as published by
18
 * the Free Software Foundation; either version 2 of the License, or
19
 * (at your option) any later version.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 * GNU General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU General Public License
27
 * along with this program; if not, write to the Free Software
28
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29
 */
30

    
31
package edu.ucsb.nceas.metacat;
32

    
33
import edu.ucsb.nceas.dbadapter.*;
34

    
35
import java.io.*;
36
import java.util.Hashtable;
37
import java.util.Stack;
38
import java.util.Vector;
39
import java.util.Enumeration;
40

    
41
import org.xml.sax.Attributes;
42
import org.xml.sax.InputSource;
43
import org.xml.sax.SAXException;
44
import org.xml.sax.SAXParseException;
45
import org.xml.sax.XMLReader;
46
import org.xml.sax.helpers.XMLReaderFactory;
47
import org.xml.sax.helpers.DefaultHandler;
48

    
49
/**
50
 * A Class that represents a structured query, and can be 
51
 * constructed from an XML serialization conforming to @see pathquery.dtd. 
52
 * The printSQL() method can be used to print a SQL serialization of the query.
53
 */
54
public class QuerySpecification extends DefaultHandler {
55
 
56
  /** flag determining whether extended query terms are present */
57
  private boolean containsExtendedSQL=false;
58
  /** Identifier for this query document */
59
  private String meta_file_id;
60
  /** Title of this query */
61
  private String queryTitle;
62
  /** List of document types to be returned using package back tracing */
63
  private Vector returnDocList;
64
  /** List of document types to be searched */
65
  private Vector filterDocList;
66
  /** List of fields to be returned in result set */
67
  private Vector returnFieldList;
68
  /** List of users owning documents to be searched */
69
  private Vector ownerList;
70
  /** List of sites/scopes used to constrain search */
71
  private Vector siteList;
72
  /** The root query group that contains the recursive query constraints */
73
  private QueryGroup query = null;
74
 
75
  // Query data structures used temporarily during XML parsing
76
  private Stack elementStack;
77
  private Stack queryStack;
78
  private String currentValue;
79
  private String currentPathexpr;
80
  private String parserName = null;
81
  private String accNumberSeparator = null;
82
  private static final AbstractDatabase dbAdapter = MetaCatUtil.dbAdapter;
83
  
84

    
85
  private boolean percentageSearch = false;
86
  
87
  private String userName = null;
88
  private static final String PUBLIC = "public";
89
  private String [] group = null;
90

    
91
  public static final String ATTRIBUTESYMBOL = "@";
92
  private boolean hasAttributeReturnField = false;
93
  private Hashtable attributeReturnList = new Hashtable();
94
  private int countAttributeReturnField = 0;
95
  /**
96
   * construct an instance of the QuerySpecification class 
97
   *
98
   * @param queryspec the XML representation of the query (should conform
99
   *                  to pathquery.dtd) as a Reader
100
   * @param parserName the fully qualified name of a Java Class implementing
101
   *                  the org.xml.sax.XMLReader interface
102
   */
103
  public QuerySpecification( Reader queryspec, String parserName,
104
         String accNumberSeparator ) throws IOException {
105
    super();
106
    
107
    // Initialize the class variables
108
    returnDocList = new Vector();
109
    filterDocList = new Vector();
110
    elementStack = new Stack();
111
    queryStack   = new Stack();
112
    returnFieldList = new Vector();
113
    ownerList = new Vector();
114
    siteList = new Vector();
115
    this.parserName = parserName;
116
    this.accNumberSeparator = accNumberSeparator;
117

    
118
    // Initialize the parser and read the queryspec
119
    XMLReader parser = initializeParser();
120
    if (parser == null) {
121
      System.err.println("SAX parser not instantiated properly.");
122
    }
123
    try {
124
      parser.parse(new InputSource(queryspec));
125
    } catch (SAXException e) {
126
      System.err.println("error parsing data in " + 
127
                         "QuerySpecification.QuerySpecification");
128
      System.err.println(e.getMessage());
129
    }
130
  }
131

    
132
  /**
133
   * construct an instance of the QuerySpecification class 
134
   *
135
   * @param queryspec the XML representation of the query (should conform
136
   *                  to pathquery.dtd) as a String
137
   * @param parserName the fully qualified name of a Java Class implementing
138
   *                  the org.xml.sax.Parser interface
139
   */
140
  public QuerySpecification( String queryspec, String parserName,
141
         String accNumberSeparator) throws IOException {
142
    this(new StringReader(queryspec), parserName, accNumberSeparator);
143
  }
144
  
145
  /**
146
   * construct an instance of the QuerySpecification class which don't need 
147
   * to parser a xml document
148
   * @param accNumberSeparator  the separator between doc version
149
   */
150
  public QuerySpecification(String accNumberSeparator ) throws IOException 
151
  {
152
    // Initialize the class variables
153
    returnDocList = new Vector();
154
    filterDocList = new Vector();
155
    elementStack = new Stack();
156
    queryStack   = new Stack();
157
    returnFieldList = new Vector();
158
    ownerList = new Vector();
159
    siteList = new Vector();
160
    this.accNumberSeparator = accNumberSeparator;
161
   }
162
  
163
  
164
  /**
165
   * Method to set user name
166
   *
167
   * @param myName  the user name
168
   */
169
  public void setUserName(String myName)
170
  { 
171
    //to lower case
172
    if (myName != null)
173
    {
174
      this.userName = myName.toLowerCase();
175
    }
176
    else
177
    {
178
      this.userName = myName;
179
    }
180
  }
181
  
182
  /**
183
   * Method to set user group
184
   *
185
   * @param myGroup  the user group
186
   */
187
  public void setGroup(String [] myGroup)
188
  {
189
    this.group = myGroup;
190
  }
191
  /**
192
   * Method to indicate this query is a percentage search
193
   */
194
  public boolean isPercentageSearch()
195
  {
196
    return percentageSearch;
197
  }
198
  /*
199
   * Method to get owner query. If it is owner it has all permission
200
   */
201
  private String createOwerQuery()
202
  {
203
    String ownerQuery = null;
204
    ownerQuery = "SELECT docid FROM xml_documents WHERE ";
205
    if (userName != null && !userName.equals(""))
206
    {
207
      ownerQuery = ownerQuery + "lower(user_owner) ='"+ userName +"'";
208
    }
209
    
210
    MetaCatUtil.debugMessage("OwnerQuery: "+ownerQuery, 30);
211
    return ownerQuery;
212
  }
213
  
214
  /*
215
   * Method to create query for xml_access, this part is to get docid list which
216
   * have a allow rule for a given user
217
   */
218
  private String createAllowRuleQuery()
219
  {
220
    String allowQuery = null;
221
    String allowString = constructAllowString();
222
    allowQuery ="SELECT docid from xml_access WHERE( "+allowString;
223
    allowQuery = allowQuery +") AND subtreeid IS NULL";
224
    MetaCatUtil.debugMessage("allow query is: "+ allowQuery, 30);
225
    return allowQuery;
226
    
227
  
228
  }
229
  
230
  /* Method to construct a allow rule string */
231
  private String constructAllowString()
232
  {
233
    String allowQuery ="";
234
     // add allow rule for user name
235
     if (userName != null && !userName.equals(""))
236
    {
237
      allowQuery = allowQuery +"(lower(principal_name) = '" + userName 
238
                              +"' AND perm_type = 'allow'"
239
                              +" AND (permission='4' OR permission='7'))";
240
    }
241
    // add allow rule for public
242
    allowQuery = allowQuery +"OR (lower(principal_name) = '" + PUBLIC 
243
                              +"' AND perm_type = 'allow'"
244
                              +" AND (permission='4' OR permission='7'))";
245
    
246
    // add allow rule for group
247
    if (group != null)
248
    {
249
      for (int i = 0; i< group.length; i++)
250
      {
251
        String groupUint = group[i];
252
        if (groupUint != null && !groupUint.equals(""))
253
        {
254
          groupUint = groupUint.toLowerCase();
255
          allowQuery = allowQuery +" OR (lower(principal_name) = '" + groupUint 
256
                              +"' AND perm_type = 'allow'"
257
                              +" AND (permission='4' OR permission='7'))";
258
        }//if
259
      }//for
260
    }//if
261
    MetaCatUtil.debugMessage("allow string is: "+ allowQuery, 40);
262
    return allowQuery;
263
  }
264

    
265
   /*
266
   * Method to create query for xml_access, this part is to get docid list which
267
   * have a deny rule and perm_order is allowFirst for a given user. This means
268
   * the user will be denied to read
269
   */
270
  private String createDenyRuleQuery()
271
  {
272
    String denyQuery = null;
273
    String denyString = constructDenyString();
274
    denyQuery ="SELECT docid from xml_access WHERE( " + denyString;
275
    denyQuery = denyQuery + ") AND subtreeid IS NULL ";
276
    MetaCatUtil.debugMessage("denyquery is: "+ denyQuery, 30);
277
    return denyQuery;
278
  
279
  }
280
  /* Construct deny string */
281
  private String constructDenyString()
282
  {
283
    String denyQuery ="";
284
    // add deny rule for user name
285
    if (userName != null && !userName.equals(""))
286
    {
287
      denyQuery = denyQuery +"(lower(principal_name) = '" + userName 
288
                              +"' AND perm_type = 'deny' "
289
                              +"AND perm_order ='allowFirst'"
290
                              +" AND (permission='4' OR permission='7'))";
291
    }
292
    // add deny rule for public
293
    denyQuery = denyQuery +"OR (lower(principal_name) = '" + PUBLIC 
294
                               +"' AND perm_type = 'deny' "
295
                               +"AND perm_order ='allowFirst'"
296
                               +" AND (permission='4' OR permission='7'))";
297
    
298
    // add allow rule for group
299
    if (group != null)
300
    {
301
      for (int i = 0; i< group.length; i++)
302
      {
303
        String groupUint = group[i];
304
        if (groupUint != null && !groupUint.equals(""))
305
        {
306
          groupUint = groupUint.toLowerCase();
307
          denyQuery = denyQuery +" OR (lower(principal_name) = '" + groupUint 
308
                                +"' AND perm_type = 'deny' "
309
                                +"AND perm_order ='allowFirst'"
310
                                +" AND (permission='4' OR permission='7'))";
311
        }//if
312
      }//for
313
    }//if
314
    return denyQuery;
315
  }
316
  
317
  /**
318
   * Method to append a access control query to SQL. So in DBQuery class, we can
319
   * get docid from both user specified query and access control query. We don't
320
   * need to checking permission after we get the doclist. It will be good to 
321
   * performance
322
   *
323
   */
324
  public String getAccessQuery()
325
  {
326
    String accessQuery = null;
327
    String onwer = createOwerQuery();
328
    String allow = createAllowRuleQuery();
329
    String deny = createDenyRuleQuery();
330
    accessQuery = " AND (docid IN("+ onwer + ")";
331
    accessQuery = accessQuery + " OR (docid IN (" + allow + ")" 
332
                 + " AND docid NOT IN ("+ deny + ")))";
333
    MetaCatUtil.debugMessage("accessquery is: "+ accessQuery, 30);
334
    return accessQuery;
335
  }
336
  
337
  /** Main routine for testing */
338
  static public void main(String[] args) {
339

    
340
     if (args.length < 1) {
341
       System.err.println("Wrong number of arguments!!!");
342
       System.err.println("USAGE: java QuerySpecification <xmlfile>");
343
       return;
344
     } else {
345
       int i = 0;
346
       boolean useXMLIndex = true;
347
       if ( args[i].equals( "-noindex" ) ) {
348
         useXMLIndex = false;
349
         i++;
350
       }
351
       String xmlfile  = args[i];
352

    
353
       try {
354
         MetaCatUtil util = new MetaCatUtil();
355
         FileReader xml = new FileReader(new File(xmlfile));
356
         QuerySpecification qspec = 
357
                 new QuerySpecification(xml, util.getOption("saxparser"),
358
                                        util.getOption("accNumberSeparator"));
359
         System.out.println(qspec.printSQL(useXMLIndex));
360

    
361
       } catch (IOException e) {
362
         System.err.println(e.getMessage());
363
       }
364
         
365
     }
366
  }
367
  
368
  /**
369
   * Returns true if the parsed query contains and extended xml query 
370
   * (i.e. there is at least one &lt;returnfield&gt; in the pathquery document)
371
   */
372
  public boolean containsExtendedSQL()
373
  {
374
    if(containsExtendedSQL)
375
    {
376
      return true;
377
    }
378
    else
379
    {
380
      return false;
381
    }
382
  }
383
  
384
  /**
385
   * A method to get if the query has an attribute return field
386
   */
387
  public boolean containAttributeReturnField()
388
  {
389
    return hasAttributeReturnField;
390
  }
391
  
392
  /**
393
   * Accessor method to return the identifier of this Query
394
   */
395
  public String getIdentifier()
396
  {
397
    return meta_file_id;
398
  }
399

    
400
  /**
401
   * method to set the identifier of this query
402
   */
403
  public void setIdentifier(String id) {
404
    this.meta_file_id = id;
405
  }
406

    
407
  /**
408
   * Accessor method to return the title of this Query
409
   */
410
  public String getQueryTitle()
411
  {
412
    return queryTitle;
413
  }
414

    
415
  /**
416
   * method to set the title of this query
417
   */
418
  public void setQueryTitle(String title)
419
  {
420
    this.queryTitle = title;
421
  }
422

    
423
  /**
424
   * Accessor method to return a vector of the return document types as
425
   * defined in the &lt;returndoctype&gt; tag in the pathquery dtd.
426
   */
427
  public Vector getReturnDocList()
428
  {
429
    return this.returnDocList;
430
  }
431

    
432
  /**
433
   * method to set the list of return docs of this query
434
   */
435
  public void setReturnDocList(Vector returnDocList)
436
  {
437
    this.returnDocList = returnDocList;
438
  }
439

    
440
  /**
441
   * Accessor method to return a vector of the filter doc types as
442
   * defined in the &lt;filterdoctype&gt; tag in the pathquery dtd.
443
   */
444
  public Vector getFilterDocList()
445
  {
446
    return this.filterDocList;
447
  }
448

    
449
  /**
450
   * method to set the list of filter docs of this query
451
   */
452
  public void setFilterDocList(Vector filterDocList)
453
  {
454
    this.filterDocList = filterDocList;
455
  }
456

    
457
  /**
458
   * Accessor method to return a vector of the extended return fields as
459
   * defined in the &lt;returnfield&gt; tag in the pathquery dtd.
460
   */
461
  public Vector getReturnFieldList()
462
  {
463
    return this.returnFieldList; 
464
  }
465

    
466
  /**
467
   * method to set the list of fields to be returned by this query
468
   */
469
  public void setReturnFieldList(Vector returnFieldList)
470
  {
471
    this.returnFieldList = returnFieldList;
472
  }
473

    
474
  /**
475
   * Accessor method to return a vector of the owner fields as
476
   * defined in the &lt;owner&gt; tag in the pathquery dtd.
477
   */
478
  public Vector getOwnerList()
479
  {
480
    return this.ownerList;
481
  }
482

    
483
  /**
484
   * method to set the list of owners used to constrain this query
485
   */
486
  public void setOwnerList(Vector ownerList)
487
  {
488
    this.ownerList = ownerList;
489
  }
490

    
491
  /**
492
   * Accessor method to return a vector of the site fields as
493
   * defined in the &lt;site&gt; tag in the pathquery dtd.
494
   */
495
  public Vector getSiteList()
496
  {
497
    return this.siteList;
498
  }
499

    
500
  /**
501
   * method to set the list of sites used to constrain this query
502
   */
503
  public void setSiteList(Vector siteList)
504
  {
505
    this.siteList = siteList;
506
  }
507

    
508
  /**
509
   * get the QueryGroup used to express query constraints
510
   */
511
  public QueryGroup getQueryGroup()
512
  {
513
    return query;
514
  }
515
  
516
  /**
517
   * set the querygroup
518
   */
519
  public void setQueryGroup(QueryGroup group)
520
  {
521
    query = group;
522
  }
523
  
524
  /**
525
   * set if this query sepcification has extendQuery(has return doc type or not)
526
   */
527
  public void setContainsExtenedSQL(boolean hasExtenedQuery)
528
  {
529
     containsExtendedSQL = hasExtenedQuery;
530
  }  
531
   
532
  /**
533
   * Set up the SAX parser for reading the XML serialized query
534
   */
535
  private XMLReader initializeParser() {
536
    XMLReader parser = null;
537

    
538
    // Set up the SAX document handlers for parsing
539
    try {
540

    
541
      // Get an instance of the parser
542
      parser = XMLReaderFactory.createXMLReader(parserName);
543

    
544
      // Set the ContentHandler to this instance
545
      parser.setContentHandler(this);
546

    
547
      // Set the error Handler to this instance
548
      parser.setErrorHandler(this);
549

    
550
    } catch (Exception e) {
551
       System.err.println("Error in QuerySpcecification.initializeParser " + 
552
                           e.toString());
553
    }
554

    
555
    return parser;
556
  }
557

    
558
  /**
559
   * callback method used by the SAX Parser when the start tag of an 
560
   * element is detected. Used in this context to parse and store
561
   * the query information in class variables.
562
   */
563
  public void startElement (String uri, String localName, 
564
                            String qName, Attributes atts) 
565
         throws SAXException {
566
    BasicNode currentNode = new BasicNode(localName);
567
    // add attributes to BasicNode here
568
    if (atts != null) {
569
      int len = atts.getLength();
570
      for (int i = 0; i < len; i++) {
571
        currentNode.setAttribute(atts.getLocalName(i), atts.getValue(i));
572
      }
573
    }
574

    
575
    elementStack.push(currentNode); 
576
    if (currentNode.getTagName().equals("querygroup")) {
577
      QueryGroup currentGroup = new QueryGroup(
578
                                currentNode.getAttribute("operator"));
579
      if (query == null) {
580
        query = currentGroup;
581
      } else {
582
        QueryGroup parentGroup = (QueryGroup)queryStack.peek();
583
        parentGroup.addChild(currentGroup);
584
      }
585
      queryStack.push(currentGroup);
586
    }
587
  }
588

    
589
  /**
590
   * callback method used by the SAX Parser when the end tag of an 
591
   * element is detected. Used in this context to parse and store
592
   * the query information in class variables.
593
   */
594
  public void endElement (String uri, String localName,
595
                          String qName) throws SAXException {
596
    BasicNode leaving = (BasicNode)elementStack.pop(); 
597
    if (leaving.getTagName().equals("queryterm")) {
598
      boolean isCaseSensitive = (new Boolean(
599
              leaving.getAttribute("casesensitive"))).booleanValue();
600
      QueryTerm currentTerm = null;
601
      if (currentPathexpr == null) {
602
        currentTerm = new QueryTerm(isCaseSensitive,
603
                      leaving.getAttribute("searchmode"),currentValue);
604
      } else {
605
        currentTerm = new QueryTerm(isCaseSensitive,
606
                      leaving.getAttribute("searchmode"),currentValue,
607
                      currentPathexpr);
608
      }
609
      QueryGroup currentGroup = (QueryGroup)queryStack.peek();
610
      currentGroup.addChild(currentTerm);
611
      currentValue = null;
612
      currentPathexpr = null;
613
    } else if (leaving.getTagName().equals("querygroup")) {
614
      QueryGroup leavingGroup = (QueryGroup)queryStack.pop();
615
    }
616
  }
617

    
618
  /**
619
   * callback method used by the SAX Parser when the text sequences of an 
620
   * xml stream are detected. Used in this context to parse and store
621
   * the query information in class variables.
622
   */
623
  public void characters(char ch[], int start, int length) {
624

    
625
    String inputString = new String(ch, start, length);
626
    BasicNode currentNode = (BasicNode)elementStack.peek(); 
627
    String currentTag = currentNode.getTagName();
628
    if (currentTag.equals("meta_file_id")) {
629
      meta_file_id = inputString;
630
    } else if (currentTag.equals("querytitle")) {
631
      queryTitle = inputString;
632
    } else if (currentTag.equals("value")) {
633
      currentValue = inputString;
634
    } else if (currentTag.equals("pathexpr")) {
635
      currentPathexpr = inputString;
636
    } else if (currentTag.equals("returndoctype")) {
637
      returnDocList.add(inputString);
638
    } else if (currentTag.equals("filterdoctype")) {
639
      filterDocList.add(inputString);
640
    } else if (currentTag.equals("returnfield")) {
641
       handleReturnField(inputString);
642
    } else if (currentTag.equals("filterdoctype")) {
643
      filterDocList.add(inputString);
644
    } else if (currentTag.equals("owner")) {
645
      ownerList.add(inputString);
646
    } else if (currentTag.equals("site")) {
647
      siteList.add(inputString);
648
    }
649
  }
650
  
651
  /**
652
   * Method to transfer string to return field
653
   */
654
  public void handleReturnField(String inputString)
655
  {
656
     // make sure if return fields has an attribute or not
657
      if (inputString.indexOf(ATTRIBUTESYMBOL) ==-1)
658
      {
659
        // no attribute value will be returned
660
        returnFieldList.add(inputString);
661
        containsExtendedSQL = true;
662
      }
663
      else
664
      {
665
        // has a attribute return field
666
        // divied the return filed into two parts, one is path and the
667
        // other is attribue name
668
        String returnPath = newPathExpressionWithOutAttribute(inputString);
669
        String attributeName = getAttributeName(inputString);
670
        Vector pathInfo = new Vector();
671
        // the vector has the information about return path and attributename
672
        pathInfo.addElement(returnPath);
673
        pathInfo.addElement(attributeName);
674
        // put the vector into a hash table. The reseaon why don't put
675
        // return path or attributename as a key is because they are not unique
676
        attributeReturnList.put
677
                            (new Integer(countAttributeReturnField), pathInfo);
678
        countAttributeReturnField++;
679
        hasAttributeReturnField = true;
680
        containsExtendedSQL = true;
681
        
682
      }
683
  }
684
  /**
685
   * create a SQL serialization of the query that this instance represents
686
   */
687
  public String printSQL(boolean useXMLIndex) {
688
    
689
   
690
    StringBuffer self = new StringBuffer();
691

    
692
    self.append("SELECT docid,docname,doctype,");
693
    self.append("date_created, date_updated, rev ");
694
    self.append("FROM xml_documents WHERE docid IN (");
695

    
696
    // This determines the documents that meet the query conditions
697
    self.append(query.printSQL(useXMLIndex));
698

    
699
    self.append(") ");
700
 
701
    // Add SQL to filter for doctypes requested in the query
702
    // This is an implicit OR for the list of doctypes. Only doctypes in this
703
    // list will be searched if the tag is present
704
    if (!filterDocList.isEmpty()) {
705
      boolean firstdoctype = true;
706
      self.append(" AND ("); 
707
      Enumeration en = filterDocList.elements();
708
      while (en.hasMoreElements()) {
709
        String currentDoctype = (String)en.nextElement();
710
        if (firstdoctype) {
711
           firstdoctype = false;
712
           self.append(" doctype = '" + currentDoctype + "'"); 
713
        } else {
714
          self.append(" OR doctype = '" + currentDoctype + "'"); 
715
        }
716
      }
717
      self.append(") ");
718
    }
719

    
720
    // Add SQL to filter for owners requested in the query
721
    // This is an implicit OR for the list of owners
722
    if (!ownerList.isEmpty()) {
723
      boolean first = true;
724
      self.append(" AND ("); 
725
      Enumeration en = ownerList.elements();
726
      while (en.hasMoreElements()) {
727
        String current = (String)en.nextElement();
728
        if (current != null)
729
        {
730
          current = current.toLowerCase();
731
        }
732
        if (first) {
733
           first = false;
734
           self.append(" lower(user_owner) = '" + current + "'"); 
735
        } else {
736
          self.append(" OR lower(user_owner) = '" + current + "'"); 
737
        }
738
      }
739
      self.append(") ");
740
    }
741

    
742
    // Add SQL to filter for sites requested in the query
743
    // This is an implicit OR for the list of sites
744
    if (!siteList.isEmpty()) {
745
      boolean first = true;
746
      self.append(" AND ("); 
747
      Enumeration en = siteList.elements();
748
      while (en.hasMoreElements()) {
749
        String current = (String)en.nextElement();
750
        if (first) {
751
           first = false;
752
           self.append(" SUBSTR(docid, 1, INSTR(docid, '" +
753
               accNumberSeparator + "')-1) = '" + current + "'"); 
754
        } else {
755
          self.append(" OR SUBSTR(docid, 1, INSTR(docid, '" +
756
               accNumberSeparator + "')-1) = '" + current + "'"); 
757
        }
758
      }
759
      self.append(") ");
760
    }
761
    
762
    // if there is only one percentage search item, this query is a percentage
763
    // search query
764
    MetaCatUtil.debugMessage("percentage number: " + 
765
                                         query.getPercentageSymbolCount(), 35); 
766
    if (query.getPercentageSymbolCount() ==1 )
767
    {
768
      MetaCatUtil.debugMessage("it is a percentage search", 30);
769
      percentageSearch =true;
770
    }
771
    
772
    return self.toString();
773
  }
774
  
775
  /** This sql command will selecet startnodeid and endnodeid that user can NOT
776
    * access
777
    */
778
  public String printAccessControlSQLForReturnField(String doclist)
779
  {
780
    StringBuffer sql = new StringBuffer();
781
    String allowString = constructAllowString();
782
    String denyString = constructDenyString();
783
    sql.append("SELECT distinct startnodeid, endnodeid from xml_access ");
784
    sql.append("WHERE docid in (");
785
    sql.append(doclist);
786
    sql.append(") AND startnodeid IS NOT NULL AND ");
787
    sql.append("(");
788
    sql.append("(");
789
    sql.append("startnodeid NOT IN (SELECT startnodeid from xml_access, xml_documents ");
790
    sql.append(" WHERE xml_access.docid = xml_documents.docid");
791
    sql.append(" AND lower(xml_documents.user_owner) ='");
792
    sql.append(userName);
793
    sql.append("' AND xml_access.startnodeid IS NOT NULL)"); 
794
    sql.append(")");
795
    sql.append(" AND ");
796
    sql.append("(");
797
    sql.append("(startnodeid NOT IN (SELECT startnodeid from xml_access where( ");
798
    sql.append(allowString);
799
    sql.append(") AND (startnodeid IS NOT NULL))");
800
    sql.append(")");
801
    sql.append(" OR (startnodeid IN (SELECT startnodeid from xml_access where( ");
802
    sql.append(denyString);
803
    sql.append(") AND (startnodeid IS NOT NULL))");
804
    sql.append(")");
805
    sql.append(")");
806
    sql.append(")");
807
    MetaCatUtil.debugMessage("accessControlSQLForReturnField: " +
808
                             sql.toString(), 30);
809
    return sql.toString();
810
  }
811
  
812
  /**
813
   * This method prints sql based upon the &lt;returnfield&gt; tag in the
814
   * pathquery document.  This allows for customization of the 
815
   * returned fields
816
   * @param doclist the list of document ids to search by
817
   * @param unaccessableNodePair  the node pair(start id and end id) which this
818
   *                               user could not access it
819
   */
820
  public String printExtendedSQL(String doclist, Hashtable unaccessableNodePair)
821
  {  
822
    StringBuffer self = new StringBuffer();
823
    self.append("select xml_nodes.docid, xml_index.path, xml_nodes.nodedata, ");
824
    self.append("xml_nodes.parentnodeid ");
825
    self.append("from xml_index, xml_nodes where xml_index.nodeid=");
826
    self.append("xml_nodes.parentnodeid and (xml_index.path like '");
827
    boolean firstfield = true;
828
    //put the returnfields into the query
829
    //the for loop allows for multiple fields
830
    for(int i=0; i<returnFieldList.size(); i++)
831
    {
832
      if(firstfield)
833
      {
834
        firstfield = false;
835
        self.append((String)returnFieldList.elementAt(i));
836
        self.append("' ");
837
      }
838
      else
839
      {
840
        self.append("or xml_index.path like '");
841
        self.append((String)returnFieldList.elementAt(i));
842
        self.append("' ");
843
      }
844
    }
845
    self.append(") AND xml_nodes.docid in (");
846
    //self.append(query.printSQL());
847
    self.append(doclist);
848
    self.append(")");
849
    self.append(" AND xml_nodes.nodetype = 'TEXT'");
850
    
851
    // add control part for extended query
852
    Enumeration en = unaccessableNodePair.keys();
853
    
854
    while (en.hasMoreElements())
855
    {
856
      // Get control pairs in object
857
      Long startNodeIdObject = (Long)en.nextElement();
858
      Long endNodeIdObject = (Long)unaccessableNodePair.get(startNodeIdObject);
859
      // change it to long
860
      long startNodeId = startNodeIdObject.longValue();
861
      long endNodeId   = endNodeIdObject.longValue();
862
      // add into query
863
      self.append(" AND( xml_nodes.nodeid < ");
864
      self.append(startNodeId);
865
      self.append(" OR xml_nodes.nodeid > ");
866
      self.append(endNodeId);
867
      self.append(")");
868
    }
869

    
870
   
871
    return self.toString();
872
  }
873
  
874
  /**
875
   * This method prints sql based upon the returnfield tag in the
876
   * pathquery document has an attribute.  This allows for customization of the 
877
   * returned fields
878
   * @param doclist the list of document ids to search by
879
   */
880
  public String printAttributeQuery(String doclist)
881
  {
882
    StringBuffer self = new StringBuffer();
883
    self.append("select xml_nodes.docid, xml_index.path, ");
884
    self.append("xml_nodes.nodedata, xml_nodes.nodename ");
885
    self.append("from xml_index, xml_nodes where xml_index.nodeid=");
886
    self.append("xml_nodes.parentnodeid and (");
887
    boolean firstfield = true;
888
    //put the returnfields attributes into the query
889
    //the for loop allows for multiple fields and attributes
890
    Enumeration returnAttributes = attributeReturnList.elements();
891
    while (returnAttributes.hasMoreElements())
892
    {
893
      Vector currentVector = (Vector)returnAttributes.nextElement();
894
      String returnPath = (String)currentVector.elementAt(0);
895
      String attributeName = (String)currentVector.elementAt(1);
896
      if(firstfield)
897
      {
898
        firstfield = false;
899
        self.append("( xml_index.path like '");
900
        self.append(returnPath);
901
        self.append("' AND xml_nodes.nodename like '");
902
        self.append(attributeName);
903
        self.append("') ");
904
      }
905
      else
906
      {
907
        self.append(" or ( xml_index.path like '");
908
        self.append(returnPath);
909
        self.append("' AND xml_nodes.nodename like '");
910
        self.append(attributeName);
911
        self.append("') "); 
912
      }
913
    }
914
    self.append(") AND xml_nodes.docid in (");
915
    //self.append(query.printSQL());
916
    self.append(doclist);
917
    self.append(")");
918
    self.append(" AND xml_nodes.nodetype = 'ATTRIBUTE'");
919
    MetaCatUtil.debugMessage("Attribute query: "+self.toString(), 30);
920
   
921
    return self.toString();
922
  }
923
  
924
  public static String printRelationSQL(String docid)
925
  {
926
    StringBuffer self = new StringBuffer();
927
    self.append("select subject, relationship, object, subdoctype, ");
928
    self.append("objdoctype from xml_relation ");
929
    self.append("where docid like '").append(docid).append("'");
930
    return self.toString();
931
  }
932
   
933
  /**
934
   * Prints sql that returns all relations in the database.
935
   */
936
  public static String printPackageSQL()
937
  {
938
    StringBuffer self = new StringBuffer();
939
    self.append("select z.nodedata, x.nodedata, y.nodedata from ");
940
    self.append("(select nodeid, parentnodeid from xml_index where path like ");
941
    self.append("'triple/subject') s, (select nodeid, parentnodeid ");
942
    self.append("from xml_index where path like ");
943
    self.append("'triple/relationship') rel, ");
944
    self.append("(select nodeid, parentnodeid from xml_index where path like ");
945
    self.append("'triple/object') o, ");
946
    self.append("xml_nodes x, xml_nodes y, xml_nodes z ");
947
    self.append("where s.parentnodeid = rel.parentnodeid ");
948
    self.append("and rel.parentnodeid = o.parentnodeid ");
949
    self.append("and x.parentnodeid in (rel.nodeid) ");
950
    self.append("and y.parentnodeid in (o.nodeid) ");
951
    self.append("and z.parentnodeid in (s.nodeid) ");
952
    //self.append("and z.nodedata like '%");
953
    //self.append(docid);
954
    //self.append("%'");
955
    return self.toString();
956
  }
957
  
958
  /**
959
   * Prints sql that returns all relations in the database that were input
960
   * under a specific docid
961
   * @param docid the docid to search for.
962
   */
963
  public static String printPackageSQL(String docid)
964
  {
965
    StringBuffer self = new StringBuffer();
966
    self.append("select z.nodedata, z.parentnodeid, ");
967
    self.append("x.nodedata, x.parentnodeid, y.nodedata, y.parentnodeid from ");
968
    self.append("(select nodeid, parentnodeid from xml_index where path like ");
969
    self.append("'triple/subject') s, (select nodeid, parentnodeid ");
970
    self.append("from xml_index where path like ");
971
    self.append("'triple/relationship') rel, ");
972
    self.append("(select nodeid, parentnodeid from xml_index where path like ");
973
    self.append("'triple/object') o, ");
974
    self.append("xml_nodes x, xml_nodes y, xml_nodes z ");
975
    self.append("where s.parentnodeid = rel.parentnodeid ");
976
    self.append("and rel.parentnodeid = o.parentnodeid ");
977
    self.append("and x.parentnodeid in (rel.nodeid) ");
978
    self.append("and y.parentnodeid in (o.nodeid) ");
979
    self.append("and z.parentnodeid in (s.nodeid) ");
980
    self.append("and z.docid like '").append(docid).append("'");
981
    
982
    return self.toString();
983
  }
984
  
985
  /**
986
   * Returns all of the relations that has a certain docid in the subject
987
   * or the object.
988
   * 
989
   * @param docid the docid to search for
990
   */
991
  public static String printPackageSQL(String subDocidURL, String objDocidURL)
992
  {
993
    StringBuffer self = new StringBuffer();
994
    self.append("select z.nodedata, x.nodedata, y.nodedata from ");
995
    self.append("(select nodeid, parentnodeid from xml_index where path like ");
996
    self.append("'triple/subject') s, (select nodeid, parentnodeid ");
997
    self.append("from xml_index where path like ");
998
    self.append("'triple/relationship') rel, ");
999
    self.append("(select nodeid, parentnodeid from xml_index where path like ");
1000
    self.append("'triple/object') o, ");
1001
    self.append("xml_nodes x, xml_nodes y, xml_nodes z ");
1002
    self.append("where s.parentnodeid = rel.parentnodeid ");
1003
    self.append("and rel.parentnodeid = o.parentnodeid ");
1004
    self.append("and x.parentnodeid in (rel.nodeid) ");
1005
    self.append("and y.parentnodeid in (o.nodeid) ");
1006
    self.append("and z.parentnodeid in (s.nodeid) ");
1007
    self.append("and (z.nodedata like '");
1008
    self.append(subDocidURL);
1009
    self.append("' or y.nodedata like '");
1010
    self.append(objDocidURL);
1011
    self.append("')");
1012
    return self.toString();
1013
  }
1014
  
1015
  public static String printGetDocByDoctypeSQL(String docid)
1016
  {
1017
    StringBuffer self = new StringBuffer();
1018

    
1019
    self.append("SELECT docid,docname,doctype,");
1020
    self.append("date_created, date_updated ");
1021
    self.append("FROM xml_documents WHERE docid IN (");
1022
    self.append(docid).append(")");
1023
    return self.toString();
1024
  }
1025
  
1026
  /**
1027
   * create a String description of the query that this instance represents.
1028
   * This should become a way to get the XML serialization of the query.
1029
   */
1030
  public String toString() {
1031
    return "meta_file_id=" + meta_file_id + "\n" + query;
1032
//DOCTITLE attr cleared from the db
1033
//    return "meta_file_id=" + meta_file_id + "\n" + 
1034
//           "querytitle=" + querytitle + "\n" + query;
1035
  }
1036
  
1037
  /* A method to get rid of attribute part in path expression*/
1038
  public static String newPathExpressionWithOutAttribute(String pathExpression)
1039
  {
1040
      if (pathExpression == null)
1041
      {
1042
        return null;
1043
      }
1044
      int index = pathExpression.lastIndexOf(ATTRIBUTESYMBOL);
1045
      String newExpression = null;
1046
      if (index != 1)
1047
      {
1048
        newExpression=pathExpression.substring(0, index-1);
1049
      } 
1050
      MetaCatUtil.debugMessage("The path expression without attributes: " + 
1051
                               newExpression, 30);
1052
      return newExpression;
1053
  }
1054
    
1055
  /* A method to get attribute name from path */
1056
  public static String getAttributeName(String path)
1057
  {
1058
      if (path == null)
1059
      {
1060
        return null;
1061
      }
1062
      int index = path.lastIndexOf(ATTRIBUTESYMBOL);
1063
      int size = path.length();
1064
      String attributeName = null;
1065
       if (index != 1)
1066
      {
1067
        attributeName = path.substring(index+1, size);
1068
      } 
1069
      MetaCatUtil.debugMessage("The attirbute name from path: " + 
1070
                               attributeName, 30);
1071
      return attributeName;
1072
  }
1073

    
1074
 
1075
}
(48-48/58)