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: 2003-10-18 16:36:09 -0700 (Sat, 18 Oct 2003) $'
14
 * '$Revision: 1837 $'
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
    this.userName = myName;
172
  }
173
  
174
  /**
175
   * Method to set user group
176
   *
177
   * @param myGroup  the user group
178
   */
179
  public void setGroup(String [] myGroup)
180
  {
181
    this.group = myGroup;
182
  }
183
  /**
184
   * Method to indicate this query is a percentage search
185
   */
186
  public boolean isPercentageSearch()
187
  {
188
    return percentageSearch;
189
  }
190
  /*
191
   * Method to get owner query. If it is owner it has all permission
192
   */
193
  private String createOwerQuery()
194
  {
195
    String ownerQuery = null;
196
    ownerQuery = "SELECT docid FROM xml_documents WHERE ";
197
    if (userName != null && !userName.equals(""))
198
    {
199
      ownerQuery = ownerQuery + "user_owner ='"+ userName +"'";
200
    }
201
    
202
    MetaCatUtil.debugMessage("OwnerQuery: "+ownerQuery, 30);
203
    return ownerQuery;
204
  }
205
  
206
  /*
207
   * Method to create query for xml_access, this part is to get docid list which
208
   * have a allow rule for a given user
209
   */
210
  private String createAllowRuleQuery()
211
  {
212
    String allowQuery = null;
213
    String allowString = constructAllowString();
214
    allowQuery ="SELECT docid from xml_access WHERE( "+allowString;
215
    allowQuery = allowQuery +") AND subtreeid IS NULL";
216
    MetaCatUtil.debugMessage("allow query is: "+ allowQuery, 30);
217
    return allowQuery;
218
    
219
  
220
  }
221
  
222
  /* Method to construct a allow rule string */
223
  private String constructAllowString()
224
  {
225
    String allowQuery ="";
226
     // add allow rule for user name
227
     if (userName != null && !userName.equals(""))
228
    {
229
      allowQuery = allowQuery +"(principal_name = '" + userName 
230
                              +"' AND perm_type = 'allow'"
231
                              +" AND (permission='4' OR permission='7'))";
232
    }
233
    // add allow rule for public
234
    allowQuery = allowQuery +"OR (principal_name = '" + PUBLIC 
235
                              +"' AND perm_type = 'allow'"
236
                              +" AND (permission='4' OR permission='7'))";
237
    
238
    // add allow rule for group
239
    if (group != null)
240
    {
241
      for (int i = 0; i< group.length; i++)
242
      {
243
        String groupUint = group[i];
244
        if (groupUint != null && !groupUint.equals(""))
245
        {
246
          allowQuery = allowQuery +" OR (principal_name = '" + groupUint 
247
                              +"' AND perm_type = 'allow'"
248
                              +" AND (permission='4' OR permission='7'))";
249
        }//if
250
      }//for
251
    }//if
252
    MetaCatUtil.debugMessage("allow string is: "+ allowQuery, 40);
253
    return allowQuery;
254
  }
255

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

    
330
     if (args.length < 1) {
331
       System.err.println("Wrong number of arguments!!!");
332
       System.err.println("USAGE: java QuerySpecification <xmlfile>");
333
       return;
334
     } else {
335
       int i = 0;
336
       boolean useXMLIndex = true;
337
       if ( args[i].equals( "-noindex" ) ) {
338
         useXMLIndex = false;
339
         i++;
340
       }
341
       String xmlfile  = args[i];
342

    
343
       try {
344
         MetaCatUtil util = new MetaCatUtil();
345
         FileReader xml = new FileReader(new File(xmlfile));
346
         QuerySpecification qspec = 
347
                 new QuerySpecification(xml, util.getOption("saxparser"),
348
                                        util.getOption("accNumberSeparator"));
349
         System.out.println(qspec.printSQL(useXMLIndex));
350

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

    
390
  /**
391
   * method to set the identifier of this query
392
   */
393
  public void setIdentifier(String id) {
394
    this.meta_file_id = id;
395
  }
396

    
397
  /**
398
   * Accessor method to return the title of this Query
399
   */
400
  public String getQueryTitle()
401
  {
402
    return queryTitle;
403
  }
404

    
405
  /**
406
   * method to set the title of this query
407
   */
408
  public void setQueryTitle(String title)
409
  {
410
    this.queryTitle = title;
411
  }
412

    
413
  /**
414
   * Accessor method to return a vector of the return document types as
415
   * defined in the &lt;returndoctype&gt; tag in the pathquery dtd.
416
   */
417
  public Vector getReturnDocList()
418
  {
419
    return this.returnDocList;
420
  }
421

    
422
  /**
423
   * method to set the list of return docs of this query
424
   */
425
  public void setReturnDocList(Vector returnDocList)
426
  {
427
    this.returnDocList = returnDocList;
428
  }
429

    
430
  /**
431
   * Accessor method to return a vector of the filter doc types as
432
   * defined in the &lt;filterdoctype&gt; tag in the pathquery dtd.
433
   */
434
  public Vector getFilterDocList()
435
  {
436
    return this.filterDocList;
437
  }
438

    
439
  /**
440
   * method to set the list of filter docs of this query
441
   */
442
  public void setFilterDocList(Vector filterDocList)
443
  {
444
    this.filterDocList = filterDocList;
445
  }
446

    
447
  /**
448
   * Accessor method to return a vector of the extended return fields as
449
   * defined in the &lt;returnfield&gt; tag in the pathquery dtd.
450
   */
451
  public Vector getReturnFieldList()
452
  {
453
    return this.returnFieldList; 
454
  }
455

    
456
  /**
457
   * method to set the list of fields to be returned by this query
458
   */
459
  public void setReturnFieldList(Vector returnFieldList)
460
  {
461
    this.returnFieldList = returnFieldList;
462
  }
463

    
464
  /**
465
   * Accessor method to return a vector of the owner fields as
466
   * defined in the &lt;owner&gt; tag in the pathquery dtd.
467
   */
468
  public Vector getOwnerList()
469
  {
470
    return this.ownerList;
471
  }
472

    
473
  /**
474
   * method to set the list of owners used to constrain this query
475
   */
476
  public void setOwnerList(Vector ownerList)
477
  {
478
    this.ownerList = ownerList;
479
  }
480

    
481
  /**
482
   * Accessor method to return a vector of the site fields as
483
   * defined in the &lt;site&gt; tag in the pathquery dtd.
484
   */
485
  public Vector getSiteList()
486
  {
487
    return this.siteList;
488
  }
489

    
490
  /**
491
   * method to set the list of sites used to constrain this query
492
   */
493
  public void setSiteList(Vector siteList)
494
  {
495
    this.siteList = siteList;
496
  }
497

    
498
  /**
499
   * get the QueryGroup used to express query constraints
500
   */
501
  public QueryGroup getQueryGroup()
502
  {
503
    return query;
504
  }
505
  
506
  /**
507
   * set the querygroup
508
   */
509
  public void setQueryGroup(QueryGroup group)
510
  {
511
    query = group;
512
  }
513
  
514
  /**
515
   * set if this query sepcification has extendQuery(has return doc type or not)
516
   */
517
  public void setContainsExtenedSQL(boolean hasExtenedQuery)
518
  {
519
     containsExtendedSQL = hasExtenedQuery;
520
  }  
521
   
522
  /**
523
   * Set up the SAX parser for reading the XML serialized query
524
   */
525
  private XMLReader initializeParser() {
526
    XMLReader parser = null;
527

    
528
    // Set up the SAX document handlers for parsing
529
    try {
530

    
531
      // Get an instance of the parser
532
      parser = XMLReaderFactory.createXMLReader(parserName);
533

    
534
      // Set the ContentHandler to this instance
535
      parser.setContentHandler(this);
536

    
537
      // Set the error Handler to this instance
538
      parser.setErrorHandler(this);
539

    
540
    } catch (Exception e) {
541
       System.err.println("Error in QuerySpcecification.initializeParser " + 
542
                           e.toString());
543
    }
544

    
545
    return parser;
546
  }
547

    
548
  /**
549
   * callback method used by the SAX Parser when the start tag of an 
550
   * element is detected. Used in this context to parse and store
551
   * the query information in class variables.
552
   */
553
  public void startElement (String uri, String localName, 
554
                            String qName, Attributes atts) 
555
         throws SAXException {
556
    BasicNode currentNode = new BasicNode(localName);
557
    // add attributes to BasicNode here
558
    if (atts != null) {
559
      int len = atts.getLength();
560
      for (int i = 0; i < len; i++) {
561
        currentNode.setAttribute(atts.getLocalName(i), atts.getValue(i));
562
      }
563
    }
564

    
565
    elementStack.push(currentNode); 
566
    if (currentNode.getTagName().equals("querygroup")) {
567
      QueryGroup currentGroup = new QueryGroup(
568
                                currentNode.getAttribute("operator"));
569
      if (query == null) {
570
        query = currentGroup;
571
      } else {
572
        QueryGroup parentGroup = (QueryGroup)queryStack.peek();
573
        parentGroup.addChild(currentGroup);
574
      }
575
      queryStack.push(currentGroup);
576
    }
577
  }
578

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

    
608
  /**
609
   * callback method used by the SAX Parser when the text sequences of an 
610
   * xml stream are detected. Used in this context to parse and store
611
   * the query information in class variables.
612
   */
613
  public void characters(char ch[], int start, int length) {
614

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

    
682
    self.append("SELECT docid,docname,doctype,");
683
    self.append("date_created, date_updated, rev ");
684
    self.append("FROM xml_documents WHERE docid IN (");
685

    
686
    // This determines the documents that meet the query conditions
687
    self.append(query.printSQL(useXMLIndex));
688

    
689
    self.append(") ");
690
 
691
    // Add SQL to filter for doctypes requested in the query
692
    // This is an implicit OR for the list of doctypes. Only doctypes in this
693
    // list will be searched if the tag is present
694
    if (!filterDocList.isEmpty()) {
695
      boolean firstdoctype = true;
696
      self.append(" AND ("); 
697
      Enumeration en = filterDocList.elements();
698
      while (en.hasMoreElements()) {
699
        String currentDoctype = (String)en.nextElement();
700
        if (firstdoctype) {
701
           firstdoctype = false;
702
           self.append(" doctype = '" + currentDoctype + "'"); 
703
        } else {
704
          self.append(" OR doctype = '" + currentDoctype + "'"); 
705
        }
706
      }
707
      self.append(") ");
708
    }
709

    
710
    // Add SQL to filter for owners requested in the query
711
    // This is an implicit OR for the list of owners
712
    if (!ownerList.isEmpty()) {
713
      boolean first = true;
714
      self.append(" AND ("); 
715
      Enumeration en = ownerList.elements();
716
      while (en.hasMoreElements()) {
717
        String current = (String)en.nextElement();
718
        if (first) {
719
           first = false;
720
           self.append(" user_owner = '" + current + "'"); 
721
        } else {
722
          self.append(" OR user_owner = '" + current + "'"); 
723
        }
724
      }
725
      self.append(") ");
726
    }
727

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

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

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

    
1060
 
1061
}
(48-48/58)