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
 *
11
 *   '$Author: tao $'
12
 *     '$Date: 2008-03-17 18:51:28 -0700 (Mon, 17 Mar 2008) $'
13
 * '$Revision: 3766 $'
14
 *
15
 * This program is free software; you can redistribute it and/or modify
16
 * it under the terms of the GNU General Public License as published by
17
 * the Free Software Foundation; either version 2 of the License, or
18
 * (at your option) any later version.
19
 *
20
 * This program is distributed in the hope that it will be useful,
21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
 * GNU General Public License for more details.
24
 *
25
 * You should have received a copy of the GNU General Public License
26
 * along with this program; if not, write to the Free Software
27
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28
 */
29

    
30
package edu.ucsb.nceas.metacat;
31

    
32
import java.io.IOException;
33
import java.io.Reader;
34
import java.io.StringReader;
35
import java.util.Enumeration;
36
import java.util.Hashtable;
37
import java.util.Stack;
38
import java.util.Vector;
39

    
40
import edu.ucsb.nceas.dbadapter.AbstractDatabase;
41

    
42
import org.apache.log4j.Logger;
43
import org.xml.sax.Attributes;
44
import org.xml.sax.InputSource;
45
import org.xml.sax.SAXException;
46
import org.xml.sax.XMLReader;
47
import org.xml.sax.helpers.DefaultHandler;
48
import org.xml.sax.helpers.XMLReaderFactory;
49
import java.util.Iterator;
50

    
51
/**
52
 * A Class that represents a structured query, and can be constructed from an
53
 * XML serialization conforming to
54
 *
55
 * @see pathquery.dtd. The printSQL() method can be used to print a SQL
56
 *      serialization of the query.
57
 */
58
public class QuerySpecification extends DefaultHandler
59
{
60

    
61
    /** flag determining whether extended query terms are present */
62
    private boolean containsExtendedSQL = false;
63

    
64
    /** flag determining whether predicates are present */
65
    private boolean containsPredicates = false;
66

    
67
    /** Identifier for this query document */
68
    private String meta_file_id;
69

    
70
    /** Title of this query */
71
    private String queryTitle;
72

    
73
    /** List of document types to be returned using package back tracing */
74
    private Vector returnDocList;
75

    
76
    /** List of document types to be searched */
77
    private Vector filterDocList;
78

    
79
    /** List of fields to be returned in result set */
80
    private Vector returnFieldList;
81

    
82
    /** List of users owning documents to be searched */
83
    private Vector ownerList;
84

    
85
    /** The root query group that contains the recursive query constraints */
86
    private QueryGroup query = null;
87
    
88
    /** A string buffer to stored normalized query (Sometimes, the query have 
89
     * a value like "&", it will cause problem in html transform). So we need a
90
     * normalized query xml string.
91
     */
92
    private StringBuffer xml = new StringBuffer();
93

    
94
    // Query data structures used temporarily during XML parsing
95
    private Stack elementStack;
96

    
97
    private Stack queryStack;
98

    
99
    private String currentValue;
100

    
101
    private String currentPathexpr;
102

    
103
    private String parserName = null;
104

    
105
    private String accNumberSeparator = null;
106

    
107
    private static final AbstractDatabase dbAdapter = MetaCatUtil.dbAdapter;
108

    
109
    private boolean percentageSearch = false;
110

    
111
    private String userName = null;
112

    
113
    private static final String PUBLIC = "public";
114

    
115
    private String[] group = null;
116

    
117
    public static final String ATTRIBUTESYMBOL = "@";
118

    
119
    public static final char PREDICATE_START = '[';
120

    
121
    public static final char PREDICATE_END = ']';
122

    
123
    //private boolean hasAttributeReturnField = false;
124

    
125
    //private Hashtable attributeReturnList = new Hashtable();
126

    
127
    //private int countAttributeReturnField = 0;
128

    
129
    private StringBuffer textBuffer = new StringBuffer();
130
    
131
   
132
    private static Logger logMetacat = Logger.getLogger(QuerySpecification.class);
133

    
134
    /**
135
     * construct an instance of the QuerySpecification class
136
     *
137
     * @param queryspec
138
     *            the XML representation of the query (should conform to
139
     *            pathquery.dtd) as a Reader
140
     * @param parserName
141
     *            the fully qualified name of a Java Class implementing the
142
     *            org.xml.sax.XMLReader interface
143
     */
144
    public QuerySpecification(Reader queryspec, String parserName,
145
            String accNumberSeparator) throws IOException
146
    {
147
        super();
148

    
149
        // Initialize the class variables
150
        returnDocList = new Vector();
151
        filterDocList = new Vector();
152
        elementStack = new Stack();
153
        queryStack = new Stack();
154
        returnFieldList = new Vector();
155
        ownerList = new Vector();
156
        this.parserName = parserName;
157
        this.accNumberSeparator = accNumberSeparator;
158

    
159
        // Initialize the parser and read the queryspec
160
        XMLReader parser = initializeParser();
161
        if (parser == null) {
162
            System.err.println("SAX parser not instantiated properly.");
163
        }
164
        try {
165
            parser.parse(new InputSource(queryspec));
166
        } catch (SAXException e) {
167
            System.err.println("error parsing data in "
168
                    + "QuerySpecification.QuerySpecification");
169
            System.err.println(e.getMessage());
170
        }
171
    }
172

    
173
    /**
174
     * construct an instance of the QuerySpecification class
175
     *
176
     * @param queryspec
177
     *            the XML representation of the query (should conform to
178
     *            pathquery.dtd) as a String
179
     * @param parserName
180
     *            the fully qualified name of a Java Class implementing the
181
     *            org.xml.sax.Parser interface
182
     */
183
    public QuerySpecification(String queryspec, String parserName,
184
            String accNumberSeparator) throws IOException
185
    {
186
        this(new StringReader(queryspec), parserName, accNumberSeparator);
187
    }
188

    
189
    /**
190
     * construct an instance of the QuerySpecification class which don't need
191
     * to parser a xml document
192
     *
193
     * @param accNumberSeparator
194
     *            the separator between doc version
195
     */
196
    public QuerySpecification(String accNumberSeparator) throws IOException
197
    {
198
        // Initialize the class variables
199
        returnDocList = new Vector();
200
        filterDocList = new Vector();
201
        elementStack = new Stack();
202
        queryStack = new Stack();
203
        returnFieldList = new Vector();
204
        ownerList = new Vector();
205
        this.accNumberSeparator = accNumberSeparator;
206
    }
207

    
208
    /**
209
     * Method to set user name
210
     *
211
     * @param myName
212
     *            the user name
213
     */
214
    public void setUserName(String myName)
215
    {
216
        //to lower case
217
        if (myName != null) {
218
            this.userName = myName.toLowerCase();
219
        } else {
220
            this.userName = myName;
221
        }
222
    }
223

    
224
    /**
225
     * Method to set user group
226
     *
227
     * @param myGroup
228
     *            the user group
229
     */
230
    public void setGroup(String[] myGroup)
231
    {
232
        this.group = myGroup;
233
    }
234

    
235
    /**
236
     * Method to indicate this query is a percentage search
237
     */
238
    public boolean isPercentageSearch()
239
    {
240
        return percentageSearch;
241
    }
242

    
243
    /*
244
     * Method to get owner query. If it is owner it has all permission
245
     */
246
    private String createOwerQuery()
247
    {
248
        String ownerQuery = null;
249
        //if user is public, we don't need to run owner query
250
        if (userName != null && !userName.equalsIgnoreCase(PUBLIC))
251
        {
252
	        ownerQuery = "SELECT docid FROM xml_documents WHERE ";
253
	        if (userName != null && !userName.equals("")) {
254
	            ownerQuery = ownerQuery + "lower(user_owner) ='" + userName + "'";
255
	        }
256
        }
257
        logMetacat.info("OwnerQuery: " + ownerQuery);
258
        return ownerQuery;
259
    }
260

    
261
    /*
262
     * Method to create query for xml_access, this part is to get docid list
263
     * which have a allow rule for a given user
264
     */
265
    private String createAllowRuleQuery()
266
    {
267
        String allowQuery = null;
268
        String allowString = constructAllowString();
269
        allowQuery = "SELECT docid from xml_access WHERE( " + allowString;
270
        allowQuery = allowQuery + ")";
271
        logMetacat.info("allow query is: " + allowQuery);
272
        return allowQuery;
273

    
274
    }
275

    
276
    /* Method to construct a allow rule string */
277
    private String constructAllowString()
278
    {
279
        String allowQuery = "";
280
        
281
       // add public
282
        allowQuery = "(lower(principal_name) = '" + PUBLIC
283
                + "'";
284
                
285
        // add user name
286
        if (userName != null && !userName.equals("") && !userName.equalsIgnoreCase(PUBLIC)) {
287
            allowQuery = allowQuery + "OR lower(principal_name) = '" + userName +"'";
288
                    
289
        }
290
        // add  group
291
        if (group != null) {
292
            for (int i = 0; i < group.length; i++) {
293
                String groupUint = group[i];
294
                if (groupUint != null && !groupUint.equals("")) {
295
                    groupUint = groupUint.toLowerCase();
296
                    allowQuery = allowQuery + " OR lower(principal_name) = '"
297
                            + groupUint + "'";
298
                }//if
299
            }//for
300
        }//if
301
        // add allow rule
302
        allowQuery = allowQuery + ") AND perm_type = 'allow'" + " AND permission > 3";
303
        logMetacat.info("allow string is: " + allowQuery);
304
        return allowQuery;
305
    }
306

    
307
    /*
308
     * Method to create query for xml_access, this part is to get docid list
309
     * which have a deny rule and perm_order is allowFirst for a given user.
310
     * This means the user will be denied to read
311
     */
312
    private String createDenyRuleQuery()
313
    {
314
        String denyQuery = null;
315
        String denyString = constructDenyString();
316
        denyQuery = "SELECT docid from xml_access WHERE( " + denyString;
317
        denyQuery = denyQuery + ") ";
318
        logMetacat.info("denyquery is: " + denyQuery);
319
        return denyQuery;
320

    
321
    }
322

    
323
    /* Construct deny string */
324
    private String constructDenyString()
325
    {
326
        String denyQuery = "";
327
         
328
        // add public
329
        denyQuery = "(lower(principal_name) = '" + PUBLIC
330
                 + "'";
331
                 
332
         // add user name
333
         if (userName != null && !userName.equals("") && !userName.equalsIgnoreCase(PUBLIC)) {
334
        	 denyQuery = denyQuery + "OR lower(principal_name) = '" + userName +"'";
335
                     
336
         }
337
         // add  groups
338
         if (group != null) {
339
             for (int i = 0; i < group.length; i++) {
340
                 String groupUint = group[i];
341
                 if (groupUint != null && !groupUint.equals("")) {
342
                     groupUint = groupUint.toLowerCase();
343
                     denyQuery = denyQuery + " OR lower(principal_name) = '"
344
                             + groupUint + "'";
345
                 }//if
346
             }//for
347
         }//if
348
         // add deny rules
349
         denyQuery = denyQuery + ") AND perm_type = 'deny'" +  " AND perm_order ='allowFirst'" +" AND permission > 3";
350
         logMetacat.info("allow string is: " + denyQuery);
351
         return denyQuery;
352
        
353
    }
354

    
355
    /**
356
     * Method to append a access control query to SQL. So in DBQuery class, we
357
     * can get docid from both user specified query and access control query.
358
     * We don't need to checking permission after we get the doclist. It will
359
     * be good to performance
360
     *
361
     */
362
    public String getAccessQuery()
363
    {
364
        String accessQuery = null;
365
        String onwer = createOwerQuery();
366
        String allow = createAllowRuleQuery();
367
        String deny = createDenyRuleQuery();
368
        //logMetacat.warn("onwer " +onwer);
369
        //logMetacat.warn("allow "+allow);
370
        //logMetacat.warn("deny "+deny);
371
        if (onwer != null)
372
        {
373
          accessQuery = " AND (docid IN(" + onwer + ")";
374
          accessQuery = accessQuery + " OR (docid IN (" + allow + ")"
375
                + " AND docid NOT IN (" + deny + ")))";
376
        }
377
        else
378
        {
379
        	accessQuery = " AND (docid IN (" + allow + ")"
380
                + " AND docid NOT IN (" + deny + "))";
381
        }
382
        logMetacat.warn("accessquery is: " + accessQuery);
383
        return accessQuery;
384
    }
385

    
386
    /**
387
     * Returns true if the parsed query contains and extended xml query (i.e.
388
     * there is at least one &lt;returnfield&gt; in the pathquery document)
389
     */
390
    public boolean containsExtendedSQL()
391
    {
392
        if (containsExtendedSQL) {
393
            return true;
394
        } else {
395
            return false;
396
        }
397
    }
398

    
399
  
400
    /**
401
     * Accessor method to return the identifier of this Query
402
     */
403
    public String getIdentifier()
404
    {
405
        return meta_file_id;
406
    }
407

    
408
    /**
409
     * method to set the identifier of this query
410
     */
411
    public void setIdentifier(String id)
412
    {
413
        this.meta_file_id = id;
414
    }
415

    
416
    /**
417
     * Accessor method to return the title of this Query
418
     */
419
    public String getQueryTitle()
420
    {
421
        return queryTitle;
422
    }
423

    
424
    /**
425
     * method to set the title of this query
426
     */
427
    public void setQueryTitle(String title)
428
    {
429
        this.queryTitle = title;
430
    }
431

    
432
    /**
433
     * Accessor method to return a vector of the return document types as
434
     * defined in the &lt;returndoctype&gt; tag in the pathquery dtd.
435
     */
436
    public Vector getReturnDocList()
437
    {
438
        return this.returnDocList;
439
    }
440

    
441
    /**
442
     * method to set the list of return docs of this query
443
     */
444
    public void setReturnDocList(Vector returnDocList)
445
    {
446
        this.returnDocList = returnDocList;
447
    }
448

    
449
    /**
450
     * Accessor method to return a vector of the filter doc types as defined in
451
     * the &lt;filterdoctype&gt; tag in the pathquery dtd.
452
     */
453
    public Vector getFilterDocList()
454
    {
455
        return this.filterDocList;
456
    }
457

    
458
    /**
459
     * method to set the list of filter docs of this query
460
     */
461
    public void setFilterDocList(Vector filterDocList)
462
    {
463
        this.filterDocList = filterDocList;
464
    }
465

    
466
    /**
467
     * Accessor method to return a vector of the extended return fields as
468
     * defined in the &lt;returnfield&gt; tag in the pathquery dtd.
469
     */
470
    public Vector getReturnFieldList()
471
    {
472
        return this.returnFieldList;
473
    }
474

    
475
    /**
476
     * method to set the list of fields to be returned by this query
477
     */
478
    public void setReturnFieldList(Vector returnFieldList)
479
    {
480
        this.returnFieldList = returnFieldList;
481
    }
482

    
483
    /**
484
     * Accessor method to return a vector of the owner fields as defined in the
485
     * &lt;owner&gt; tag in the pathquery dtd.
486
     */
487
    public Vector getOwnerList()
488
    {
489
        return this.ownerList;
490
    }
491

    
492
    /**
493
     * method to set the list of owners used to constrain this query
494
     */
495
    public void setOwnerList(Vector ownerList)
496
    {
497
        this.ownerList = ownerList;
498
    }
499

    
500
    /**
501
     * get the QueryGroup used to express query constraints
502
     */
503
    public QueryGroup getQueryGroup()
504
    {
505
        return query;
506
    }
507

    
508
    /**
509
     * set the querygroup
510
     */
511
    public void setQueryGroup(QueryGroup group)
512
    {
513
        query = group;
514
    }
515

    
516
    /**
517
     * set if this query sepcification has extendQuery(has return doc type or
518
     * not)
519
     */
520
    public void setContainsExtenedSQL(boolean hasExtenedQuery)
521
    {
522
        containsExtendedSQL = hasExtenedQuery;
523
    }
524

    
525
    /**
526
     * Set up the SAX parser for reading the XML serialized query
527
     */
528
    private XMLReader initializeParser()
529
    {
530
        XMLReader parser = null;
531

    
532
        // Set up the SAX document handlers for parsing
533
        try {
534

    
535
            // Get an instance of the parser
536
            parser = XMLReaderFactory.createXMLReader(parserName);
537

    
538
            // Set the ContentHandler to this instance
539
            parser.setContentHandler(this);
540

    
541
            // Set the error Handler to this instance
542
            parser.setErrorHandler(this);
543

    
544
        } catch (Exception e) {
545
            System.err.println("Error in QuerySpcecification.initializeParser "
546
                    + e.toString());
547
        }
548

    
549
        return parser;
550
    }
551

    
552
    /**
553
     * callback method used by the SAX Parser when the start tag of an element
554
     * is detected. Used in this context to parse and store the query
555
     * information in class variables.
556
     */
557
    public void startElement(String uri, String localName, String qName,
558
            Attributes atts) throws SAXException
559
    {
560
        logMetacat.debug("start at startElement "+localName);
561
        BasicNode currentNode = new BasicNode(localName);
562
        //write element name into xml buffer.
563
        xml.append("<");
564
        xml.append(localName);
565
        // add attributes to BasicNode here
566
        if (atts != null) {
567
            int len = atts.getLength();
568
            for (int i = 0; i < len; i++) {
569
                currentNode
570
                        .setAttribute(atts.getLocalName(i), atts.getValue(i));
571
                xml.append(" ");
572
                xml.append(atts.getLocalName(i));
573
                xml.append("=\"");
574
                xml.append(atts.getValue(i));
575
                xml.append("\"");
576
            }
577
        }
578
        xml.append(">");
579

    
580
        elementStack.push(currentNode);
581
        if (currentNode.getTagName().equals("querygroup")) {
582
            QueryGroup currentGroup = new QueryGroup(currentNode
583
                    .getAttribute("operator"));
584
            if (query == null) {
585
                query = currentGroup;
586
            } else {
587
                QueryGroup parentGroup = (QueryGroup) queryStack.peek();
588
                parentGroup.addChild(currentGroup);
589
            }
590
            queryStack.push(currentGroup);
591
        }
592
        logMetacat.debug("end in startElement "+localName);
593
    }
594

    
595
    /**
596
     * callback method used by the SAX Parser when the end tag of an element is
597
     * detected. Used in this context to parse and store the query information
598
     * in class variables.
599
     */
600
    public void endElement(String uri, String localName, String qName)
601
            throws SAXException
602
    {
603
    	 logMetacat.debug("start in endElement "+localName);
604
        BasicNode leaving = (BasicNode) elementStack.pop();
605
        if (leaving.getTagName().equals("queryterm")) {
606
            boolean isCaseSensitive = (new Boolean(leaving
607
                    .getAttribute("casesensitive"))).booleanValue();
608
            QueryTerm currentTerm = null;
609
            if (currentPathexpr == null) {
610
                currentTerm = new QueryTerm(isCaseSensitive, leaving
611
                        .getAttribute("searchmode"), currentValue);
612
            } else {
613
                currentTerm = new QueryTerm(isCaseSensitive, leaving
614
                        .getAttribute("searchmode"), currentValue,
615
                        currentPathexpr);
616
            }
617
            QueryGroup currentGroup = (QueryGroup) queryStack.peek();
618
            currentGroup.addChild(currentTerm);
619
            currentValue = null;
620
            currentPathexpr = null;
621
        } else if (leaving.getTagName().equals("querygroup")) {
622
            QueryGroup leavingGroup = (QueryGroup) queryStack.pop();
623
        } else if (leaving.getTagName().equals("meta_file_id")) {
624
              meta_file_id = textBuffer.toString().trim();
625
        } else if (leaving.getTagName().equals("querytitle")) {
626
              queryTitle = textBuffer.toString().trim();
627
        } else if (leaving.getTagName().equals("value")) {
628
              currentValue = textBuffer.toString().trim();
629
              currentValue = MetaCatUtil.normalize(currentValue);
630
        } else if (leaving.getTagName().equals("pathexpr")) {
631
              currentPathexpr = textBuffer.toString().trim();
632
        } else if (leaving.getTagName().equals("returndoctype")) {
633
              returnDocList.add(textBuffer.toString().trim());
634
        } else if (leaving.getTagName().equals("filterdoctype")) {
635
              filterDocList.add(textBuffer.toString().trim());
636
        } else if (leaving.getTagName().equals("returnfield")) {
637
              handleReturnField(textBuffer.toString().trim());
638
        } else if (leaving.getTagName().equals("filterdoctype")) {
639
              filterDocList.add(textBuffer.toString().trim());
640
        } else if (leaving.getTagName().equals("owner")) {
641
              ownerList.add(textBuffer.toString().trim());
642
        }
643
        String normalizedXML = textBuffer.toString().trim();
644
        logMetacat.debug("================before normailze "+normalizedXML);
645
        normalizedXML =  MetaCatUtil.normalize(normalizedXML);
646
        logMetacat.debug("================after normailze "+normalizedXML);
647
        xml.append(normalizedXML);
648
        xml.append("</");
649
        xml.append(localName);
650
        xml.append(">");
651
        //rest textBuffer
652
        textBuffer = new StringBuffer();
653

    
654
    }
655
    
656
    /**
657
     * Gets normailized query string in xml format, which can be transformed
658
     * to html
659
     */
660
    public String getNormalizedXMLQuery()
661
    {
662
    	//System.out.println("normailized xml \n"+xml.toString());
663
    	return xml.toString();
664
    }
665
    
666

    
667
    /**
668
     * callback method used by the SAX Parser when the text sequences of an xml
669
     * stream are detected. Used in this context to parse and store the query
670
     * information in class variables.
671
     */
672
    public void characters(char ch[], int start, int length)
673
    {
674
      // buffer all text nodes for same element. This is for text was splited
675
      // into different nodes
676
      String text = new String(ch, start, length);
677
      logMetacat.debug("the text in characters "+text);
678
      textBuffer.append(text);
679

    
680
    }
681

    
682
   /**
683
    * Method to handle return field. It will be callied in ecogrid part
684
    * @param inputString
685
    */
686
    public void handleReturnField(String inputString)
687
    {
688
        int attributePos = inputString.indexOf(ATTRIBUTESYMBOL);
689
        int predicateStart = -1;
690
        int predicateEnd;
691
        boolean hasPredicate = false;
692

    
693
        while (true)
694
        {
695
            predicateStart = inputString.indexOf(PREDICATE_START, predicateStart + 1);
696

    
697
            if (attributePos == -1)
698
                break;
699

    
700
            if (predicateStart == -1)
701
                break;
702

    
703
            hasPredicate = true;
704

    
705
            if (attributePos < predicateStart)
706
                break;
707

    
708
            predicateEnd = inputString.indexOf(PREDICATE_END, predicateStart);
709

    
710
            if (predicateEnd == -1)
711
            {
712
                logMetacat.warn("handleReturnField(): ");
713
                logMetacat.warn("    Invalid path: " + inputString);
714
                return;
715
            }
716

    
717
            while (attributePos < predicateEnd)
718
            {
719
                attributePos = inputString.indexOf(ATTRIBUTESYMBOL, attributePos + 1);
720

    
721
                if (attributePos == -1)
722
                    break;
723
            }
724
        }
725

    
726
        if (hasPredicate)
727
            containsPredicates = true;
728

    
729
        containsExtendedSQL = true;
730

    
731
     
732
            // no attribute value will be returned
733
            logMetacat.info("QuerySpecification.handleReturnField(): " );
734
            logMetacat.info("  there are no attributes in the XPATH statement" );
735
            returnFieldList.add(inputString);
736
       
737

    
738
       
739
    }
740

    
741
    /**
742
     * create a SQL serialization of the query that this instance represents
743
     */
744
    public String printSQL(boolean useXMLIndex)
745
    {
746

    
747
        StringBuffer self = new StringBuffer();
748
        StringBuffer queryString = new StringBuffer();
749

    
750
        queryString.append("SELECT docid,docname,doctype,");
751
        queryString.append("date_created, date_updated, rev ");
752
        queryString.append("FROM xml_documents WHERE");
753

    
754
        // Get the query from the QueryGroup and check
755
        // if no query has been returned
756
        String queryFromQueryGroup = query.printSQL(useXMLIndex);
757
        logMetacat.info("Query from query in QuerySpec.printSQL: " 
758
        		+ queryFromQueryGroup);
759
        
760
        if(!queryFromQueryGroup.trim().equals("")){
761
            self.append(" docid IN (");
762
            self.append(queryFromQueryGroup);
763
            self.append(") ");
764
        }
765

    
766
        // Add SQL to filter for doctypes requested in the query
767
        // This is an implicit OR for the list of doctypes. Only doctypes in
768
        // this
769
        // list will be searched if the tag is present
770
        if (!filterDocList.isEmpty()) {
771
            boolean firstdoctype = true;
772
            boolean emptyString = true;
773

    
774
            if(!self.toString().equals("")){
775
                self.append(" AND (");
776
                emptyString = false;
777
            }
778

    
779
            Enumeration en = filterDocList.elements();
780
            while (en.hasMoreElements()) {
781
                String currentDoctype = (String) en.nextElement();
782
                if (firstdoctype) {
783
                    firstdoctype = false;
784
                    self.append(" doctype = '" + currentDoctype + "'");
785
                } else {
786
                    self.append(" OR doctype = '" + currentDoctype + "'");
787
                }
788
            }
789

    
790
            if(!emptyString){
791
                self.append(") ");
792
            }
793
        }
794

    
795
        // Add SQL to filter for owners requested in the query
796
        // This is an implicit OR for the list of owners
797
        if (!ownerList.isEmpty()) {
798
            boolean first = true;
799
            boolean emptyString = true;
800

    
801
            if(!self.toString().equals("")){
802
                self.append(" AND (");
803
                emptyString = false;
804
            }
805

    
806
            Enumeration en = ownerList.elements();
807
            while (en.hasMoreElements()) {
808
                String current = (String) en.nextElement();
809
                if (current != null) {
810
                    current = current.toLowerCase();
811
                }
812
                if (first) {
813
                    first = false;
814
                    self.append(" lower(user_owner) = '" + current + "'");
815
                } else {
816
                    self.append(" OR lower(user_owner) = '" + current + "'");
817
                }
818
            }
819

    
820
            if(!emptyString){
821
                self.append(") ");
822
            }
823
        }
824

    
825
        // if there is only one percentage search item, this query is a
826
        // percentage
827
        // search query
828
        logMetacat.info("percentage number: "
829
                + query.getPercentageSymbolCount());
830
        if (query.getPercentageSymbolCount() == 1) {
831
            logMetacat.info("It is a percentage search");
832
            percentageSearch = true;
833
        }
834

    
835
        queryString.append(self.toString());
836
        return queryString.toString();
837
    }
838

    
839
   
840

    
841
    /**
842
     * This method prints sql based upon the &lt;returnfield&gt; tag in the
843
     * pathquery document. This allows for customization of the returned fields.
844
     * If the boolean useXMLIndex paramter is false, it uses a recursive query on
845
     * xml_nodes to find the fields to be included by their path expression, and
846
     * avoids the use of the xml_index table.
847
     *
848
     * @param doclist the list of document ids to search
849
     * @param unaccessableNodePair the node pairs (start id and end id) which
850
     *            this user should not access
851
     * @param useXMLIndex a boolean flag indicating whether to search using
852
     *            xml_index
853
     */
854
    public String printExtendedSQL(String doclist, boolean useXMLIndex)
855
    {
856
        if (useXMLIndex && !containsPredicates)
857
        {
858
            return printExtendedSQL(doclist);
859
        }
860
        else
861
        {
862
            StringBuffer self = new StringBuffer();
863

    
864
            boolean firstfield = true;
865
            //put the returnfields into the query
866
            //the for loop allows for multiple fields
867
            for (int i = 0; i < returnFieldList.size(); i++)
868
            {
869
                if (firstfield)
870
                {
871
                    firstfield = false;
872
                }
873
                else
874
                {
875
                    self.append(" UNION ");
876
                }
877
                String path  = (String) returnFieldList.elementAt(i);
878
                self.append("select xml_nodes.docid, ");
879
                self.append("'"+ path.replaceAll("'", "''") + "' as path, ");
880
                self.append("xml_nodes.nodedata, ");
881
                self.append("xml_nodes.parentnodeid, ");
882
                self.append("xml_nodes.nodetype ");
883
                self.append("from xml_nodes, xml_documents ");
884
                self.append("where parentnodeid IN ");
885
                self.append(QueryTerm.useNestedStatements(path));
886

    
887
                self.append(" AND xml_nodes.docid in (");
888
                self.append(doclist);
889
                self.append(") AND xml_nodes.nodetype = 'TEXT'");
890
                self.append(" AND xml_nodes.rootnodeid = xml_documents.rootnodeid");
891

    
892
                //addAccessRestrictionSQL(unaccessableNodePair, self);
893
            }
894

    
895
            return self.toString();
896
        }
897
    }
898

    
899
    /**
900
     * This method prints sql based upon the &lt;returnfield&gt; tag in the
901
     * pathquery document. This allows for customization of the returned fields.
902
     * It uses the xml_index table and so assumes that this table has been
903
     * built.
904
     *
905
     * @param doclist the list of document ids to search
906
     * @param unaccessableNodePair the node pairs (start id and end id)
907
     *            which this user should not access
908
     */
909
    private String printExtendedSQL(String doclist)
910
    {
911
        logMetacat.info("querySpecification.printExtendedSQL called\n");
912
        StringBuffer self = new StringBuffer();
913
        Vector elementVector = new Vector();
914
        Vector attributeVector = new Vector();
915

    
916
        boolean usePathIndex = true;
917

    
918
        // test if the are elements in the return fields
919
        if ( returnFieldList.size() == 0 ) {
920
            return null;
921
        }
922

    
923
        for (int i = 0; i < returnFieldList.size(); i++) {
924
        	String path = (String)returnFieldList.elementAt(i);
925
        	if (path != null && path.indexOf(ATTRIBUTESYMBOL) != -1)
926
        	{
927
        		attributeVector.add(path);
928
        	}
929
        	else 
930
        	{
931
        		elementVector.add(path);
932
        	}       	
933
            if(!MetaCatUtil.pathsForIndexing.contains(path)){
934
                usePathIndex = false;              
935
            }
936
         
937
        }
938
        // check if has return field
939
        if (elementVector.size() == 0 && attributeVector.size()==0)
940
        {
941
        	return null;
942
        }
943

    
944
        if(usePathIndex){
945
            self.append("select docid, path, nodedata, parentnodeid, null as nodetype ");
946
            self.append("from xml_path_index where path in( '");
947

    
948
            boolean firstfield = true;
949
            //put the returnfields into the query
950
            //the for loop allows for multiple fields
951
            for (int i = 0; i < returnFieldList.size(); i++) {
952
                if (firstfield) {
953
                    firstfield = false;
954
                    self.append( (String) returnFieldList.elementAt(i));
955
                    self.append("' ");
956
                }
957
                else {
958
                    self.append(", '");
959
                    self.append( (String) returnFieldList.elementAt(i));
960
                    self.append("' ");
961
                }
962
            }
963
            self.append(") AND docid in (");
964
            self.append(doclist);
965
            self.append(")");
966

    
967
        } else {
968
            self.append("select xml_nodes.docid, xml_index.path, xml_nodes.nodedata,  ");
969
            self.append("xml_nodes.parentnodeid, ");
970
            self.append("xml_nodes.nodetype ");
971
            self.append("FROM xml_index, xml_nodes WHERE (");
972
           
973

    
974
            boolean firstElement = true;
975
            boolean firstAttribute = true;
976
            //put the returnfields into the query
977
            //the for loop allows for multiple fields
978
            if (elementVector.size() != 0)
979
            {
980
	            for (int i = 0; i < elementVector.size(); i++) {
981
	            	String path = (String) elementVector.elementAt(i);
982
	                if (firstElement) {
983
	                	firstElement = false;
984
	                	self.append(" (xml_index.nodeid=xml_nodes.parentnodeid AND xml_index.path IN ('");
985
	                    self.append(path);
986
	                    self.append("'");
987
	                 }
988
	                else 
989
	                {
990
	                    self.append(", '");
991
	                    self.append(path);
992
	                    self.append("' ");
993
	                }
994
	            }
995
	            self.append(") AND xml_nodes.nodetype = 'TEXT')");
996
            }
997
            
998
            if (attributeVector.size() != 0)
999
            {
1000
            	for (int j=0; j<attributeVector.size(); j++)
1001
            	{
1002
            		String path = (String) attributeVector.elementAt(j);
1003
            		if (firstAttribute)
1004
            		{
1005
            			firstAttribute = false;
1006
            			if (!firstElement)
1007
                		{
1008
                			self.append(" OR ");
1009
                		}
1010
            			self.append(" (xml_index.nodeid=xml_nodes.nodeid AND ( xml_index.path IN ( '");
1011
	                    self.append(path);
1012
	                    self.append("'");
1013
            		}
1014
            		else 
1015
	                {
1016
	                    self.append(", '");
1017
	                    self.append(path);
1018
	                    self.append("' ");
1019
	                }
1020
            	}
1021
            	self.append(") AND xml_nodes.nodetype = 'ATTRIBUTE'))");
1022
            }
1023
            
1024
          
1025
            self.append(") AND xml_nodes.docid in (");
1026
            self.append(doclist);
1027
            self.append(")");
1028

    
1029
        }
1030

    
1031
        return self.toString();
1032
    }
1033

    
1034

    
1035
    /**
1036
     * Method to return a String generated after sorting the returnFieldList
1037
     * Vector
1038
     */
1039
    public String getSortedReturnFieldString(){
1040
        String returnFields = "";
1041

    
1042
        // Create a temporary vector and copy returnFieldList into it
1043
        Vector tempVector = new Vector();
1044

    
1045
        Iterator it = returnFieldList.iterator();
1046
        while(it.hasNext()){
1047
            tempVector.add(it.next());
1048
        }
1049

    
1050
        /*Enumeration attEnum = attributeReturnList.elements();
1051
        while(attEnum.hasMoreElements()){
1052
            Iterator tempIt = ((Vector)attEnum.nextElement()).iterator();
1053
	    String rfield = "";
1054
            if(tempIt.hasNext()){
1055
		String element = (String)tempIt.next();
1056
		if(element != null) {
1057
		    rfield +=element;
1058
		}
1059
	    }
1060
            if(tempIt.hasNext()){
1061
		String attribute = (String)tempIt.next();
1062
		if(attribute != null) {
1063
  		    rfield = rfield + "@" + attribute;
1064
                }
1065
	    }
1066
            tempVector.add(rfield);
1067
        }*/
1068

    
1069
        // Sort the temporary vector
1070
        java.util.Collections.sort(tempVector);
1071

    
1072
        // Generate the string and return it
1073
        it = tempVector.iterator();
1074
        while(it.hasNext()){
1075
            returnFields = returnFields + it.next() + "|";
1076
        }
1077
        return returnFields;
1078
    }
1079

    
1080

    
1081
  
1082

    
1083

    
1084
    public static String printRelationSQL(String docid)
1085
    {
1086
        StringBuffer self = new StringBuffer();
1087
        self.append("select subject, relationship, object, subdoctype, ");
1088
        self.append("objdoctype from xml_relation ");
1089
        self.append("where docid like '").append(docid).append("'");
1090
        return self.toString();
1091
    }
1092

    
1093
    public static String printGetDocByDoctypeSQL(String docid)
1094
    {
1095
        StringBuffer self = new StringBuffer();
1096

    
1097
        self.append("SELECT docid,docname,doctype,");
1098
        self.append("date_created, date_updated ");
1099
        self.append("FROM xml_documents WHERE docid IN (");
1100
        self.append(docid).append(")");
1101
        return self.toString();
1102
    }
1103

    
1104
    /**
1105
     * create a String description of the query that this instance represents.
1106
     * This should become a way to get the XML serialization of the query.
1107
     */
1108
    public String toString()
1109
    {
1110
        return "meta_file_id=" + meta_file_id + "\n" + query;
1111
        //DOCTITLE attr cleared from the db
1112
        //return "meta_file_id=" + meta_file_id + "\n" +
1113
        //"querytitle=" + querytitle + "\n" + query;
1114
    }
1115

    
1116
    /** A method to get rid of attribute part in path expression */
1117
    public static String newPathExpressionWithOutAttribute(String pathExpression)
1118
    {
1119
        if (pathExpression == null) { return null; }
1120
        int index = pathExpression.lastIndexOf(ATTRIBUTESYMBOL);
1121
        String newExpression = null;
1122
        if (index != 0) {
1123
            newExpression = pathExpression.substring(0, index - 1);
1124
        }
1125
        logMetacat.info("The path expression without attributes: "
1126
                + newExpression);
1127
        return newExpression;
1128
    }
1129

    
1130
    /** A method to get attribute name from path */
1131
    public static String getAttributeName(String path)
1132
    {
1133
        if (path == null) { return null; }
1134
        int index = path.lastIndexOf(ATTRIBUTESYMBOL);
1135
        int size = path.length();
1136
        String attributeName = null;
1137
        if (index != 1) {
1138
            attributeName = path.substring(index + 1, size);
1139
        }
1140
        logMetacat.info("The attirbute name from path: "
1141
                + attributeName);
1142
        return attributeName;
1143
    }
1144

    
1145
}
(52-52/64)