Project

General

Profile

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