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