Project

General

Profile

1 155 jones
/**
2 203 jones
 *  '$RCSfile$'
3 2093 tao
 *    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 203 jones
 *             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 155 jones
 *
11 203 jones
 *   '$Author$'
12
 *     '$Date$'
13
 * '$Revision$'
14 669 jones
 *
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 155 jones
 */
29
30
package edu.ucsb.nceas.metacat;
31
32 2067 jones
import java.io.IOException;
33
import java.io.Reader;
34
import java.io.StringReader;
35
import java.util.Enumeration;
36 1354 tao
import java.util.Hashtable;
37 155 jones
import java.util.Stack;
38 158 jones
import java.util.Vector;
39 155 jones
40 2067 jones
import edu.ucsb.nceas.dbadapter.AbstractDatabase;
41
42 2663 sgarg
import org.apache.log4j.Logger;
43 185 jones
import org.xml.sax.Attributes;
44 158 jones
import org.xml.sax.InputSource;
45
import org.xml.sax.SAXException;
46 185 jones
import org.xml.sax.XMLReader;
47 2067 jones
import org.xml.sax.helpers.DefaultHandler;
48 185 jones
import org.xml.sax.helpers.XMLReaderFactory;
49 2419 sgarg
import java.util.Iterator;
50 155 jones
51 402 berkley
/**
52 2067 jones
 * A Class that represents a structured query, and can be constructed from an
53
 * XML serialization conforming to
54 2093 tao
 *
55 2067 jones
 * @see pathquery.dtd. The printSQL() method can be used to print a SQL
56
 *      serialization of the query.
57 155 jones
 */
58 2067 jones
public class QuerySpecification extends DefaultHandler
59
{
60 1832 tao
61 2067 jones
    /** flag determining whether extended query terms are present */
62
    private boolean containsExtendedSQL = false;
63 158 jones
64 3235 sledge
    /** flag determining whether predicates are present */
65
    private boolean containsPredicates = false;
66
67 2067 jones
    /** Identifier for this query document */
68
    private String meta_file_id;
69 158 jones
70 2067 jones
    /** 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
    // Query data structures used temporarily during XML parsing
89
    private Stack elementStack;
90
91
    private Stack queryStack;
92
93
    private String currentValue;
94
95
    private String currentPathexpr;
96
97
    private String parserName = null;
98
99
    private String accNumberSeparator = null;
100
101
    private static final AbstractDatabase dbAdapter = MetaCatUtil.dbAdapter;
102
103
    private boolean percentageSearch = false;
104
105
    private String userName = null;
106
107
    private static final String PUBLIC = "public";
108
109
    private String[] group = null;
110
111
    public static final String ATTRIBUTESYMBOL = "@";
112
113 3235 sledge
    public static final char PREDICATE_START = '[';
114
115
    public static final char PREDICATE_END = ']';
116
117 3308 tao
    //private boolean hasAttributeReturnField = false;
118 2067 jones
119 3308 tao
    //private Hashtable attributeReturnList = new Hashtable();
120 2067 jones
121 3308 tao
    //private int countAttributeReturnField = 0;
122 2067 jones
123 2093 tao
    private StringBuffer textBuffer = new StringBuffer();
124 3223 tao
125
126 2663 sgarg
    private static Logger logMetacat = Logger.getLogger(QuerySpecification.class);
127
128 2067 jones
    /**
129
     * construct an instance of the QuerySpecification class
130 2093 tao
     *
131 2067 jones
     * @param queryspec
132
     *            the XML representation of the query (should conform to
133
     *            pathquery.dtd) as a Reader
134
     * @param parserName
135
     *            the fully qualified name of a Java Class implementing the
136
     *            org.xml.sax.XMLReader interface
137
     */
138
    public QuerySpecification(Reader queryspec, String parserName,
139
            String accNumberSeparator) throws IOException
140
    {
141
        super();
142
143
        // Initialize the class variables
144
        returnDocList = new Vector();
145
        filterDocList = new Vector();
146
        elementStack = new Stack();
147
        queryStack = new Stack();
148
        returnFieldList = new Vector();
149
        ownerList = new Vector();
150
        this.parserName = parserName;
151
        this.accNumberSeparator = accNumberSeparator;
152
153
        // Initialize the parser and read the queryspec
154
        XMLReader parser = initializeParser();
155
        if (parser == null) {
156
            System.err.println("SAX parser not instantiated properly.");
157
        }
158
        try {
159
            parser.parse(new InputSource(queryspec));
160
        } catch (SAXException e) {
161
            System.err.println("error parsing data in "
162
                    + "QuerySpecification.QuerySpecification");
163
            System.err.println(e.getMessage());
164
        }
165 181 jones
    }
166 2067 jones
167
    /**
168
     * construct an instance of the QuerySpecification class
169 2093 tao
     *
170 2067 jones
     * @param queryspec
171
     *            the XML representation of the query (should conform to
172
     *            pathquery.dtd) as a String
173
     * @param parserName
174
     *            the fully qualified name of a Java Class implementing the
175
     *            org.xml.sax.Parser interface
176
     */
177
    public QuerySpecification(String queryspec, String parserName,
178
            String accNumberSeparator) throws IOException
179
    {
180
        this(new StringReader(queryspec), parserName, accNumberSeparator);
181 155 jones
    }
182
183 2067 jones
    /**
184
     * construct an instance of the QuerySpecification class which don't need
185
     * to parser a xml document
186 2093 tao
     *
187 2067 jones
     * @param accNumberSeparator
188
     *            the separator between doc version
189
     */
190
    public QuerySpecification(String accNumberSeparator) throws IOException
191 2045 tao
    {
192 2067 jones
        // Initialize the class variables
193
        returnDocList = new Vector();
194
        filterDocList = new Vector();
195
        elementStack = new Stack();
196
        queryStack = new Stack();
197
        returnFieldList = new Vector();
198
        ownerList = new Vector();
199
        this.accNumberSeparator = accNumberSeparator;
200 2045 tao
    }
201 2067 jones
202
    /**
203
     * Method to set user name
204 2093 tao
     *
205 2067 jones
     * @param myName
206
     *            the user name
207
     */
208
    public void setUserName(String myName)
209 2045 tao
    {
210 2067 jones
        //to lower case
211
        if (myName != null) {
212
            this.userName = myName.toLowerCase();
213
        } else {
214
            this.userName = myName;
215
        }
216 2045 tao
    }
217 2067 jones
218
    /**
219
     * Method to set user group
220 2093 tao
     *
221 2067 jones
     * @param myGroup
222
     *            the user group
223
     */
224
    public void setGroup(String[] myGroup)
225 1301 tao
    {
226 2067 jones
        this.group = myGroup;
227 1301 tao
    }
228 2067 jones
229
    /**
230
     * Method to indicate this query is a percentage search
231
     */
232
    public boolean isPercentageSearch()
233 1301 tao
    {
234 2067 jones
        return percentageSearch;
235 1301 tao
    }
236 2067 jones
237
    /*
238
     * Method to get owner query. If it is owner it has all permission
239
     */
240
    private String createOwerQuery()
241 1301 tao
    {
242 2067 jones
        String ownerQuery = null;
243 3223 tao
        //if user is public, we don't need to run owner query
244
        if (userName != null && !userName.equalsIgnoreCase(PUBLIC))
245
        {
246
	        ownerQuery = "SELECT docid FROM xml_documents WHERE ";
247
	        if (userName != null && !userName.equals("")) {
248
	            ownerQuery = ownerQuery + "lower(user_owner) ='" + userName + "'";
249
	        }
250 2067 jones
        }
251 2663 sgarg
        logMetacat.info("OwnerQuery: " + ownerQuery);
252 2067 jones
        return ownerQuery;
253
    }
254
255
    /*
256
     * Method to create query for xml_access, this part is to get docid list
257
     * which have a allow rule for a given user
258
     */
259
    private String createAllowRuleQuery()
260 1301 tao
    {
261 2067 jones
        String allowQuery = null;
262
        String allowString = constructAllowString();
263
        allowQuery = "SELECT docid from xml_access WHERE( " + allowString;
264 3312 tao
        allowQuery = allowQuery + ")";
265 2663 sgarg
        logMetacat.info("allow query is: " + allowQuery);
266 2067 jones
        return allowQuery;
267
268 1301 tao
    }
269 2067 jones
270
    /* Method to construct a allow rule string */
271
    private String constructAllowString()
272 1301 tao
    {
273 2067 jones
        String allowQuery = "";
274 3313 tao
275
       // add public
276
        allowQuery = "(lower(principal_name) = '" + PUBLIC
277
                + "'";
278
279
        // add user name
280
        if (userName != null && !userName.equals("") && !userName.equalsIgnoreCase(PUBLIC)) {
281
            allowQuery = allowQuery + "OR lower(principal_name) = '" + userName +"'";
282
283 2067 jones
        }
284 3313 tao
        // add  group
285 2067 jones
        if (group != null) {
286
            for (int i = 0; i < group.length; i++) {
287
                String groupUint = group[i];
288
                if (groupUint != null && !groupUint.equals("")) {
289
                    groupUint = groupUint.toLowerCase();
290 3313 tao
                    allowQuery = allowQuery + " OR lower(principal_name) = '"
291
                            + groupUint + "'";
292 2067 jones
                }//if
293
            }//for
294 1301 tao
        }//if
295 3313 tao
        // add allow rule
296
        allowQuery = allowQuery + ") AND perm_type = 'allow'" + " AND permission > 3";
297 2663 sgarg
        logMetacat.info("allow string is: " + allowQuery);
298 2067 jones
        return allowQuery;
299
    }
300 155 jones
301 2067 jones
    /*
302
     * Method to create query for xml_access, this part is to get docid list
303
     * which have a deny rule and perm_order is allowFirst for a given user.
304
     * This means the user will be denied to read
305
     */
306
    private String createDenyRuleQuery()
307
    {
308
        String denyQuery = null;
309
        String denyString = constructDenyString();
310
        denyQuery = "SELECT docid from xml_access WHERE( " + denyString;
311 3312 tao
        denyQuery = denyQuery + ") ";
312 2663 sgarg
        logMetacat.info("denyquery is: " + denyQuery);
313 2067 jones
        return denyQuery;
314 711 jones
315 2067 jones
    }
316 181 jones
317 2067 jones
    /* Construct deny string */
318
    private String constructDenyString()
319 402 berkley
    {
320 2067 jones
        String denyQuery = "";
321 3313 tao
322
        // add public
323
        denyQuery = "(lower(principal_name) = '" + PUBLIC
324
                 + "'";
325
326
         // add user name
327
         if (userName != null && !userName.equals("") && !userName.equalsIgnoreCase(PUBLIC)) {
328
        	 denyQuery = denyQuery + "OR lower(principal_name) = '" + userName +"'";
329
330
         }
331
         // add  groups
332
         if (group != null) {
333
             for (int i = 0; i < group.length; i++) {
334
                 String groupUint = group[i];
335
                 if (groupUint != null && !groupUint.equals("")) {
336
                     groupUint = groupUint.toLowerCase();
337
                     denyQuery = denyQuery + " OR lower(principal_name) = '"
338
                             + groupUint + "'";
339
                 }//if
340
             }//for
341
         }//if
342
         // add deny rules
343
         denyQuery = denyQuery + ") AND perm_type = 'deny'" +  " AND perm_order ='allowFirst'" +" AND permission > 3";
344
         logMetacat.info("allow string is: " + denyQuery);
345
         return denyQuery;
346
347 402 berkley
    }
348 2067 jones
349
    /**
350
     * Method to append a access control query to SQL. So in DBQuery class, we
351
     * can get docid from both user specified query and access control query.
352
     * We don't need to checking permission after we get the doclist. It will
353
     * be good to performance
354 2093 tao
     *
355 2067 jones
     */
356
    public String getAccessQuery()
357 402 berkley
    {
358 2067 jones
        String accessQuery = null;
359
        String onwer = createOwerQuery();
360
        String allow = createAllowRuleQuery();
361
        String deny = createDenyRuleQuery();
362 3313 tao
        //logMetacat.warn("onwer " +onwer);
363
        //logMetacat.warn("allow "+allow);
364
        //logMetacat.warn("deny "+deny);
365 3223 tao
        if (onwer != null)
366
        {
367
          accessQuery = " AND (docid IN(" + onwer + ")";
368
          accessQuery = accessQuery + " OR (docid IN (" + allow + ")"
369 2067 jones
                + " AND docid NOT IN (" + deny + ")))";
370 3223 tao
        }
371
        else
372
        {
373
        	accessQuery = " AND (docid IN (" + allow + ")"
374
                + " AND docid NOT IN (" + deny + "))";
375
        }
376 3313 tao
        logMetacat.warn("accessquery is: " + accessQuery);
377 2067 jones
        return accessQuery;
378 402 berkley
    }
379 745 jones
380 2067 jones
    /**
381
     * Returns true if the parsed query contains and extended xml query (i.e.
382
     * there is at least one &lt;returnfield&gt; in the pathquery document)
383
     */
384
    public boolean containsExtendedSQL()
385
    {
386
        if (containsExtendedSQL) {
387
            return true;
388
        } else {
389
            return false;
390
        }
391
    }
392 745 jones
393 3308 tao
394 2067 jones
    /**
395
     * Accessor method to return the identifier of this Query
396
     */
397
    public String getIdentifier()
398
    {
399
        return meta_file_id;
400
    }
401 155 jones
402 2067 jones
    /**
403
     * method to set the identifier of this query
404
     */
405
    public void setIdentifier(String id)
406
    {
407
        this.meta_file_id = id;
408
    }
409 745 jones
410 2067 jones
    /**
411
     * Accessor method to return the title of this Query
412
     */
413
    public String getQueryTitle()
414
    {
415
        return queryTitle;
416
    }
417 745 jones
418 2067 jones
    /**
419
     * method to set the title of this query
420
     */
421
    public void setQueryTitle(String title)
422
    {
423
        this.queryTitle = title;
424
    }
425 745 jones
426 2067 jones
    /**
427
     * Accessor method to return a vector of the return document types as
428
     * defined in the &lt;returndoctype&gt; tag in the pathquery dtd.
429
     */
430
    public Vector getReturnDocList()
431
    {
432
        return this.returnDocList;
433
    }
434 745 jones
435 2067 jones
    /**
436
     * method to set the list of return docs of this query
437
     */
438
    public void setReturnDocList(Vector returnDocList)
439
    {
440
        this.returnDocList = returnDocList;
441
    }
442 745 jones
443 2067 jones
    /**
444
     * Accessor method to return a vector of the filter doc types as defined in
445
     * the &lt;filterdoctype&gt; tag in the pathquery dtd.
446
     */
447
    public Vector getFilterDocList()
448
    {
449
        return this.filterDocList;
450
    }
451 172 jones
452 2067 jones
    /**
453
     * method to set the list of filter docs of this query
454
     */
455
    public void setFilterDocList(Vector filterDocList)
456
    {
457
        this.filterDocList = filterDocList;
458
    }
459 155 jones
460 2067 jones
    /**
461
     * Accessor method to return a vector of the extended return fields as
462
     * defined in the &lt;returnfield&gt; tag in the pathquery dtd.
463
     */
464
    public Vector getReturnFieldList()
465
    {
466
        return this.returnFieldList;
467
    }
468 155 jones
469 2067 jones
    /**
470
     * method to set the list of fields to be returned by this query
471
     */
472
    public void setReturnFieldList(Vector returnFieldList)
473
    {
474
        this.returnFieldList = returnFieldList;
475
    }
476 155 jones
477 2067 jones
    /**
478
     * Accessor method to return a vector of the owner fields as defined in the
479
     * &lt;owner&gt; tag in the pathquery dtd.
480
     */
481
    public Vector getOwnerList()
482
    {
483
        return this.ownerList;
484
    }
485 155 jones
486 2067 jones
    /**
487
     * method to set the list of owners used to constrain this query
488
     */
489
    public void setOwnerList(Vector ownerList)
490
    {
491
        this.ownerList = ownerList;
492 155 jones
    }
493
494 2067 jones
    /**
495
     * get the QueryGroup used to express query constraints
496
     */
497
    public QueryGroup getQueryGroup()
498
    {
499
        return query;
500 158 jones
    }
501 155 jones
502 2067 jones
    /**
503
     * set the querygroup
504
     */
505
    public void setQueryGroup(QueryGroup group)
506
    {
507
        query = group;
508 158 jones
    }
509
510 2067 jones
    /**
511
     * set if this query sepcification has extendQuery(has return doc type or
512
     * not)
513
     */
514
    public void setContainsExtenedSQL(boolean hasExtenedQuery)
515
    {
516
        containsExtendedSQL = hasExtenedQuery;
517
    }
518 158 jones
519 2067 jones
    /**
520
     * Set up the SAX parser for reading the XML serialized query
521
     */
522
    private XMLReader initializeParser()
523
    {
524
        XMLReader parser = null;
525
526
        // Set up the SAX document handlers for parsing
527
        try {
528
529
            // Get an instance of the parser
530
            parser = XMLReaderFactory.createXMLReader(parserName);
531
532
            // Set the ContentHandler to this instance
533
            parser.setContentHandler(this);
534
535
            // Set the error Handler to this instance
536
            parser.setErrorHandler(this);
537
538
        } catch (Exception e) {
539
            System.err.println("Error in QuerySpcecification.initializeParser "
540
                    + e.toString());
541
        }
542
543
        return parser;
544 1833 tao
    }
545 170 jones
546 2067 jones
    /**
547
     * callback method used by the SAX Parser when the start tag of an element
548
     * is detected. Used in this context to parse and store the query
549
     * information in class variables.
550
     */
551
    public void startElement(String uri, String localName, String qName,
552
            Attributes atts) throws SAXException
553
    {
554
        BasicNode currentNode = new BasicNode(localName);
555
        // add attributes to BasicNode here
556
        if (atts != null) {
557
            int len = atts.getLength();
558
            for (int i = 0; i < len; i++) {
559
                currentNode
560
                        .setAttribute(atts.getLocalName(i), atts.getValue(i));
561
            }
562
        }
563 170 jones
564 2067 jones
        elementStack.push(currentNode);
565
        if (currentNode.getTagName().equals("querygroup")) {
566
            QueryGroup currentGroup = new QueryGroup(currentNode
567
                    .getAttribute("operator"));
568
            if (query == null) {
569
                query = currentGroup;
570
            } else {
571
                QueryGroup parentGroup = (QueryGroup) queryStack.peek();
572
                parentGroup.addChild(currentGroup);
573
            }
574
            queryStack.push(currentGroup);
575
        }
576
    }
577 172 jones
578 2067 jones
    /**
579
     * callback method used by the SAX Parser when the end tag of an element is
580
     * detected. Used in this context to parse and store the query information
581
     * in class variables.
582
     */
583
    public void endElement(String uri, String localName, String qName)
584
            throws SAXException
585
    {
586
        BasicNode leaving = (BasicNode) elementStack.pop();
587
        if (leaving.getTagName().equals("queryterm")) {
588
            boolean isCaseSensitive = (new Boolean(leaving
589
                    .getAttribute("casesensitive"))).booleanValue();
590
            QueryTerm currentTerm = null;
591
            if (currentPathexpr == null) {
592
                currentTerm = new QueryTerm(isCaseSensitive, leaving
593
                        .getAttribute("searchmode"), currentValue);
594
            } else {
595
                currentTerm = new QueryTerm(isCaseSensitive, leaving
596
                        .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 2093 tao
        } else if (leaving.getTagName().equals("meta_file_id")) {
606
              meta_file_id = textBuffer.toString().trim();
607
        } else if (leaving.getTagName().equals("querytitle")) {
608
              queryTitle = textBuffer.toString().trim();
609
        } else if (leaving.getTagName().equals("value")) {
610
              currentValue = textBuffer.toString().trim();
611
        } else if (leaving.getTagName().equals("pathexpr")) {
612
              currentPathexpr = textBuffer.toString().trim();
613
        } else if (leaving.getTagName().equals("returndoctype")) {
614
              returnDocList.add(textBuffer.toString().trim());
615
        } else if (leaving.getTagName().equals("filterdoctype")) {
616
              filterDocList.add(textBuffer.toString().trim());
617
        } else if (leaving.getTagName().equals("returnfield")) {
618
              handleReturnField(textBuffer.toString().trim());
619
        } else if (leaving.getTagName().equals("filterdoctype")) {
620
              filterDocList.add(textBuffer.toString().trim());
621
        } else if (leaving.getTagName().equals("owner")) {
622
              ownerList.add(textBuffer.toString().trim());
623 172 jones
        }
624 2093 tao
625
        //rest textBuffer
626
        textBuffer = new StringBuffer();
627
628 172 jones
    }
629 743 jones
630 2067 jones
    /**
631
     * callback method used by the SAX Parser when the text sequences of an xml
632
     * stream are detected. Used in this context to parse and store the query
633
     * information in class variables.
634
     */
635
    public void characters(char ch[], int start, int length)
636
    {
637 2093 tao
      // buffer all text nodes for same element. This is for text was splited
638
      // into different nodes
639
      textBuffer.append(new String(ch, start, length));
640 2067 jones
641
    }
642
643 3358 tao
   /**
644
    * Method to handle return field. It will be callied in ecogrid part
645
    * @param inputString
646
    */
647
    public void handleReturnField(String inputString)
648 3235 sledge
    {
649
        int attributePos = inputString.indexOf(ATTRIBUTESYMBOL);
650
        int predicateStart = -1;
651
        int predicateEnd;
652
        boolean hasPredicate = false;
653 535 jones
654 3235 sledge
        while (true)
655
        {
656
            predicateStart = inputString.indexOf(PREDICATE_START, predicateStart + 1);
657
658
            if (attributePos == -1)
659
                break;
660
661
            if (predicateStart == -1)
662
                break;
663
664
            hasPredicate = true;
665
666
            if (attributePos < predicateStart)
667
                break;
668
669
            predicateEnd = inputString.indexOf(PREDICATE_END, predicateStart);
670
671
            if (predicateEnd == -1)
672
            {
673
                logMetacat.warn("handleReturnField(): ");
674
                logMetacat.warn("    Invalid path: " + inputString);
675
                return;
676
            }
677
678
            while (attributePos < predicateEnd)
679
            {
680
                attributePos = inputString.indexOf(ATTRIBUTESYMBOL, attributePos + 1);
681
682
                if (attributePos == -1)
683
                    break;
684
            }
685
        }
686
687
        if (hasPredicate)
688
            containsPredicates = true;
689
690
        containsExtendedSQL = true;
691
692 3308 tao
693 3235 sledge
            // no attribute value will be returned
694
            logMetacat.info("QuerySpecification.handleReturnField(): " );
695
            logMetacat.info("  there are no attributes in the XPATH statement" );
696
            returnFieldList.add(inputString);
697 3308 tao
698 3235 sledge
699 3308 tao
700 3235 sledge
    }
701
702 2067 jones
    /**
703
     * create a SQL serialization of the query that this instance represents
704
     */
705
    public String printSQL(boolean useXMLIndex)
706
    {
707
708
        StringBuffer self = new StringBuffer();
709 2366 sgarg
        StringBuffer queryString = new StringBuffer();
710 2067 jones
711 2366 sgarg
        queryString.append("SELECT docid,docname,doctype,");
712
        queryString.append("date_created, date_updated, rev ");
713
        queryString.append("FROM xml_documents WHERE");
714 2067 jones
715 2366 sgarg
        // Get the query from the QueryGroup and check
716
        // if no query has been returned
717
        String queryFromQueryGroup = query.printSQL(useXMLIndex);
718 2677 sgarg
        logMetacat.info("Query from query in QuerySpec.printSQL: "
719
        		+ queryFromQueryGroup);
720
721 2373 sgarg
        if(!queryFromQueryGroup.trim().equals("")){
722 2366 sgarg
            self.append(" docid IN (");
723 2373 sgarg
            self.append(queryFromQueryGroup);
724 2366 sgarg
            self.append(") ");
725
        }
726 2067 jones
727
        // Add SQL to filter for doctypes requested in the query
728
        // This is an implicit OR for the list of doctypes. Only doctypes in
729
        // this
730
        // list will be searched if the tag is present
731
        if (!filterDocList.isEmpty()) {
732
            boolean firstdoctype = true;
733 2366 sgarg
            boolean emptyString = true;
734
735
            if(!self.toString().equals("")){
736
                self.append(" AND (");
737
                emptyString = false;
738
            }
739
740 2067 jones
            Enumeration en = filterDocList.elements();
741
            while (en.hasMoreElements()) {
742
                String currentDoctype = (String) en.nextElement();
743
                if (firstdoctype) {
744
                    firstdoctype = false;
745
                    self.append(" doctype = '" + currentDoctype + "'");
746
                } else {
747
                    self.append(" OR doctype = '" + currentDoctype + "'");
748
                }
749
            }
750 2366 sgarg
751
            if(!emptyString){
752
                self.append(") ");
753
            }
754 535 jones
        }
755 2067 jones
756
        // Add SQL to filter for owners requested in the query
757
        // This is an implicit OR for the list of owners
758
        if (!ownerList.isEmpty()) {
759
            boolean first = true;
760 2366 sgarg
            boolean emptyString = true;
761
762
            if(!self.toString().equals("")){
763
                self.append(" AND (");
764
                emptyString = false;
765
            }
766
767 2067 jones
            Enumeration en = ownerList.elements();
768
            while (en.hasMoreElements()) {
769
                String current = (String) en.nextElement();
770
                if (current != null) {
771
                    current = current.toLowerCase();
772
                }
773
                if (first) {
774
                    first = false;
775
                    self.append(" lower(user_owner) = '" + current + "'");
776
                } else {
777
                    self.append(" OR lower(user_owner) = '" + current + "'");
778
                }
779
            }
780 2366 sgarg
781
            if(!emptyString){
782
                self.append(") ");
783
            }
784 2067 jones
        }
785
786
        // if there is only one percentage search item, this query is a
787
        // percentage
788
        // search query
789 2663 sgarg
        logMetacat.info("percentage number: "
790
                + query.getPercentageSymbolCount());
791 2067 jones
        if (query.getPercentageSymbolCount() == 1) {
792 2663 sgarg
            logMetacat.info("It is a percentage search");
793 2067 jones
            percentageSearch = true;
794
        }
795
796 2366 sgarg
        queryString.append(self.toString());
797
        return queryString.toString();
798 535 jones
    }
799 2067 jones
800 3355 tao
801 2067 jones
802
    /**
803
     * This method prints sql based upon the &lt;returnfield&gt; tag in the
804 2069 jones
     * pathquery document. This allows for customization of the returned fields.
805 2093 tao
     * If the boolean useXMLIndex paramter is false, it uses a recursive query on
806
     * xml_nodes to find the fields to be included by their path expression, and
807 2069 jones
     * avoids the use of the xml_index table.
808 2093 tao
     *
809 2073 jones
     * @param doclist the list of document ids to search
810 2093 tao
     * @param unaccessableNodePair the node pairs (start id and end id) which
811 2073 jones
     *            this user should not access
812 2093 tao
     * @param useXMLIndex a boolean flag indicating whether to search using
813 2073 jones
     *            xml_index
814 2069 jones
     */
815 3248 tao
    public String printExtendedSQL(String doclist, boolean useXMLIndex)
816 2069 jones
    {
817 3235 sledge
        if (useXMLIndex && !containsPredicates)
818
        {
819 3248 tao
            return printExtendedSQL(doclist);
820 3235 sledge
        }
821
        else
822
        {
823 2069 jones
            StringBuffer self = new StringBuffer();
824
825
            boolean firstfield = true;
826
            //put the returnfields into the query
827
            //the for loop allows for multiple fields
828 3235 sledge
            for (int i = 0; i < returnFieldList.size(); i++)
829
            {
830
                if (firstfield)
831
                {
832 2069 jones
                    firstfield = false;
833 3235 sledge
                }
834
                else
835
                {
836 2093 tao
                    self.append(" UNION ");
837 2069 jones
                }
838
                String path  = (String) returnFieldList.elementAt(i);
839
                self.append("select xml_nodes.docid, ");
840 3634 leinfelder
                self.append("'"+ path.replaceAll("'", "''") + "' as path, ");
841
                self.append("xml_nodes.nodedata, ");
842
                self.append("xml_nodes.parentnodeid, ");
843
                self.append("xml_nodes.nodetype ");
844 2069 jones
                self.append("from xml_nodes, xml_documents ");
845
                self.append("where parentnodeid IN ");
846
                self.append(QueryTerm.useNestedStatements(path));
847 2093 tao
848 2069 jones
                self.append(" AND xml_nodes.docid in (");
849
                self.append(doclist);
850 2073 jones
                self.append(") AND xml_nodes.nodetype = 'TEXT'");
851 2069 jones
                self.append(" AND xml_nodes.rootnodeid = xml_documents.rootnodeid");
852 2093 tao
853 3248 tao
                //addAccessRestrictionSQL(unaccessableNodePair, self);
854 2069 jones
            }
855
856
            return self.toString();
857
        }
858
    }
859 2093 tao
860 2069 jones
    /**
861
     * This method prints sql based upon the &lt;returnfield&gt; tag in the
862
     * pathquery document. This allows for customization of the returned fields.
863
     * It uses the xml_index table and so assumes that this table has been
864
     * built.
865 2093 tao
     *
866 2073 jones
     * @param doclist the list of document ids to search
867 2093 tao
     * @param unaccessableNodePair the node pairs (start id and end id)
868 2073 jones
     *            which this user should not access
869 2067 jones
     */
870 3355 tao
    private String printExtendedSQL(String doclist)
871 402 berkley
    {
872 2663 sgarg
        logMetacat.info("querySpecification.printExtendedSQL called\n");
873 2067 jones
        StringBuffer self = new StringBuffer();
874 3355 tao
        Vector elementVector = new Vector();
875
        Vector attributeVector = new Vector();
876 2472 cjones
877 2523 sgarg
        boolean usePathIndex = true;
878 2434 sgarg
879 2523 sgarg
        // test if the are elements in the return fields
880
        if ( returnFieldList.size() == 0 ) {
881
            return null;
882
        }
883 2067 jones
884 2523 sgarg
        for (int i = 0; i < returnFieldList.size(); i++) {
885 3355 tao
        	String path = (String)returnFieldList.elementAt(i);
886 3360 tao
        	if (path != null && path.indexOf(ATTRIBUTESYMBOL) != -1)
887 3355 tao
        	{
888
        		attributeVector.add(path);
889
        	}
890
        	else
891
        	{
892
        		elementVector.add(path);
893
        	}
894
            if(!MetaCatUtil.pathsForIndexing.contains(path)){
895
                usePathIndex = false;
896 2523 sgarg
            }
897 3355 tao
898 2523 sgarg
        }
899 3355 tao
        // check if has return field
900
        if (elementVector.size() == 0 && attributeVector.size()==0)
901
        {
902
        	return null;
903
        }
904 2073 jones
905 2523 sgarg
        if(usePathIndex){
906 3634 leinfelder
            self.append("select docid, path, nodedata, parentnodeid, nodetype ");
907 3355 tao
            self.append("from xml_path_index where path in( '");
908 2523 sgarg
909
            boolean firstfield = true;
910
            //put the returnfields into the query
911
            //the for loop allows for multiple fields
912
            for (int i = 0; i < returnFieldList.size(); i++) {
913
                if (firstfield) {
914
                    firstfield = false;
915
                    self.append( (String) returnFieldList.elementAt(i));
916
                    self.append("' ");
917
                }
918
                else {
919 3355 tao
                    self.append(", '");
920 2523 sgarg
                    self.append( (String) returnFieldList.elementAt(i));
921
                    self.append("' ");
922
                }
923
            }
924
            self.append(") AND docid in (");
925
            self.append(doclist);
926
            self.append(")");
927
928
        } else {
929
            self.append("select xml_nodes.docid, xml_index.path, xml_nodes.nodedata,  ");
930 3634 leinfelder
            self.append("xml_nodes.parentnodeid, ");
931
            self.append("xml_nodes.nodetype ");
932 3355 tao
            self.append("FROM xml_index, xml_nodes WHERE (");
933
934 2523 sgarg
935 3355 tao
            boolean firstElement = true;
936
            boolean firstAttribute = true;
937 2523 sgarg
            //put the returnfields into the query
938
            //the for loop allows for multiple fields
939 3355 tao
            if (elementVector.size() != 0)
940
            {
941
	            for (int i = 0; i < elementVector.size(); i++) {
942
	            	String path = (String) elementVector.elementAt(i);
943
	                if (firstElement) {
944
	                	firstElement = false;
945
	                	self.append(" (xml_index.nodeid=xml_nodes.parentnodeid AND xml_index.path IN ('");
946
	                    self.append(path);
947
	                    self.append("'");
948
	                 }
949
	                else
950
	                {
951
	                    self.append(", '");
952
	                    self.append(path);
953
	                    self.append("' ");
954
	                }
955
	            }
956
	            self.append(") AND xml_nodes.nodetype = 'TEXT')");
957 2523 sgarg
            }
958 3355 tao
959
            if (attributeVector.size() != 0)
960
            {
961
            	for (int j=0; j<attributeVector.size(); j++)
962
            	{
963
            		String path = (String) attributeVector.elementAt(j);
964
            		if (firstAttribute)
965
            		{
966
            			firstAttribute = false;
967
            			if (!firstElement)
968
                		{
969
                			self.append(" OR ");
970
                		}
971
            			self.append(" (xml_index.nodeid=xml_nodes.nodeid AND ( xml_index.path IN ( '");
972
	                    self.append(path);
973
	                    self.append("'");
974
            		}
975
            		else
976
	                {
977
	                    self.append(", '");
978
	                    self.append(path);
979
	                    self.append("' ");
980
	                }
981
            	}
982
            	self.append(") AND xml_nodes.nodetype = 'ATTRIBUTE'))");
983
            }
984
985
986 2523 sgarg
            self.append(") AND xml_nodes.docid in (");
987
            self.append(doclist);
988 3355 tao
            self.append(")");
989 2523 sgarg
990
        }
991
992
        return self.toString();
993 2073 jones
    }
994
995 2419 sgarg
996 2073 jones
    /**
997 2419 sgarg
     * Method to return a String generated after sorting the returnFieldList
998
     * Vector
999
     */
1000
    public String getSortedReturnFieldString(){
1001
        String returnFields = "";
1002
1003
        // Create a temporary vector and copy returnFieldList into it
1004
        Vector tempVector = new Vector();
1005 2464 sgarg
1006 2419 sgarg
        Iterator it = returnFieldList.iterator();
1007
        while(it.hasNext()){
1008
            tempVector.add(it.next());
1009
        }
1010
1011 3308 tao
        /*Enumeration attEnum = attributeReturnList.elements();
1012 2464 sgarg
        while(attEnum.hasMoreElements()){
1013
            Iterator tempIt = ((Vector)attEnum.nextElement()).iterator();
1014
	    String rfield = "";
1015
            if(tempIt.hasNext()){
1016
		String element = (String)tempIt.next();
1017 2474 sgarg
		if(element != null) {
1018
		    rfield +=element;
1019 2464 sgarg
		}
1020
	    }
1021
            if(tempIt.hasNext()){
1022
		String attribute = (String)tempIt.next();
1023 2474 sgarg
		if(attribute != null) {
1024
  		    rfield = rfield + "@" + attribute;
1025 2464 sgarg
                }
1026
	    }
1027
            tempVector.add(rfield);
1028 3308 tao
        }*/
1029 2464 sgarg
1030 2419 sgarg
        // Sort the temporary vector
1031
        java.util.Collections.sort(tempVector);
1032
1033
        // Generate the string and return it
1034
        it = tempVector.iterator();
1035
        while(it.hasNext()){
1036
            returnFields = returnFields + it.next() + "|";
1037
        }
1038
        return returnFields;
1039
    }
1040
1041
1042 3355 tao
1043 2067 jones
1044 2074 jones
1045 2067 jones
    public static String printRelationSQL(String docid)
1046 1354 tao
    {
1047 2067 jones
        StringBuffer self = new StringBuffer();
1048
        self.append("select subject, relationship, object, subdoctype, ");
1049
        self.append("objdoctype from xml_relation ");
1050
        self.append("where docid like '").append(docid).append("'");
1051
        return self.toString();
1052 1354 tao
    }
1053 2066 jones
1054 2067 jones
    public static String printGetDocByDoctypeSQL(String docid)
1055
    {
1056
        StringBuffer self = new StringBuffer();
1057 465 berkley
1058 2067 jones
        self.append("SELECT docid,docname,doctype,");
1059
        self.append("date_created, date_updated ");
1060
        self.append("FROM xml_documents WHERE docid IN (");
1061
        self.append(docid).append(")");
1062
        return self.toString();
1063
    }
1064 159 jones
1065 2067 jones
    /**
1066
     * create a String description of the query that this instance represents.
1067
     * This should become a way to get the XML serialization of the query.
1068
     */
1069
    public String toString()
1070
    {
1071
        return "meta_file_id=" + meta_file_id + "\n" + query;
1072
        //DOCTITLE attr cleared from the db
1073
        //return "meta_file_id=" + meta_file_id + "\n" +
1074
        //"querytitle=" + querytitle + "\n" + query;
1075
    }
1076
1077 2073 jones
    /** A method to get rid of attribute part in path expression */
1078 2067 jones
    public static String newPathExpressionWithOutAttribute(String pathExpression)
1079
    {
1080
        if (pathExpression == null) { return null; }
1081
        int index = pathExpression.lastIndexOf(ATTRIBUTESYMBOL);
1082
        String newExpression = null;
1083 2458 cjones
        if (index != 0) {
1084 2067 jones
            newExpression = pathExpression.substring(0, index - 1);
1085
        }
1086 2663 sgarg
        logMetacat.info("The path expression without attributes: "
1087
                + newExpression);
1088 2067 jones
        return newExpression;
1089
    }
1090
1091 2073 jones
    /** A method to get attribute name from path */
1092 2067 jones
    public static String getAttributeName(String path)
1093
    {
1094
        if (path == null) { return null; }
1095
        int index = path.lastIndexOf(ATTRIBUTESYMBOL);
1096
        int size = path.length();
1097
        String attributeName = null;
1098
        if (index != 1) {
1099
            attributeName = path.substring(index + 1, size);
1100
        }
1101 2663 sgarg
        logMetacat.info("The attirbute name from path: "
1102
                + attributeName);
1103 2067 jones
        return attributeName;
1104
    }
1105
1106 155 jones
}